kstlib 0.0.1a0__py3-none-any.whl → 1.0.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.
Files changed (166) hide show
  1. kstlib/__init__.py +266 -1
  2. kstlib/__main__.py +16 -0
  3. kstlib/alerts/__init__.py +110 -0
  4. kstlib/alerts/channels/__init__.py +36 -0
  5. kstlib/alerts/channels/base.py +197 -0
  6. kstlib/alerts/channels/email.py +227 -0
  7. kstlib/alerts/channels/slack.py +389 -0
  8. kstlib/alerts/exceptions.py +72 -0
  9. kstlib/alerts/manager.py +651 -0
  10. kstlib/alerts/models.py +142 -0
  11. kstlib/alerts/throttle.py +263 -0
  12. kstlib/auth/__init__.py +139 -0
  13. kstlib/auth/callback.py +399 -0
  14. kstlib/auth/config.py +502 -0
  15. kstlib/auth/errors.py +127 -0
  16. kstlib/auth/models.py +316 -0
  17. kstlib/auth/providers/__init__.py +14 -0
  18. kstlib/auth/providers/base.py +393 -0
  19. kstlib/auth/providers/oauth2.py +645 -0
  20. kstlib/auth/providers/oidc.py +821 -0
  21. kstlib/auth/session.py +338 -0
  22. kstlib/auth/token.py +482 -0
  23. kstlib/cache/__init__.py +50 -0
  24. kstlib/cache/decorator.py +261 -0
  25. kstlib/cache/strategies.py +516 -0
  26. kstlib/cli/__init__.py +8 -0
  27. kstlib/cli/app.py +195 -0
  28. kstlib/cli/commands/__init__.py +5 -0
  29. kstlib/cli/commands/auth/__init__.py +39 -0
  30. kstlib/cli/commands/auth/common.py +122 -0
  31. kstlib/cli/commands/auth/login.py +325 -0
  32. kstlib/cli/commands/auth/logout.py +74 -0
  33. kstlib/cli/commands/auth/providers.py +57 -0
  34. kstlib/cli/commands/auth/status.py +291 -0
  35. kstlib/cli/commands/auth/token.py +199 -0
  36. kstlib/cli/commands/auth/whoami.py +106 -0
  37. kstlib/cli/commands/config.py +89 -0
  38. kstlib/cli/commands/ops/__init__.py +39 -0
  39. kstlib/cli/commands/ops/attach.py +49 -0
  40. kstlib/cli/commands/ops/common.py +269 -0
  41. kstlib/cli/commands/ops/list_sessions.py +252 -0
  42. kstlib/cli/commands/ops/logs.py +49 -0
  43. kstlib/cli/commands/ops/start.py +98 -0
  44. kstlib/cli/commands/ops/status.py +138 -0
  45. kstlib/cli/commands/ops/stop.py +60 -0
  46. kstlib/cli/commands/rapi/__init__.py +60 -0
  47. kstlib/cli/commands/rapi/call.py +341 -0
  48. kstlib/cli/commands/rapi/list.py +99 -0
  49. kstlib/cli/commands/rapi/show.py +206 -0
  50. kstlib/cli/commands/secrets/__init__.py +35 -0
  51. kstlib/cli/commands/secrets/common.py +425 -0
  52. kstlib/cli/commands/secrets/decrypt.py +88 -0
  53. kstlib/cli/commands/secrets/doctor.py +743 -0
  54. kstlib/cli/commands/secrets/encrypt.py +242 -0
  55. kstlib/cli/commands/secrets/shred.py +96 -0
  56. kstlib/cli/common.py +86 -0
  57. kstlib/config/__init__.py +76 -0
  58. kstlib/config/exceptions.py +110 -0
  59. kstlib/config/export.py +225 -0
  60. kstlib/config/loader.py +963 -0
  61. kstlib/config/sops.py +287 -0
  62. kstlib/db/__init__.py +54 -0
  63. kstlib/db/aiosqlcipher.py +137 -0
  64. kstlib/db/cipher.py +112 -0
  65. kstlib/db/database.py +367 -0
  66. kstlib/db/exceptions.py +25 -0
  67. kstlib/db/pool.py +302 -0
  68. kstlib/helpers/__init__.py +35 -0
  69. kstlib/helpers/exceptions.py +11 -0
  70. kstlib/helpers/time_trigger.py +396 -0
  71. kstlib/kstlib.conf.yml +890 -0
  72. kstlib/limits.py +963 -0
  73. kstlib/logging/__init__.py +108 -0
  74. kstlib/logging/manager.py +633 -0
  75. kstlib/mail/__init__.py +42 -0
  76. kstlib/mail/builder.py +626 -0
  77. kstlib/mail/exceptions.py +27 -0
  78. kstlib/mail/filesystem.py +248 -0
  79. kstlib/mail/transport.py +224 -0
  80. kstlib/mail/transports/__init__.py +19 -0
  81. kstlib/mail/transports/gmail.py +268 -0
  82. kstlib/mail/transports/resend.py +324 -0
  83. kstlib/mail/transports/smtp.py +326 -0
  84. kstlib/meta.py +72 -0
  85. kstlib/metrics/__init__.py +88 -0
  86. kstlib/metrics/decorators.py +1090 -0
  87. kstlib/metrics/exceptions.py +14 -0
  88. kstlib/monitoring/__init__.py +116 -0
  89. kstlib/monitoring/_styles.py +163 -0
  90. kstlib/monitoring/cell.py +57 -0
  91. kstlib/monitoring/config.py +424 -0
  92. kstlib/monitoring/delivery.py +579 -0
  93. kstlib/monitoring/exceptions.py +63 -0
  94. kstlib/monitoring/image.py +220 -0
  95. kstlib/monitoring/kv.py +79 -0
  96. kstlib/monitoring/list.py +69 -0
  97. kstlib/monitoring/metric.py +88 -0
  98. kstlib/monitoring/monitoring.py +341 -0
  99. kstlib/monitoring/renderer.py +139 -0
  100. kstlib/monitoring/service.py +392 -0
  101. kstlib/monitoring/table.py +129 -0
  102. kstlib/monitoring/types.py +56 -0
  103. kstlib/ops/__init__.py +86 -0
  104. kstlib/ops/base.py +148 -0
  105. kstlib/ops/container.py +577 -0
  106. kstlib/ops/exceptions.py +209 -0
  107. kstlib/ops/manager.py +407 -0
  108. kstlib/ops/models.py +176 -0
  109. kstlib/ops/tmux.py +372 -0
  110. kstlib/ops/validators.py +287 -0
  111. kstlib/py.typed +0 -0
  112. kstlib/rapi/__init__.py +118 -0
  113. kstlib/rapi/client.py +875 -0
  114. kstlib/rapi/config.py +861 -0
  115. kstlib/rapi/credentials.py +887 -0
  116. kstlib/rapi/exceptions.py +213 -0
  117. kstlib/resilience/__init__.py +101 -0
  118. kstlib/resilience/circuit_breaker.py +440 -0
  119. kstlib/resilience/exceptions.py +95 -0
  120. kstlib/resilience/heartbeat.py +491 -0
  121. kstlib/resilience/rate_limiter.py +506 -0
  122. kstlib/resilience/shutdown.py +417 -0
  123. kstlib/resilience/watchdog.py +637 -0
  124. kstlib/secrets/__init__.py +29 -0
  125. kstlib/secrets/exceptions.py +19 -0
  126. kstlib/secrets/models.py +62 -0
  127. kstlib/secrets/providers/__init__.py +79 -0
  128. kstlib/secrets/providers/base.py +58 -0
  129. kstlib/secrets/providers/environment.py +66 -0
  130. kstlib/secrets/providers/keyring.py +107 -0
  131. kstlib/secrets/providers/kms.py +223 -0
  132. kstlib/secrets/providers/kwargs.py +101 -0
  133. kstlib/secrets/providers/sops.py +209 -0
  134. kstlib/secrets/resolver.py +221 -0
  135. kstlib/secrets/sensitive.py +130 -0
  136. kstlib/secure/__init__.py +23 -0
  137. kstlib/secure/fs.py +194 -0
  138. kstlib/secure/permissions.py +70 -0
  139. kstlib/ssl.py +347 -0
  140. kstlib/ui/__init__.py +23 -0
  141. kstlib/ui/exceptions.py +26 -0
  142. kstlib/ui/panels.py +484 -0
  143. kstlib/ui/spinner.py +864 -0
  144. kstlib/ui/tables.py +382 -0
  145. kstlib/utils/__init__.py +48 -0
  146. kstlib/utils/dict.py +36 -0
  147. kstlib/utils/formatting.py +338 -0
  148. kstlib/utils/http_trace.py +237 -0
  149. kstlib/utils/lazy.py +49 -0
  150. kstlib/utils/secure_delete.py +205 -0
  151. kstlib/utils/serialization.py +247 -0
  152. kstlib/utils/text.py +56 -0
  153. kstlib/utils/validators.py +124 -0
  154. kstlib/websocket/__init__.py +97 -0
  155. kstlib/websocket/exceptions.py +214 -0
  156. kstlib/websocket/manager.py +1102 -0
  157. kstlib/websocket/models.py +361 -0
  158. kstlib-1.0.1.dist-info/METADATA +201 -0
  159. kstlib-1.0.1.dist-info/RECORD +163 -0
  160. {kstlib-0.0.1a0.dist-info → kstlib-1.0.1.dist-info}/WHEEL +1 -1
  161. kstlib-1.0.1.dist-info/entry_points.txt +2 -0
  162. kstlib-1.0.1.dist-info/licenses/LICENSE.md +9 -0
  163. kstlib-0.0.1a0.dist-info/METADATA +0 -29
  164. kstlib-0.0.1a0.dist-info/RECORD +0 -6
  165. kstlib-0.0.1a0.dist-info/licenses/LICENSE.md +0 -5
  166. {kstlib-0.0.1a0.dist-info → kstlib-1.0.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,213 @@
1
+ """Exceptions for the RAPI module.
2
+
3
+ This module defines the exception hierarchy for REST API operations.
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ from typing import Any
9
+
10
+
11
+ class RapiError(Exception):
12
+ """Base exception for all RAPI errors.
13
+
14
+ Attributes:
15
+ message: Human-readable error message.
16
+ details: Additional error context as key-value pairs.
17
+
18
+ Examples:
19
+ >>> raise RapiError("Something went wrong", details={"endpoint": "test"})
20
+ Traceback (most recent call last):
21
+ ...
22
+ kstlib.rapi.exceptions.RapiError: Something went wrong
23
+ """
24
+
25
+ def __init__(
26
+ self,
27
+ message: str,
28
+ *,
29
+ details: dict[str, Any] | None = None,
30
+ ) -> None:
31
+ """Initialize RapiError.
32
+
33
+ Args:
34
+ message: Human-readable error message.
35
+ details: Additional error context.
36
+ """
37
+ super().__init__(message)
38
+ self.message = message
39
+ self.details = details or {}
40
+
41
+
42
+ class CredentialError(RapiError):
43
+ """Raised when credential resolution fails.
44
+
45
+ Attributes:
46
+ credential_name: Name of the credential that failed.
47
+ reason: Reason for the failure.
48
+
49
+ Examples:
50
+ >>> raise CredentialError("github", "Environment variable not set")
51
+ Traceback (most recent call last):
52
+ ...
53
+ kstlib.rapi.exceptions.CredentialError: Credential 'github' failed: Environment variable not set
54
+ """
55
+
56
+ def __init__(self, credential_name: str, reason: str) -> None:
57
+ """Initialize CredentialError.
58
+
59
+ Args:
60
+ credential_name: Name of the credential that failed.
61
+ reason: Reason for the failure.
62
+ """
63
+ super().__init__(
64
+ f"Credential '{credential_name}' failed: {reason}",
65
+ details={"credential_name": credential_name, "reason": reason},
66
+ )
67
+ self.credential_name = credential_name
68
+ self.reason = reason
69
+
70
+
71
+ class EndpointNotFoundError(RapiError):
72
+ """Raised when an endpoint cannot be resolved.
73
+
74
+ Attributes:
75
+ endpoint_ref: The endpoint reference that was not found.
76
+ searched_apis: List of API names that were searched.
77
+
78
+ Examples:
79
+ >>> raise EndpointNotFoundError("unknown.endpoint")
80
+ Traceback (most recent call last):
81
+ ...
82
+ kstlib.rapi.exceptions.EndpointNotFoundError: Endpoint 'unknown.endpoint' not found
83
+ """
84
+
85
+ def __init__(
86
+ self,
87
+ endpoint_ref: str,
88
+ searched_apis: list[str] | None = None,
89
+ ) -> None:
90
+ """Initialize EndpointNotFoundError.
91
+
92
+ Args:
93
+ endpoint_ref: The endpoint reference that was not found.
94
+ searched_apis: List of API names that were searched.
95
+ """
96
+ super().__init__(
97
+ f"Endpoint '{endpoint_ref}' not found",
98
+ details={"endpoint_ref": endpoint_ref, "searched_apis": searched_apis or []},
99
+ )
100
+ self.endpoint_ref = endpoint_ref
101
+ self.searched_apis = searched_apis or []
102
+
103
+
104
+ class EndpointAmbiguousError(RapiError):
105
+ """Raised when an endpoint name matches multiple APIs.
106
+
107
+ Attributes:
108
+ endpoint_name: The ambiguous endpoint name.
109
+ matching_apis: List of API names containing this endpoint.
110
+
111
+ Examples:
112
+ >>> raise EndpointAmbiguousError("get_data", ["api1", "api2"])
113
+ Traceback (most recent call last):
114
+ ...
115
+ kstlib.rapi.exceptions.EndpointAmbiguousError: Endpoint 'get_data' is ambiguous, found in: api1, api2
116
+ """
117
+
118
+ def __init__(self, endpoint_name: str, matching_apis: list[str]) -> None:
119
+ """Initialize EndpointAmbiguousError.
120
+
121
+ Args:
122
+ endpoint_name: The ambiguous endpoint name.
123
+ matching_apis: List of API names containing this endpoint.
124
+ """
125
+ super().__init__(
126
+ f"Endpoint '{endpoint_name}' is ambiguous, found in: {', '.join(matching_apis)}",
127
+ details={"endpoint_name": endpoint_name, "matching_apis": matching_apis},
128
+ )
129
+ self.endpoint_name = endpoint_name
130
+ self.matching_apis = matching_apis
131
+
132
+
133
+ class RequestError(RapiError):
134
+ """Raised when an HTTP request fails.
135
+
136
+ Attributes:
137
+ status_code: HTTP status code (if available).
138
+ response_body: Response body (if available).
139
+ retryable: Whether the error is potentially retryable.
140
+
141
+ Examples:
142
+ >>> raise RequestError("Server error", status_code=500, retryable=True)
143
+ Traceback (most recent call last):
144
+ ...
145
+ kstlib.rapi.exceptions.RequestError: Server error
146
+ """
147
+
148
+ def __init__(
149
+ self,
150
+ message: str,
151
+ *,
152
+ status_code: int | None = None,
153
+ response_body: str | None = None,
154
+ retryable: bool = False,
155
+ ) -> None:
156
+ """Initialize RequestError.
157
+
158
+ Args:
159
+ message: Human-readable error message.
160
+ status_code: HTTP status code (if available).
161
+ response_body: Response body (if available).
162
+ retryable: Whether the error is potentially retryable.
163
+ """
164
+ super().__init__(
165
+ message,
166
+ details={
167
+ "status_code": status_code,
168
+ "response_body": response_body,
169
+ "retryable": retryable,
170
+ },
171
+ )
172
+ self.status_code = status_code
173
+ self.response_body = response_body
174
+ self.retryable = retryable
175
+
176
+
177
+ class ResponseTooLargeError(RapiError):
178
+ """Raised when response exceeds max_response_size limit.
179
+
180
+ Attributes:
181
+ response_size: Actual response size in bytes.
182
+ max_size: Maximum allowed size in bytes.
183
+
184
+ Examples:
185
+ >>> raise ResponseTooLargeError(15_000_000, 10_000_000)
186
+ Traceback (most recent call last):
187
+ ...
188
+ kstlib.rapi.exceptions.ResponseTooLargeError: Response size 15000000 exceeds limit 10000000
189
+ """
190
+
191
+ def __init__(self, response_size: int, max_size: int) -> None:
192
+ """Initialize ResponseTooLargeError.
193
+
194
+ Args:
195
+ response_size: Actual response size in bytes.
196
+ max_size: Maximum allowed size in bytes.
197
+ """
198
+ super().__init__(
199
+ f"Response size {response_size} exceeds limit {max_size}",
200
+ details={"response_size": response_size, "max_size": max_size},
201
+ )
202
+ self.response_size = response_size
203
+ self.max_size = max_size
204
+
205
+
206
+ __all__ = [
207
+ "CredentialError",
208
+ "EndpointAmbiguousError",
209
+ "EndpointNotFoundError",
210
+ "RapiError",
211
+ "RequestError",
212
+ "ResponseTooLargeError",
213
+ ]
@@ -0,0 +1,101 @@
1
+ """Resilience utilities for fault-tolerant applications.
2
+
3
+ This module provides core components for building resilient systems:
4
+
5
+ - **Heartbeat**: Periodic liveness signaling via state files
6
+ - **GracefulShutdown**: Orderly shutdown with prioritized callbacks
7
+ - **CircuitBreaker**: Protect against cascading failures
8
+ - **RateLimiter**: Token bucket rate limiting for request throttling
9
+ - **Watchdog**: Detect thread/process freezes and hangs
10
+
11
+ Examples:
12
+ Heartbeat for process monitoring:
13
+
14
+ >>> from kstlib.resilience import Heartbeat
15
+ >>> with Heartbeat("/tmp/app.heartbeat") as hb: # doctest: +SKIP
16
+ ... run_application()
17
+ >>> Heartbeat.is_alive("/tmp/app.heartbeat") # doctest: +SKIP
18
+ True
19
+
20
+ Graceful shutdown with cleanup:
21
+
22
+ >>> from kstlib.resilience import GracefulShutdown
23
+ >>> with GracefulShutdown() as shutdown: # doctest: +SKIP
24
+ ... shutdown.register("db", close_database, priority=10)
25
+ ... shutdown.register("cache", flush_cache, priority=20)
26
+ ... run_application()
27
+
28
+ Circuit breaker for external calls:
29
+
30
+ >>> from kstlib.resilience import circuit_breaker
31
+ >>> @circuit_breaker(max_failures=3, reset_timeout=30)
32
+ ... def call_external_api(): # doctest: +SKIP
33
+ ... return requests.get("http://api.example.com")
34
+
35
+ Rate limiting API calls:
36
+
37
+ >>> from kstlib.resilience import rate_limiter, RateLimiter
38
+ >>> @rate_limiter(rate=10, per=1.0) # 10 requests per second
39
+ ... def call_api(): # doctest: +SKIP
40
+ ... return requests.get("http://api.example.com")
41
+
42
+ >>> limiter = RateLimiter(rate=100, per=60.0) # 100 per minute
43
+ >>> limiter.acquire() # doctest: +SKIP
44
+ True
45
+
46
+ Watchdog for freeze detection:
47
+
48
+ >>> from kstlib.resilience import Watchdog
49
+ >>> def on_freeze(): # doctest: +SKIP
50
+ ... print("Thread frozen!")
51
+ >>> with Watchdog(timeout=30, on_timeout=on_freeze) as wd: # doctest: +SKIP
52
+ ... while running:
53
+ ... wd.ping()
54
+ ... do_work()
55
+ """
56
+
57
+ from kstlib.resilience.circuit_breaker import (
58
+ CircuitBreaker,
59
+ CircuitState,
60
+ CircuitStats,
61
+ circuit_breaker,
62
+ )
63
+ from kstlib.resilience.exceptions import (
64
+ CircuitBreakerError,
65
+ CircuitOpenError,
66
+ HeartbeatError,
67
+ RateLimitError,
68
+ RateLimitExceededError,
69
+ ShutdownError,
70
+ WatchdogError,
71
+ WatchdogTimeoutError,
72
+ )
73
+ from kstlib.resilience.heartbeat import Heartbeat, HeartbeatState
74
+ from kstlib.resilience.rate_limiter import RateLimiter, RateLimiterStats, rate_limiter
75
+ from kstlib.resilience.shutdown import CleanupCallback, GracefulShutdown
76
+ from kstlib.resilience.watchdog import Watchdog, WatchdogStats, watchdog_context
77
+
78
+ __all__ = [
79
+ "CircuitBreaker",
80
+ "CircuitBreakerError",
81
+ "CircuitOpenError",
82
+ "CircuitState",
83
+ "CircuitStats",
84
+ "CleanupCallback",
85
+ "GracefulShutdown",
86
+ "Heartbeat",
87
+ "HeartbeatError",
88
+ "HeartbeatState",
89
+ "RateLimitError",
90
+ "RateLimitExceededError",
91
+ "RateLimiter",
92
+ "RateLimiterStats",
93
+ "ShutdownError",
94
+ "Watchdog",
95
+ "WatchdogError",
96
+ "WatchdogStats",
97
+ "WatchdogTimeoutError",
98
+ "circuit_breaker",
99
+ "rate_limiter",
100
+ "watchdog_context",
101
+ ]