kstlib 1.0.2__py3-none-any.whl → 1.1.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
kstlib/rapi/exceptions.py CHANGED
@@ -203,11 +203,175 @@ class ResponseTooLargeError(RapiError):
203
203
  self.max_size = max_size
204
204
 
205
205
 
206
+ class ConfirmationRequiredError(RapiError):
207
+ """Raised when a dangerous endpoint requires confirmation.
208
+
209
+ This exception is raised at runtime when calling an endpoint
210
+ that has a safeguard configured but the confirm parameter is
211
+ missing or incorrect.
212
+
213
+ Attributes:
214
+ endpoint_ref: Full endpoint reference (api.endpoint).
215
+ expected: Expected confirmation string.
216
+ actual: Actual confirmation string provided (None if missing).
217
+
218
+ Examples:
219
+ >>> raise ConfirmationRequiredError("api.delete", expected="DELETE X")
220
+ Traceback (most recent call last):
221
+ ...
222
+ kstlib.rapi.exceptions.ConfirmationRequiredError: ... requires confirmation...
223
+ """
224
+
225
+ def __init__(
226
+ self,
227
+ endpoint_ref: str,
228
+ *,
229
+ expected: str,
230
+ actual: str | None = None,
231
+ ) -> None:
232
+ """Initialize ConfirmationRequiredError.
233
+
234
+ Args:
235
+ endpoint_ref: Full endpoint reference (api.endpoint).
236
+ expected: Expected confirmation string.
237
+ actual: Actual confirmation string provided (None if missing).
238
+ """
239
+ if actual is None:
240
+ message = f"Endpoint '{endpoint_ref}' requires confirmation. Pass confirm=\"{expected}\" to proceed."
241
+ else:
242
+ message = f'Confirmation mismatch for \'{endpoint_ref}\'. Expected: "{expected}", got: "{actual}"'
243
+ super().__init__(
244
+ message,
245
+ details={
246
+ "endpoint_ref": endpoint_ref,
247
+ "expected": expected,
248
+ "actual": actual,
249
+ },
250
+ )
251
+ self.endpoint_ref = endpoint_ref
252
+ self.expected = expected
253
+ self.actual = actual
254
+
255
+
256
+ class SafeguardMissingError(RapiError):
257
+ """Raised when endpoint requires safeguard but none is configured.
258
+
259
+ This exception is raised at config load time when an endpoint uses
260
+ a method that requires a safeguard (e.g., DELETE, PUT) but no
261
+ safeguard string is provided in the endpoint configuration.
262
+
263
+ Attributes:
264
+ endpoint_ref: Full endpoint reference (api.endpoint).
265
+ method: HTTP method that requires the safeguard.
266
+
267
+ Examples:
268
+ >>> raise SafeguardMissingError("api.delete", "DELETE")
269
+ Traceback (most recent call last):
270
+ ...
271
+ kstlib.rapi.exceptions.SafeguardMissingError: ... requires a safeguard...
272
+ """
273
+
274
+ def __init__(self, endpoint_ref: str, method: str) -> None:
275
+ """Initialize SafeguardMissingError.
276
+
277
+ Args:
278
+ endpoint_ref: Full endpoint reference (api.endpoint).
279
+ method: HTTP method that requires the safeguard.
280
+ """
281
+ message = (
282
+ f"Endpoint '{endpoint_ref}' uses method {method} which requires a safeguard. "
283
+ f"Add 'safeguard: \"...\"' to the endpoint or remove {method} from "
284
+ f"rapi.safeguard.required_methods in kstlib.conf.yml."
285
+ )
286
+ super().__init__(
287
+ message,
288
+ details={"endpoint_ref": endpoint_ref, "method": method},
289
+ )
290
+ self.endpoint_ref = endpoint_ref
291
+ self.method = method
292
+
293
+
294
+ class EndpointCollisionError(RapiError):
295
+ """Raised when endpoints collide in strict mode.
296
+
297
+ This exception is raised at config load time when the same endpoint
298
+ reference is defined in multiple files and strict mode is enabled.
299
+
300
+ Attributes:
301
+ endpoint_ref: Full endpoint reference (api.endpoint).
302
+ source_files: List of files defining this endpoint.
303
+
304
+ Examples:
305
+ >>> raise EndpointCollisionError("api.create", ["a.rapi.yml", "b.rapi.yml"])
306
+ Traceback (most recent call last):
307
+ ...
308
+ kstlib.rapi.exceptions.EndpointCollisionError: Endpoint 'api.create' defined in multiple files...
309
+ """
310
+
311
+ def __init__(self, endpoint_ref: str, source_files: list[str]) -> None:
312
+ """Initialize EndpointCollisionError.
313
+
314
+ Args:
315
+ endpoint_ref: Full endpoint reference (api.endpoint).
316
+ source_files: List of files defining this endpoint.
317
+ """
318
+ message = (
319
+ f"Endpoint '{endpoint_ref}' defined in multiple files: {', '.join(source_files)}. "
320
+ f"Set rapi.strict: false to allow overwriting (last file wins)."
321
+ )
322
+ super().__init__(
323
+ message,
324
+ details={"endpoint_ref": endpoint_ref, "source_files": source_files},
325
+ )
326
+ self.endpoint_ref = endpoint_ref
327
+ self.source_files = source_files
328
+
329
+
330
+ class EnvVarError(RapiError):
331
+ """Raised when environment variable substitution fails.
332
+
333
+ This exception is raised at config load time when a required
334
+ environment variable is not set and no default value is provided.
335
+
336
+ Attributes:
337
+ var_name: Name of the missing environment variable.
338
+ source: Source file or context where the variable was referenced.
339
+
340
+ Examples:
341
+ >>> raise EnvVarError("VIYA_HOST")
342
+ Traceback (most recent call last):
343
+ ...
344
+ kstlib.rapi.exceptions.EnvVarError: Environment variable 'VIYA_HOST' is not set...
345
+ """
346
+
347
+ def __init__(self, var_name: str, source: str | None = None) -> None:
348
+ """Initialize EnvVarError.
349
+
350
+ Args:
351
+ var_name: Name of the missing environment variable.
352
+ source: Source file or context where the variable was referenced.
353
+ """
354
+ if source:
355
+ message = f"Environment variable '{var_name}' is not set (required by {source}). Use ${{VAR:-default}} for optional variables."
356
+ else:
357
+ message = f"Environment variable '{var_name}' is not set. Use ${{VAR:-default}} for optional variables."
358
+ super().__init__(
359
+ message,
360
+ details={"var_name": var_name, "source": source},
361
+ )
362
+ self.var_name = var_name
363
+ self.source = source
364
+
365
+
206
366
  __all__ = [
367
+ "ConfirmationRequiredError",
207
368
  "CredentialError",
208
369
  "EndpointAmbiguousError",
370
+ "EndpointCollisionError",
209
371
  "EndpointNotFoundError",
372
+ "EnvVarError",
210
373
  "RapiError",
211
374
  "RequestError",
212
375
  "ResponseTooLargeError",
376
+ "SafeguardMissingError",
213
377
  ]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kstlib
3
- Version: 1.0.2
3
+ Version: 1.1.1
4
4
  Summary: Config-driven helpers for Python projects (dynamic config, secure secrets, preset logging, and more…)
5
5
  Author-email: Michel TRUONG <michel.truong@gmail.com>
6
6
  Maintainer-email: Michel TRUONG <michel.truong@gmail.com>
@@ -9,15 +9,20 @@ Project-URL: Homepage, https://github.com/KaminoU/kstlib
9
9
  Project-URL: Repository, https://github.com/KaminoU/kstlib
10
10
  Project-URL: Bug Tracker, https://github.com/KaminoU/kstlib/issues
11
11
  Project-URL: Changelog, https://github.com/KaminoU/kstlib/blob/main/CHANGELOG.md
12
- Keywords: kstlib
12
+ Keywords: kstlib,config,configuration,yaml,secrets,sops,logging,oauth2,oidc,rest-api,http-client,resilience,circuit-breaker,rate-limiter,websocket,alerts,toolkit
13
13
  Classifier: Development Status :: 5 - Production/Stable
14
+ Classifier: Environment :: Console
14
15
  Classifier: Intended Audience :: Developers
16
+ Classifier: Operating System :: OS Independent
15
17
  Classifier: Programming Language :: Python :: 3
16
18
  Classifier: Programming Language :: Python :: 3.10
17
19
  Classifier: Programming Language :: Python :: 3.11
18
20
  Classifier: Programming Language :: Python :: 3.12
19
21
  Classifier: Programming Language :: Python :: 3.13
20
22
  Classifier: Programming Language :: Python :: 3.14
23
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
+ Classifier: Topic :: System :: Systems Administration
25
+ Classifier: Typing :: Typed
21
26
  Requires-Python: >=3.10
22
27
  Description-Content-Type: text/markdown
23
28
  License-File: LICENSE.md
@@ -1,8 +1,8 @@
1
1
  kstlib/__init__.py,sha256=MO6fLXlSp_EKA-itBMmPMPoQDLja9MTMxGSgMFicaZE,10518
2
2
  kstlib/__main__.py,sha256=l9-cxF6BGDYCb-giF4hDEewFv5ytrhKZTxfsVenUB3A,323
3
- kstlib/kstlib.conf.yml,sha256=6NJznp7xBilNexSpRWHpxPVWH_fIs25vVjcKYVIXiNA,29616
3
+ kstlib/kstlib.conf.yml,sha256=qqfg4rfEtJAXkE5ujML864yq46lGQaSN2p0PTPgJegA,30040
4
4
  kstlib/limits.py,sha256=i3E1O_qvniUlJoyzh6Gv14h7faqxEwydX6Gk6uOHCFo,31578
5
- kstlib/meta.py,sha256=UN-1r-en-rXM3Af5DFGGbx5Q37BoBUuHD-Niy6vGOKk,6149
5
+ kstlib/meta.py,sha256=7CG0R4S3ZyZSjuNBKTiyHvdbJCP_D1VcND_nmpApfmU,6149
6
6
  kstlib/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
7
  kstlib/ssl.py,sha256=LudzVfYFAoSxKFyEzACQlYnjPmuusoRl4tAPPsdBBmU,10355
8
8
  kstlib/alerts/__init__.py,sha256=mixRr15D5jIhoyLWn6PWrZI6K-urwuw0aMBzMGhqTXQ,3153
@@ -51,13 +51,13 @@ kstlib/cli/commands/ops/status.py,sha256=83yXo-3EamyXyYkGW22tMc0CjT577SYfE8jQp2o
51
51
  kstlib/cli/commands/ops/stop.py,sha256=dXo0HPKqEA1quWY4tIXWB8aZzFas06tWkFL4Fy86MVA,1421
52
52
  kstlib/cli/commands/rapi/__init__.py,sha256=OUbYf-C1Blt7ItIV2-G5LMo61zw_xLQaPrNB-xWwLXk,1712
53
53
  kstlib/cli/commands/rapi/call.py,sha256=hMLpZ8SFinLjwFpAHnl2bGzMbLZxUiZzm5e-pR6om9s,9976
54
- kstlib/cli/commands/rapi/list.py,sha256=w7rU9CtudAuY_7dAwDBh5pPCrk5yhjbfYfVw0kDQM7o,3014
54
+ kstlib/cli/commands/rapi/list.py,sha256=Sm8MbcYklevhmvZMnqvez3Hsl1dx_Pclc_M-hSUcEMw,7873
55
55
  kstlib/cli/commands/rapi/show.py,sha256=dLRq5WeG3wvoysEt8ivNp06wHep14PvQNaiAlRVJQrQ,7599
56
56
  kstlib/cli/commands/secrets/__init__.py,sha256=qxmuaeAgyVexnnOx72oqNOFJNBsn-CtEuMrXSAu3_vk,760
57
- kstlib/cli/commands/secrets/common.py,sha256=9nurm3R1BVb_-Oa3t-LcpywBYK6SGeLGR6fzqm4bl_k,12043
57
+ kstlib/cli/commands/secrets/common.py,sha256=y8KMQkWEc7qDVMJkzobMdHGsgoIeLwsOmYjq7TAe478,13277
58
58
  kstlib/cli/commands/secrets/decrypt.py,sha256=Qrkx-xHIahbr8SRk4YvD8ddWazHcy8Ur6HhNiaEmxfE,2380
59
59
  kstlib/cli/commands/secrets/doctor.py,sha256=KptEKMIaBTO1sftqDSr4LzuvCZPetigOjBh3ddaMems,25987
60
- kstlib/cli/commands/secrets/encrypt.py,sha256=jDB0Q777I1XVOU6Fb8M7Mwou2rKOV_zwVNxy5hES-ls,7821
60
+ kstlib/cli/commands/secrets/encrypt.py,sha256=vggzg44hwc6EUW_cv44qtmsaT-4DPY3RqF6Zb73Ao_U,7827
61
61
  kstlib/cli/commands/secrets/shred.py,sha256=V0ndvIib4chiHq_7YqkliQ06GI9pQfGCc7xTPtiKx-U,2732
62
62
  kstlib/config/__init__.py,sha256=urn7ZmbYMgDEIbZFxFA7wrgutscIptH1BqbS17FuYWQ,1805
63
63
  kstlib/config/exceptions.py,sha256=MJqo_j5_WJU1pxbNYdpOqD5VqYbdQ2a-pCKzufcUk0c,2758
@@ -110,11 +110,11 @@ kstlib/ops/manager.py,sha256=mcGCUOP8BZ_kZobn4YJcu1ZgEOMG2AKn12NJLgFanFE,12933
110
110
  kstlib/ops/models.py,sha256=PTBhPSxBdzK-gRGQznwj5i-mg2gNBhXbV6Ojgc31t-w,5317
111
111
  kstlib/ops/tmux.py,sha256=9WxCcKYmkmYMehEazTz4oWmlU7TDzfT3VVPTKQ9L1_0,11175
112
112
  kstlib/ops/validators.py,sha256=CfkEdv5pxg5vYESz2XG5ghU9wcuUW0yWD8V8xb5gYw0,8072
113
- kstlib/rapi/__init__.py,sha256=To_PLcyuTeATI8J_7z56CXjZGfxPZ80l5ux1tQu3h68,3236
114
- kstlib/rapi/client.py,sha256=b1Kvyf2RbQerp43N-WRgTVMiRQ6qFQzPQ86yuPXAM8o,29427
115
- kstlib/rapi/config.py,sha256=TsjcydfTNMwsyBn0vRuitMKGLamvy99hVUhQTsFB7OA,28870
113
+ kstlib/rapi/__init__.py,sha256=7RsJCkcL95iB7i9YZQom-AXZJDi1WLnSMOzO-Yre5fk,3436
114
+ kstlib/rapi/client.py,sha256=OFmNcUy28S-VF7JhVmwdPQdkhQ_xkJBXA0LxJsplmL4,31421
115
+ kstlib/rapi/config.py,sha256=RwHt6oASsr8A1DNiEu2p9YMShqT6LB54RUrf-9xNymw,48083
116
116
  kstlib/rapi/credentials.py,sha256=Q8zGwhx1JLdJFSU8XoKKwch8i_rB6n4Xb87VUruv9c0,31502
117
- kstlib/rapi/exceptions.py,sha256=eK7t93uyjDkmoM2mpCz8F3SQ4NyC9KtU99dNQI23PDg,6528
117
+ kstlib/rapi/exceptions.py,sha256=aF3kddBzLGR-3VhHzQKVco_ctArxWamWqVyPipIEV9E,12439
118
118
  kstlib/resilience/__init__.py,sha256=5u8anwYCOD2bvyCPT3RQkZBuSZKzzu3p-ljpx8__4NI,3167
119
119
  kstlib/resilience/circuit_breaker.py,sha256=MiliIvNUiqH7DcXjWLs6lIDTh-jOfnBnNt5EWxmV5EI,13781
120
120
  kstlib/resilience/exceptions.py,sha256=5UNyEHR-TEP66jB2RyqsYjPyisyL_FKjiGCBQziNShw,2556
@@ -155,9 +155,9 @@ kstlib/websocket/__init__.py,sha256=yNpCeg3S0NA61WEOIaVW2-DeFFdPyNhFpV4Xi7ZEUT4,
155
155
  kstlib/websocket/exceptions.py,sha256=Mku-3SoaadbRwQZLR7Rx5J4VVrp8wwJjKnCWOOxse3s,5957
156
156
  kstlib/websocket/manager.py,sha256=rxiQ1N-H9PVWl9WEr_24QxeIHu9j8REL4GH31QrmTSg,42587
157
157
  kstlib/websocket/models.py,sha256=-Ooe2oZJLH9wAW9_yZyUE1mreaguQZK3c4Y_Zt8MOgM,10986
158
- kstlib-1.0.2.dist-info/licenses/LICENSE.md,sha256=y9Wv0ooml-DVaNOLi2BKvWJyklSACRKnLGOYXhnrdiQ,1077
159
- kstlib-1.0.2.dist-info/METADATA,sha256=qUGJK6Cj171pAR2ap-1wVEcNqB1E18mbgl30f9AbpWQ,7384
160
- kstlib-1.0.2.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
161
- kstlib-1.0.2.dist-info/entry_points.txt,sha256=mqwbGFeHB_sJYnZMTpx-_64FPW6apGcfeK8VvObs5jM,48
162
- kstlib-1.0.2.dist-info/top_level.txt,sha256=tgPJhgVk1CqZM_mx4fmT0_GUKmnLpJuntTo5GMs7EOs,7
163
- kstlib-1.0.2.dist-info/RECORD,,
158
+ kstlib-1.1.1.dist-info/licenses/LICENSE.md,sha256=y9Wv0ooml-DVaNOLi2BKvWJyklSACRKnLGOYXhnrdiQ,1077
159
+ kstlib-1.1.1.dist-info/METADATA,sha256=oyCiXhTVc0iEHeMhg7GHOmzuMyrcODoAc3FqVKeZfbw,7766
160
+ kstlib-1.1.1.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
161
+ kstlib-1.1.1.dist-info/entry_points.txt,sha256=mqwbGFeHB_sJYnZMTpx-_64FPW6apGcfeK8VvObs5jM,48
162
+ kstlib-1.1.1.dist-info/top_level.txt,sha256=tgPJhgVk1CqZM_mx4fmT0_GUKmnLpJuntTo5GMs7EOs,7
163
+ kstlib-1.1.1.dist-info/RECORD,,
File without changes