tempest-fastapi-sdk 0.7.2__tar.gz → 0.7.3__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.
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/PKG-INFO +1 -1
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/pyproject.toml +1 -1
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/__init__.py +1 -1
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/api/middlewares/request_id.py +17 -1
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/api/routers/health.py +10 -3
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/db/connection.py +20 -3
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/settings/mixins.py +12 -2
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/sse/event_stream.py +4 -3
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/webpush/dispatcher.py +33 -3
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/webpush/schemas.py +29 -1
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/api/test_health_router.py +19 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/api/test_request_id_middleware.py +23 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/db/test_connection.py +24 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/sse/test_event_stream.py +30 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/webpush/test_schemas.py +18 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/uv.lock +2 -2
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/.github/workflows/ci.yml +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/.github/workflows/release-pypi.yml +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/.gitignore +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/.python-version +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/Makefile +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/README.md +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/api/__init__.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/api/dependencies/__init__.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/api/dependencies/auth.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/api/handlers.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/api/middlewares/__init__.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/api/middlewares/cors.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/api/routers/__init__.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/cache/__init__.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/cache/redis_manager.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/controllers/__init__.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/controllers/base.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/core/__init__.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/core/context.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/core/logging.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/db/__init__.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/db/_alembic_templates/__init__.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/db/_alembic_templates/env.py.template +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/db/migrations.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/db/mixins.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/db/model.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/db/repository.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/exceptions/__init__.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/exceptions/base.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/exceptions/conflict.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/exceptions/forbidden.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/exceptions/jwt.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/exceptions/not_found.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/exceptions/unauthorized.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/exceptions/upload.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/exceptions/validation.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/queue/__init__.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/queue/manager.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/schemas/__init__.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/schemas/base.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/schemas/pagination.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/schemas/response.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/services/__init__.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/services/base.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/settings/__init__.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/settings/base.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/sse/__init__.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/tasks/__init__.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/tasks/manager.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/testing/__init__.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/testing/database.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/utils/__init__.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/utils/datetime.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/utils/dict.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/utils/email.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/utils/jwt.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/utils/log.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/utils/metrics.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/utils/password.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/utils/regex.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/utils/upload.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/webpush/__init__.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/__init__.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/api/__init__.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/api/test_cors.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/api/test_dependencies_auth.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/api/test_handlers.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/cache/__init__.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/cache/test_redis_manager.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/conftest.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/controllers/__init__.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/controllers/test_base.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/core/__init__.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/core/test_context.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/core/test_logging.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/db/__init__.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/db/test_migrations.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/db/test_mixins.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/db/test_model.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/db/test_repository.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/exceptions/__init__.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/exceptions/test_exceptions.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/queue/__init__.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/queue/test_manager.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/schemas/__init__.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/schemas/test_base.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/schemas/test_cursor_pagination.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/schemas/test_pagination.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/schemas/test_response.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/services/__init__.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/services/test_base.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/settings/__init__.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/settings/test_base.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/settings/test_mixins.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/sse/__init__.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/tasks/__init__.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/tasks/test_manager.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/testing/__init__.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/testing/test_database.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/utils/__init__.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/utils/test_datetime.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/utils/test_dict.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/utils/test_email.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/utils/test_jwt.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/utils/test_lazy_extras.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/utils/test_log.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/utils/test_metrics.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/utils/test_password.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/utils/test_regex.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/utils/test_upload.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/webpush/__init__.py +0 -0
- {tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/webpush/test_dispatcher.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tempest-fastapi-sdk
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.3
|
|
4
4
|
Summary: Shared FastAPI building blocks: base schemas, ORM model, async repository, exceptions, pagination and settings — the conventions used across Tempest projects.
|
|
5
5
|
Project-URL: Homepage, https://github.com/mauriciobenjamin700/tempest-fastapi-sdk
|
|
6
6
|
Project-URL: Repository, https://github.com/mauriciobenjamin700/tempest-fastapi-sdk
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "tempest-fastapi-sdk"
|
|
3
|
-
version = "0.7.
|
|
3
|
+
version = "0.7.3"
|
|
4
4
|
description = "Shared FastAPI building blocks: base schemas, ORM model, async repository, exceptions, pagination and settings — the conventions used across Tempest projects."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.11"
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import re
|
|
5
6
|
import uuid
|
|
6
7
|
from collections.abc import Awaitable, Callable
|
|
7
8
|
|
|
@@ -12,6 +13,16 @@ from starlette.types import ASGIApp
|
|
|
12
13
|
|
|
13
14
|
from tempest_fastapi_sdk.core.context import clear_request_id, set_request_id
|
|
14
15
|
|
|
16
|
+
_VALID_REQUEST_ID = re.compile(r"^[A-Za-z0-9._\-:+/=]{1,128}$")
|
|
17
|
+
"""Whitelist for inbound request IDs.
|
|
18
|
+
|
|
19
|
+
Restricts the header value to printable ASCII without whitespace or
|
|
20
|
+
control characters so it cannot be used to forge log lines (CRLF
|
|
21
|
+
injection inside :class:`JSONFormatter`) or response headers when
|
|
22
|
+
echoed back. Generous enough to cover UUIDs, ULIDs, base64 trace
|
|
23
|
+
IDs, and most OpenTelemetry trace identifiers.
|
|
24
|
+
"""
|
|
25
|
+
|
|
15
26
|
|
|
16
27
|
class RequestIDMiddleware(BaseHTTPMiddleware):
|
|
17
28
|
"""Bind an ``X-Request-ID`` header to the request-scoped context.
|
|
@@ -51,7 +62,12 @@ class RequestIDMiddleware(BaseHTTPMiddleware):
|
|
|
51
62
|
Response: The handler's response with the request ID
|
|
52
63
|
echoed in the configured header.
|
|
53
64
|
"""
|
|
54
|
-
|
|
65
|
+
inbound = request.headers.get(self.header_name)
|
|
66
|
+
rid = (
|
|
67
|
+
inbound
|
|
68
|
+
if inbound is not None and _VALID_REQUEST_ID.fullmatch(inbound)
|
|
69
|
+
else str(uuid.uuid4())
|
|
70
|
+
)
|
|
55
71
|
token = set_request_id(rid)
|
|
56
72
|
try:
|
|
57
73
|
response = await call_next(request)
|
{tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/api/routers/health.py
RENAMED
|
@@ -29,6 +29,7 @@ def make_health_router(
|
|
|
29
29
|
prefix: str = "/health",
|
|
30
30
|
tag: str = "health",
|
|
31
31
|
version: str | None = None,
|
|
32
|
+
expose_checks: bool = True,
|
|
32
33
|
) -> APIRouter:
|
|
33
34
|
"""Build the canonical ``/health`` router.
|
|
34
35
|
|
|
@@ -40,8 +41,8 @@ def make_health_router(
|
|
|
40
41
|
liveness probes as "restart the pod"). This endpoint takes
|
|
41
42
|
precedence over readiness for that reason.
|
|
42
43
|
* ``GET <prefix>/readiness`` — runs every configured check and
|
|
43
|
-
returns ``200`` only when all pass. Returns ``503``
|
|
44
|
-
|
|
44
|
+
returns ``200`` only when all pass. Returns ``503`` when at
|
|
45
|
+
least one fails.
|
|
45
46
|
|
|
46
47
|
Args:
|
|
47
48
|
db (AsyncDatabaseManager | None): When provided, a
|
|
@@ -55,6 +56,11 @@ def make_health_router(
|
|
|
55
56
|
tag (str): OpenAPI tag applied to both endpoints.
|
|
56
57
|
version (str | None): When provided, attached to the
|
|
57
58
|
readiness payload as ``version``.
|
|
59
|
+
expose_checks (bool): Whether to surface the per-dependency
|
|
60
|
+
breakdown in the readiness payload. Defaults to ``True``
|
|
61
|
+
for development ergonomics; set ``False`` in production
|
|
62
|
+
so unauthenticated probes don't reveal which backends
|
|
63
|
+
(database, Redis, RabbitMQ, etc.) the service depends on.
|
|
58
64
|
|
|
59
65
|
Returns:
|
|
60
66
|
APIRouter: A router ready to ``include_router(...)`` on the
|
|
@@ -96,8 +102,9 @@ def make_health_router(
|
|
|
96
102
|
overall = all(results.values()) if results else True
|
|
97
103
|
payload: dict[str, Any] = {
|
|
98
104
|
"status": "ready" if overall else "not_ready",
|
|
99
|
-
"checks": results,
|
|
100
105
|
}
|
|
106
|
+
if expose_checks:
|
|
107
|
+
payload["checks"] = results
|
|
101
108
|
if version is not None:
|
|
102
109
|
payload["version"] = version
|
|
103
110
|
return JSONResponse(
|
{tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/db/connection.py
RENAMED
|
@@ -31,8 +31,11 @@ class AsyncDatabaseManager:
|
|
|
31
31
|
relying on substring tricks.
|
|
32
32
|
|
|
33
33
|
Attributes:
|
|
34
|
-
db_url (str): The database connection URL.
|
|
35
34
|
is_sqlite (bool): Whether the URL targets a SQLite backend.
|
|
35
|
+
|
|
36
|
+
The connection URL itself is stored on a private attribute so it
|
|
37
|
+
never leaks through ``repr()`` or accidental logging. Use the
|
|
38
|
+
:attr:`db_url_safe` property when a redacted form is needed.
|
|
36
39
|
"""
|
|
37
40
|
|
|
38
41
|
def __init__(
|
|
@@ -69,7 +72,7 @@ class AsyncDatabaseManager:
|
|
|
69
72
|
**engine_kwargs: Any additional keyword arguments are
|
|
70
73
|
passed through to ``create_async_engine`` verbatim.
|
|
71
74
|
"""
|
|
72
|
-
self.
|
|
75
|
+
self._db_url: str = db_url
|
|
73
76
|
self.is_sqlite: bool = make_url(db_url).get_backend_name() == "sqlite"
|
|
74
77
|
self._echo: bool = echo
|
|
75
78
|
self._pool_size: int = pool_size
|
|
@@ -81,6 +84,20 @@ class AsyncDatabaseManager:
|
|
|
81
84
|
self._engine: AsyncEngine | None = None
|
|
82
85
|
self._session_maker: async_sessionmaker[AsyncSession] | None = None
|
|
83
86
|
|
|
87
|
+
@property
|
|
88
|
+
def db_url_safe(self) -> str:
|
|
89
|
+
"""Return the URL with credentials masked.
|
|
90
|
+
|
|
91
|
+
Useful for diagnostics, health payloads or log lines —
|
|
92
|
+
``postgresql+asyncpg://user:pass@host/db`` becomes
|
|
93
|
+
``postgresql+asyncpg://***@host/db``.
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
str: The URL safe to surface outside the manager.
|
|
97
|
+
"""
|
|
98
|
+
url = make_url(self._db_url)
|
|
99
|
+
return url.render_as_string(hide_password=True)
|
|
100
|
+
|
|
84
101
|
@property
|
|
85
102
|
def is_connected(self) -> bool:
|
|
86
103
|
"""Whether the engine is currently initialized.
|
|
@@ -115,7 +132,7 @@ class AsyncDatabaseManager:
|
|
|
115
132
|
if self._poolclass is not None:
|
|
116
133
|
kwargs["poolclass"] = self._poolclass
|
|
117
134
|
|
|
118
|
-
self._engine = create_async_engine(self.
|
|
135
|
+
self._engine = create_async_engine(self._db_url, **kwargs)
|
|
119
136
|
self._session_maker = async_sessionmaker(
|
|
120
137
|
self._engine,
|
|
121
138
|
expire_on_commit=False,
|
{tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/settings/mixins.py
RENAMED
|
@@ -123,9 +123,19 @@ class JWTSettings(BaseSettings):
|
|
|
123
123
|
class CORSSettings(BaseSettings):
|
|
124
124
|
"""CORS middleware configuration.
|
|
125
125
|
|
|
126
|
+
.. warning::
|
|
127
|
+
The default ``CORS_ORIGINS=["*"]`` is permissive on purpose
|
|
128
|
+
so local development works out of the box. **Never** ship
|
|
129
|
+
this default to production — set ``CORS_ORIGINS`` to the
|
|
130
|
+
explicit list of trusted frontend origins (e.g.
|
|
131
|
+
``["https://app.example.com"]``) in your production
|
|
132
|
+
configuration. ``"*"`` is also incompatible with
|
|
133
|
+
``CORS_ALLOW_CREDENTIALS=True`` (browsers ignore credentialed
|
|
134
|
+
requests sent to a wildcard origin).
|
|
135
|
+
|
|
126
136
|
Attributes:
|
|
127
|
-
CORS_ORIGINS (list[str]): Allowed origins.
|
|
128
|
-
|
|
137
|
+
CORS_ORIGINS (list[str]): Allowed origins. **Override in
|
|
138
|
+
production.** Defaults to ``["*"]`` for development only.
|
|
129
139
|
CORS_ALLOW_CREDENTIALS (bool): Whether to allow cookies/auth
|
|
130
140
|
headers cross-origin.
|
|
131
141
|
CORS_ALLOW_METHODS (list[str]): Allowed HTTP methods.
|
{tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/sse/event_stream.py
RENAMED
|
@@ -176,8 +176,9 @@ def sse_response(
|
|
|
176
176
|
Adds the SSE-specific headers (``Cache-Control: no-cache``,
|
|
177
177
|
``Connection: keep-alive``, ``X-Accel-Buffering: no``) so
|
|
178
178
|
intermediate proxies don't buffer or cache the long-lived
|
|
179
|
-
response.
|
|
180
|
-
|
|
179
|
+
response. Caller-supplied ``headers`` are layered **below** the
|
|
180
|
+
SSE defaults so the three critical headers above cannot be
|
|
181
|
+
accidentally overridden — pass extra metadata, not replacements.
|
|
181
182
|
|
|
182
183
|
Args:
|
|
183
184
|
stream (AsyncIterable[bytes]): The byte stream produced by
|
|
@@ -188,7 +189,7 @@ def sse_response(
|
|
|
188
189
|
Returns:
|
|
189
190
|
StreamingResponse: A ready-to-return SSE response.
|
|
190
191
|
"""
|
|
191
|
-
merged: dict[str, str] = {**
|
|
192
|
+
merged: dict[str, str] = {**(headers or {}), **_SSE_HEADERS}
|
|
192
193
|
return StreamingResponse(
|
|
193
194
|
stream,
|
|
194
195
|
media_type="text/event-stream",
|
{tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/webpush/dispatcher.py
RENAMED
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import asyncio
|
|
6
|
+
import hashlib
|
|
6
7
|
import json
|
|
7
8
|
import logging
|
|
8
9
|
from typing import Any
|
|
10
|
+
from urllib.parse import urlsplit
|
|
9
11
|
|
|
10
12
|
from tempest_fastapi_sdk.webpush.schemas import (
|
|
11
13
|
WebPushPayloadSchema,
|
|
@@ -15,6 +17,29 @@ from tempest_fastapi_sdk.webpush.schemas import (
|
|
|
15
17
|
logger = logging.getLogger(__name__)
|
|
16
18
|
|
|
17
19
|
|
|
20
|
+
def _mask_endpoint(endpoint: str) -> str:
|
|
21
|
+
"""Return a stable but non-sensitive identifier for an endpoint.
|
|
22
|
+
|
|
23
|
+
Keeps the host (useful for routing errors to the right push
|
|
24
|
+
service) and replaces the full path + query with a short SHA-256
|
|
25
|
+
prefix so subscription tokens never reach logs or API responses.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
endpoint (str): The full push service URL.
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
str: ``<host>/<sha256-prefix>`` or the original string when it
|
|
32
|
+
cannot be parsed.
|
|
33
|
+
"""
|
|
34
|
+
try:
|
|
35
|
+
parsed = urlsplit(endpoint)
|
|
36
|
+
except ValueError:
|
|
37
|
+
return "<unparsable-endpoint>"
|
|
38
|
+
host = parsed.netloc or "<unknown-host>"
|
|
39
|
+
digest = hashlib.sha256(endpoint.encode("utf-8")).hexdigest()[:12]
|
|
40
|
+
return f"{host}/{digest}"
|
|
41
|
+
|
|
42
|
+
|
|
18
43
|
class WebPushError(RuntimeError):
|
|
19
44
|
"""Raised when a push delivery attempt fails irrecoverably.
|
|
20
45
|
|
|
@@ -169,14 +194,15 @@ class WebPushDispatcher:
|
|
|
169
194
|
)
|
|
170
195
|
except pywebpush.WebPushException as exc:
|
|
171
196
|
status = exc.response.status_code if exc.response is not None else None
|
|
197
|
+
masked = _mask_endpoint(subscription.endpoint)
|
|
172
198
|
if status in {404, 410}:
|
|
173
199
|
raise WebPushGoneError(
|
|
174
|
-
f"Subscription gone (HTTP {status})",
|
|
200
|
+
f"Subscription gone (HTTP {status}) for {masked}",
|
|
175
201
|
status_code=status,
|
|
176
202
|
endpoint=subscription.endpoint,
|
|
177
203
|
) from exc
|
|
178
204
|
raise WebPushError(
|
|
179
|
-
f"Web Push delivery failed
|
|
205
|
+
f"Web Push delivery failed for {masked} (HTTP {status})",
|
|
180
206
|
status_code=status,
|
|
181
207
|
endpoint=subscription.endpoint,
|
|
182
208
|
) from exc
|
|
@@ -216,7 +242,11 @@ class WebPushDispatcher:
|
|
|
216
242
|
except WebPushGoneError:
|
|
217
243
|
gone.append(sub.endpoint)
|
|
218
244
|
except WebPushError as exc:
|
|
219
|
-
logger.warning(
|
|
245
|
+
logger.warning(
|
|
246
|
+
"Web Push send failed for %s: %s",
|
|
247
|
+
_mask_endpoint(sub.endpoint),
|
|
248
|
+
exc,
|
|
249
|
+
)
|
|
220
250
|
|
|
221
251
|
await asyncio.gather(*(_one(sub) for sub in subscriptions))
|
|
222
252
|
return gone
|
{tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/webpush/schemas.py
RENAMED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
from typing import Any
|
|
6
|
+
from urllib.parse import urlsplit
|
|
6
7
|
|
|
7
|
-
from pydantic import ConfigDict, Field
|
|
8
|
+
from pydantic import ConfigDict, Field, field_validator
|
|
8
9
|
|
|
9
10
|
from tempest_fastapi_sdk.schemas.base import BaseSchema
|
|
10
11
|
|
|
@@ -58,6 +59,33 @@ class WebPushSubscriptionSchema(BaseSchema):
|
|
|
58
59
|
description="Optional expiration time (ms since epoch).",
|
|
59
60
|
)
|
|
60
61
|
|
|
62
|
+
@field_validator("endpoint")
|
|
63
|
+
@classmethod
|
|
64
|
+
def _endpoint_must_be_https(cls, value: str) -> str:
|
|
65
|
+
"""Reject endpoints that aren't ``https://`` URLs.
|
|
66
|
+
|
|
67
|
+
The Web Push spec requires HTTPS, and accepting arbitrary
|
|
68
|
+
schemes (``file://``, ``http://localhost``, etc.) would turn
|
|
69
|
+
the server into an SSRF proxy when subscriptions come from
|
|
70
|
+
untrusted clients.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
value (str): The candidate endpoint URL.
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
str: The same URL when valid.
|
|
77
|
+
|
|
78
|
+
Raises:
|
|
79
|
+
ValueError: When the URL is malformed or not HTTPS.
|
|
80
|
+
"""
|
|
81
|
+
try:
|
|
82
|
+
parsed = urlsplit(value)
|
|
83
|
+
except ValueError as exc:
|
|
84
|
+
raise ValueError("Invalid endpoint URL") from exc
|
|
85
|
+
if parsed.scheme != "https" or not parsed.netloc:
|
|
86
|
+
raise ValueError("Push endpoints must be HTTPS URLs.")
|
|
87
|
+
return value
|
|
88
|
+
|
|
61
89
|
|
|
62
90
|
class WebPushPayloadSchema(BaseSchema):
|
|
63
91
|
"""Optional helper for the JSON payload delivered with each push.
|
|
@@ -76,3 +76,22 @@ async def test_custom_prefix() -> None:
|
|
|
76
76
|
async with _client(app) as client:
|
|
77
77
|
liveness = await client.get("/ops/health/liveness")
|
|
78
78
|
assert liveness.status_code == 200
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@pytest.mark.asyncio
|
|
82
|
+
async def test_readiness_hides_checks_when_expose_checks_false() -> None:
|
|
83
|
+
"""Production deployments can hide the per-dependency breakdown."""
|
|
84
|
+
|
|
85
|
+
async def db_check() -> bool:
|
|
86
|
+
return False
|
|
87
|
+
|
|
88
|
+
app = FastAPI()
|
|
89
|
+
app.include_router(
|
|
90
|
+
make_health_router(checks={"database": db_check}, expose_checks=False),
|
|
91
|
+
)
|
|
92
|
+
async with _client(app) as client:
|
|
93
|
+
response = await client.get("/health/readiness")
|
|
94
|
+
body = response.json()
|
|
95
|
+
assert response.status_code == 503
|
|
96
|
+
assert body["status"] == "not_ready"
|
|
97
|
+
assert "checks" not in body
|
{tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/api/test_request_id_middleware.py
RENAMED
|
@@ -54,6 +54,29 @@ async def test_context_is_isolated_between_requests() -> None:
|
|
|
54
54
|
assert get_request_id() is None
|
|
55
55
|
|
|
56
56
|
|
|
57
|
+
@pytest.mark.asyncio
|
|
58
|
+
@pytest.mark.parametrize(
|
|
59
|
+
"malicious",
|
|
60
|
+
[
|
|
61
|
+
"abc\r\nX-Injected: 1",
|
|
62
|
+
"abc\nlevel=CRITICAL",
|
|
63
|
+
"abc with spaces",
|
|
64
|
+
"abc;rm -rf /",
|
|
65
|
+
"x" * 200, # exceeds 128-char cap
|
|
66
|
+
],
|
|
67
|
+
)
|
|
68
|
+
async def test_malicious_header_replaced_with_uuid(malicious: str) -> None:
|
|
69
|
+
"""Reject CRLF and other unsafe characters to block log/header injection."""
|
|
70
|
+
app = _make_app()
|
|
71
|
+
transport = ASGITransport(app=app)
|
|
72
|
+
async with AsyncClient(transport=transport, base_url="http://test") as client:
|
|
73
|
+
response = await client.get("/echo", headers={"X-Request-ID": malicious})
|
|
74
|
+
rid = response.headers["X-Request-ID"]
|
|
75
|
+
uuid.UUID(rid) # must be a fresh UUID, not the attacker's value
|
|
76
|
+
assert rid != malicious
|
|
77
|
+
assert response.json()["request_id"] == rid
|
|
78
|
+
|
|
79
|
+
|
|
57
80
|
@pytest.mark.asyncio
|
|
58
81
|
async def test_custom_header_name() -> None:
|
|
59
82
|
app = FastAPI()
|
|
@@ -120,6 +120,30 @@ class TestHealthCheck:
|
|
|
120
120
|
await manager.disconnect()
|
|
121
121
|
|
|
122
122
|
|
|
123
|
+
class TestUrlMasking:
|
|
124
|
+
def test_db_url_safe_hides_password(self) -> None:
|
|
125
|
+
manager = AsyncDatabaseManager(
|
|
126
|
+
"postgresql+asyncpg://alice:supersecret@db.internal:5432/app",
|
|
127
|
+
)
|
|
128
|
+
safe = manager.db_url_safe
|
|
129
|
+
assert "supersecret" not in safe
|
|
130
|
+
assert "alice" in safe
|
|
131
|
+
assert "db.internal" in safe
|
|
132
|
+
|
|
133
|
+
def test_db_url_safe_handles_url_without_password(self) -> None:
|
|
134
|
+
manager = AsyncDatabaseManager("sqlite+aiosqlite:///:memory:")
|
|
135
|
+
assert manager.db_url_safe.startswith("sqlite+aiosqlite://")
|
|
136
|
+
|
|
137
|
+
def test_db_url_no_public_attribute(self) -> None:
|
|
138
|
+
manager = AsyncDatabaseManager(
|
|
139
|
+
"postgresql+asyncpg://alice:supersecret@db.internal:5432/app",
|
|
140
|
+
)
|
|
141
|
+
# Credentials must not be reachable via a public attribute.
|
|
142
|
+
assert not hasattr(manager, "db_url") or "supersecret" not in str(
|
|
143
|
+
getattr(manager, "db_url", "")
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
|
|
123
147
|
class TestRequireConnected:
|
|
124
148
|
async def test_session_methods_lazy_connect(self) -> None:
|
|
125
149
|
# get_session / get_session_context / session_dependency all
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Tests for tempest_fastapi_sdk.sse."""
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
|
+
from collections.abc import AsyncIterator
|
|
4
5
|
|
|
5
6
|
import pytest
|
|
6
7
|
from fastapi import FastAPI
|
|
@@ -98,3 +99,32 @@ async def test_sse_response_end_to_end() -> None:
|
|
|
98
99
|
assert b"event: ping" in response.content
|
|
99
100
|
assert b"data: hello" in response.content
|
|
100
101
|
assert b"data: world" in response.content
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
async def test_sse_response_caller_headers_cannot_override_defaults() -> None:
|
|
105
|
+
"""Caller-supplied headers must not override SSE-critical headers."""
|
|
106
|
+
from fastapi import FastAPI
|
|
107
|
+
|
|
108
|
+
app = FastAPI()
|
|
109
|
+
|
|
110
|
+
async def empty() -> AsyncIterator[bytes]:
|
|
111
|
+
if False: # pragma: no cover - generator never yields
|
|
112
|
+
yield b""
|
|
113
|
+
|
|
114
|
+
@app.get("/events")
|
|
115
|
+
async def events() -> object:
|
|
116
|
+
return sse_response(
|
|
117
|
+
empty(),
|
|
118
|
+
headers={
|
|
119
|
+
"Cache-Control": "public, max-age=3600",
|
|
120
|
+
"X-Accel-Buffering": "yes",
|
|
121
|
+
"X-Custom": "ok",
|
|
122
|
+
},
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
transport = ASGITransport(app=app)
|
|
126
|
+
async with AsyncClient(transport=transport, base_url="http://test") as client:
|
|
127
|
+
response = await client.get("/events")
|
|
128
|
+
assert response.headers["cache-control"] == "no-cache"
|
|
129
|
+
assert response.headers["x-accel-buffering"] == "no"
|
|
130
|
+
assert response.headers["x-custom"] == "ok"
|
|
@@ -45,6 +45,24 @@ class TestWebPushSubscription:
|
|
|
45
45
|
keys=WebPushKeysSchema(p256dh="pk", auth="a"),
|
|
46
46
|
)
|
|
47
47
|
|
|
48
|
+
@pytest.mark.parametrize(
|
|
49
|
+
"endpoint",
|
|
50
|
+
[
|
|
51
|
+
"http://push.example.com/abc",
|
|
52
|
+
"file:///etc/passwd",
|
|
53
|
+
"ftp://push.example.com/abc",
|
|
54
|
+
"javascript:alert(1)",
|
|
55
|
+
"not-a-url",
|
|
56
|
+
],
|
|
57
|
+
)
|
|
58
|
+
def test_non_https_endpoint_rejected(self, endpoint: str) -> None:
|
|
59
|
+
"""Reject non-HTTPS endpoints to prevent SSRF via subscriptions."""
|
|
60
|
+
with pytest.raises(ValueError):
|
|
61
|
+
WebPushSubscriptionSchema(
|
|
62
|
+
endpoint=endpoint,
|
|
63
|
+
keys=WebPushKeysSchema(p256dh="pk", auth="a"),
|
|
64
|
+
)
|
|
65
|
+
|
|
48
66
|
|
|
49
67
|
class TestWebPushPayload:
|
|
50
68
|
def test_all_fields_optional(self) -> None:
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
version = 1
|
|
2
|
-
revision =
|
|
2
|
+
revision = 2
|
|
3
3
|
requires-python = ">=3.11"
|
|
4
4
|
resolution-markers = [
|
|
5
5
|
"python_full_version >= '3.15'",
|
|
@@ -1948,7 +1948,7 @@ wheels = [
|
|
|
1948
1948
|
|
|
1949
1949
|
[[package]]
|
|
1950
1950
|
name = "tempest-fastapi-sdk"
|
|
1951
|
-
version = "0.7.
|
|
1951
|
+
version = "0.7.3"
|
|
1952
1952
|
source = { editable = "." }
|
|
1953
1953
|
dependencies = [
|
|
1954
1954
|
{ name = "alembic" },
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/api/dependencies/auth.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/api/middlewares/cors.py
RENAMED
|
File without changes
|
{tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/api/routers/__init__.py
RENAMED
|
File without changes
|
{tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/cache/__init__.py
RENAMED
|
File without changes
|
{tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/cache/redis_manager.py
RENAMED
|
File without changes
|
{tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/controllers/__init__.py
RENAMED
|
File without changes
|
{tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/controllers/base.py
RENAMED
|
File without changes
|
{tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/core/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/db/migrations.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/db/repository.py
RENAMED
|
File without changes
|
{tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/exceptions/__init__.py
RENAMED
|
File without changes
|
{tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/exceptions/base.py
RENAMED
|
File without changes
|
{tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/exceptions/conflict.py
RENAMED
|
File without changes
|
{tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/exceptions/forbidden.py
RENAMED
|
File without changes
|
{tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/exceptions/jwt.py
RENAMED
|
File without changes
|
{tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/exceptions/not_found.py
RENAMED
|
File without changes
|
|
File without changes
|
{tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/exceptions/upload.py
RENAMED
|
File without changes
|
{tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/exceptions/validation.py
RENAMED
|
File without changes
|
{tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/queue/__init__.py
RENAMED
|
File without changes
|
{tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/queue/manager.py
RENAMED
|
File without changes
|
{tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/schemas/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/schemas/pagination.py
RENAMED
|
File without changes
|
{tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/schemas/response.py
RENAMED
|
File without changes
|
{tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/services/__init__.py
RENAMED
|
File without changes
|
{tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/services/base.py
RENAMED
|
File without changes
|
{tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/settings/__init__.py
RENAMED
|
File without changes
|
{tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/settings/base.py
RENAMED
|
File without changes
|
|
File without changes
|
{tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/tasks/__init__.py
RENAMED
|
File without changes
|
{tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/tasks/manager.py
RENAMED
|
File without changes
|
{tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/testing/__init__.py
RENAMED
|
File without changes
|
{tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/testing/database.py
RENAMED
|
File without changes
|
{tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/utils/__init__.py
RENAMED
|
File without changes
|
{tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/utils/datetime.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/utils/metrics.py
RENAMED
|
File without changes
|
{tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/utils/password.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tempest_fastapi_sdk/webpush/__init__.py
RENAMED
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tempest_fastapi_sdk-0.7.2 → tempest_fastapi_sdk-0.7.3}/tests/schemas/test_cursor_pagination.py
RENAMED
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|