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.
- kstlib/__init__.py +266 -1
- kstlib/__main__.py +16 -0
- kstlib/alerts/__init__.py +110 -0
- kstlib/alerts/channels/__init__.py +36 -0
- kstlib/alerts/channels/base.py +197 -0
- kstlib/alerts/channels/email.py +227 -0
- kstlib/alerts/channels/slack.py +389 -0
- kstlib/alerts/exceptions.py +72 -0
- kstlib/alerts/manager.py +651 -0
- kstlib/alerts/models.py +142 -0
- kstlib/alerts/throttle.py +263 -0
- kstlib/auth/__init__.py +139 -0
- kstlib/auth/callback.py +399 -0
- kstlib/auth/config.py +502 -0
- kstlib/auth/errors.py +127 -0
- kstlib/auth/models.py +316 -0
- kstlib/auth/providers/__init__.py +14 -0
- kstlib/auth/providers/base.py +393 -0
- kstlib/auth/providers/oauth2.py +645 -0
- kstlib/auth/providers/oidc.py +821 -0
- kstlib/auth/session.py +338 -0
- kstlib/auth/token.py +482 -0
- kstlib/cache/__init__.py +50 -0
- kstlib/cache/decorator.py +261 -0
- kstlib/cache/strategies.py +516 -0
- kstlib/cli/__init__.py +8 -0
- kstlib/cli/app.py +195 -0
- kstlib/cli/commands/__init__.py +5 -0
- kstlib/cli/commands/auth/__init__.py +39 -0
- kstlib/cli/commands/auth/common.py +122 -0
- kstlib/cli/commands/auth/login.py +325 -0
- kstlib/cli/commands/auth/logout.py +74 -0
- kstlib/cli/commands/auth/providers.py +57 -0
- kstlib/cli/commands/auth/status.py +291 -0
- kstlib/cli/commands/auth/token.py +199 -0
- kstlib/cli/commands/auth/whoami.py +106 -0
- kstlib/cli/commands/config.py +89 -0
- kstlib/cli/commands/ops/__init__.py +39 -0
- kstlib/cli/commands/ops/attach.py +49 -0
- kstlib/cli/commands/ops/common.py +269 -0
- kstlib/cli/commands/ops/list_sessions.py +252 -0
- kstlib/cli/commands/ops/logs.py +49 -0
- kstlib/cli/commands/ops/start.py +98 -0
- kstlib/cli/commands/ops/status.py +138 -0
- kstlib/cli/commands/ops/stop.py +60 -0
- kstlib/cli/commands/rapi/__init__.py +60 -0
- kstlib/cli/commands/rapi/call.py +341 -0
- kstlib/cli/commands/rapi/list.py +99 -0
- kstlib/cli/commands/rapi/show.py +206 -0
- kstlib/cli/commands/secrets/__init__.py +35 -0
- kstlib/cli/commands/secrets/common.py +425 -0
- kstlib/cli/commands/secrets/decrypt.py +88 -0
- kstlib/cli/commands/secrets/doctor.py +743 -0
- kstlib/cli/commands/secrets/encrypt.py +242 -0
- kstlib/cli/commands/secrets/shred.py +96 -0
- kstlib/cli/common.py +86 -0
- kstlib/config/__init__.py +76 -0
- kstlib/config/exceptions.py +110 -0
- kstlib/config/export.py +225 -0
- kstlib/config/loader.py +963 -0
- kstlib/config/sops.py +287 -0
- kstlib/db/__init__.py +54 -0
- kstlib/db/aiosqlcipher.py +137 -0
- kstlib/db/cipher.py +112 -0
- kstlib/db/database.py +367 -0
- kstlib/db/exceptions.py +25 -0
- kstlib/db/pool.py +302 -0
- kstlib/helpers/__init__.py +35 -0
- kstlib/helpers/exceptions.py +11 -0
- kstlib/helpers/time_trigger.py +396 -0
- kstlib/kstlib.conf.yml +890 -0
- kstlib/limits.py +963 -0
- kstlib/logging/__init__.py +108 -0
- kstlib/logging/manager.py +633 -0
- kstlib/mail/__init__.py +42 -0
- kstlib/mail/builder.py +626 -0
- kstlib/mail/exceptions.py +27 -0
- kstlib/mail/filesystem.py +248 -0
- kstlib/mail/transport.py +224 -0
- kstlib/mail/transports/__init__.py +19 -0
- kstlib/mail/transports/gmail.py +268 -0
- kstlib/mail/transports/resend.py +324 -0
- kstlib/mail/transports/smtp.py +326 -0
- kstlib/meta.py +72 -0
- kstlib/metrics/__init__.py +88 -0
- kstlib/metrics/decorators.py +1090 -0
- kstlib/metrics/exceptions.py +14 -0
- kstlib/monitoring/__init__.py +116 -0
- kstlib/monitoring/_styles.py +163 -0
- kstlib/monitoring/cell.py +57 -0
- kstlib/monitoring/config.py +424 -0
- kstlib/monitoring/delivery.py +579 -0
- kstlib/monitoring/exceptions.py +63 -0
- kstlib/monitoring/image.py +220 -0
- kstlib/monitoring/kv.py +79 -0
- kstlib/monitoring/list.py +69 -0
- kstlib/monitoring/metric.py +88 -0
- kstlib/monitoring/monitoring.py +341 -0
- kstlib/monitoring/renderer.py +139 -0
- kstlib/monitoring/service.py +392 -0
- kstlib/monitoring/table.py +129 -0
- kstlib/monitoring/types.py +56 -0
- kstlib/ops/__init__.py +86 -0
- kstlib/ops/base.py +148 -0
- kstlib/ops/container.py +577 -0
- kstlib/ops/exceptions.py +209 -0
- kstlib/ops/manager.py +407 -0
- kstlib/ops/models.py +176 -0
- kstlib/ops/tmux.py +372 -0
- kstlib/ops/validators.py +287 -0
- kstlib/py.typed +0 -0
- kstlib/rapi/__init__.py +118 -0
- kstlib/rapi/client.py +875 -0
- kstlib/rapi/config.py +861 -0
- kstlib/rapi/credentials.py +887 -0
- kstlib/rapi/exceptions.py +213 -0
- kstlib/resilience/__init__.py +101 -0
- kstlib/resilience/circuit_breaker.py +440 -0
- kstlib/resilience/exceptions.py +95 -0
- kstlib/resilience/heartbeat.py +491 -0
- kstlib/resilience/rate_limiter.py +506 -0
- kstlib/resilience/shutdown.py +417 -0
- kstlib/resilience/watchdog.py +637 -0
- kstlib/secrets/__init__.py +29 -0
- kstlib/secrets/exceptions.py +19 -0
- kstlib/secrets/models.py +62 -0
- kstlib/secrets/providers/__init__.py +79 -0
- kstlib/secrets/providers/base.py +58 -0
- kstlib/secrets/providers/environment.py +66 -0
- kstlib/secrets/providers/keyring.py +107 -0
- kstlib/secrets/providers/kms.py +223 -0
- kstlib/secrets/providers/kwargs.py +101 -0
- kstlib/secrets/providers/sops.py +209 -0
- kstlib/secrets/resolver.py +221 -0
- kstlib/secrets/sensitive.py +130 -0
- kstlib/secure/__init__.py +23 -0
- kstlib/secure/fs.py +194 -0
- kstlib/secure/permissions.py +70 -0
- kstlib/ssl.py +347 -0
- kstlib/ui/__init__.py +23 -0
- kstlib/ui/exceptions.py +26 -0
- kstlib/ui/panels.py +484 -0
- kstlib/ui/spinner.py +864 -0
- kstlib/ui/tables.py +382 -0
- kstlib/utils/__init__.py +48 -0
- kstlib/utils/dict.py +36 -0
- kstlib/utils/formatting.py +338 -0
- kstlib/utils/http_trace.py +237 -0
- kstlib/utils/lazy.py +49 -0
- kstlib/utils/secure_delete.py +205 -0
- kstlib/utils/serialization.py +247 -0
- kstlib/utils/text.py +56 -0
- kstlib/utils/validators.py +124 -0
- kstlib/websocket/__init__.py +97 -0
- kstlib/websocket/exceptions.py +214 -0
- kstlib/websocket/manager.py +1102 -0
- kstlib/websocket/models.py +361 -0
- kstlib-1.0.1.dist-info/METADATA +201 -0
- kstlib-1.0.1.dist-info/RECORD +163 -0
- {kstlib-0.0.1a0.dist-info → kstlib-1.0.1.dist-info}/WHEEL +1 -1
- kstlib-1.0.1.dist-info/entry_points.txt +2 -0
- kstlib-1.0.1.dist-info/licenses/LICENSE.md +9 -0
- kstlib-0.0.1a0.dist-info/METADATA +0 -29
- kstlib-0.0.1a0.dist-info/RECORD +0 -6
- kstlib-0.0.1a0.dist-info/licenses/LICENSE.md +0 -5
- {kstlib-0.0.1a0.dist-info → kstlib-1.0.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
"""Caching decorator with config-based strategy selection.
|
|
2
|
+
|
|
3
|
+
Provides @cache decorator with automatic async/sync detection
|
|
4
|
+
and configuration priority chain.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
# pylint: disable=too-many-arguments
|
|
8
|
+
|
|
9
|
+
import functools
|
|
10
|
+
import inspect
|
|
11
|
+
from collections.abc import Callable
|
|
12
|
+
from typing import Any, TypeVar, overload
|
|
13
|
+
|
|
14
|
+
from kstlib.cache.strategies import (
|
|
15
|
+
CacheStrategy,
|
|
16
|
+
FileCacheStrategy,
|
|
17
|
+
LRUCacheStrategy,
|
|
18
|
+
TTLCacheStrategy,
|
|
19
|
+
)
|
|
20
|
+
from kstlib.config import get_config
|
|
21
|
+
from kstlib.config.exceptions import ConfigFileNotFoundError
|
|
22
|
+
|
|
23
|
+
F = TypeVar("F", bound=Callable[..., Any])
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _get_cache_config() -> dict[str, Any]:
|
|
27
|
+
"""Get cache configuration from kstlib config.
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
Cache configuration dict with defaults
|
|
31
|
+
"""
|
|
32
|
+
try:
|
|
33
|
+
config = get_config()
|
|
34
|
+
if hasattr(config, "cache"):
|
|
35
|
+
return dict(config.cache)
|
|
36
|
+
except (AttributeError, ImportError, ConfigFileNotFoundError):
|
|
37
|
+
# Config not available or cache section missing
|
|
38
|
+
pass
|
|
39
|
+
|
|
40
|
+
# Fallback defaults
|
|
41
|
+
return {
|
|
42
|
+
"default_strategy": "ttl",
|
|
43
|
+
"ttl": {"default_seconds": 300, "max_entries": 1000, "cleanup_interval": 60},
|
|
44
|
+
"lru": {"maxsize": 128, "typed": False},
|
|
45
|
+
"file": {"enabled": True, "cache_dir": ".cache", "check_mtime": True, "serializer": "json"},
|
|
46
|
+
"async_support": {"enabled": True, "executor_workers": 4},
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _create_strategy(
|
|
51
|
+
strategy: str | None = None,
|
|
52
|
+
*,
|
|
53
|
+
ttl: int | None = None,
|
|
54
|
+
maxsize: int | None = None,
|
|
55
|
+
cache_dir: str | None = None,
|
|
56
|
+
check_mtime: bool | None = None,
|
|
57
|
+
serializer: str | None = None,
|
|
58
|
+
) -> CacheStrategy:
|
|
59
|
+
"""Create cache strategy based on parameters and config.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
strategy: Strategy name ('ttl', 'lru', 'file')
|
|
63
|
+
ttl: TTL in seconds (for TTL strategy)
|
|
64
|
+
maxsize: Max cache size (for LRU strategy)
|
|
65
|
+
cache_dir: Cache directory (for file strategy)
|
|
66
|
+
check_mtime: Check file mtime (for file strategy)
|
|
67
|
+
serializer: Serializer name for the file strategy ('json', 'pickle', 'auto')
|
|
68
|
+
|
|
69
|
+
Returns:
|
|
70
|
+
Configured cache strategy instance
|
|
71
|
+
"""
|
|
72
|
+
config = _get_cache_config()
|
|
73
|
+
|
|
74
|
+
# Determine strategy (argument > config)
|
|
75
|
+
strategy_name = strategy or config.get("default_strategy", "ttl")
|
|
76
|
+
|
|
77
|
+
if strategy_name == "ttl":
|
|
78
|
+
ttl_config = config.get("ttl", {})
|
|
79
|
+
return TTLCacheStrategy(
|
|
80
|
+
ttl=ttl or ttl_config.get("default_seconds", 300),
|
|
81
|
+
max_entries=ttl_config.get("max_entries", 1000),
|
|
82
|
+
cleanup_interval=ttl_config.get("cleanup_interval", 60),
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
if strategy_name == "lru":
|
|
86
|
+
lru_config = config.get("lru", {})
|
|
87
|
+
return LRUCacheStrategy(
|
|
88
|
+
maxsize=maxsize or lru_config.get("maxsize", 128),
|
|
89
|
+
typed=lru_config.get("typed", False),
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
if strategy_name == "file":
|
|
93
|
+
file_config = config.get("file", {})
|
|
94
|
+
return FileCacheStrategy(
|
|
95
|
+
cache_dir=cache_dir or file_config.get("cache_dir", ".cache"),
|
|
96
|
+
check_mtime=check_mtime if check_mtime is not None else file_config.get("check_mtime", True),
|
|
97
|
+
serializer=serializer or file_config.get("serializer", "json"),
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
# Fallback to TTL
|
|
101
|
+
return TTLCacheStrategy()
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
@overload
|
|
105
|
+
def cache(func: F) -> F: ...
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
@overload
|
|
109
|
+
def cache(
|
|
110
|
+
*,
|
|
111
|
+
strategy: str | None = None,
|
|
112
|
+
ttl: int | None = None,
|
|
113
|
+
maxsize: int | None = None,
|
|
114
|
+
cache_dir: str | None = None,
|
|
115
|
+
check_mtime: bool | None = None,
|
|
116
|
+
serializer: str | None = None,
|
|
117
|
+
) -> Callable[[F], F]: ...
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def cache(
|
|
121
|
+
func: F | None = None,
|
|
122
|
+
*,
|
|
123
|
+
strategy: str | None = None,
|
|
124
|
+
ttl: int | None = None,
|
|
125
|
+
maxsize: int | None = None,
|
|
126
|
+
cache_dir: str | None = None,
|
|
127
|
+
check_mtime: bool | None = None,
|
|
128
|
+
serializer: str | None = None,
|
|
129
|
+
) -> F | Callable[[F], F]:
|
|
130
|
+
"""Cache decorator with automatic async/sync detection.
|
|
131
|
+
|
|
132
|
+
Supports multiple caching strategies configured via kstlib.conf.yml
|
|
133
|
+
or decorator arguments. Automatically detects async functions and
|
|
134
|
+
handles them appropriately.
|
|
135
|
+
|
|
136
|
+
Args:
|
|
137
|
+
func: Function to cache (when used without parentheses)
|
|
138
|
+
strategy: Cache strategy ('ttl', 'lru', 'file')
|
|
139
|
+
ttl: Time to live in seconds (TTL strategy)
|
|
140
|
+
maxsize: Maximum cache size (LRU strategy)
|
|
141
|
+
cache_dir: Cache directory path (file strategy)
|
|
142
|
+
check_mtime: Check file modification time (file strategy)
|
|
143
|
+
serializer: Serialization format for file strategy ('json', 'pickle', 'auto')
|
|
144
|
+
|
|
145
|
+
Returns:
|
|
146
|
+
Decorated function with caching
|
|
147
|
+
|
|
148
|
+
Examples:
|
|
149
|
+
Basic usage (uses config defaults):
|
|
150
|
+
|
|
151
|
+
>>> @cache
|
|
152
|
+
... def double(x: int) -> int:
|
|
153
|
+
... return x * 2
|
|
154
|
+
>>> double(5)
|
|
155
|
+
10
|
|
156
|
+
>>> double(5) # Returns cached value
|
|
157
|
+
10
|
|
158
|
+
|
|
159
|
+
With explicit TTL strategy:
|
|
160
|
+
|
|
161
|
+
>>> @cache(strategy="ttl", ttl=60)
|
|
162
|
+
... def compute(n: int) -> int:
|
|
163
|
+
... return n * n
|
|
164
|
+
>>> compute(4)
|
|
165
|
+
16
|
|
166
|
+
|
|
167
|
+
LRU cache for recursive functions:
|
|
168
|
+
|
|
169
|
+
>>> @cache(strategy="lru", maxsize=128)
|
|
170
|
+
... def fibonacci(n: int) -> int:
|
|
171
|
+
... if n < 2:
|
|
172
|
+
... return n
|
|
173
|
+
... return fibonacci(n - 1) + fibonacci(n - 2)
|
|
174
|
+
>>> fibonacci(10)
|
|
175
|
+
55
|
|
176
|
+
|
|
177
|
+
Cache management methods:
|
|
178
|
+
|
|
179
|
+
>>> double.cache_info()
|
|
180
|
+
{'strategy': 'ttl', 'is_async': False}
|
|
181
|
+
>>> double.cache_clear() # Clear cached values
|
|
182
|
+
"""
|
|
183
|
+
|
|
184
|
+
def decorator(f: F) -> F:
|
|
185
|
+
# Create strategy instance
|
|
186
|
+
cache_strategy = _create_strategy(
|
|
187
|
+
strategy=strategy,
|
|
188
|
+
ttl=ttl,
|
|
189
|
+
maxsize=maxsize,
|
|
190
|
+
cache_dir=cache_dir,
|
|
191
|
+
check_mtime=check_mtime,
|
|
192
|
+
serializer=serializer,
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
# Check if function is async
|
|
196
|
+
is_async = inspect.iscoroutinefunction(f)
|
|
197
|
+
|
|
198
|
+
if is_async:
|
|
199
|
+
# Async wrapper
|
|
200
|
+
@functools.wraps(f)
|
|
201
|
+
async def async_wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
202
|
+
# Generate cache key
|
|
203
|
+
cache_key = cache_strategy.make_key(f, args, kwargs)
|
|
204
|
+
|
|
205
|
+
# Check cache
|
|
206
|
+
cached_value = cache_strategy.get(cache_key)
|
|
207
|
+
if cached_value is not None:
|
|
208
|
+
return cached_value
|
|
209
|
+
|
|
210
|
+
# Call async function
|
|
211
|
+
result = await f(*args, **kwargs)
|
|
212
|
+
|
|
213
|
+
# Store in cache
|
|
214
|
+
cache_strategy.set(cache_key, result)
|
|
215
|
+
|
|
216
|
+
return result
|
|
217
|
+
|
|
218
|
+
# Add cache management methods
|
|
219
|
+
async_wrapper.cache_clear = cache_strategy.clear # type: ignore[attr-defined]
|
|
220
|
+
|
|
221
|
+
def _async_cache_info() -> dict[str, Any]:
|
|
222
|
+
return {"strategy": strategy or "ttl", "is_async": True}
|
|
223
|
+
|
|
224
|
+
async_wrapper.cache_info = _async_cache_info # type: ignore[attr-defined]
|
|
225
|
+
|
|
226
|
+
return async_wrapper # type: ignore[return-value]
|
|
227
|
+
|
|
228
|
+
# Sync wrapper
|
|
229
|
+
@functools.wraps(f)
|
|
230
|
+
def sync_wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
231
|
+
# Generate cache key
|
|
232
|
+
cache_key = cache_strategy.make_key(f, args, kwargs)
|
|
233
|
+
|
|
234
|
+
# Check cache
|
|
235
|
+
cached_value = cache_strategy.get(cache_key)
|
|
236
|
+
if cached_value is not None:
|
|
237
|
+
return cached_value
|
|
238
|
+
|
|
239
|
+
# Call function
|
|
240
|
+
result = f(*args, **kwargs)
|
|
241
|
+
|
|
242
|
+
# Store in cache
|
|
243
|
+
cache_strategy.set(cache_key, result)
|
|
244
|
+
|
|
245
|
+
return result
|
|
246
|
+
|
|
247
|
+
# Add cache management methods
|
|
248
|
+
sync_wrapper.cache_clear = cache_strategy.clear # type: ignore[attr-defined]
|
|
249
|
+
|
|
250
|
+
def _sync_cache_info() -> dict[str, Any]:
|
|
251
|
+
return {"strategy": strategy or "ttl", "is_async": False}
|
|
252
|
+
|
|
253
|
+
sync_wrapper.cache_info = _sync_cache_info # type: ignore[attr-defined]
|
|
254
|
+
|
|
255
|
+
return sync_wrapper # type: ignore[return-value]
|
|
256
|
+
|
|
257
|
+
# Handle both @cache and @cache(...) syntax
|
|
258
|
+
if func is not None:
|
|
259
|
+
return decorator(func)
|
|
260
|
+
|
|
261
|
+
return decorator
|