sotkalib 0.0.5__tar.gz → 0.0.5.post2__tar.gz
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.
- {sotkalib-0.0.5 → sotkalib-0.0.5.post2}/PKG-INFO +1 -1
- {sotkalib-0.0.5 → sotkalib-0.0.5.post2}/pyproject.toml +2 -2
- {sotkalib-0.0.5 → sotkalib-0.0.5.post2}/src/sotkalib/http/client_session.py +15 -28
- {sotkalib-0.0.5 → sotkalib-0.0.5.post2}/src/sotkalib/log/factory.py +1 -5
- {sotkalib-0.0.5 → sotkalib-0.0.5.post2}/README.md +0 -0
- {sotkalib-0.0.5 → sotkalib-0.0.5.post2}/src/sotkalib/__init__.py +0 -0
- {sotkalib-0.0.5 → sotkalib-0.0.5.post2}/src/sotkalib/config/__init__.py +0 -0
- {sotkalib-0.0.5 → sotkalib-0.0.5.post2}/src/sotkalib/config/field.py +0 -0
- {sotkalib-0.0.5 → sotkalib-0.0.5.post2}/src/sotkalib/config/struct.py +0 -0
- {sotkalib-0.0.5 → sotkalib-0.0.5.post2}/src/sotkalib/enum/__init__.py +0 -0
- {sotkalib-0.0.5 → sotkalib-0.0.5.post2}/src/sotkalib/enum/mixins.py +0 -0
- {sotkalib-0.0.5 → sotkalib-0.0.5.post2}/src/sotkalib/exceptions/__init__.py +0 -0
- {sotkalib-0.0.5 → sotkalib-0.0.5.post2}/src/sotkalib/exceptions/api/__init__.py +0 -0
- {sotkalib-0.0.5 → sotkalib-0.0.5.post2}/src/sotkalib/exceptions/api/exc.py +0 -0
- {sotkalib-0.0.5 → sotkalib-0.0.5.post2}/src/sotkalib/exceptions/handlers/__init__.py +0 -0
- {sotkalib-0.0.5 → sotkalib-0.0.5.post2}/src/sotkalib/exceptions/handlers/args_incl_error.py +0 -0
- {sotkalib-0.0.5 → sotkalib-0.0.5.post2}/src/sotkalib/exceptions/handlers/core.py +0 -0
- {sotkalib-0.0.5 → sotkalib-0.0.5.post2}/src/sotkalib/http/__init__.py +0 -0
- {sotkalib-0.0.5 → sotkalib-0.0.5.post2}/src/sotkalib/log/__init__.py +0 -0
- {sotkalib-0.0.5 → sotkalib-0.0.5.post2}/src/sotkalib/py.typed +0 -0
- {sotkalib-0.0.5 → sotkalib-0.0.5.post2}/src/sotkalib/redis/__init__.py +0 -0
- {sotkalib-0.0.5 → sotkalib-0.0.5.post2}/src/sotkalib/redis/client.py +0 -0
- {sotkalib-0.0.5 → sotkalib-0.0.5.post2}/src/sotkalib/redis/lock.py +0 -0
- {sotkalib-0.0.5 → sotkalib-0.0.5.post2}/src/sotkalib/sqla/__init__.py +0 -0
- {sotkalib-0.0.5 → sotkalib-0.0.5.post2}/src/sotkalib/sqla/db.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "sotkalib"
|
|
3
|
-
version = "0.0.5"
|
|
3
|
+
version = "0.0.5.post2"
|
|
4
4
|
description = ""
|
|
5
5
|
authors = [
|
|
6
6
|
{ email = "me@pyrorhythm.dev", name = "alexey" }
|
|
@@ -78,7 +78,7 @@ select = [
|
|
|
78
78
|
"PL",
|
|
79
79
|
"PERF"
|
|
80
80
|
]
|
|
81
|
-
ignore = ["PERF401"]
|
|
81
|
+
ignore = ["PERF401", "G004"]
|
|
82
82
|
|
|
83
83
|
[tool.ruff.lint.isort]
|
|
84
84
|
known-first-party = [
|
|
@@ -107,16 +107,21 @@ class RequestContext:
|
|
|
107
107
|
type Next[T] = Callable[[RequestContext], Awaitable[T]]
|
|
108
108
|
type Middleware[T, R] = Callable[[RequestContext, Next[T]], Awaitable[R]]
|
|
109
109
|
|
|
110
|
-
type ExcArgFunc = Callable[
|
|
111
|
-
type StatArgFunc = Callable[
|
|
110
|
+
type ExcArgFunc = Callable[[RequestContext], tuple[Sequence[Any], Mapping[str, Any] | None]]
|
|
111
|
+
type StatArgFunc = Callable[[RequestContext], tuple[Sequence[Any], Mapping[str, Any] | None]]
|
|
112
112
|
|
|
113
113
|
|
|
114
|
-
async def default_stat_arg_func(
|
|
114
|
+
async def default_stat_arg_func(ctx: RequestContext) -> tuple[Sequence[Any], None]:
|
|
115
|
+
resp = ctx.response
|
|
116
|
+
if resp is None:
|
|
117
|
+
return (), None
|
|
115
118
|
return (f"[{resp.status}]; {await resp.text()=}",), None
|
|
116
119
|
|
|
117
120
|
|
|
118
|
-
def default_exc_arg_func(
|
|
119
|
-
|
|
121
|
+
def default_exc_arg_func(ctx: RequestContext) -> tuple[Sequence[Any], None]:
|
|
122
|
+
exc = ctx.last_error
|
|
123
|
+
msg = f"exception {type(exc)}: ({exc=}) attempt={ctx.attempt}; url={ctx.url} method={ctx.method}"
|
|
124
|
+
return (msg,), None
|
|
120
125
|
|
|
121
126
|
|
|
122
127
|
class StatusSettings(BaseModel):
|
|
@@ -171,11 +176,6 @@ class ClientSettings(BaseModel):
|
|
|
171
176
|
use_cookies_from_response: bool = Field(default=False)
|
|
172
177
|
|
|
173
178
|
|
|
174
|
-
# ============================================================================
|
|
175
|
-
# SSL Context
|
|
176
|
-
# ============================================================================
|
|
177
|
-
|
|
178
|
-
|
|
179
179
|
def _make_ssl_context(disable_tls13: bool = False) -> ssl.SSLContext:
|
|
180
180
|
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
|
|
181
181
|
ctx.load_default_certs()
|
|
@@ -199,11 +199,6 @@ def _make_ssl_context(disable_tls13: bool = False) -> ssl.SSLContext:
|
|
|
199
199
|
return ctx
|
|
200
200
|
|
|
201
201
|
|
|
202
|
-
# ============================================================================
|
|
203
|
-
# HTTP Session
|
|
204
|
-
# ============================================================================
|
|
205
|
-
|
|
206
|
-
|
|
207
202
|
class HTTPSession[R = aiohttp.ClientResponse | None]:
|
|
208
203
|
config: ClientSettings
|
|
209
204
|
_session: aiohttp.ClientSession | None
|
|
@@ -253,20 +248,16 @@ class HTTPSession[R = aiohttp.ClientResponse | None]:
|
|
|
253
248
|
await self._session.close()
|
|
254
249
|
|
|
255
250
|
def _build_pipeline(self) -> Next[R]:
|
|
256
|
-
"""Build the middleware pipeline with the core request at the end."""
|
|
257
|
-
|
|
258
251
|
async def core_request(ctx: RequestContext) -> aiohttp.ClientResponse | None:
|
|
259
|
-
"""The innermost handler that actually makes the HTTP request."""
|
|
260
252
|
return await self._execute_request(ctx)
|
|
261
253
|
|
|
262
254
|
pipeline: Next[Any] = core_request
|
|
263
255
|
for middleware in reversed(self._middlewares):
|
|
264
|
-
pipeline = (lambda mw, nxt: lambda c: mw(c, nxt))(middleware, pipeline)
|
|
256
|
+
pipeline = (lambda mw, nxt: lambda c: mw(c, nxt))(middleware, pipeline) # noqa: PLC3002
|
|
265
257
|
|
|
266
258
|
return pipeline
|
|
267
259
|
|
|
268
260
|
async def _execute_request(self, ctx: RequestContext) -> aiohttp.ClientResponse | None:
|
|
269
|
-
"""Execute the actual HTTP request and handle status codes."""
|
|
270
261
|
if self._session is None:
|
|
271
262
|
raise RuntimeError("HTTPSession must be used as async context manager")
|
|
272
263
|
|
|
@@ -280,7 +271,6 @@ class HTTPSession[R = aiohttp.ClientResponse | None]:
|
|
|
280
271
|
ctx: RequestContext,
|
|
281
272
|
response: aiohttp.ClientResponse,
|
|
282
273
|
) -> aiohttp.ClientResponse | None:
|
|
283
|
-
"""Handle HTTP status codes according to settings."""
|
|
284
274
|
status = response.status
|
|
285
275
|
settings = self.config.status_settings
|
|
286
276
|
|
|
@@ -294,7 +284,7 @@ class HTTPSession[R = aiohttp.ClientResponse | None]:
|
|
|
294
284
|
|
|
295
285
|
if HTTPStatus(status) in settings.to_raise:
|
|
296
286
|
exc_cls = settings.exc_to_raise
|
|
297
|
-
args, kwargs =
|
|
287
|
+
args, kwargs = settings.args_for_exc_func(ctx)
|
|
298
288
|
if kwargs is None:
|
|
299
289
|
raise exc_cls(*args)
|
|
300
290
|
raise exc_cls(*args, **kwargs)
|
|
@@ -304,9 +294,7 @@ class HTTPSession[R = aiohttp.ClientResponse | None]:
|
|
|
304
294
|
|
|
305
295
|
return response
|
|
306
296
|
|
|
307
|
-
|
|
308
297
|
async def _request_with_retry(self, ctx: RequestContext) -> R:
|
|
309
|
-
"""Execute request with retry logic."""
|
|
310
298
|
ctx.started_at = time.monotonic()
|
|
311
299
|
ctx.max_attempts = self.config.maximum_retries + 1
|
|
312
300
|
|
|
@@ -357,14 +345,11 @@ class HTTPSession[R = aiohttp.ClientResponse | None]:
|
|
|
357
345
|
await asyncio.sleep(delay)
|
|
358
346
|
|
|
359
347
|
async def _handle_to_raise(self, ctx: RequestContext, e: Exception) -> None:
|
|
360
|
-
"""Handle exceptions that should be re-raised (possibly wrapped)."""
|
|
361
348
|
exc_cls = self.config.exception_settings.exc_to_raise
|
|
362
349
|
if exc_cls is None:
|
|
363
350
|
raise e
|
|
364
351
|
|
|
365
|
-
args, kwargs = self.config.exception_settings.args_for_exc_func(
|
|
366
|
-
e, ctx.attempt, ctx.url, ctx.method, **ctx.to_request_kwargs()
|
|
367
|
-
)
|
|
352
|
+
args, kwargs = self.config.exception_settings.args_for_exc_func(ctx)
|
|
368
353
|
if kwargs is None:
|
|
369
354
|
raise exc_cls(*args) from e
|
|
370
355
|
raise exc_cls(*args, **kwargs) from e
|
|
@@ -439,6 +424,8 @@ class HTTPSession[R = aiohttp.ClientResponse | None]:
|
|
|
439
424
|
|
|
440
425
|
def merge_tuples[T](t1: tuple[T, ...], t2: tuple[T, ...]) -> tuple[T, ...]:
|
|
441
426
|
return t1 + t2
|
|
427
|
+
|
|
428
|
+
|
|
442
429
|
# ============================================================================
|
|
443
430
|
# Legacy compatibility aliases
|
|
444
431
|
# ============================================================================
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|