tempest-fastapi-sdk 0.82.0__tar.gz → 0.87.0__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.82.0 → tempest_fastapi_sdk-0.87.0}/CHANGELOG.md +118 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/CLAUDE.md +66 -24
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/PKG-INFO +38 -31
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/README.md +34 -30
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/admin.en.md +110 -3
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/admin.md +108 -3
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/auth-flow.en.md +117 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/auth-flow.md +116 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/cache.en.md +2 -1
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/cache.md +2 -1
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/index.en.md +1 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/index.md +1 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/security.en.md +2 -1
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/security.md +2 -1
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/sessions.en.md +4 -2
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/sessions.md +4 -2
- tempest_fastapi_sdk-0.87.0/docs/recipes/vision.en.md +128 -0
- tempest_fastapi_sdk-0.87.0/docs/recipes/vision.md +127 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/reference.md +18 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/mkdocs.yml +1 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/pyproject.toml +18 -1
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/__init__.py +17 -1
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/__init__.py +8 -0
- tempest_fastapi_sdk-0.87.0/tempest_fastapi_sdk/admin/actions.py +160 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/config.py +58 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/forms.py +16 -2
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/router.py +287 -41
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/static/admin.css +18 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/templates/form.html +4 -1
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/templates/list.html +16 -4
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/dependencies/auth.py +28 -7
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/__init__.py +14 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/router.py +234 -50
- tempest_fastapi_sdk-0.87.0/tempest_fastapi_sdk/auth/token_delivery.py +158 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/settings/mixins.py +76 -1
- tempest_fastapi_sdk-0.87.0/tempest_fastapi_sdk/vision/__init__.py +85 -0
- tempest_fastapi_sdk-0.87.0/tempest_fastapi_sdk/vision/mapping.py +123 -0
- tempest_fastapi_sdk-0.87.0/tempest_fastapi_sdk/vision/schemas.py +111 -0
- tempest_fastapi_sdk-0.87.0/tests/admin/test_actions.py +183 -0
- tempest_fastapi_sdk-0.87.0/tests/admin/test_rich_filters.py +176 -0
- tempest_fastapi_sdk-0.87.0/tests/admin/test_upload_field.py +161 -0
- tempest_fastapi_sdk-0.87.0/tests/auth/test_cookie_delivery.py +303 -0
- tempest_fastapi_sdk-0.87.0/tests/vision/test_vision.py +95 -0
- tempest_fastapi_sdk-0.87.0/tests/websockets/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/uv.lock +297 -3
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/.github/workflows/ci.yml +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/.github/workflows/docs.yml +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/.github/workflows/release-pypi.yml +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/.gitignore +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/.python-version +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/Makefile +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/architecture.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/architecture.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/changelog.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/changelog.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/contributing.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/contributing.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/index.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/index.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/installation.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/installation.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/learning/index.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/learning/index.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/learning/marketplace/api.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/learning/marketplace/api.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/learning/marketplace/business-rules.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/learning/marketplace/business-rules.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/learning/marketplace/domain.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/learning/marketplace/domain.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/learning/marketplace/flows.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/learning/marketplace/flows.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/learning/marketplace/index.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/learning/marketplace/index.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/migration.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/migration.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/audit-trail.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/audit-trail.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/br-helpers.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/br-helpers.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/cli.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/cli.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/database.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/database.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/deploy-safety.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/deploy-safety.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/downloads.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/downloads.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/email.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/email.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/feature-flags.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/feature-flags.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/fields.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/fields.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/http-client.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/http-client.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/http.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/http.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/idempotency.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/idempotency.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/logging.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/logging.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/metrics.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/metrics.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/mfa.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/mfa.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/multi-tenant.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/multi-tenant.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/observability.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/observability.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/offline-sync.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/offline-sync.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/outbox.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/outbox.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/queue-tasks.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/queue-tasks.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/realtime.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/realtime.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/refresh-tokens.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/refresh-tokens.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/sse.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/sse.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/storage.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/storage.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/stored-files.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/stored-files.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/testing.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/testing.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/typing.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/typing.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/uploads.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/uploads.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/utilities.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/utilities.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/webpush.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/webpush.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/websocket.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/recipes/websocket.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/reference.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/roadmap.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/roadmap.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/tutorial.en.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/docs/tutorial.md +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/mkdocs_hooks/llmstxt.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/scripts/extract_recipe.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/auth.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/discovery.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/session.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/site.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/templates/base.html +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/templates/dashboard.html +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/templates/detail.html +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/templates/login.html +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/templates/logs.html +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/templates/mfa.html +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/theme.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/cookies.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/dependencies/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/handlers.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/middlewares/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/middlewares/body_size.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/middlewares/cors.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/middlewares/csrf.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/middlewares/graceful.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/middlewares/idempotency.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/middlewares/rate_limit.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/middlewares/request_id.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/oauth.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/routers/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/routers/health.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/routers/logs.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/routers/metrics.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/routers/tool_spec.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/server.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/static.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/tracing.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/webhooks.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/guards.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/locale.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/page_renderer.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/schemas.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/service.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/templates/en-US/activation.html +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/templates/en-US/activation_error.html +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/templates/en-US/activation_success.html +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/templates/en-US/password_reset.html +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/templates/en-US/password_reset_error.html +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/templates/en-US/password_reset_form.html +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/templates/en-US/password_reset_success.html +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/templates/pt-BR/activation.html +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/templates/pt-BR/activation_error.html +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/templates/pt-BR/activation_success.html +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/templates/pt-BR/password_reset.html +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/templates/pt-BR/password_reset_error.html +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/templates/pt-BR/password_reset_form.html +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/templates/pt-BR/password_reset_success.html +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cache/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cache/decorator.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cache/invalidation.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cache/redis_manager.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/Dockerfile.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/README.md.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/dockerignore.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/env.example.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/gitignore.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/main.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/pyproject.toml.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/api/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/api/app.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/api/dependencies/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/api/dependencies/auth.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/api/dependencies/resources.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/api/routers/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/controllers/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/core/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/core/exceptions.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/core/settings.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/db/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/db/models/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/db/models/user.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/db/repositories/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/schemas/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/server.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/services/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/utils/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/tests/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/tests/test_smoke.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/config.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/db.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/docker_compose.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/generate.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/lint.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/main.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/new.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/secrets.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/src_layers.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/user.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/controllers/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/controllers/base.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/core/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/core/context.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/core/enums.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/core/logging.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/core/typed.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/_alembic_templates/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/_alembic_templates/env.py.template +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/alembic_hooks.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/audit.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/backup.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/connection.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/migrations.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/mixins.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/model.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/outbox.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/repository.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/slow_query.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/tenant.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/user_model.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/user_recovery_code_model.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/user_refresh_token_model.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/user_token_model.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/webpush_subscription_model.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/exceptions/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/exceptions/base.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/exceptions/conflict.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/exceptions/forbidden.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/exceptions/i18n.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/exceptions/jwt.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/exceptions/not_found.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/exceptions/too_many_requests.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/exceptions/unauthorized.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/exceptions/upload.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/exceptions/validation.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/flags/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/flags/backends.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/flags/dependencies.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/flags/service.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/py.typed +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/queue/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/queue/manager.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/schemas/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/schemas/base.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/schemas/link_headers.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/schemas/logs.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/schemas/pagination.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/schemas/response.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/services/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/services/base.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/services/file_mixin.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/sessions/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/sessions/dependencies.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/sessions/middleware.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/sessions/router.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/sessions/schemas.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/sessions/service.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/sessions/store.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/settings/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/settings/base.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/sse/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/sse/broker.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/sse/event_stream.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/storage/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/storage/minio_client.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/tasks/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/tasks/manager.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/tasks/scheduler.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/testing/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/testing/database.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/client_ip.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/data/br_locations.json +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/datetime.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/dict.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/download.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/email.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/fields.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/http_client.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/jwt.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/locations.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/log.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/metrics.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/opaque_token.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/password.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/regex.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/storage_backends.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/throttle.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/totp.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/upload.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/webpush/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/webpush/dispatcher.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/webpush/router.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/webpush/schemas.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/webpush/service.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/websockets/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/websockets/hub.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/websockets/router.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/websockets/schemas.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/admin/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/admin/test_auth.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/admin/test_discovery.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/admin/test_forms.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/admin/test_logs_nav.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/admin/test_mfa.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/admin/test_router.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/admin/test_site.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/admin/test_theme.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/admin/test_user_model.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/api/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/api/test_body_size.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/api/test_cookies.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/api/test_cors.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/api/test_csrf.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/api/test_dependencies_auth.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/api/test_graceful.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/api/test_handlers.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/api/test_health_router.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/api/test_idempotency.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/api/test_jwt_dependency.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/api/test_logs_router.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/api/test_oauth.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/api/test_prometheus.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/api/test_rate_limit.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/api/test_rate_limit_extras.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/api/test_request_id_middleware.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/api/test_role_dependency.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/api/test_server.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/api/test_static.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/api/test_tool_spec.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/api/test_tracing.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/api/test_webhooks.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/api/test_webhooks_rsa.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/auth/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/auth/test_guards.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/auth/test_locale.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/auth/test_mfa.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/auth/test_refresh.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/auth/test_refresh_db.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/auth/test_service.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/cache/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/cache/test_decorator.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/cache/test_invalidation.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/cache/test_redis_manager.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/cli/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/cli/test_config.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/cli/test_db.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/cli/test_db_seed.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/cli/test_docker_compose.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/cli/test_generate.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/cli/test_lint_strictness.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/cli/test_main.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/cli/test_secrets.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/cli/test_user.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/conftest.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/controllers/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/controllers/test_base.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/core/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/core/test_context.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/core/test_enums.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/core/test_logging.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/core/test_typed.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/db/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/db/test_alembic_hooks.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/db/test_audit.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/db/test_backup.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/db/test_bulk_ops.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/db/test_connection.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/db/test_migrations.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/db/test_mixins.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/db/test_model.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/db/test_outbox.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/db/test_repository.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/db/test_safe_upgrade.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/db/test_slow_query.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/db/test_tenant.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/exceptions/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/exceptions/test_exceptions.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/exceptions/test_i18n.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/flags/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/flags/test_flags.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/queue/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/queue/test_manager.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/schemas/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/schemas/test_base.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/schemas/test_cursor_pagination.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/schemas/test_link_headers.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/schemas/test_pagination.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/schemas/test_response.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/services/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/services/test_base.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/services/test_file_mixin.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/sessions/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/sessions/test_sessions.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/settings/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/settings/test_base.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/settings/test_mixins.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/sse/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/sse/test_broker.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/sse/test_event_stream.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/storage/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/storage/test_minio_client.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/tasks/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/tasks/test_manager.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/tasks/test_scheduler.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/testing/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/testing/test_database.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/utils/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_client_ip.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_datetime.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_dict.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_download.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_email.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_fields.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_http_client.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_jwt.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_lazy_extras.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_locations.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_log.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_metrics.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_opaque_token.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_password.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_regex.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_storage_backends.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_throttle.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_upload.py +0 -0
- {tempest_fastapi_sdk-0.82.0/tests/webpush → tempest_fastapi_sdk-0.87.0/tests/vision}/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0/tests/websockets → tempest_fastapi_sdk-0.87.0/tests/webpush}/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/webpush/test_dispatcher.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/webpush/test_router.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/webpush/test_schemas.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/webpush/test_service.py +0 -0
- {tempest_fastapi_sdk-0.82.0 → tempest_fastapi_sdk-0.87.0}/tests/websockets/test_hub_and_router.py +0 -0
|
@@ -5,6 +5,124 @@ All notable changes to **tempest-fastapi-sdk** are listed below.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.87.0] — 2026-07-02
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **Configurable token delivery for the auth router.** `make_auth_router`
|
|
13
|
+
now supports three ways of handing back the JWT pair, selected by
|
|
14
|
+
`AUTH_TOKEN_DELIVERY` (or the `token_delivery=` argument):
|
|
15
|
+
- `"bearer"` (default) — tokens in the JSON body only. Unchanged,
|
|
16
|
+
fully backward-compatible behaviour.
|
|
17
|
+
- `"cookie"` — `access_token` / `refresh_token` set as `HttpOnly`
|
|
18
|
+
cookies on `/auth/login`, `/auth/refresh`, `/auth/logout`; the body
|
|
19
|
+
omits the token values (safer against XSS). `POST /auth/refresh`
|
|
20
|
+
reads the refresh token from the cookie and rotates the pair;
|
|
21
|
+
`POST /auth/logout` clears the cookies (and revokes the refresh
|
|
22
|
+
family when a `refresh_token_model` is wired).
|
|
23
|
+
- `"both"` — the bearer endpoints stay at `/auth/*` and a parallel
|
|
24
|
+
cookie set is mounted at `/auth/cookie/*`, so one backend can serve
|
|
25
|
+
web (cookie) and mobile/API (bearer) clients.
|
|
26
|
+
- New `AUTH_COOKIE_SECURE`, `AUTH_COOKIE_SAMESITE`, `AUTH_COOKIE_DOMAIN`,
|
|
27
|
+
`AUTH_ACCESS_COOKIE_NAME` and `AUTH_REFRESH_COOKIE_NAME` settings tune
|
|
28
|
+
the cookie security attributes.
|
|
29
|
+
- New public exports: `TokenDelivery`, `AuthCookieConfig`,
|
|
30
|
+
`apply_auth_cookies`, `clear_auth_cookies`.
|
|
31
|
+
- `make_bearer_token_dependency` / `make_jwt_user_dependency` gained a
|
|
32
|
+
`cookie_name=` argument: when set, the access token is read from that
|
|
33
|
+
cookie if the `Authorization` header is absent (header still wins), so
|
|
34
|
+
the same guarded routes work in cookie mode.
|
|
35
|
+
|
|
36
|
+
### Notes
|
|
37
|
+
|
|
38
|
+
- Activation, signup auto-login and the MFA-verify step still return the
|
|
39
|
+
JWT pair in the body regardless of `AUTH_TOKEN_DELIVERY` — cookie
|
|
40
|
+
delivery covers the login / refresh / logout session lifecycle.
|
|
41
|
+
|
|
42
|
+
## [0.86.0] — 2026-06-28
|
|
43
|
+
|
|
44
|
+
### Added
|
|
45
|
+
|
|
46
|
+
- **Admin rich list filters.** `list_filter` fields now auto-pick a
|
|
47
|
+
widget by column type instead of rendering a useful dropdown only for
|
|
48
|
+
booleans: **enum** columns become a member dropdown, **foreign keys**
|
|
49
|
+
(whose target has a registered `AdminModel`) become a related-row
|
|
50
|
+
dropdown, **date/datetime** columns become an inclusive date-range
|
|
51
|
+
(two date inputs → `<field>__gte` / `<field>__lte`), and any other
|
|
52
|
+
column becomes a text input (equality). Booleans keep the Yes/No
|
|
53
|
+
dropdown. All filters preserve search / sort / pagination in the URL.
|
|
54
|
+
|
|
55
|
+
## [0.85.0] — 2026-06-28
|
|
56
|
+
|
|
57
|
+
### Added
|
|
58
|
+
|
|
59
|
+
- **Admin file / image upload fields.** `AdminModel` gained
|
|
60
|
+
`upload_fields=[...]` + `upload_storage=...`: listed String columns
|
|
61
|
+
render as file inputs in the create/edit form (which auto-switches to
|
|
62
|
+
`multipart/form-data`), the posted file is streamed to the storage
|
|
63
|
+
backend (`LocalUploadStorage` / `MinIOUploadStorage`), and the returned
|
|
64
|
+
storage key is written to the column. On edit, omitting the file keeps
|
|
65
|
+
the current value; on create, a missing file for a non-nullable column
|
|
66
|
+
is a required-field error. Registering `upload_fields` without
|
|
67
|
+
`upload_storage` raises `ValueError`.
|
|
68
|
+
|
|
69
|
+
## [0.84.0] — 2026-06-28
|
|
70
|
+
|
|
71
|
+
### Added
|
|
72
|
+
|
|
73
|
+
- **Admin custom actions (`@admin_action`).** Beyond the three hardcoded
|
|
74
|
+
bulk operations (activate / deactivate / delete), the admin now takes
|
|
75
|
+
user-defined actions: decorate an async function with `@admin_action`
|
|
76
|
+
and register it via `AdminModel(actions=[...])`. Each renders in the
|
|
77
|
+
list view's bulk dropdown (namespaced `custom:<name>` so it can't
|
|
78
|
+
collide with the built-ins), runs on the checked rows, and flashes a
|
|
79
|
+
banner from its `AdminActionResult`. The handler receives an
|
|
80
|
+
`AdminActionContext` (selected ids, a request-scoped repository, the DB
|
|
81
|
+
session, the request, the admin session, and the acting principal) and
|
|
82
|
+
stays directly callable/testable — the decorator only attaches
|
|
83
|
+
metadata. Exported from `tempest_fastapi_sdk` and
|
|
84
|
+
`tempest_fastapi_sdk.admin` (`admin_action`, `AdminAction`,
|
|
85
|
+
`AdminActionContext`, `AdminActionResult`).
|
|
86
|
+
|
|
87
|
+
## [0.83.0] — 2026-06-28
|
|
88
|
+
|
|
89
|
+
### Added
|
|
90
|
+
|
|
91
|
+
- **Computer-vision integration via the `[vision]` extra
|
|
92
|
+
(`ort-vision-sdk`).** New `tempest_fastapi_sdk.vision` submodule wraps
|
|
93
|
+
the ONNX Runtime inference library with the FastAPI layer it lacks:
|
|
94
|
+
Pydantic response schemas (`DetectionSchema`, `ClassificationSchema`,
|
|
95
|
+
`SegmentationSchema`, `BoundingBoxSchema`, `ClassProbabilitySchema`)
|
|
96
|
+
and mappers (`to_detection_schemas`, `to_classification_schema`,
|
|
97
|
+
`to_segmentation_schemas`) that convert a model result into them. The
|
|
98
|
+
`Detector` / `Classifier` / `Segmenter` task classes are re-exported
|
|
99
|
+
**lazily** — accessing one without the extra raises a clear
|
|
100
|
+
`ImportError` pointing at `[vision]`; the schemas and mappers carry no
|
|
101
|
+
such dependency. Like `cache` / `queue` / `tasks`, vision is
|
|
102
|
+
submodule-only (`from tempest_fastapi_sdk.vision import Detector`).
|
|
103
|
+
|
|
104
|
+
## [0.82.1] — 2026-06-28
|
|
105
|
+
|
|
106
|
+
### Fixed
|
|
107
|
+
|
|
108
|
+
- **Docs: removed code that the API never offered.** A doc audit
|
|
109
|
+
(cross-checking every `tempest_fastapi_sdk` import and example against
|
|
110
|
+
the package) found and fixed drift in the README:
|
|
111
|
+
- The brute-force throttling recipe invented `MemoryThrottleBackend` /
|
|
112
|
+
`RedisThrottleBackend`, `throttle.check()` returning a `ThrottleStatus`
|
|
113
|
+
enum, `record_failure()`, and `lock_seconds=` — none exist. Rewritten
|
|
114
|
+
to the real API (`AttemptThrottle(backend, max_attempts=, window_seconds=)`
|
|
115
|
+
with `raise_if_blocked` / `hit` / `reset` / `status`).
|
|
116
|
+
- The client-IP recipe used `trusted_proxies=` / `accept_private=` — the
|
|
117
|
+
real parameter is `trusted_header=`.
|
|
118
|
+
- The cookie recipe treated `SameSite` as a `BaseStrEnum` (`SameSite.LAX`)
|
|
119
|
+
with `same_site=` / `key=` kwargs and an auto-`Secure` claim; `SameSite`
|
|
120
|
+
is a `Literal` alias and `set_cookie` takes positional `name`/`value`
|
|
121
|
+
+ `samesite=`.
|
|
122
|
+
- `AsyncRedisManager` was imported from the top level in several recipes
|
|
123
|
+
(cache / sessions / security) — it lives in `tempest_fastapi_sdk.cache`
|
|
124
|
+
(submodule-only, like `queue` / `tasks`). No code changes.
|
|
125
|
+
|
|
8
126
|
## [0.82.0] — 2026-06-28
|
|
9
127
|
|
|
10
128
|
### Added
|
|
@@ -88,8 +88,32 @@ The SDK currently covers (Sep 2025+, post-v0.31.x):
|
|
|
88
88
|
- **Pagination** — offset + cursor.
|
|
89
89
|
- **Settings mixins** — every `*Settings` carries
|
|
90
90
|
`title`/`description`/`examples` on every field.
|
|
91
|
-
- **SSE** — `EventStream`, `sse_response
|
|
92
|
-
|
|
91
|
+
- **SSE** — `EventStream`, `ServerSentEvent`, `sse_response`, and
|
|
92
|
+
`SSEBroker` (per-channel fan-out; in-memory single-process, or
|
|
93
|
+
multi-worker via an injected Redis pub/sub bridge — same call site).
|
|
94
|
+
- **Throttle** — `AttemptThrottle` (any `ThrottleBackend`, e.g.
|
|
95
|
+
`redis.asyncio.Redis`; no in-memory backend bundled).
|
|
96
|
+
- **Base CRUD layers** — `BaseService[Repo, Resp, UpdateT]` and
|
|
97
|
+
`BaseController[Service, Resp, UpdateT]` with
|
|
98
|
+
`get_by_id`/`get_or_none`/`list`/`paginate`/`count`/`exists`/`update`/
|
|
99
|
+
`delete`; `update` is partial-aware (PUT/PATCH) and `UpdateT` is an
|
|
100
|
+
optional 3rd generic (defaults to `BaseSchema`, PEP 696).
|
|
101
|
+
- **Base enums** — `BaseStrEnum` / `BaseIntEnum` with
|
|
102
|
+
`values`/`keys`/`choices`/`to_dict`/`from_value`/`has_value`/`has_key`.
|
|
103
|
+
- **Validated field types** — `tempest_fastapi_sdk.utils` Annotated
|
|
104
|
+
Pydantic types: `PositiveIntField`/`NonNegativeIntField`/`CentsField`/
|
|
105
|
+
`PortField`/`PositiveFloatField`/`NonNegativeFloatField`/`PercentField`/
|
|
106
|
+
`RatioField`/`LatitudeField`/`LongitudeField`/`PriceField`/
|
|
107
|
+
`NonEmptyStrField`/`SlugField`/`HexColorField`.
|
|
108
|
+
- **Runtime typing** — `strict_types` / `typed` / `require_annotations`
|
|
109
|
+
decorators (over `pydantic.validate_call`); ruff `ANN` enabled in the
|
|
110
|
+
SDK and `tempest new` templates (ANN401 off — `Any` is valid); a
|
|
111
|
+
`[tool.tempest] typing_strictness` knob (`lenient`/`standard`/`strict`,
|
|
112
|
+
`--strictness` override) layered onto `tempest lint`/`fix`/`type`/`check`.
|
|
113
|
+
- **Vision** (`[vision]` extra) — `tempest_fastapi_sdk.vision` wrapping
|
|
114
|
+
`ort-vision-sdk`: lazy `Detector`/`Classifier`/`Segmenter` + prediction
|
|
115
|
+
schemas + `to_detection_schemas`/`to_classification_schema`/
|
|
116
|
+
`to_segmentation_schemas` mappers.
|
|
93
117
|
- **Upload** — `UploadUtils` with pluggable backends
|
|
94
118
|
(`LocalUploadStorage`, `MinIOUploadStorage`), download helpers,
|
|
95
119
|
presigned URLs.
|
|
@@ -99,17 +123,26 @@ The SDK currently covers (Sep 2025+, post-v0.31.x):
|
|
|
99
123
|
- **Email** — SMTP via `EmailUtils` + Jinja2 template rendering
|
|
100
124
|
with bundled defaults (`activation.html`, `password_reset.html`)
|
|
101
125
|
shadowable by the project's `template_dir`.
|
|
102
|
-
- **WebPush**
|
|
126
|
+
- **WebPush** — `WebPushDispatcher` (`send`/`send_many`, 404/410
|
|
127
|
+
pruning), subscription storage (`BaseWebPushSubscriptionModel` +
|
|
128
|
+
`make_web_push_subscription_model`) + `WebPushSubscriptionService`
|
|
129
|
+
(`subscribe`/`unsubscribe`/`list_for_user`/`notify_user` with
|
|
130
|
+
auto-prune of gone endpoints) + `make_web_push_router` (opt-in
|
|
131
|
+
`/subscribe` + `/unsubscribe`, aligned with `tempest-react-sdk`);
|
|
132
|
+
webhook signatures.
|
|
103
133
|
- **Cache** — Redis manager + `@cached`.
|
|
104
134
|
- **Queue / tasks** — FastStream + TaskIQ wrappers.
|
|
105
|
-
- **BR validators** — CPF/CNPJ/CEP/phone
|
|
135
|
+
- **BR validators** — CPF/CNPJ/CEP/phone, with `*Field` Pydantic types
|
|
136
|
+
(`CPFField`/`CNPJField`/`CPFOrCNPJField`/`PhoneBRField`/`CEPField`;
|
|
137
|
+
pre-0.76 unsuffixed names kept as deprecated aliases).
|
|
106
138
|
- **BR localities** — `UF` (StrEnum, 27 siglas) + `Region`
|
|
107
139
|
(5 macro-regiões IBGE), `StateBR`/`CityBR` schemas, offline
|
|
108
140
|
dataset of 27 states + 5606 municipalities (IBGE-derived,
|
|
109
141
|
DF as 36 administrative regions), `list_states`/`get_state`/
|
|
110
142
|
`cities_by_uf`/`states_by_region`, `is_valid_uf`/`normalize_uf`,
|
|
111
143
|
`is_valid_city`/`normalize_city` (accent/case-insensitive),
|
|
112
|
-
`UFField`/`CityNameField
|
|
144
|
+
`UFField`/`CityNameField`, plus `ChoiceBR` + `uf_choices`/
|
|
145
|
+
`region_choices`/`city_choices` (frontend `<select>` choices).
|
|
113
146
|
- **Rate limit** — `RateLimitMiddleware` (sliding window) with
|
|
114
147
|
pluggable store (`MemoryRateLimitStore` / `RedisRateLimitStore`,
|
|
115
148
|
atomic Lua) and per-principal key extractors (`key_by_ip`,
|
|
@@ -131,7 +164,11 @@ The SDK currently covers (Sep 2025+, post-v0.31.x):
|
|
|
131
164
|
- **Admin panel** — Jinja + HTMX (`AdminSite`, `AdminModel`,
|
|
132
165
|
`make_admin_router`), typed theming via `AdminTheme` (colors /
|
|
133
166
|
logo / favicon / font / radius / footer / dark mode /
|
|
134
|
-
`custom_css_url`, injected as `:root` overrides)
|
|
167
|
+
`custom_css_url`, injected as `:root` overrides), custom bulk actions
|
|
168
|
+
(`@admin_action` + `AdminModel(actions=[...])`, `AdminActionContext` /
|
|
169
|
+
`AdminActionResult`), file/image upload fields (`AdminModel(
|
|
170
|
+
upload_fields=[...], upload_storage=...)`), rich list filters
|
|
171
|
+
(bool/enum/FK select, date-range, text — auto by column type).
|
|
135
172
|
- **CLI** — `tempest new` (scaffolds layered service +
|
|
136
173
|
docker-compose + multi-stage uv `Dockerfile`/`.dockerignore`),
|
|
137
174
|
`tempest generate --docker` (regen compose) / `--dockerfile`
|
|
@@ -169,41 +206,46 @@ then move it up to the covers list.
|
|
|
169
206
|
foundation the user asked for first; the functional Tier 1 items below
|
|
170
207
|
inherit the look for free. Now in the covers list.
|
|
171
208
|
|
|
209
|
+
**Shipped — custom actions (v0.84.0).** `@admin_action` decorator +
|
|
210
|
+
`AdminModel(actions=[...])` + `AdminActionContext`/`AdminActionResult`;
|
|
211
|
+
custom entries render in the bulk dropdown (namespaced `custom:<name>`),
|
|
212
|
+
run on the checked rows, and flash a banner on the list view. Now in the
|
|
213
|
+
covers list.
|
|
214
|
+
|
|
215
|
+
**Shipped — file / image upload field (v0.85.0).** `AdminModel(
|
|
216
|
+
upload_fields=[...], upload_storage=...)` renders String columns as file
|
|
217
|
+
inputs, streams the upload to `LocalUploadStorage` / `MinIOUploadStorage`,
|
|
218
|
+
and stores the returned key. Now in the covers list.
|
|
219
|
+
|
|
220
|
+
**Shipped — rich filters (v0.86.0).** `list_filter` fields auto-pick a
|
|
221
|
+
widget by column type: bool / enum / FK → select, date/datetime →
|
|
222
|
+
inclusive date-range (two inputs → `__gte`/`__lte`), other → text.
|
|
223
|
+
Now in the covers list.
|
|
224
|
+
|
|
172
225
|
**Tier 1 — high value, reuses an existing engine (low effort):**
|
|
173
226
|
|
|
174
|
-
1. **
|
|
175
|
-
for user-defined row / bulk operations (Django `actions`, Nova
|
|
176
|
-
actions). Today only 3 are hardcoded (activate / deactivate /
|
|
177
|
-
delete). This is the foundation the rest build on.
|
|
178
|
-
2. **File / image upload field** — a new form widget wired to the
|
|
179
|
-
existing `UploadUtils` (`LocalUploadStorage` / `MinIOUploadStorage`).
|
|
180
|
-
Engine is already shipped; admin just needs the widget + storage
|
|
181
|
-
binding.
|
|
182
|
-
3. **Rich filters** — enum / choice / FK / date-range filters in the
|
|
183
|
-
list view (today only boolean fields auto-render a filter dropdown).
|
|
184
|
-
Quick UX win.
|
|
185
|
-
4. **Audit history viewer** — a per-row change timeline wired to the
|
|
227
|
+
1. **Audit history viewer (NEXT)** — a per-row change timeline wired to the
|
|
186
228
|
existing `BaseAuditLogModel` + `diff_snapshots`. Today the detail
|
|
187
229
|
view only shows `created_by` / `updated_by` stamps, not full history.
|
|
188
230
|
Engine is already shipped.
|
|
189
231
|
|
|
190
232
|
**Tier 2 — high value, medium effort:**
|
|
191
233
|
|
|
192
|
-
|
|
234
|
+
2. **Autocomplete FK fields** — HTMX search endpoint backing FK inputs,
|
|
193
235
|
removing the 1000-row `<select>` cap and the plain-UUID fallback
|
|
194
236
|
(Django `autocomplete_fields`, Nova search).
|
|
195
|
-
|
|
237
|
+
3. **Inlines / nested relations** — edit child rows inside the parent's
|
|
196
238
|
detail / edit view (Django `StackedInline` / `TabularInline`).
|
|
197
|
-
|
|
239
|
+
4. **Dashboard business metrics / charts** — value / trend / partition
|
|
198
240
|
cards (Nova metrics), wired to the existing metrics module. Distinct
|
|
199
241
|
from today's system CPU/RAM/disk panel.
|
|
200
242
|
|
|
201
243
|
**Tier 3 — nice-to-have:**
|
|
202
244
|
|
|
203
|
-
|
|
245
|
+
5. **RBAC granular** — per-model / per-action admin permissions beyond
|
|
204
246
|
today's `is_admin` + `can_create` / `can_edit` / `can_delete`.
|
|
205
|
-
|
|
206
|
-
|
|
247
|
+
6. **CSV import** — bulk upload counterpart to the existing export.
|
|
248
|
+
7. **Lenses** — saved alternate views / queries per model (Nova).
|
|
207
249
|
|
|
208
250
|
Origin: competitor gap analysis (Django Admin, Laravel Nova, SQLAdmin,
|
|
209
251
|
Starlette-Admin) run 2026-06-26. Do **not** treat the tiers as locked —
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tempest-fastapi-sdk
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.87.0
|
|
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
|
|
@@ -49,6 +49,7 @@ Requires-Dist: opentelemetry-instrumentation-fastapi>=0.48b0; extra == 'all'
|
|
|
49
49
|
Requires-Dist: opentelemetry-instrumentation-httpx>=0.48b0; extra == 'all'
|
|
50
50
|
Requires-Dist: opentelemetry-instrumentation-sqlalchemy>=0.48b0; extra == 'all'
|
|
51
51
|
Requires-Dist: opentelemetry-sdk>=1.27.0; extra == 'all'
|
|
52
|
+
Requires-Dist: ort-vision-sdk>=0.4.0; extra == 'all'
|
|
52
53
|
Requires-Dist: prometheus-client>=0.20.0; extra == 'all'
|
|
53
54
|
Requires-Dist: psutil>=6.0.0; extra == 'all'
|
|
54
55
|
Requires-Dist: pyjwt>=2.12.1; extra == 'all'
|
|
@@ -96,6 +97,8 @@ Requires-Dist: taskiq>=0.11.0; extra == 'tasks'
|
|
|
96
97
|
Provides-Extra: upload
|
|
97
98
|
Requires-Dist: aiofiles>=24.1.0; extra == 'upload'
|
|
98
99
|
Requires-Dist: python-multipart>=0.0.12; extra == 'upload'
|
|
100
|
+
Provides-Extra: vision
|
|
101
|
+
Requires-Dist: ort-vision-sdk>=0.4.0; extra == 'vision'
|
|
99
102
|
Provides-Extra: webpush
|
|
100
103
|
Requires-Dist: cryptography>=42.0.0; extra == 'webpush'
|
|
101
104
|
Requires-Dist: pywebpush>=2.0.0; extra == 'webpush'
|
|
@@ -219,6 +222,7 @@ Feature-rich helpers pull in third-party dependencies that you only need when yo
|
|
|
219
222
|
| `[http]` | `httpx` | `HTTPClient`, `RetryPolicy`, `CircuitOpenError`, OAuth2 / OIDC providers |
|
|
220
223
|
| `[prometheus]` | `prometheus-client` | `PrometheusMiddleware`, `make_prometheus_router`, `make_prometheus_registry` |
|
|
221
224
|
| `[mfa]` | `pyotp` | `TOTPHelper` + MFA/2FA endpoints on the bundled auth flow |
|
|
225
|
+
| `[vision]` | `ort-vision-sdk` | `Detector` / `Classifier` / `Segmenter` (ONNX) + prediction schemas |
|
|
222
226
|
| `[otel]` | `opentelemetry-sdk` + OTLP/gRPC exporter + FastAPI/SQLAlchemy/httpx instrumentors | `setup_tracing` — distributed tracing |
|
|
223
227
|
| `[sqlite]` | `aiosqlite` | SQLite async driver for `sqlite+aiosqlite://` URLs (dev default) |
|
|
224
228
|
| `[postgres]` | `asyncpg` | PostgreSQL async driver for `postgresql+asyncpg://` URLs (production) |
|
|
@@ -259,10 +263,11 @@ Since `0.7.1` every optional dependency is imported lazily at first instantiatio
|
|
|
259
263
|
| `tempest_fastapi_sdk.utils.http_client` *(extra: `[http]`)* | `HTTPClient`, `RetryPolicy`, `CircuitOpenError`, `REQUEST_ID_HEADER` — typed httpx wrapper |
|
|
260
264
|
| `tempest_fastapi_sdk.utils.storage_backends` *(extra: `[upload]`)* | `UploadStorage` protocol, `LocalUploadStorage`, `MinIOUploadStorage`, `UploadResult`, `ContentValidator` |
|
|
261
265
|
| `tempest_fastapi_sdk.tasks` *(extra: `[tasks]`)* | `AsyncTaskBrokerManager` (TaskIQ lifecycle wrapper), `AsyncTaskScheduler` (periodic / cron tasks) |
|
|
266
|
+
| `tempest_fastapi_sdk.vision` *(extra: `[vision]`)* | `Detector`, `Classifier`, `Segmenter` (ONNX, lazy), `DetectionSchema`/`ClassificationSchema`/`SegmentationSchema`/`BoundingBoxSchema`/`ClassProbabilitySchema`, `to_detection_schemas`/`to_classification_schema`/`to_segmentation_schemas` |
|
|
262
267
|
| `tempest_fastapi_sdk.utils` | `to_utc`, `utcnow`, `modify_dict`, `LogUtils`, `AttemptThrottle`/`ThrottleBackend`/`ThrottleStatus`, `generate_opaque_token`/`hash_opaque_token`/`verify_opaque_token`, `get_client_ip`/`get_client_ip_from_scope`, `PasswordUtils` *(extra: `[auth]`)*, `JWTUtils` *(extra: `[auth]`)*, `TOTPHelper` *(extra: `[mfa]`)*, `EmailUtils` *(extra: `[email]`)*, `UploadUtils`/`sniff_mime` *(extra: `[upload]`)*, `DownloadUtils`/`build_content_disposition` *(no extra)*, `MetricsUtils`/`CPUMetrics`/`MemoryMetrics`/`DiskMetrics`/`GPUMetrics`/`SystemMetrics` *(extra: `[metrics]`)*, validated field types (`PositiveIntField`, `NonNegativeIntField`, `CentsField`, `PortField`, `PositiveFloatField`, `NonNegativeFloatField`, `PercentField`, `RatioField`, `LatitudeField`, `LongitudeField`, `PriceField`, `NonEmptyStrField`, `SlugField`, `HexColorField`), BR regex helpers (`CPFField`, `CNPJField`, `CPFOrCNPJField`, `PhoneBRField`, `CEPField` — old names without the suffix kept as deprecated aliases — `is_valid_*`, `normalize_*`, `only_digits`, `*_PATTERN`), BR states/cities (`UF`, `Region`, `StateBR`, `CityBR`, `ChoiceBR`, `UFField`, `CityNameField`, `list_states`, `get_state`, `cities_by_uf`, `states_by_region`, `uf_choices`/`region_choices`/`city_choices`, `is_valid_uf`/`normalize_uf`, `is_valid_city`/`normalize_city`) |
|
|
263
268
|
| `tempest_fastapi_sdk.cli` | `tempest` console script — `new <name>` (scaffold layered service), `lint` / `format` / `fmt-check` / `type` / `test` / `check` (run preferred quality gates), `version` / `--version` |
|
|
264
269
|
|
|
265
|
-
Core primitives are re-exported from `tempest_fastapi_sdk` at the top level — `from tempest_fastapi_sdk import BaseModel, BaseRepository, AppException` always works. The extras-gated managers in `tempest_fastapi_sdk.cache`, `tempest_fastapi_sdk.queue` and `tempest_fastapi_sdk.
|
|
270
|
+
Core primitives are re-exported from `tempest_fastapi_sdk` at the top level — `from tempest_fastapi_sdk import BaseModel, BaseRepository, AppException` always works. The extras-gated managers in `tempest_fastapi_sdk.cache`, `tempest_fastapi_sdk.queue`, `tempest_fastapi_sdk.tasks` and `tempest_fastapi_sdk.vision` must be imported from their own submodule (`from tempest_fastapi_sdk.queue import AsyncBrokerManager`).
|
|
266
271
|
|
|
267
272
|
---
|
|
268
273
|
|
|
@@ -3314,62 +3319,66 @@ app.mount(
|
|
|
3314
3319
|
)
|
|
3315
3320
|
```
|
|
3316
3321
|
|
|
3317
|
-
For cookie-based session flows, `set_cookie` / `clear_cookie` write headers that already include the safe combo (`HttpOnly`, `Secure`, `SameSite=Lax`) so the caller only picks the bits they want to deviate from. `SameSite` is a `
|
|
3322
|
+
For cookie-based session flows, `set_cookie` / `clear_cookie` write headers that already include the safe combo (`HttpOnly`, `Secure`, `SameSite=Lax`) so the caller only picks the bits they want to deviate from. `SameSite` is a **type alias** `Literal["lax", "strict", "none"]` — pass the literal string, not an enum. The SDK does **not** auto-force `Secure` for `samesite="none"`: pass `samesite="none", secure=True` yourself in cross-site scenarios (the browser rejects `SameSite=None` without `Secure`).
|
|
3318
3323
|
|
|
3319
3324
|
```python
|
|
3320
3325
|
from fastapi import Response
|
|
3321
3326
|
|
|
3322
|
-
from tempest_fastapi_sdk import
|
|
3327
|
+
from tempest_fastapi_sdk import clear_cookie, set_cookie
|
|
3323
3328
|
|
|
3324
3329
|
|
|
3325
3330
|
def login(response: Response, token: str) -> None:
|
|
3326
3331
|
set_cookie(
|
|
3327
3332
|
response,
|
|
3328
|
-
|
|
3329
|
-
|
|
3333
|
+
"session", # name (positional)
|
|
3334
|
+
token, # value (positional)
|
|
3330
3335
|
max_age=3600,
|
|
3331
|
-
|
|
3332
|
-
# secure=True,
|
|
3333
|
-
# http_only=True,
|
|
3336
|
+
samesite="lax", # "lax" (default), "strict" or "none"
|
|
3337
|
+
# secure=True, # default — set False only for local HTTP
|
|
3338
|
+
# http_only=True, # default
|
|
3334
3339
|
path="/",
|
|
3335
3340
|
)
|
|
3336
3341
|
|
|
3337
3342
|
|
|
3338
3343
|
def logout(response: Response) -> None:
|
|
3339
|
-
clear_cookie(response,
|
|
3344
|
+
clear_cookie(response, "session", path="/")
|
|
3340
3345
|
```
|
|
3341
3346
|
|
|
3342
3347
|
### Brute-force throttling recipe
|
|
3343
3348
|
|
|
3344
|
-
`AttemptThrottle` counts failed attempts per key (typically `<endpoint>:<identifier>` — login email, password-reset target, etc.)
|
|
3349
|
+
`AttemptThrottle` counts failed attempts per key (typically `<endpoint>:<identifier>` — login email, password-reset target, IP, etc.). The constructor takes a `backend` — any object matching the `ThrottleBackend` Protocol (`get`/`incr`/`expire`/`ttl`/`delete`), which `redis.asyncio.Redis` satisfies out of the box — plus `max_attempts` + `window_seconds`. No in-memory backend is bundled: pass the Redis client from `AsyncRedisManager` (or a [fakeredis](https://github.com/cunla/fakeredis-py) double in tests).
|
|
3345
3350
|
|
|
3346
3351
|
```python
|
|
3347
|
-
from tempest_fastapi_sdk import AttemptThrottle,
|
|
3348
|
-
from tempest_fastapi_sdk.
|
|
3352
|
+
from tempest_fastapi_sdk import AttemptThrottle, UnauthorizedException
|
|
3353
|
+
from tempest_fastapi_sdk.cache import AsyncRedisManager
|
|
3354
|
+
|
|
3355
|
+
from src.core.settings import settings
|
|
3349
3356
|
|
|
3357
|
+
cache = AsyncRedisManager(settings.REDIS_URL)
|
|
3358
|
+
# cache.client is redis.asyncio.Redis — matches the ThrottleBackend Protocol
|
|
3350
3359
|
throttle = AttemptThrottle(
|
|
3351
|
-
|
|
3360
|
+
cache.client,
|
|
3352
3361
|
max_attempts=5,
|
|
3353
|
-
window_seconds=300,
|
|
3354
|
-
|
|
3362
|
+
window_seconds=300, # fixed window; also the TTL on the first failure
|
|
3363
|
+
namespace="login", # key prefix so multiple throttles can coexist
|
|
3364
|
+
fail_open=True, # a Redis outage degrades to "allow", never locks everyone out
|
|
3355
3365
|
)
|
|
3356
3366
|
|
|
3357
3367
|
|
|
3358
3368
|
async def login(email: str, password: str) -> User:
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
raise TooManyRequestsException(message="Too many attempts; try again later.")
|
|
3369
|
+
key = f"login:{email}"
|
|
3370
|
+
await throttle.raise_if_blocked(key) # raises 429 when over budget
|
|
3362
3371
|
|
|
3363
|
-
user = await users_repo.
|
|
3364
|
-
if not password_utils.verify(password, user.
|
|
3365
|
-
await throttle.
|
|
3372
|
+
user = await users_repo.get_or_none({"email": email})
|
|
3373
|
+
if user is None or not password_utils.verify(password, user.hashed_password):
|
|
3374
|
+
await throttle.hit(key) # +1 failure, applies the TTL
|
|
3366
3375
|
raise UnauthorizedException(message="Invalid credentials.")
|
|
3367
3376
|
|
|
3368
|
-
await throttle.reset(
|
|
3377
|
+
await throttle.reset(key) # success clears the counter
|
|
3369
3378
|
return user
|
|
3370
3379
|
```
|
|
3371
3380
|
|
|
3372
|
-
`
|
|
3381
|
+
`throttle.status(key)` (peek without incrementing) and `throttle.hit(key)` (increment) both return a frozen `ThrottleStatus` dataclass — `attempts: int`, `blocked: bool`, `retry_after_seconds: int` — to build friendly error payloads. `raise_if_blocked` already raises `TooManyRequestsException`, which the SDK exception handler turns into the canonical `{detail, code, details}` envelope with HTTP 429 and a `Retry-After` header.
|
|
3373
3382
|
|
|
3374
3383
|
### Opaque tokens recipe
|
|
3375
3384
|
|
|
@@ -3408,7 +3417,7 @@ async def consume_reset_token(plain: str, user_id: UUID) -> bool:
|
|
|
3408
3417
|
|
|
3409
3418
|
### Client IP extraction recipe
|
|
3410
3419
|
|
|
3411
|
-
`get_client_ip(request)` and `get_client_ip_from_scope(scope)` return the real client IP behind
|
|
3420
|
+
`get_client_ip(request)` and `get_client_ip_from_scope(scope)` return the real client IP behind a proxy. By design they accept **one** trusted header name (`trusted_header=`) that your edge proxy is known to set (e.g. `"x-real-ip"` on Nginx) — without it, they use the direct peer address. Anti-spoofing belongs at the proxy (which overwrites the header with the real peer), not in Python, so the SDK only reads the header you declare trusted.
|
|
3412
3421
|
|
|
3413
3422
|
```python
|
|
3414
3423
|
from fastapi import Request
|
|
@@ -3418,15 +3427,13 @@ from tempest_fastapi_sdk import get_client_ip
|
|
|
3418
3427
|
|
|
3419
3428
|
@router.post("/login")
|
|
3420
3429
|
async def login(request: Request, payload: LoginIn) -> LoginOut:
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
)
|
|
3425
|
-
await throttle.check(f"login:{ip}")
|
|
3430
|
+
# Behind Nginx that overwrites X-Real-IP with the real peer:
|
|
3431
|
+
ip = get_client_ip(request, trusted_header="x-real-ip")
|
|
3432
|
+
await throttle.raise_if_blocked(f"login:{ip}")
|
|
3426
3433
|
...
|
|
3427
3434
|
```
|
|
3428
3435
|
|
|
3429
|
-
Use `get_client_ip_from_scope(scope)` from middleware or websocket handlers where only the ASGI scope is in reach.
|
|
3436
|
+
Use `get_client_ip_from_scope(scope, trusted_header=...)` from middleware or websocket handlers where only the ASGI scope is in reach. If you expose the app directly to the internet, omit `trusted_header=` so the peer address is used.
|
|
3430
3437
|
|
|
3431
3438
|
### Command-line interface recipe
|
|
3432
3439
|
|
|
@@ -116,6 +116,7 @@ Feature-rich helpers pull in third-party dependencies that you only need when yo
|
|
|
116
116
|
| `[http]` | `httpx` | `HTTPClient`, `RetryPolicy`, `CircuitOpenError`, OAuth2 / OIDC providers |
|
|
117
117
|
| `[prometheus]` | `prometheus-client` | `PrometheusMiddleware`, `make_prometheus_router`, `make_prometheus_registry` |
|
|
118
118
|
| `[mfa]` | `pyotp` | `TOTPHelper` + MFA/2FA endpoints on the bundled auth flow |
|
|
119
|
+
| `[vision]` | `ort-vision-sdk` | `Detector` / `Classifier` / `Segmenter` (ONNX) + prediction schemas |
|
|
119
120
|
| `[otel]` | `opentelemetry-sdk` + OTLP/gRPC exporter + FastAPI/SQLAlchemy/httpx instrumentors | `setup_tracing` — distributed tracing |
|
|
120
121
|
| `[sqlite]` | `aiosqlite` | SQLite async driver for `sqlite+aiosqlite://` URLs (dev default) |
|
|
121
122
|
| `[postgres]` | `asyncpg` | PostgreSQL async driver for `postgresql+asyncpg://` URLs (production) |
|
|
@@ -156,10 +157,11 @@ Since `0.7.1` every optional dependency is imported lazily at first instantiatio
|
|
|
156
157
|
| `tempest_fastapi_sdk.utils.http_client` *(extra: `[http]`)* | `HTTPClient`, `RetryPolicy`, `CircuitOpenError`, `REQUEST_ID_HEADER` — typed httpx wrapper |
|
|
157
158
|
| `tempest_fastapi_sdk.utils.storage_backends` *(extra: `[upload]`)* | `UploadStorage` protocol, `LocalUploadStorage`, `MinIOUploadStorage`, `UploadResult`, `ContentValidator` |
|
|
158
159
|
| `tempest_fastapi_sdk.tasks` *(extra: `[tasks]`)* | `AsyncTaskBrokerManager` (TaskIQ lifecycle wrapper), `AsyncTaskScheduler` (periodic / cron tasks) |
|
|
160
|
+
| `tempest_fastapi_sdk.vision` *(extra: `[vision]`)* | `Detector`, `Classifier`, `Segmenter` (ONNX, lazy), `DetectionSchema`/`ClassificationSchema`/`SegmentationSchema`/`BoundingBoxSchema`/`ClassProbabilitySchema`, `to_detection_schemas`/`to_classification_schema`/`to_segmentation_schemas` |
|
|
159
161
|
| `tempest_fastapi_sdk.utils` | `to_utc`, `utcnow`, `modify_dict`, `LogUtils`, `AttemptThrottle`/`ThrottleBackend`/`ThrottleStatus`, `generate_opaque_token`/`hash_opaque_token`/`verify_opaque_token`, `get_client_ip`/`get_client_ip_from_scope`, `PasswordUtils` *(extra: `[auth]`)*, `JWTUtils` *(extra: `[auth]`)*, `TOTPHelper` *(extra: `[mfa]`)*, `EmailUtils` *(extra: `[email]`)*, `UploadUtils`/`sniff_mime` *(extra: `[upload]`)*, `DownloadUtils`/`build_content_disposition` *(no extra)*, `MetricsUtils`/`CPUMetrics`/`MemoryMetrics`/`DiskMetrics`/`GPUMetrics`/`SystemMetrics` *(extra: `[metrics]`)*, validated field types (`PositiveIntField`, `NonNegativeIntField`, `CentsField`, `PortField`, `PositiveFloatField`, `NonNegativeFloatField`, `PercentField`, `RatioField`, `LatitudeField`, `LongitudeField`, `PriceField`, `NonEmptyStrField`, `SlugField`, `HexColorField`), BR regex helpers (`CPFField`, `CNPJField`, `CPFOrCNPJField`, `PhoneBRField`, `CEPField` — old names without the suffix kept as deprecated aliases — `is_valid_*`, `normalize_*`, `only_digits`, `*_PATTERN`), BR states/cities (`UF`, `Region`, `StateBR`, `CityBR`, `ChoiceBR`, `UFField`, `CityNameField`, `list_states`, `get_state`, `cities_by_uf`, `states_by_region`, `uf_choices`/`region_choices`/`city_choices`, `is_valid_uf`/`normalize_uf`, `is_valid_city`/`normalize_city`) |
|
|
160
162
|
| `tempest_fastapi_sdk.cli` | `tempest` console script — `new <name>` (scaffold layered service), `lint` / `format` / `fmt-check` / `type` / `test` / `check` (run preferred quality gates), `version` / `--version` |
|
|
161
163
|
|
|
162
|
-
Core primitives are re-exported from `tempest_fastapi_sdk` at the top level — `from tempest_fastapi_sdk import BaseModel, BaseRepository, AppException` always works. The extras-gated managers in `tempest_fastapi_sdk.cache`, `tempest_fastapi_sdk.queue` and `tempest_fastapi_sdk.
|
|
164
|
+
Core primitives are re-exported from `tempest_fastapi_sdk` at the top level — `from tempest_fastapi_sdk import BaseModel, BaseRepository, AppException` always works. The extras-gated managers in `tempest_fastapi_sdk.cache`, `tempest_fastapi_sdk.queue`, `tempest_fastapi_sdk.tasks` and `tempest_fastapi_sdk.vision` must be imported from their own submodule (`from tempest_fastapi_sdk.queue import AsyncBrokerManager`).
|
|
163
165
|
|
|
164
166
|
---
|
|
165
167
|
|
|
@@ -3211,62 +3213,66 @@ app.mount(
|
|
|
3211
3213
|
)
|
|
3212
3214
|
```
|
|
3213
3215
|
|
|
3214
|
-
For cookie-based session flows, `set_cookie` / `clear_cookie` write headers that already include the safe combo (`HttpOnly`, `Secure`, `SameSite=Lax`) so the caller only picks the bits they want to deviate from. `SameSite` is a `
|
|
3216
|
+
For cookie-based session flows, `set_cookie` / `clear_cookie` write headers that already include the safe combo (`HttpOnly`, `Secure`, `SameSite=Lax`) so the caller only picks the bits they want to deviate from. `SameSite` is a **type alias** `Literal["lax", "strict", "none"]` — pass the literal string, not an enum. The SDK does **not** auto-force `Secure` for `samesite="none"`: pass `samesite="none", secure=True` yourself in cross-site scenarios (the browser rejects `SameSite=None` without `Secure`).
|
|
3215
3217
|
|
|
3216
3218
|
```python
|
|
3217
3219
|
from fastapi import Response
|
|
3218
3220
|
|
|
3219
|
-
from tempest_fastapi_sdk import
|
|
3221
|
+
from tempest_fastapi_sdk import clear_cookie, set_cookie
|
|
3220
3222
|
|
|
3221
3223
|
|
|
3222
3224
|
def login(response: Response, token: str) -> None:
|
|
3223
3225
|
set_cookie(
|
|
3224
3226
|
response,
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
+
"session", # name (positional)
|
|
3228
|
+
token, # value (positional)
|
|
3227
3229
|
max_age=3600,
|
|
3228
|
-
|
|
3229
|
-
# secure=True,
|
|
3230
|
-
# http_only=True,
|
|
3230
|
+
samesite="lax", # "lax" (default), "strict" or "none"
|
|
3231
|
+
# secure=True, # default — set False only for local HTTP
|
|
3232
|
+
# http_only=True, # default
|
|
3231
3233
|
path="/",
|
|
3232
3234
|
)
|
|
3233
3235
|
|
|
3234
3236
|
|
|
3235
3237
|
def logout(response: Response) -> None:
|
|
3236
|
-
clear_cookie(response,
|
|
3238
|
+
clear_cookie(response, "session", path="/")
|
|
3237
3239
|
```
|
|
3238
3240
|
|
|
3239
3241
|
### Brute-force throttling recipe
|
|
3240
3242
|
|
|
3241
|
-
`AttemptThrottle` counts failed attempts per key (typically `<endpoint>:<identifier>` — login email, password-reset target, etc.)
|
|
3243
|
+
`AttemptThrottle` counts failed attempts per key (typically `<endpoint>:<identifier>` — login email, password-reset target, IP, etc.). The constructor takes a `backend` — any object matching the `ThrottleBackend` Protocol (`get`/`incr`/`expire`/`ttl`/`delete`), which `redis.asyncio.Redis` satisfies out of the box — plus `max_attempts` + `window_seconds`. No in-memory backend is bundled: pass the Redis client from `AsyncRedisManager` (or a [fakeredis](https://github.com/cunla/fakeredis-py) double in tests).
|
|
3242
3244
|
|
|
3243
3245
|
```python
|
|
3244
|
-
from tempest_fastapi_sdk import AttemptThrottle,
|
|
3245
|
-
from tempest_fastapi_sdk.
|
|
3246
|
+
from tempest_fastapi_sdk import AttemptThrottle, UnauthorizedException
|
|
3247
|
+
from tempest_fastapi_sdk.cache import AsyncRedisManager
|
|
3248
|
+
|
|
3249
|
+
from src.core.settings import settings
|
|
3246
3250
|
|
|
3251
|
+
cache = AsyncRedisManager(settings.REDIS_URL)
|
|
3252
|
+
# cache.client is redis.asyncio.Redis — matches the ThrottleBackend Protocol
|
|
3247
3253
|
throttle = AttemptThrottle(
|
|
3248
|
-
|
|
3254
|
+
cache.client,
|
|
3249
3255
|
max_attempts=5,
|
|
3250
|
-
window_seconds=300,
|
|
3251
|
-
|
|
3256
|
+
window_seconds=300, # fixed window; also the TTL on the first failure
|
|
3257
|
+
namespace="login", # key prefix so multiple throttles can coexist
|
|
3258
|
+
fail_open=True, # a Redis outage degrades to "allow", never locks everyone out
|
|
3252
3259
|
)
|
|
3253
3260
|
|
|
3254
3261
|
|
|
3255
3262
|
async def login(email: str, password: str) -> User:
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
raise TooManyRequestsException(message="Too many attempts; try again later.")
|
|
3263
|
+
key = f"login:{email}"
|
|
3264
|
+
await throttle.raise_if_blocked(key) # raises 429 when over budget
|
|
3259
3265
|
|
|
3260
|
-
user = await users_repo.
|
|
3261
|
-
if not password_utils.verify(password, user.
|
|
3262
|
-
await throttle.
|
|
3266
|
+
user = await users_repo.get_or_none({"email": email})
|
|
3267
|
+
if user is None or not password_utils.verify(password, user.hashed_password):
|
|
3268
|
+
await throttle.hit(key) # +1 failure, applies the TTL
|
|
3263
3269
|
raise UnauthorizedException(message="Invalid credentials.")
|
|
3264
3270
|
|
|
3265
|
-
await throttle.reset(
|
|
3271
|
+
await throttle.reset(key) # success clears the counter
|
|
3266
3272
|
return user
|
|
3267
3273
|
```
|
|
3268
3274
|
|
|
3269
|
-
`
|
|
3275
|
+
`throttle.status(key)` (peek without incrementing) and `throttle.hit(key)` (increment) both return a frozen `ThrottleStatus` dataclass — `attempts: int`, `blocked: bool`, `retry_after_seconds: int` — to build friendly error payloads. `raise_if_blocked` already raises `TooManyRequestsException`, which the SDK exception handler turns into the canonical `{detail, code, details}` envelope with HTTP 429 and a `Retry-After` header.
|
|
3270
3276
|
|
|
3271
3277
|
### Opaque tokens recipe
|
|
3272
3278
|
|
|
@@ -3305,7 +3311,7 @@ async def consume_reset_token(plain: str, user_id: UUID) -> bool:
|
|
|
3305
3311
|
|
|
3306
3312
|
### Client IP extraction recipe
|
|
3307
3313
|
|
|
3308
|
-
`get_client_ip(request)` and `get_client_ip_from_scope(scope)` return the real client IP behind
|
|
3314
|
+
`get_client_ip(request)` and `get_client_ip_from_scope(scope)` return the real client IP behind a proxy. By design they accept **one** trusted header name (`trusted_header=`) that your edge proxy is known to set (e.g. `"x-real-ip"` on Nginx) — without it, they use the direct peer address. Anti-spoofing belongs at the proxy (which overwrites the header with the real peer), not in Python, so the SDK only reads the header you declare trusted.
|
|
3309
3315
|
|
|
3310
3316
|
```python
|
|
3311
3317
|
from fastapi import Request
|
|
@@ -3315,15 +3321,13 @@ from tempest_fastapi_sdk import get_client_ip
|
|
|
3315
3321
|
|
|
3316
3322
|
@router.post("/login")
|
|
3317
3323
|
async def login(request: Request, payload: LoginIn) -> LoginOut:
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
)
|
|
3322
|
-
await throttle.check(f"login:{ip}")
|
|
3324
|
+
# Behind Nginx that overwrites X-Real-IP with the real peer:
|
|
3325
|
+
ip = get_client_ip(request, trusted_header="x-real-ip")
|
|
3326
|
+
await throttle.raise_if_blocked(f"login:{ip}")
|
|
3323
3327
|
...
|
|
3324
3328
|
```
|
|
3325
3329
|
|
|
3326
|
-
Use `get_client_ip_from_scope(scope)` from middleware or websocket handlers where only the ASGI scope is in reach.
|
|
3330
|
+
Use `get_client_ip_from_scope(scope, trusted_header=...)` from middleware or websocket handlers where only the ASGI scope is in reach. If you expose the app directly to the internet, omit `trusted_header=` so the peer address is used.
|
|
3327
3331
|
|
|
3328
3332
|
### Command-line interface recipe
|
|
3329
3333
|
|