tempest-fastapi-sdk 0.82.1__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.1 → tempest_fastapi_sdk-0.87.0}/CHANGELOG.md +96 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/CLAUDE.md +66 -24
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/PKG-INFO +7 -2
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/README.md +3 -1
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/admin.en.md +110 -3
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/admin.md +108 -3
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/auth-flow.en.md +117 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/auth-flow.md +116 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/index.en.md +1 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/index.md +1 -0
- 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.1 → tempest_fastapi_sdk-0.87.0}/docs/reference.md +18 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/mkdocs.yml +1 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/pyproject.toml +18 -1
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/__init__.py +17 -1
- {tempest_fastapi_sdk-0.82.1 → 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.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/config.py +58 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/forms.py +16 -2
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/router.py +287 -41
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/static/admin.css +18 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/templates/form.html +4 -1
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/templates/list.html +16 -4
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/dependencies/auth.py +28 -7
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/__init__.py +14 -0
- {tempest_fastapi_sdk-0.82.1 → 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.1 → 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.1 → tempest_fastapi_sdk-0.87.0}/uv.lock +297 -3
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/.github/workflows/ci.yml +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/.github/workflows/docs.yml +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/.github/workflows/release-pypi.yml +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/.gitignore +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/.python-version +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/Makefile +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/architecture.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/architecture.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/changelog.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/changelog.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/contributing.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/contributing.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/index.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/index.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/installation.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/installation.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/learning/index.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/learning/index.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/learning/marketplace/api.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/learning/marketplace/api.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/learning/marketplace/business-rules.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/learning/marketplace/business-rules.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/learning/marketplace/domain.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/learning/marketplace/domain.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/learning/marketplace/flows.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/learning/marketplace/flows.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/learning/marketplace/index.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/learning/marketplace/index.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/migration.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/migration.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/audit-trail.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/audit-trail.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/br-helpers.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/br-helpers.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/cache.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/cache.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/cli.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/cli.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/database.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/database.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/deploy-safety.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/deploy-safety.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/downloads.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/downloads.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/email.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/email.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/feature-flags.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/feature-flags.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/fields.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/fields.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/http-client.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/http-client.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/http.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/http.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/idempotency.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/idempotency.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/logging.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/logging.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/metrics.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/metrics.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/mfa.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/mfa.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/multi-tenant.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/multi-tenant.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/observability.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/observability.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/offline-sync.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/offline-sync.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/outbox.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/outbox.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/queue-tasks.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/queue-tasks.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/realtime.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/realtime.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/refresh-tokens.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/refresh-tokens.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/security.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/security.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/sessions.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/sessions.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/sse.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/sse.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/storage.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/storage.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/stored-files.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/stored-files.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/testing.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/testing.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/typing.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/typing.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/uploads.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/uploads.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/utilities.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/utilities.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/webpush.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/webpush.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/websocket.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/recipes/websocket.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/reference.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/roadmap.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/roadmap.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/tutorial.en.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/docs/tutorial.md +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/mkdocs_hooks/llmstxt.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/scripts/extract_recipe.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/auth.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/discovery.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/session.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/site.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/templates/base.html +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/templates/dashboard.html +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/templates/detail.html +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/templates/login.html +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/templates/logs.html +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/templates/mfa.html +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/admin/theme.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/cookies.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/dependencies/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/handlers.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/middlewares/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/middlewares/body_size.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/middlewares/cors.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/middlewares/csrf.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/middlewares/graceful.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/middlewares/idempotency.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/middlewares/rate_limit.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/middlewares/request_id.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/oauth.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/routers/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/routers/health.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/routers/logs.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/routers/metrics.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/routers/tool_spec.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/server.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/static.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/tracing.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/api/webhooks.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/guards.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/locale.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/page_renderer.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/schemas.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/service.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/templates/en-US/activation.html +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/templates/en-US/activation_error.html +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/templates/en-US/activation_success.html +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/templates/en-US/password_reset.html +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/templates/en-US/password_reset_error.html +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/templates/en-US/password_reset_form.html +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/templates/en-US/password_reset_success.html +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/templates/pt-BR/activation.html +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/templates/pt-BR/activation_error.html +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/templates/pt-BR/activation_success.html +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/templates/pt-BR/password_reset.html +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/templates/pt-BR/password_reset_error.html +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/templates/pt-BR/password_reset_form.html +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/auth/templates/pt-BR/password_reset_success.html +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cache/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cache/decorator.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cache/invalidation.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cache/redis_manager.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/Dockerfile.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/README.md.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/dockerignore.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/env.example.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/gitignore.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/main.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/pyproject.toml.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/api/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/api/app.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/api/dependencies/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/api/dependencies/auth.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/api/dependencies/resources.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/api/routers/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/controllers/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/core/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/core/exceptions.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/core/settings.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/db/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/db/models/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/db/models/user.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/db/repositories/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/schemas/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/server.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/services/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/src/utils/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/tests/__init__.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/_templates/tests/test_smoke.py.tmpl +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/config.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/db.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/docker_compose.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/generate.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/lint.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/main.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/new.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/secrets.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/src_layers.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/cli/user.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/controllers/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/controllers/base.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/core/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/core/context.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/core/enums.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/core/logging.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/core/typed.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/_alembic_templates/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/_alembic_templates/env.py.template +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/alembic_hooks.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/audit.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/backup.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/connection.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/migrations.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/mixins.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/model.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/outbox.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/repository.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/slow_query.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/tenant.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/user_model.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/user_recovery_code_model.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/user_refresh_token_model.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/user_token_model.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/db/webpush_subscription_model.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/exceptions/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/exceptions/base.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/exceptions/conflict.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/exceptions/forbidden.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/exceptions/i18n.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/exceptions/jwt.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/exceptions/not_found.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/exceptions/too_many_requests.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/exceptions/unauthorized.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/exceptions/upload.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/exceptions/validation.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/flags/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/flags/backends.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/flags/dependencies.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/flags/service.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/py.typed +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/queue/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/queue/manager.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/schemas/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/schemas/base.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/schemas/link_headers.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/schemas/logs.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/schemas/pagination.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/schemas/response.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/services/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/services/base.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/services/file_mixin.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/sessions/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/sessions/dependencies.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/sessions/middleware.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/sessions/router.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/sessions/schemas.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/sessions/service.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/sessions/store.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/settings/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/settings/base.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/sse/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/sse/broker.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/sse/event_stream.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/storage/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/storage/minio_client.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/tasks/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/tasks/manager.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/tasks/scheduler.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/testing/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/testing/database.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/client_ip.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/data/br_locations.json +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/datetime.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/dict.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/download.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/email.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/fields.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/http_client.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/jwt.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/locations.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/log.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/metrics.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/opaque_token.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/password.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/regex.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/storage_backends.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/throttle.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/totp.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/utils/upload.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/webpush/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/webpush/dispatcher.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/webpush/router.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/webpush/schemas.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/webpush/service.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/websockets/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/websockets/hub.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/websockets/router.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tempest_fastapi_sdk/websockets/schemas.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/admin/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/admin/test_auth.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/admin/test_discovery.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/admin/test_forms.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/admin/test_logs_nav.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/admin/test_mfa.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/admin/test_router.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/admin/test_site.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/admin/test_theme.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/admin/test_user_model.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_body_size.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_cookies.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_cors.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_csrf.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_dependencies_auth.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_graceful.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_handlers.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_health_router.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_idempotency.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_jwt_dependency.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_logs_router.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_oauth.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_prometheus.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_rate_limit.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_rate_limit_extras.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_request_id_middleware.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_role_dependency.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_server.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_static.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_tool_spec.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_tracing.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_webhooks.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/api/test_webhooks_rsa.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/auth/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/auth/test_guards.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/auth/test_locale.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/auth/test_mfa.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/auth/test_refresh.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/auth/test_refresh_db.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/auth/test_service.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/cache/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/cache/test_decorator.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/cache/test_invalidation.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/cache/test_redis_manager.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/cli/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/cli/test_config.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/cli/test_db.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/cli/test_db_seed.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/cli/test_docker_compose.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/cli/test_generate.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/cli/test_lint_strictness.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/cli/test_main.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/cli/test_secrets.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/cli/test_user.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/conftest.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/controllers/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/controllers/test_base.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/core/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/core/test_context.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/core/test_enums.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/core/test_logging.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/core/test_typed.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/db/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/db/test_alembic_hooks.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/db/test_audit.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/db/test_backup.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/db/test_bulk_ops.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/db/test_connection.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/db/test_migrations.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/db/test_mixins.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/db/test_model.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/db/test_outbox.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/db/test_repository.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/db/test_safe_upgrade.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/db/test_slow_query.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/db/test_tenant.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/exceptions/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/exceptions/test_exceptions.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/exceptions/test_i18n.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/flags/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/flags/test_flags.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/queue/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/queue/test_manager.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/schemas/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/schemas/test_base.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/schemas/test_cursor_pagination.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/schemas/test_link_headers.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/schemas/test_pagination.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/schemas/test_response.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/services/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/services/test_base.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/services/test_file_mixin.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/sessions/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/sessions/test_sessions.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/settings/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/settings/test_base.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/settings/test_mixins.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/sse/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/sse/test_broker.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/sse/test_event_stream.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/storage/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/storage/test_minio_client.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/tasks/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/tasks/test_manager.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/tasks/test_scheduler.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/testing/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/testing/test_database.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/utils/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_client_ip.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_datetime.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_dict.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_download.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_email.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_fields.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_http_client.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_jwt.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_lazy_extras.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_locations.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_log.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_metrics.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_opaque_token.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_password.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_regex.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_storage_backends.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_throttle.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/utils/test_upload.py +0 -0
- {tempest_fastapi_sdk-0.82.1/tests/webpush → tempest_fastapi_sdk-0.87.0/tests/vision}/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1/tests/websockets → tempest_fastapi_sdk-0.87.0/tests/webpush}/__init__.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/webpush/test_dispatcher.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/webpush/test_router.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/webpush/test_schemas.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/webpush/test_service.py +0 -0
- {tempest_fastapi_sdk-0.82.1 → tempest_fastapi_sdk-0.87.0}/tests/websockets/test_hub_and_router.py +0 -0
|
@@ -5,6 +5,102 @@ 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
|
+
|
|
8
104
|
## [0.82.1] — 2026-06-28
|
|
9
105
|
|
|
10
106
|
### Fixed
|
|
@@ -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
|
|
|
@@ -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
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Admin site
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
Django-style management UI mounted under `/admin`. Operators sign in with a user row from the database (no separate admin password store) and browse every registered model from the browser, so the database port can stay closed on private networks. The panel is feature-complete (Django-admin parity): a list view with search / per-field filters / sortable columns, full CRUD (create / edit / delete), bulk actions, CSV/JSON export, FK-select widgets, a dashboard with live row counts + system metrics, optional TOTP MFA at login, and an audit trail stamping `created_by` / `updated_by`. Still on the roadmap:
|
|
4
|
+
Django-style management UI mounted under `/admin`. Operators sign in with a user row from the database (no separate admin password store) and browse every registered model from the browser, so the database port can stay closed on private networks. The panel is feature-complete (Django-admin parity): a list view with search / rich per-field filters (enum / FK / date-range) / sortable columns, full CRUD (create / edit / delete), bulk actions, CSV/JSON export, FK-select widgets, a dashboard with live row counts + system metrics, optional TOTP MFA at login, file/image upload fields, and an audit trail stamping `created_by` / `updated_by`. Still on the roadmap: inline/related editing.
|
|
5
5
|
|
|
6
6
|
Requires the `[admin]` extra:
|
|
7
7
|
|
|
@@ -88,6 +88,14 @@ site.register(AdminModel(
|
|
|
88
88
|
|
|
89
89
|
Every field reference also accepts a plain string (`list_display=["email", ...]`) for dynamic configuration, and `ordering` accepts a column (ascending), `desc(column)` / `asc(column)`, or a Django-style `"-created_at"` string. `register` returns the instance and raises `ValueError` on a duplicate slug. Slugs default to the model's `__tablename__` so URLs and database tables stay in sync.
|
|
90
90
|
|
|
91
|
+
!!! info "Filters auto-pick a widget per column type"
|
|
92
|
+
Each `list_filter` field renders the right widget by column type:
|
|
93
|
+
**boolean** → Yes/No dropdown; **enum** → dropdown of the members;
|
|
94
|
+
**FK** (whose target has a registered `AdminModel`) → dropdown of the
|
|
95
|
+
related rows (labelled via `search_fields`); **date/datetime** → two
|
|
96
|
+
date inputs (from/to, inclusive range); any other column → a text
|
|
97
|
+
input (equality). All preserve search/sort/pagination in the URL.
|
|
98
|
+
|
|
91
99
|
!!! tip "Centered, customizable brand"
|
|
92
100
|
The name shown in the center of the header comes from `brand`
|
|
93
101
|
(optional). Without it, it falls back to `title` — so existing sites
|
|
@@ -178,7 +186,7 @@ app.include_router(
|
|
|
178
186
|
- `GET /admin/logs` — **application logs** (when `show_logs=True`): reads the structured JSON files written by `configure_logging(log_dir=…)`, with source filter (`?source=`), free-text search (`?q=`) and pagination. Color-coded level badges. Renders an empty state when no log files exist yet.
|
|
179
187
|
- `GET /admin/m/{slug}/` — list view with pagination + free-text search (`?q=`) + per-field filters (`?filter_<field>=value`) + clickable **column sorting** (`?sort=<column>&dir=asc|desc`).
|
|
180
188
|
- `GET /admin/m/{slug}/export.csv` / `export.json` — **export** the current result set (honoring search/filters/sort) as CSV or JSON. Row cap via `make_admin_router(export_max_rows=…)` (default 5000).
|
|
181
|
-
- `POST /admin/m/{slug}/bulk` — **bulk actions** (delete / activate / deactivate) on the selected rows.
|
|
189
|
+
- `POST /admin/m/{slug}/bulk` — **bulk actions** (delete / activate / deactivate + your **custom actions**) on the selected rows.
|
|
182
190
|
- `GET/POST /admin/m/{slug}/new` — **create** a record (when `can_create`).
|
|
183
191
|
- `GET /admin/m/{slug}/{identity}` — detail view with Edit/Delete controls.
|
|
184
192
|
- `GET/POST /admin/m/{slug}/{identity}/edit` — **edit** a record (when `can_edit`).
|
|
@@ -196,7 +204,82 @@ app.include_router(
|
|
|
196
204
|
|
|
197
205
|
**Audit trail**: create/edit through the admin stamps `created_by`/`updated_by` (from `AuditMixin`) with the acting admin's id; the detail view shows an **Audit** panel with timestamps and — when the model has the audit columns — the actor (UUID resolved to a display name via the auth backend). Models without `AuditMixin` show timestamps only.
|
|
198
206
|
|
|
199
|
-
Not yet included (later roadmap phases):
|
|
207
|
+
Not yet included (later roadmap phases): inline/related editing.
|
|
208
|
+
|
|
209
|
+
## Custom actions (`@admin_action`)
|
|
210
|
+
|
|
211
|
+
Beyond the 3 built-ins (activate / deactivate / delete), you register
|
|
212
|
+
**your own actions** — an async function decorated with `@admin_action`
|
|
213
|
+
and passed to `AdminModel(actions=[...])`. Each becomes an option in the
|
|
214
|
+
bulk-action dropdown, operating on the checked rows.
|
|
215
|
+
|
|
216
|
+
```python
|
|
217
|
+
from tempest_fastapi_sdk import (
|
|
218
|
+
AdminActionContext,
|
|
219
|
+
AdminActionResult,
|
|
220
|
+
AdminModel,
|
|
221
|
+
admin_action,
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
@admin_action(label="Send welcome")
|
|
226
|
+
async def send_welcome(ctx: AdminActionContext) -> AdminActionResult:
|
|
227
|
+
"""Runs on the selected rows; the message is shown on the list view."""
|
|
228
|
+
users = await ctx.repository.list(filters={"id": ctx.ids})
|
|
229
|
+
for user in users:
|
|
230
|
+
await mailer.send_welcome(user.email)
|
|
231
|
+
return AdminActionResult(f"Sent {len(users)} emails.")
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
site.register(AdminModel(model=UserModel, actions=[send_welcome]))
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
The handler receives an `AdminActionContext`:
|
|
238
|
+
|
|
239
|
+
| Field | What it is |
|
|
240
|
+
| --- | --- |
|
|
241
|
+
| `ids` | Identities of the checked rows. |
|
|
242
|
+
| `repository` | The model's `BaseRepository`, on the request session. |
|
|
243
|
+
| `db_session` | The DB session (for work beyond the repository). |
|
|
244
|
+
| `request` | The inbound request. |
|
|
245
|
+
| `session` | The authenticated admin session. |
|
|
246
|
+
| `principal` | The admin user row that triggered the action. |
|
|
247
|
+
|
|
248
|
+
Return an `AdminActionResult(message, category="success"|"error"|"warning")`
|
|
249
|
+
to flash a banner on the list view (or `None` for no banner). The
|
|
250
|
+
function stays **directly callable/testable** — the decorator only
|
|
251
|
+
attaches metadata. Use `name=` to pin the identifier (default: the
|
|
252
|
+
function name) and `dangerous=True` to mark a destructive action.
|
|
253
|
+
|
|
254
|
+
## File / image upload field
|
|
255
|
+
|
|
256
|
+
A `String` column that stores a file's path/key can render as a **file
|
|
257
|
+
input** on the form. List the column in `upload_fields` and pass an
|
|
258
|
+
`upload_storage` (the SDK's existing backends — `LocalUploadStorage` /
|
|
259
|
+
`MinIOUploadStorage`). On submit the file is saved to storage and the
|
|
260
|
+
**returned key** is written to the column.
|
|
261
|
+
|
|
262
|
+
```python
|
|
263
|
+
from tempest_fastapi_sdk import AdminModel
|
|
264
|
+
from tempest_fastapi_sdk.utils import LocalUploadStorage
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
site.register(AdminModel(
|
|
268
|
+
model=DocumentModel,
|
|
269
|
+
upload_fields=[DocumentModel.attachment], # String column holding the key
|
|
270
|
+
upload_storage=LocalUploadStorage("media/"), # or MinIOUploadStorage(...)
|
|
271
|
+
))
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
- The form becomes `multipart/form-data` automatically when `upload_fields` is set.
|
|
275
|
+
- **Create**: a file is required only when the column is `NOT NULL` with no default.
|
|
276
|
+
- **Edit**: no new file → keeps the current value (shows "Current: …"); a file → replaces it.
|
|
277
|
+
- The column stores the storage **key** (`<slug>/<field>/<uuid>.<ext>`); use `upload_storage` (or `UploadUtils`) to serve/download it later.
|
|
278
|
+
|
|
279
|
+
!!! warning "`upload_fields` requires `upload_storage`"
|
|
280
|
+
Registering `upload_fields` without `upload_storage` raises
|
|
281
|
+
`ValueError` at `AdminModel` construction — without storage there's
|
|
282
|
+
nowhere to write the file.
|
|
200
283
|
|
|
201
284
|
!!! tip "Sidebar + burger navigation"
|
|
202
285
|
Every authenticated page has a persistent **sidebar**: Dashboard, one
|
|
@@ -230,6 +313,30 @@ app.include_router(
|
|
|
230
313
|
- Per-session CSRF token is generated at login and required by every form POST (login, logout, create, edit, delete, bulk actions).
|
|
231
314
|
- `secret_key` must be at least 32 bytes — short keys raise `ValueError` at construction time.
|
|
232
315
|
|
|
316
|
+
!!! danger "Login looping? It's the cookie `Secure` flag over plain HTTP"
|
|
317
|
+
If `POST /admin/login` returns `303` (looks like success), but the following
|
|
318
|
+
`GET /admin/` redirects back to the login — forever — the session cookie is
|
|
319
|
+
**not coming back**. Almost-certain cause: `cookie_secure=True` while the
|
|
320
|
+
admin is served over **plain HTTP** (no TLS terminator in front). The browser
|
|
321
|
+
refuses to store a `Secure` cookie on a non-HTTPS connection, so no session
|
|
322
|
+
ever persists.
|
|
323
|
+
|
|
324
|
+
```python
|
|
325
|
+
# ❌ Tied to DEBUG: in production DEBUG=false → cookie_secure=True,
|
|
326
|
+
# but with no HTTPS in front the login loops.
|
|
327
|
+
make_admin_router(..., cookie_secure=not settings.DEBUG)
|
|
328
|
+
|
|
329
|
+
# ✅ Dedicated toggle, independent of DEBUG:
|
|
330
|
+
make_admin_router(..., cookie_secure=settings.ADMIN_COOKIE_SECURE)
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
**Right fix:** put HTTPS in front (nginx/Caddy terminating TLS) and keep
|
|
334
|
+
`cookie_secure=True` — the admin session cookie must not travel in the clear.
|
|
335
|
+
**Stopgap** only when the admin genuinely runs over HTTP (intranet, MVP):
|
|
336
|
+
`cookie_secure=False`, aware the session ships without `Secure`. Don't tie
|
|
337
|
+
this flag to `DEBUG` — turning debug on in production is worse than the
|
|
338
|
+
original problem.
|
|
339
|
+
|
|
233
340
|
#### 5. Plug in a custom auth backend
|
|
234
341
|
|
|
235
342
|
`AdminAuthBackend` is an ABC, so swap the default for LDAP / OAuth / external IAM by subclassing:
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Painel admin
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
UI de gerenciamento no estilo Django montada sob `/admin`. Operadores entram com uma linha de usuário do banco (sem store de senha de admin separado) e navegam por todo modelo registrado pelo navegador, então a porta do banco pode ficar fechada em redes privadas. O painel é completo (paridade com o Django admin): list view com busca / filtros por campo / colunas ordenáveis, CRUD completo (criar / editar / excluir), ações em massa, export CSV/JSON, widgets FK-select, dashboard com contagens de linhas + métricas de sistema, MFA TOTP opcional no login, e trilha de auditoria carimbando `created_by` / `updated_by`. Ainda no roadmap:
|
|
4
|
+
UI de gerenciamento no estilo Django montada sob `/admin`. Operadores entram com uma linha de usuário do banco (sem store de senha de admin separado) e navegam por todo modelo registrado pelo navegador, então a porta do banco pode ficar fechada em redes privadas. O painel é completo (paridade com o Django admin): list view com busca / filtros ricos por campo (enum / FK / range de data) / colunas ordenáveis, CRUD completo (criar / editar / excluir), ações em massa, export CSV/JSON, widgets FK-select, dashboard com contagens de linhas + métricas de sistema, MFA TOTP opcional no login, campos de upload de arquivo/imagem, e trilha de auditoria carimbando `created_by` / `updated_by`. Ainda no roadmap: edição inline/relacionada.
|
|
5
5
|
|
|
6
6
|
Requer o extra `[admin]`:
|
|
7
7
|
|
|
@@ -88,6 +88,15 @@ site.register(AdminModel(
|
|
|
88
88
|
|
|
89
89
|
Toda referência a campo também aceita uma string simples (`list_display=["email", ...]`) para configuração dinâmica, e `ordering` aceita uma coluna (ascendente), `desc(column)` / `asc(column)`, ou uma string no estilo Django `"-created_at"`. `register` retorna a instância e levanta `ValueError` em slug duplicado. Os slugs derivam por padrão do `__tablename__` do modelo, para que URLs e tabelas do banco fiquem em sincronia.
|
|
90
90
|
|
|
91
|
+
!!! info "Filtros automáticos por tipo de coluna"
|
|
92
|
+
Cada campo em `list_filter` vira o widget certo conforme o tipo da
|
|
93
|
+
coluna: **boolean** → dropdown Sim/Não; **enum** → dropdown com os
|
|
94
|
+
membros; **FK** (cujo destino tem `AdminModel` registrado) → dropdown
|
|
95
|
+
das linhas relacionadas (label pelo `search_fields`); **date/datetime**
|
|
96
|
+
→ dois inputs de data (de/até, range inclusivo); qualquer outra coluna
|
|
97
|
+
→ input de texto (igualdade). Tudo preserva busca/ordenação/paginação
|
|
98
|
+
na URL.
|
|
99
|
+
|
|
91
100
|
!!! tip "Marca centralizada e customizável"
|
|
92
101
|
O nome exibido no centro do header vem de `brand` (opcional). Sem ele, cai no `title` — então sites existentes não mudam. Use `brand` para mostrar um nome distinto (ex.: `"servus-backend-admin"`) centralizado no topo de toda página. A sidebar é fixa e **sobrepõe header e footer** no desktop (z-index maior) — comportamento automático do CSS embutido, sem config.
|
|
93
102
|
|
|
@@ -160,7 +169,7 @@ app.include_router(
|
|
|
160
169
|
- `GET /admin/logs` — **logs da aplicação** (quando `show_logs=True`): lê os arquivos JSON estruturados escritos pelo `configure_logging(log_dir=…)`, com filtro por fonte (`?source=`), busca em texto (`?q=`) e paginação. Badges coloridos por nível. Quando ainda não há arquivos de log, mostra um estado vazio.
|
|
161
170
|
- `GET /admin/m/{slug}/` — list view com paginação + busca em texto livre (`?q=`) + filtros por campo (`?filter_<field>=value`) + **ordenação por coluna** clicável (`?sort=<coluna>&dir=asc|desc`).
|
|
162
171
|
- `GET /admin/m/{slug}/export.csv` / `export.json` — **exporta** o resultado atual (respeitando busca/filtros/ordenação) como CSV ou JSON. Limite de linhas via `make_admin_router(export_max_rows=…)` (default 5000).
|
|
163
|
-
- `POST /admin/m/{slug}/bulk` — **ações em massa** (delete / activate / deactivate) nas linhas selecionadas.
|
|
172
|
+
- `POST /admin/m/{slug}/bulk` — **ações em massa** (delete / activate / deactivate + suas **ações customizadas**) nas linhas selecionadas.
|
|
164
173
|
- `GET/POST /admin/m/{slug}/new` — **criar** registro (quando `can_create`).
|
|
165
174
|
- `GET /admin/m/{slug}/{identity}` — detail view com botões Edit/Delete.
|
|
166
175
|
- `GET/POST /admin/m/{slug}/{identity}/edit` — **editar** registro (quando `can_edit`).
|
|
@@ -178,7 +187,81 @@ app.include_router(
|
|
|
178
187
|
|
|
179
188
|
**Audit trail**: create/edit pelo admin carimba `created_by`/`updated_by` (do `AuditMixin`) com o id do admin atuante; o detail mostra um painel **Audit** com timestamps e — quando o modelo tem as colunas de auditoria — o ator (UUID resolvido para nome via o auth backend). Modelos sem `AuditMixin` mostram só os timestamps.
|
|
180
189
|
|
|
181
|
-
Ainda **não** incluídos (fases futuras do roadmap):
|
|
190
|
+
Ainda **não** incluídos (fases futuras do roadmap): inline/related editing.
|
|
191
|
+
|
|
192
|
+
## Ações customizadas (`@admin_action`)
|
|
193
|
+
|
|
194
|
+
Além das 3 fixas (activate / deactivate / delete), você registra **ações
|
|
195
|
+
próprias** — uma função async decorada com `@admin_action` e passada em
|
|
196
|
+
`AdminModel(actions=[...])`. Cada uma vira uma opção no dropdown de ações
|
|
197
|
+
em massa, operando nas linhas marcadas.
|
|
198
|
+
|
|
199
|
+
```python
|
|
200
|
+
from tempest_fastapi_sdk import (
|
|
201
|
+
AdminActionContext,
|
|
202
|
+
AdminActionResult,
|
|
203
|
+
AdminModel,
|
|
204
|
+
admin_action,
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
@admin_action(label="Enviar boas-vindas")
|
|
209
|
+
async def send_welcome(ctx: AdminActionContext) -> AdminActionResult:
|
|
210
|
+
"""Roda nas linhas selecionadas; a mensagem é exibida na list view."""
|
|
211
|
+
users = await ctx.repository.list(filters={"id": ctx.ids})
|
|
212
|
+
for user in users:
|
|
213
|
+
await mailer.send_welcome(user.email)
|
|
214
|
+
return AdminActionResult(f"{len(users)} e-mails enviados.")
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
site.register(AdminModel(model=UserModel, actions=[send_welcome]))
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
O handler recebe um `AdminActionContext` com:
|
|
221
|
+
|
|
222
|
+
| Campo | O que é |
|
|
223
|
+
| --- | --- |
|
|
224
|
+
| `ids` | Identidades das linhas marcadas. |
|
|
225
|
+
| `repository` | `BaseRepository` do modelo, na sessão do request. |
|
|
226
|
+
| `db_session` | A sessão DB (pra trabalho além do repositório). |
|
|
227
|
+
| `request` | O request inbound. |
|
|
228
|
+
| `session` | A sessão do admin autenticado. |
|
|
229
|
+
| `principal` | A linha do usuário admin que disparou a ação. |
|
|
230
|
+
|
|
231
|
+
Retorne um `AdminActionResult(message, category="success"|"error"|"warning")`
|
|
232
|
+
pra exibir um banner na list view (ou `None` pra não mostrar nada). A
|
|
233
|
+
função fica **diretamente chamável/testável** — o decorator só anexa
|
|
234
|
+
metadados. Use `name=` pra fixar o identificador (default: nome da função)
|
|
235
|
+
e `dangerous=True` pra marcar ação destrutiva.
|
|
236
|
+
|
|
237
|
+
## Campo de upload de arquivo / imagem
|
|
238
|
+
|
|
239
|
+
Uma coluna `String` que guarda o caminho/chave de um arquivo pode virar um
|
|
240
|
+
**input de upload** no formulário. Liste a coluna em `upload_fields` e
|
|
241
|
+
passe um `upload_storage` (os backends que o SDK já tem —
|
|
242
|
+
`LocalUploadStorage` / `MinIOUploadStorage`). No submit, o arquivo é
|
|
243
|
+
salvo no storage e a **chave retornada** é gravada na coluna.
|
|
244
|
+
|
|
245
|
+
```python
|
|
246
|
+
from tempest_fastapi_sdk import AdminModel
|
|
247
|
+
from tempest_fastapi_sdk.utils import LocalUploadStorage
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
site.register(AdminModel(
|
|
251
|
+
model=DocumentModel,
|
|
252
|
+
upload_fields=[DocumentModel.attachment], # coluna String que guarda a chave
|
|
253
|
+
upload_storage=LocalUploadStorage("media/"), # ou MinIOUploadStorage(...)
|
|
254
|
+
))
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
- O form vira `multipart/form-data` automaticamente quando há `upload_fields`.
|
|
258
|
+
- **Create**: arquivo obrigatório só se a coluna for `NOT NULL` e sem default.
|
|
259
|
+
- **Edit**: sem arquivo novo → mantém o valor atual (mostra "Current: …"); com arquivo → substitui.
|
|
260
|
+
- A coluna guarda a **chave** do storage (`<slug>/<campo>/<uuid>.<ext>`); use o `upload_storage` (ou `UploadUtils`) pra servir/baixar depois.
|
|
261
|
+
|
|
262
|
+
!!! warning "`upload_fields` exige `upload_storage`"
|
|
263
|
+
Registrar `upload_fields` sem `upload_storage` levanta `ValueError` na
|
|
264
|
+
construção do `AdminModel` — sem storage não há onde gravar o arquivo.
|
|
182
265
|
|
|
183
266
|
!!! tip "Navegação por sidebar + burger"
|
|
184
267
|
Toda página autenticada tem uma **sidebar** persistente: Dashboard, um
|
|
@@ -212,6 +295,28 @@ app.include_router(
|
|
|
212
295
|
- Um token CSRF por sessão é gerado no login e exigido por todo POST de formulário (login, logout, criar, editar, excluir, ações em massa).
|
|
213
296
|
- `secret_key` deve ter ao menos 32 bytes — chaves curtas levantam `ValueError` no momento da construção.
|
|
214
297
|
|
|
298
|
+
!!! danger "Login em loop? É o `Secure` do cookie sobre HTTP puro"
|
|
299
|
+
Se o `POST /admin/login` responde `303` (parece sucesso), mas o `GET /admin/`
|
|
300
|
+
seguinte redireciona de volta pro login — repetindo pra sempre — o cookie de
|
|
301
|
+
sessão **não está voltando**. Causa quase certa: `cookie_secure=True` enquanto
|
|
302
|
+
o admin é servido por **HTTP puro** (sem TLS na frente). O browser recusa
|
|
303
|
+
gravar um cookie `Secure` em conexão não-HTTPS, então nenhuma sessão persiste.
|
|
304
|
+
|
|
305
|
+
```python
|
|
306
|
+
# ❌ Atado a DEBUG: em produção DEBUG=false → cookie_secure=True,
|
|
307
|
+
# mas se não houver HTTPS na frente, o login entra em loop.
|
|
308
|
+
make_admin_router(..., cookie_secure=not settings.DEBUG)
|
|
309
|
+
|
|
310
|
+
# ✅ Controle dedicado, independente de DEBUG:
|
|
311
|
+
make_admin_router(..., cookie_secure=settings.ADMIN_COOKIE_SECURE)
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
**Correção certa:** ponha HTTPS na frente (nginx/Caddy terminando TLS) e
|
|
315
|
+
deixe `cookie_secure=True` — o cookie da sessão admin não deve trafegar em
|
|
316
|
+
claro. **Paliativo** só quando o admin roda mesmo em HTTP (intranet, MVP):
|
|
317
|
+
`cookie_secure=False`, ciente de que a sessão vai sem `Secure`. Não amarre
|
|
318
|
+
esse flag ao `DEBUG` — ligar debug em produção é pior que o problema original.
|
|
319
|
+
|
|
215
320
|
#### 5. Plugue um backend de auth customizado
|
|
216
321
|
|
|
217
322
|
`AdminAuthBackend` é uma ABC, então troque o default por LDAP / OAuth / IAM externo subclasseando:
|