tempest-fastapi-sdk 0.41.0__tar.gz → 0.43.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.
Files changed (375) hide show
  1. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/CHANGELOG.md +66 -0
  2. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/PKG-INFO +33 -4
  3. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/README.md +21 -3
  4. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/cli.en.md +53 -1
  5. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/cli.md +53 -1
  6. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/index.en.md +1 -0
  7. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/index.md +1 -0
  8. tempest_fastapi_sdk-0.43.0/docs/recipes/observability.en.md +163 -0
  9. tempest_fastapi_sdk-0.43.0/docs/recipes/observability.md +163 -0
  10. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/reference.md +2 -0
  11. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/mkdocs.yml +1 -0
  12. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/pyproject.toml +18 -1
  13. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/__init__.py +5 -1
  14. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/api/__init__.py +2 -0
  15. tempest_fastapi_sdk-0.43.0/tempest_fastapi_sdk/api/tracing.py +213 -0
  16. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/cli/generate.py +54 -1
  17. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/cli/main.py +145 -12
  18. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/cli/new.py +8 -0
  19. tempest_fastapi_sdk-0.43.0/tempest_fastapi_sdk/cli/src_layers.py +258 -0
  20. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/cli/user.py +138 -4
  21. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/db/__init__.py +2 -0
  22. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/db/connection.py +22 -0
  23. tempest_fastapi_sdk-0.43.0/tempest_fastapi_sdk/db/slow_query.py +252 -0
  24. tempest_fastapi_sdk-0.43.0/tests/api/test_tracing.py +45 -0
  25. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/cli/test_generate.py +95 -0
  26. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/cli/test_main.py +73 -0
  27. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/cli/test_user.py +156 -0
  28. tempest_fastapi_sdk-0.43.0/tests/db/test_slow_query.py +102 -0
  29. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/uv.lock +368 -4
  30. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/.github/workflows/ci.yml +0 -0
  31. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/.github/workflows/docs.yml +0 -0
  32. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/.github/workflows/release-pypi.yml +0 -0
  33. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/.gitignore +0 -0
  34. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/.python-version +0 -0
  35. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/CLAUDE.md +0 -0
  36. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/Makefile +0 -0
  37. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/architecture.en.md +0 -0
  38. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/architecture.md +0 -0
  39. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/changelog.en.md +0 -0
  40. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/changelog.md +0 -0
  41. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/contributing.en.md +0 -0
  42. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/contributing.md +0 -0
  43. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/index.en.md +0 -0
  44. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/index.md +0 -0
  45. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/installation.en.md +0 -0
  46. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/installation.md +0 -0
  47. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/learning/index.en.md +0 -0
  48. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/learning/index.md +0 -0
  49. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/learning/marketplace/api.en.md +0 -0
  50. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/learning/marketplace/api.md +0 -0
  51. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/learning/marketplace/business-rules.en.md +0 -0
  52. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/learning/marketplace/business-rules.md +0 -0
  53. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/learning/marketplace/domain.en.md +0 -0
  54. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/learning/marketplace/domain.md +0 -0
  55. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/learning/marketplace/flows.en.md +0 -0
  56. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/learning/marketplace/flows.md +0 -0
  57. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/learning/marketplace/index.en.md +0 -0
  58. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/learning/marketplace/index.md +0 -0
  59. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/migration.en.md +0 -0
  60. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/migration.md +0 -0
  61. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/admin.en.md +0 -0
  62. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/admin.md +0 -0
  63. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/auth-flow.en.md +0 -0
  64. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/auth-flow.md +0 -0
  65. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/br-helpers.en.md +0 -0
  66. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/br-helpers.md +0 -0
  67. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/cache.en.md +0 -0
  68. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/cache.md +0 -0
  69. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/database.en.md +0 -0
  70. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/database.md +0 -0
  71. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/downloads.en.md +0 -0
  72. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/downloads.md +0 -0
  73. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/email.en.md +0 -0
  74. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/email.md +0 -0
  75. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/http-client.en.md +0 -0
  76. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/http-client.md +0 -0
  77. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/http.en.md +0 -0
  78. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/http.md +0 -0
  79. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/idempotency.en.md +0 -0
  80. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/idempotency.md +0 -0
  81. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/logging.en.md +0 -0
  82. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/logging.md +0 -0
  83. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/metrics.en.md +0 -0
  84. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/metrics.md +0 -0
  85. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/mfa.en.md +0 -0
  86. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/mfa.md +0 -0
  87. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/queue-tasks.en.md +0 -0
  88. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/queue-tasks.md +0 -0
  89. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/realtime.en.md +0 -0
  90. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/realtime.md +0 -0
  91. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/security.en.md +0 -0
  92. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/security.md +0 -0
  93. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/sessions.en.md +0 -0
  94. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/sessions.md +0 -0
  95. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/storage.en.md +0 -0
  96. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/storage.md +0 -0
  97. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/testing.en.md +0 -0
  98. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/testing.md +0 -0
  99. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/uploads.en.md +0 -0
  100. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/uploads.md +0 -0
  101. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/utilities.en.md +0 -0
  102. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/utilities.md +0 -0
  103. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/webpush.en.md +0 -0
  104. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/webpush.md +0 -0
  105. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/websocket.en.md +0 -0
  106. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/recipes/websocket.md +0 -0
  107. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/reference.en.md +0 -0
  108. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/roadmap.en.md +0 -0
  109. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/roadmap.md +0 -0
  110. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/tutorial.en.md +0 -0
  111. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/docs/tutorial.md +0 -0
  112. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/scripts/extract_recipe.py +0 -0
  113. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/admin/__init__.py +0 -0
  114. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/admin/auth.py +0 -0
  115. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/admin/config.py +0 -0
  116. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/admin/forms.py +0 -0
  117. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/admin/router.py +0 -0
  118. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/admin/session.py +0 -0
  119. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/admin/site.py +0 -0
  120. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/admin/static/admin.css +0 -0
  121. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/admin/templates/base.html +0 -0
  122. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/admin/templates/dashboard.html +0 -0
  123. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/admin/templates/detail.html +0 -0
  124. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/admin/templates/form.html +0 -0
  125. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/admin/templates/list.html +0 -0
  126. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/admin/templates/login.html +0 -0
  127. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/admin/templates/logs.html +0 -0
  128. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/admin/templates/mfa.html +0 -0
  129. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/api/cookies.py +0 -0
  130. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/api/dependencies/__init__.py +0 -0
  131. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/api/dependencies/auth.py +0 -0
  132. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/api/handlers.py +0 -0
  133. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/api/middlewares/__init__.py +0 -0
  134. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/api/middlewares/body_size.py +0 -0
  135. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/api/middlewares/cors.py +0 -0
  136. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/api/middlewares/csrf.py +0 -0
  137. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/api/middlewares/idempotency.py +0 -0
  138. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/api/middlewares/rate_limit.py +0 -0
  139. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/api/middlewares/request_id.py +0 -0
  140. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/api/oauth.py +0 -0
  141. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/api/routers/__init__.py +0 -0
  142. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/api/routers/health.py +0 -0
  143. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/api/routers/logs.py +0 -0
  144. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/api/routers/metrics.py +0 -0
  145. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/api/routers/tool_spec.py +0 -0
  146. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/api/server.py +0 -0
  147. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/api/static.py +0 -0
  148. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/api/webhooks.py +0 -0
  149. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/auth/__init__.py +0 -0
  150. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/auth/page_renderer.py +0 -0
  151. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/auth/router.py +0 -0
  152. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/auth/schemas.py +0 -0
  153. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/auth/service.py +0 -0
  154. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/auth/templates/activation.html +0 -0
  155. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/auth/templates/activation_error.html +0 -0
  156. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/auth/templates/activation_success.html +0 -0
  157. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/auth/templates/password_reset.html +0 -0
  158. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/auth/templates/password_reset_error.html +0 -0
  159. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/auth/templates/password_reset_form.html +0 -0
  160. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/auth/templates/password_reset_success.html +0 -0
  161. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/cache/__init__.py +0 -0
  162. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/cache/decorator.py +0 -0
  163. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/cache/redis_manager.py +0 -0
  164. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/cli/__init__.py +0 -0
  165. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/cli/_templates/README.md.tmpl +0 -0
  166. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/cli/_templates/env.example.tmpl +0 -0
  167. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/cli/_templates/gitignore.tmpl +0 -0
  168. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/cli/_templates/main.py.tmpl +0 -0
  169. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/cli/_templates/pyproject.toml.tmpl +0 -0
  170. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/cli/_templates/src/__init__.py.tmpl +0 -0
  171. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/cli/_templates/src/api/__init__.py.tmpl +0 -0
  172. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/cli/_templates/src/api/app.py.tmpl +0 -0
  173. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/cli/_templates/src/api/dependencies/__init__.py.tmpl +0 -0
  174. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/cli/_templates/src/api/dependencies/auth.py.tmpl +0 -0
  175. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/cli/_templates/src/api/dependencies/resources.py.tmpl +0 -0
  176. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/cli/_templates/src/api/routers/__init__.py.tmpl +0 -0
  177. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/cli/_templates/src/controllers/__init__.py.tmpl +0 -0
  178. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/cli/_templates/src/core/__init__.py.tmpl +0 -0
  179. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/cli/_templates/src/core/exceptions.py.tmpl +0 -0
  180. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/cli/_templates/src/core/settings.py.tmpl +0 -0
  181. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/cli/_templates/src/db/__init__.py.tmpl +0 -0
  182. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/cli/_templates/src/db/models/__init__.py.tmpl +0 -0
  183. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/cli/_templates/src/db/models/user.py.tmpl +0 -0
  184. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/cli/_templates/src/db/repositories/__init__.py.tmpl +0 -0
  185. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/cli/_templates/src/schemas/__init__.py.tmpl +0 -0
  186. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/cli/_templates/src/server.py.tmpl +0 -0
  187. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/cli/_templates/src/services/__init__.py.tmpl +0 -0
  188. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/cli/_templates/src/utils/__init__.py.tmpl +0 -0
  189. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/cli/_templates/tests/__init__.py.tmpl +0 -0
  190. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/cli/_templates/tests/test_smoke.py.tmpl +0 -0
  191. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/cli/db.py +0 -0
  192. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/cli/docker_compose.py +0 -0
  193. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/cli/lint.py +0 -0
  194. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/controllers/__init__.py +0 -0
  195. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/controllers/base.py +0 -0
  196. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/core/__init__.py +0 -0
  197. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/core/context.py +0 -0
  198. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/core/enums.py +0 -0
  199. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/core/logging.py +0 -0
  200. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/db/_alembic_templates/__init__.py +0 -0
  201. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/db/_alembic_templates/env.py.template +0 -0
  202. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/db/alembic_hooks.py +0 -0
  203. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/db/migrations.py +0 -0
  204. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/db/mixins.py +0 -0
  205. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/db/model.py +0 -0
  206. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/db/repository.py +0 -0
  207. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/db/user_model.py +0 -0
  208. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/db/user_recovery_code_model.py +0 -0
  209. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/db/user_token_model.py +0 -0
  210. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/exceptions/__init__.py +0 -0
  211. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/exceptions/base.py +0 -0
  212. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/exceptions/conflict.py +0 -0
  213. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/exceptions/forbidden.py +0 -0
  214. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/exceptions/jwt.py +0 -0
  215. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/exceptions/not_found.py +0 -0
  216. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/exceptions/too_many_requests.py +0 -0
  217. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/exceptions/unauthorized.py +0 -0
  218. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/exceptions/upload.py +0 -0
  219. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/exceptions/validation.py +0 -0
  220. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/py.typed +0 -0
  221. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/queue/__init__.py +0 -0
  222. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/queue/manager.py +0 -0
  223. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/schemas/__init__.py +0 -0
  224. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/schemas/base.py +0 -0
  225. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/schemas/link_headers.py +0 -0
  226. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/schemas/logs.py +0 -0
  227. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/schemas/pagination.py +0 -0
  228. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/schemas/response.py +0 -0
  229. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/services/__init__.py +0 -0
  230. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/services/base.py +0 -0
  231. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/sessions/__init__.py +0 -0
  232. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/sessions/dependencies.py +0 -0
  233. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/sessions/middleware.py +0 -0
  234. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/sessions/router.py +0 -0
  235. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/sessions/schemas.py +0 -0
  236. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/sessions/service.py +0 -0
  237. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/sessions/store.py +0 -0
  238. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/settings/__init__.py +0 -0
  239. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/settings/base.py +0 -0
  240. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/settings/mixins.py +0 -0
  241. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/sse/__init__.py +0 -0
  242. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/sse/event_stream.py +0 -0
  243. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/storage/__init__.py +0 -0
  244. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/storage/minio_client.py +0 -0
  245. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/tasks/__init__.py +0 -0
  246. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/tasks/manager.py +0 -0
  247. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/tasks/scheduler.py +0 -0
  248. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/testing/__init__.py +0 -0
  249. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/testing/database.py +0 -0
  250. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/utils/__init__.py +0 -0
  251. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/utils/client_ip.py +0 -0
  252. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/utils/datetime.py +0 -0
  253. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/utils/dict.py +0 -0
  254. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/utils/download.py +0 -0
  255. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/utils/email.py +0 -0
  256. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/utils/http_client.py +0 -0
  257. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/utils/jwt.py +0 -0
  258. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/utils/log.py +0 -0
  259. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/utils/metrics.py +0 -0
  260. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/utils/opaque_token.py +0 -0
  261. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/utils/password.py +0 -0
  262. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/utils/regex.py +0 -0
  263. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/utils/storage_backends.py +0 -0
  264. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/utils/throttle.py +0 -0
  265. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/utils/totp.py +0 -0
  266. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/utils/upload.py +0 -0
  267. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/webpush/__init__.py +0 -0
  268. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/webpush/dispatcher.py +0 -0
  269. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/webpush/schemas.py +0 -0
  270. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/websockets/__init__.py +0 -0
  271. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/websockets/hub.py +0 -0
  272. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/websockets/router.py +0 -0
  273. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tempest_fastapi_sdk/websockets/schemas.py +0 -0
  274. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/__init__.py +0 -0
  275. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/admin/__init__.py +0 -0
  276. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/admin/test_auth.py +0 -0
  277. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/admin/test_forms.py +0 -0
  278. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/admin/test_logs_nav.py +0 -0
  279. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/admin/test_mfa.py +0 -0
  280. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/admin/test_router.py +0 -0
  281. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/admin/test_site.py +0 -0
  282. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/admin/test_user_model.py +0 -0
  283. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/api/__init__.py +0 -0
  284. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/api/test_body_size.py +0 -0
  285. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/api/test_cookies.py +0 -0
  286. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/api/test_cors.py +0 -0
  287. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/api/test_csrf.py +0 -0
  288. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/api/test_dependencies_auth.py +0 -0
  289. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/api/test_handlers.py +0 -0
  290. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/api/test_health_router.py +0 -0
  291. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/api/test_idempotency.py +0 -0
  292. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/api/test_jwt_dependency.py +0 -0
  293. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/api/test_logs_router.py +0 -0
  294. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/api/test_oauth.py +0 -0
  295. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/api/test_prometheus.py +0 -0
  296. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/api/test_rate_limit.py +0 -0
  297. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/api/test_request_id_middleware.py +0 -0
  298. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/api/test_role_dependency.py +0 -0
  299. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/api/test_server.py +0 -0
  300. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/api/test_static.py +0 -0
  301. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/api/test_tool_spec.py +0 -0
  302. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/api/test_webhooks.py +0 -0
  303. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/api/test_webhooks_rsa.py +0 -0
  304. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/auth/__init__.py +0 -0
  305. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/auth/test_mfa.py +0 -0
  306. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/auth/test_service.py +0 -0
  307. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/cache/__init__.py +0 -0
  308. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/cache/test_decorator.py +0 -0
  309. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/cache/test_redis_manager.py +0 -0
  310. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/cli/__init__.py +0 -0
  311. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/cli/test_db.py +0 -0
  312. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/cli/test_docker_compose.py +0 -0
  313. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/conftest.py +0 -0
  314. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/controllers/__init__.py +0 -0
  315. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/controllers/test_base.py +0 -0
  316. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/core/__init__.py +0 -0
  317. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/core/test_context.py +0 -0
  318. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/core/test_enums.py +0 -0
  319. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/core/test_logging.py +0 -0
  320. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/db/__init__.py +0 -0
  321. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/db/test_alembic_hooks.py +0 -0
  322. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/db/test_bulk_ops.py +0 -0
  323. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/db/test_connection.py +0 -0
  324. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/db/test_migrations.py +0 -0
  325. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/db/test_mixins.py +0 -0
  326. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/db/test_model.py +0 -0
  327. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/db/test_repository.py +0 -0
  328. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/exceptions/__init__.py +0 -0
  329. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/exceptions/test_exceptions.py +0 -0
  330. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/queue/__init__.py +0 -0
  331. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/queue/test_manager.py +0 -0
  332. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/schemas/__init__.py +0 -0
  333. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/schemas/test_base.py +0 -0
  334. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/schemas/test_cursor_pagination.py +0 -0
  335. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/schemas/test_link_headers.py +0 -0
  336. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/schemas/test_pagination.py +0 -0
  337. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/schemas/test_response.py +0 -0
  338. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/services/__init__.py +0 -0
  339. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/services/test_base.py +0 -0
  340. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/sessions/__init__.py +0 -0
  341. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/sessions/test_sessions.py +0 -0
  342. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/settings/__init__.py +0 -0
  343. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/settings/test_base.py +0 -0
  344. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/settings/test_mixins.py +0 -0
  345. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/sse/__init__.py +0 -0
  346. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/sse/test_event_stream.py +0 -0
  347. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/storage/__init__.py +0 -0
  348. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/storage/test_minio_client.py +0 -0
  349. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/tasks/__init__.py +0 -0
  350. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/tasks/test_manager.py +0 -0
  351. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/tasks/test_scheduler.py +0 -0
  352. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/testing/__init__.py +0 -0
  353. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/testing/test_database.py +0 -0
  354. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/utils/__init__.py +0 -0
  355. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/utils/test_client_ip.py +0 -0
  356. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/utils/test_datetime.py +0 -0
  357. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/utils/test_dict.py +0 -0
  358. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/utils/test_download.py +0 -0
  359. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/utils/test_email.py +0 -0
  360. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/utils/test_http_client.py +0 -0
  361. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/utils/test_jwt.py +0 -0
  362. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/utils/test_lazy_extras.py +0 -0
  363. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/utils/test_log.py +0 -0
  364. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/utils/test_metrics.py +0 -0
  365. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/utils/test_opaque_token.py +0 -0
  366. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/utils/test_password.py +0 -0
  367. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/utils/test_regex.py +0 -0
  368. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/utils/test_storage_backends.py +0 -0
  369. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/utils/test_throttle.py +0 -0
  370. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/utils/test_upload.py +0 -0
  371. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/webpush/__init__.py +0 -0
  372. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/webpush/test_dispatcher.py +0 -0
  373. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/webpush/test_schemas.py +0 -0
  374. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/websockets/__init__.py +0 -0
  375. {tempest_fastapi_sdk-0.41.0 → tempest_fastapi_sdk-0.43.0}/tests/websockets/test_hub_and_router.py +0 -0
@@ -5,6 +5,72 @@ 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.43.0] — 2026-06-11
9
+
10
+ ### Added
11
+
12
+ - **Distributed tracing with OpenTelemetry.** `setup_tracing(app,
13
+ service_name=..., otlp_endpoint=...)` installs an OTLP/gRPC span
14
+ exporter and auto-instruments FastAPI (incoming requests),
15
+ SQLAlchemy (queries, via `sqlalchemy_engine=db.engine`) and httpx
16
+ (outbound calls) so one trace follows a request across services.
17
+ `otlp_endpoint=None` falls back to a console exporter for local
18
+ debugging; `sample_ratio` controls head-based sampling;
19
+ `resource_attributes` merges extra span attributes. Behind the new
20
+ `[otel]` extra — importing the SDK without it costs nothing and
21
+ never crashes. Complements `RequestIDMiddleware` (which correlates
22
+ logs).
23
+ - **`SlowQueryLogger`** — attaches `before/after_cursor_execute`
24
+ listeners to a SQLAlchemy engine (sync or async) and logs every
25
+ statement slower than `threshold_ms`. Bind parameters are omitted
26
+ by default (PII); `log_parameters=True` and `explain=True` (runs
27
+ `EXPLAIN`) are opt-in for development. No extra required. Exposed
28
+ at the top level and from `tempest_fastapi_sdk.db`.
29
+ - **`AsyncDatabaseManager.engine`** — public property returning the
30
+ live `AsyncEngine`, so instrumentation (`SlowQueryLogger`, the OTel
31
+ SQLAlchemy instrumentor) can attach to it directly.
32
+
33
+ ### Docs
34
+
35
+ - New bilingual recipe **Observabilidade / Observability** covering
36
+ `setup_tracing` and `SlowQueryLogger`, added to the nav, the
37
+ recipes index, and the API reference.
38
+
39
+ ## [0.42.0] — 2026-06-11
40
+
41
+ ### Added
42
+
43
+ - **`tempest user promote` / `tempest user revoke`** — flip `is_admin`
44
+ for an existing user, found by email (case-insensitive), without
45
+ hand-written SQL. `promote` grants `/admin` access (`is_admin=True`),
46
+ `revoke` removes it. Both exit `1` with `no user found` when no user
47
+ matches the email.
48
+ - **`tempest generate --src`** — add the optional source layers
49
+ triggered by the project's pinned SDK extras to an existing project:
50
+ `[queue]` → `<root>/queue/` (FastStream broker + handlers stub),
51
+ `[tasks]` → `<root>/tasks/` (TaskIQ broker + jobs stub). The source
52
+ root (`src` or `app`) is auto-detected and generated imports point at
53
+ it. Idempotent — existing files are kept unless `--force` is passed.
54
+ `--docker` and `--src` can be combined in one invocation.
55
+ - **`tempest new` now scaffolds the chosen extras' source layers.**
56
+ `tempest new svc --extras auth,queue` ships `src/queue/` out of the
57
+ box (and `src/tasks/` with `[tasks]`); projects without those extras
58
+ get no placeholder packages.
59
+
60
+ ### Changed
61
+
62
+ - **Usage errors now print the offending command's full `--help`.**
63
+ An unknown command, an invalid option, or a missing required argument
64
+ renders the complete help (every parameter, default and description)
65
+ before the error line, instead of Click's terse `Try '... --help'`
66
+ hint. Quality-gate exit codes still propagate unchanged.
67
+ - **`tempest user create` prompts for the admin flag interactively.**
68
+ When neither `--admin` nor `--no-admin` is passed in an interactive
69
+ terminal, it asks `Should this user be an administrator? [y/N]`.
70
+ Non-interactive runs (CI, pipes, scripts) skip the prompt and default
71
+ to a regular user — pass `--admin` explicitly to create an admin
72
+ without a TTY. The flag is now `--admin/--no-admin` (tri-state).
73
+
8
74
  ## [0.41.0] — 2026-06-07
9
75
 
10
76
  ### Changed (breaking)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tempest-fastapi-sdk
3
- Version: 0.41.0
3
+ Version: 0.43.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
@@ -43,6 +43,11 @@ Requires-Dist: itsdangerous>=2.2.0; extra == 'all'
43
43
  Requires-Dist: jinja2>=3.1.0; extra == 'all'
44
44
  Requires-Dist: minio>=7.2.0; extra == 'all'
45
45
  Requires-Dist: nvidia-ml-py>=12.560.30; extra == 'all'
46
+ Requires-Dist: opentelemetry-exporter-otlp-proto-grpc>=1.27.0; extra == 'all'
47
+ Requires-Dist: opentelemetry-instrumentation-fastapi>=0.48b0; extra == 'all'
48
+ Requires-Dist: opentelemetry-instrumentation-httpx>=0.48b0; extra == 'all'
49
+ Requires-Dist: opentelemetry-instrumentation-sqlalchemy>=0.48b0; extra == 'all'
50
+ Requires-Dist: opentelemetry-sdk>=1.27.0; extra == 'all'
46
51
  Requires-Dist: prometheus-client>=0.20.0; extra == 'all'
47
52
  Requires-Dist: psutil>=6.0.0; extra == 'all'
48
53
  Requires-Dist: pyjwt>=2.12.1; extra == 'all'
@@ -70,6 +75,12 @@ Provides-Extra: mfa
70
75
  Requires-Dist: pyotp>=2.9.0; extra == 'mfa'
71
76
  Provides-Extra: minio
72
77
  Requires-Dist: minio>=7.2.0; extra == 'minio'
78
+ Provides-Extra: otel
79
+ Requires-Dist: opentelemetry-exporter-otlp-proto-grpc>=1.27.0; extra == 'otel'
80
+ Requires-Dist: opentelemetry-instrumentation-fastapi>=0.48b0; extra == 'otel'
81
+ Requires-Dist: opentelemetry-instrumentation-httpx>=0.48b0; extra == 'otel'
82
+ Requires-Dist: opentelemetry-instrumentation-sqlalchemy>=0.48b0; extra == 'otel'
83
+ Requires-Dist: opentelemetry-sdk>=1.27.0; extra == 'otel'
73
84
  Provides-Extra: postgres
74
85
  Requires-Dist: asyncpg>=0.30.0; extra == 'postgres'
75
86
  Provides-Extra: prometheus
@@ -205,6 +216,7 @@ Feature-rich helpers pull in third-party dependencies that you only need when yo
205
216
  | `[http]` | `httpx` | `HTTPClient`, `RetryPolicy`, `CircuitOpenError`, OAuth2 / OIDC providers |
206
217
  | `[prometheus]` | `prometheus-client` | `PrometheusMiddleware`, `make_prometheus_router`, `make_prometheus_registry` |
207
218
  | `[mfa]` | `pyotp` | `TOTPHelper` + MFA/2FA endpoints on the bundled auth flow |
219
+ | `[otel]` | `opentelemetry-sdk` + OTLP/gRPC exporter + FastAPI/SQLAlchemy/httpx instrumentors | `setup_tracing` — distributed tracing |
208
220
  | `[sqlite]` | `aiosqlite` | SQLite async driver for `sqlite+aiosqlite://` URLs (dev default) |
209
221
  | `[postgres]` | `asyncpg` | PostgreSQL async driver for `postgresql+asyncpg://` URLs (production) |
210
222
  | `[all]` | everything above | every helper |
@@ -226,10 +238,10 @@ Since `0.7.1` every optional dependency is imported lazily at first instantiatio
226
238
  | Module | Exports |
227
239
  | --- | --- |
228
240
  | `tempest_fastapi_sdk.schemas` | `BaseSchema`, `BaseResponseSchema`, `BasePaginationFilterSchema`, `BasePaginationSchema[T]`, `CursorPaginationFilterSchema`, `CursorPaginationSchema`, `LogEntrySchema`, `encode_cursor`, `decode_cursor`, `build_pagination_link_header` |
229
- | `tempest_fastapi_sdk.db` | `BaseModel`, `BaseUserModel`, `BaseUserTokenModel`, `BaseUserRecoveryCodeModel`, `make_user_recovery_code_model`, `UserTokenPurpose`, `BaseRepository[ModelType]`, `AsyncDatabaseManager`, `AlembicHelper`, `NAMING_CONVENTION`, `AuditMixin`, `SoftDeleteMixin`, `MFAMixin`, `BASE_COLUMN_ORDER`, `reorder_base_columns_first`, `compose_hooks` |
241
+ | `tempest_fastapi_sdk.db` | `BaseModel`, `BaseUserModel`, `BaseUserTokenModel`, `BaseUserRecoveryCodeModel`, `make_user_recovery_code_model`, `UserTokenPurpose`, `BaseRepository[ModelType]`, `AsyncDatabaseManager`, `AlembicHelper`, `NAMING_CONVENTION`, `AuditMixin`, `SoftDeleteMixin`, `MFAMixin`, `BASE_COLUMN_ORDER`, `reorder_base_columns_first`, `compose_hooks`, `SlowQueryLogger` |
230
242
  | `tempest_fastapi_sdk.exceptions` | `AppException`, `NotFoundException`, `ConflictException`, `ValidationException`, `UnauthorizedException`, `ForbiddenException`, `InvalidTokenException`, `ExpiredTokenException`, `FileTooLargeException`, `InvalidFileTypeException`, `TooManyRequestsException` |
231
243
  | `tempest_fastapi_sdk.settings` | `BaseAppSettings`, `ServerSettings`, `LogSettings`, `DatabaseSettings`, `RedisSettings`, `RabbitMQSettings`, `JWTSettings`, `CORSSettings`, `EmailSettings`, `UploadSettings`, `TokenSettings`, `WebPushSettings`, `TaskIQSettings`, `MinIOSettings`, `AuthSettings` |
232
- | `tempest_fastapi_sdk.api` | `register_exception_handlers`, `app_exception_handler`, `apply_cors`, `make_health_router`, `make_logs_router`, `make_prometheus_router`, `make_prometheus_registry`, `PrometheusMiddleware`, `LogSource`, `make_tool_spec_router`, `make_token_dependency`, `make_bearer_token_dependency`, `make_jwt_user_dependency`, `make_role_dependency`, `make_permission_dependency`, `require_x_token`, `run_server`, `RequestIDMiddleware`, `RateLimitMiddleware`, `IdempotencyMiddleware`, `MemoryIdempotencyStore`, `RedisIdempotencyStore`, `BodySizeLimitMiddleware`, `CSRFMiddleware`, `make_csrf_token_dependency`, `WebhookSignatureVerifier`, `RSAWebhookSignatureVerifier`, OAuth2 (`GoogleOAuthClient`, `GitHubOAuthClient`, `OIDCProvider`), `HardenedStaticFiles`, `DEFAULT_STATIC_SECURITY_HEADERS`, `set_cookie`, `clear_cookie`, `SameSite`, `HealthCheck` |
244
+ | `tempest_fastapi_sdk.api` | `register_exception_handlers`, `app_exception_handler`, `apply_cors`, `make_health_router`, `make_logs_router`, `make_prometheus_router`, `make_prometheus_registry`, `PrometheusMiddleware`, `LogSource`, `make_tool_spec_router`, `make_token_dependency`, `make_bearer_token_dependency`, `make_jwt_user_dependency`, `make_role_dependency`, `make_permission_dependency`, `require_x_token`, `run_server`, `RequestIDMiddleware`, `RateLimitMiddleware`, `IdempotencyMiddleware`, `MemoryIdempotencyStore`, `RedisIdempotencyStore`, `BodySizeLimitMiddleware`, `CSRFMiddleware`, `make_csrf_token_dependency`, `WebhookSignatureVerifier`, `RSAWebhookSignatureVerifier`, OAuth2 (`GoogleOAuthClient`, `GitHubOAuthClient`, `OIDCProvider`), `HardenedStaticFiles`, `DEFAULT_STATIC_SECURITY_HEADERS`, `set_cookie`, `clear_cookie`, `SameSite`, `HealthCheck`, `setup_tracing` *(extra: `[otel]`)* |
233
245
  | `tempest_fastapi_sdk.auth` *(extra: `[auth]`, opcional `[email]`, `[mfa]`)* | `UserAuthService`, `make_auth_router`, `SignupSchema` / `LoginSchema` / `PasswordResetRequestSchema` / `PasswordResetConfirmSchema` + responses, `ActivationToken`, `PasswordResetToken`, MFA schemas (`MFAEnrollResponseSchema` / `MFAConfirmSchema` / `MFAVerifySchema` / `MFADisableSchema`) — signup/activate/login/reset + TOTP 2FA out of the box |
234
246
  | `tempest_fastapi_sdk.controllers` | `BaseController` |
235
247
  | `tempest_fastapi_sdk.services` | `BaseService` |
@@ -3313,6 +3325,8 @@ tempest --help # list every command
3313
3325
  tempest --version # show the SDK version
3314
3326
  ```
3315
3327
 
3328
+ On any usage error — unknown command, invalid option, missing required argument — the CLI prints that command's **full** `--help` (every parameter, default and description) right before the error line, instead of Click's terse `Try '... --help'` hint. The fix is on screen immediately.
3329
+
3316
3330
  #### Scaffold a new service
3317
3331
 
3318
3332
  ```bash
@@ -3404,14 +3418,29 @@ tempest db history -v # revisions newest → oldest,
3404
3418
  Seeds or lists users via the project's concrete `UserModel` (default `src.db.models:UserModel`). Bootstraps the first admin row so `/admin` login works without manual SQL.
3405
3419
 
3406
3420
  ```bash
3407
- tempest user create --email ana@example.com --password strong-pass-12
3421
+ tempest user create --email ana@example.com --password strong-pass-12 --no-admin
3408
3422
  tempest user create --email admin@local --password admin-pass-12 --admin
3409
3423
  tempest user create --email admin@local --admin # prompt for password
3410
3424
  tempest user create --email x@y --password p --model myapp.models.user:User
3425
+ tempest user promote --email ana@example.com # grant /admin access (is_admin=True)
3426
+ tempest user revoke --email ana@example.com # revoke it (is_admin=False)
3411
3427
  tempest user list # everyone
3412
3428
  tempest user list --admin # admins only
3413
3429
  ```
3414
3430
 
3431
+ When `tempest user create` runs in an interactive terminal **without** `--admin`/`--no-admin`, it asks `Should this user be an administrator? [y/N]`. Non-interactive runs (CI, pipes) skip the prompt and create a regular user. `promote` / `revoke` look the user up by email (case-insensitive) and exit `1` with `no user found` when nothing matches.
3432
+
3433
+ #### Generate artifacts in an existing project — `tempest generate`
3434
+
3435
+ ```bash
3436
+ tempest generate --docker # regen docker-compose.yaml + .env.example from pinned extras
3437
+ tempest generate --src # add the src layers triggered by pinned extras
3438
+ tempest generate --docker --src # both at once
3439
+ tempest generate --src --force # overwrite existing layer files
3440
+ ```
3441
+
3442
+ `--src` reads the SDK extras pinned in `pyproject.toml` and writes only the layers that match — `[queue]` → `src/queue/` (FastStream broker + handlers), `[tasks]` → `src/tasks/` (TaskIQ broker + jobs). The source root (`src` or `app`) is auto-detected. It is idempotent: existing files are kept unless `--force` is passed. `tempest new --extras auth,queue` already scaffolds those layers — `generate --src` is for extras added after the project exists.
3443
+
3415
3444
  ### Admin site recipe
3416
3445
 
3417
3446
  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: file upload and inline/related editing.
@@ -114,6 +114,7 @@ Feature-rich helpers pull in third-party dependencies that you only need when yo
114
114
  | `[http]` | `httpx` | `HTTPClient`, `RetryPolicy`, `CircuitOpenError`, OAuth2 / OIDC providers |
115
115
  | `[prometheus]` | `prometheus-client` | `PrometheusMiddleware`, `make_prometheus_router`, `make_prometheus_registry` |
116
116
  | `[mfa]` | `pyotp` | `TOTPHelper` + MFA/2FA endpoints on the bundled auth flow |
117
+ | `[otel]` | `opentelemetry-sdk` + OTLP/gRPC exporter + FastAPI/SQLAlchemy/httpx instrumentors | `setup_tracing` — distributed tracing |
117
118
  | `[sqlite]` | `aiosqlite` | SQLite async driver for `sqlite+aiosqlite://` URLs (dev default) |
118
119
  | `[postgres]` | `asyncpg` | PostgreSQL async driver for `postgresql+asyncpg://` URLs (production) |
119
120
  | `[all]` | everything above | every helper |
@@ -135,10 +136,10 @@ Since `0.7.1` every optional dependency is imported lazily at first instantiatio
135
136
  | Module | Exports |
136
137
  | --- | --- |
137
138
  | `tempest_fastapi_sdk.schemas` | `BaseSchema`, `BaseResponseSchema`, `BasePaginationFilterSchema`, `BasePaginationSchema[T]`, `CursorPaginationFilterSchema`, `CursorPaginationSchema`, `LogEntrySchema`, `encode_cursor`, `decode_cursor`, `build_pagination_link_header` |
138
- | `tempest_fastapi_sdk.db` | `BaseModel`, `BaseUserModel`, `BaseUserTokenModel`, `BaseUserRecoveryCodeModel`, `make_user_recovery_code_model`, `UserTokenPurpose`, `BaseRepository[ModelType]`, `AsyncDatabaseManager`, `AlembicHelper`, `NAMING_CONVENTION`, `AuditMixin`, `SoftDeleteMixin`, `MFAMixin`, `BASE_COLUMN_ORDER`, `reorder_base_columns_first`, `compose_hooks` |
139
+ | `tempest_fastapi_sdk.db` | `BaseModel`, `BaseUserModel`, `BaseUserTokenModel`, `BaseUserRecoveryCodeModel`, `make_user_recovery_code_model`, `UserTokenPurpose`, `BaseRepository[ModelType]`, `AsyncDatabaseManager`, `AlembicHelper`, `NAMING_CONVENTION`, `AuditMixin`, `SoftDeleteMixin`, `MFAMixin`, `BASE_COLUMN_ORDER`, `reorder_base_columns_first`, `compose_hooks`, `SlowQueryLogger` |
139
140
  | `tempest_fastapi_sdk.exceptions` | `AppException`, `NotFoundException`, `ConflictException`, `ValidationException`, `UnauthorizedException`, `ForbiddenException`, `InvalidTokenException`, `ExpiredTokenException`, `FileTooLargeException`, `InvalidFileTypeException`, `TooManyRequestsException` |
140
141
  | `tempest_fastapi_sdk.settings` | `BaseAppSettings`, `ServerSettings`, `LogSettings`, `DatabaseSettings`, `RedisSettings`, `RabbitMQSettings`, `JWTSettings`, `CORSSettings`, `EmailSettings`, `UploadSettings`, `TokenSettings`, `WebPushSettings`, `TaskIQSettings`, `MinIOSettings`, `AuthSettings` |
141
- | `tempest_fastapi_sdk.api` | `register_exception_handlers`, `app_exception_handler`, `apply_cors`, `make_health_router`, `make_logs_router`, `make_prometheus_router`, `make_prometheus_registry`, `PrometheusMiddleware`, `LogSource`, `make_tool_spec_router`, `make_token_dependency`, `make_bearer_token_dependency`, `make_jwt_user_dependency`, `make_role_dependency`, `make_permission_dependency`, `require_x_token`, `run_server`, `RequestIDMiddleware`, `RateLimitMiddleware`, `IdempotencyMiddleware`, `MemoryIdempotencyStore`, `RedisIdempotencyStore`, `BodySizeLimitMiddleware`, `CSRFMiddleware`, `make_csrf_token_dependency`, `WebhookSignatureVerifier`, `RSAWebhookSignatureVerifier`, OAuth2 (`GoogleOAuthClient`, `GitHubOAuthClient`, `OIDCProvider`), `HardenedStaticFiles`, `DEFAULT_STATIC_SECURITY_HEADERS`, `set_cookie`, `clear_cookie`, `SameSite`, `HealthCheck` |
142
+ | `tempest_fastapi_sdk.api` | `register_exception_handlers`, `app_exception_handler`, `apply_cors`, `make_health_router`, `make_logs_router`, `make_prometheus_router`, `make_prometheus_registry`, `PrometheusMiddleware`, `LogSource`, `make_tool_spec_router`, `make_token_dependency`, `make_bearer_token_dependency`, `make_jwt_user_dependency`, `make_role_dependency`, `make_permission_dependency`, `require_x_token`, `run_server`, `RequestIDMiddleware`, `RateLimitMiddleware`, `IdempotencyMiddleware`, `MemoryIdempotencyStore`, `RedisIdempotencyStore`, `BodySizeLimitMiddleware`, `CSRFMiddleware`, `make_csrf_token_dependency`, `WebhookSignatureVerifier`, `RSAWebhookSignatureVerifier`, OAuth2 (`GoogleOAuthClient`, `GitHubOAuthClient`, `OIDCProvider`), `HardenedStaticFiles`, `DEFAULT_STATIC_SECURITY_HEADERS`, `set_cookie`, `clear_cookie`, `SameSite`, `HealthCheck`, `setup_tracing` *(extra: `[otel]`)* |
142
143
  | `tempest_fastapi_sdk.auth` *(extra: `[auth]`, opcional `[email]`, `[mfa]`)* | `UserAuthService`, `make_auth_router`, `SignupSchema` / `LoginSchema` / `PasswordResetRequestSchema` / `PasswordResetConfirmSchema` + responses, `ActivationToken`, `PasswordResetToken`, MFA schemas (`MFAEnrollResponseSchema` / `MFAConfirmSchema` / `MFAVerifySchema` / `MFADisableSchema`) — signup/activate/login/reset + TOTP 2FA out of the box |
143
144
  | `tempest_fastapi_sdk.controllers` | `BaseController` |
144
145
  | `tempest_fastapi_sdk.services` | `BaseService` |
@@ -3222,6 +3223,8 @@ tempest --help # list every command
3222
3223
  tempest --version # show the SDK version
3223
3224
  ```
3224
3225
 
3226
+ On any usage error — unknown command, invalid option, missing required argument — the CLI prints that command's **full** `--help` (every parameter, default and description) right before the error line, instead of Click's terse `Try '... --help'` hint. The fix is on screen immediately.
3227
+
3225
3228
  #### Scaffold a new service
3226
3229
 
3227
3230
  ```bash
@@ -3313,14 +3316,29 @@ tempest db history -v # revisions newest → oldest,
3313
3316
  Seeds or lists users via the project's concrete `UserModel` (default `src.db.models:UserModel`). Bootstraps the first admin row so `/admin` login works without manual SQL.
3314
3317
 
3315
3318
  ```bash
3316
- tempest user create --email ana@example.com --password strong-pass-12
3319
+ tempest user create --email ana@example.com --password strong-pass-12 --no-admin
3317
3320
  tempest user create --email admin@local --password admin-pass-12 --admin
3318
3321
  tempest user create --email admin@local --admin # prompt for password
3319
3322
  tempest user create --email x@y --password p --model myapp.models.user:User
3323
+ tempest user promote --email ana@example.com # grant /admin access (is_admin=True)
3324
+ tempest user revoke --email ana@example.com # revoke it (is_admin=False)
3320
3325
  tempest user list # everyone
3321
3326
  tempest user list --admin # admins only
3322
3327
  ```
3323
3328
 
3329
+ When `tempest user create` runs in an interactive terminal **without** `--admin`/`--no-admin`, it asks `Should this user be an administrator? [y/N]`. Non-interactive runs (CI, pipes) skip the prompt and create a regular user. `promote` / `revoke` look the user up by email (case-insensitive) and exit `1` with `no user found` when nothing matches.
3330
+
3331
+ #### Generate artifacts in an existing project — `tempest generate`
3332
+
3333
+ ```bash
3334
+ tempest generate --docker # regen docker-compose.yaml + .env.example from pinned extras
3335
+ tempest generate --src # add the src layers triggered by pinned extras
3336
+ tempest generate --docker --src # both at once
3337
+ tempest generate --src --force # overwrite existing layer files
3338
+ ```
3339
+
3340
+ `--src` reads the SDK extras pinned in `pyproject.toml` and writes only the layers that match — `[queue]` → `src/queue/` (FastStream broker + handlers), `[tasks]` → `src/tasks/` (TaskIQ broker + jobs). The source root (`src` or `app`) is auto-detected. It is idempotent: existing files are kept unless `--force` is passed. `tempest new --extras auth,queue` already scaffolds those layers — `generate --src` is for extras added after the project exists.
3341
+
3324
3342
  ### Admin site recipe
3325
3343
 
3326
3344
  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: file upload and inline/related editing.
@@ -8,6 +8,19 @@ tempest --help # list every command
8
8
  tempest --version # show the SDK version
9
9
  ```
10
10
 
11
+ !!! tip "Usage error? The full help shows up with it"
12
+ When you type an unknown command, an invalid option, or forget a
13
+ required argument, `tempest` prints that command's **complete**
14
+ `--help` (every parameter, default and description) **before** the
15
+ error line — instead of Click's terse `Try '... --help'`. You fix
16
+ it on the spot, without re-running with `--help`.
17
+
18
+ ```bash
19
+ tempest user create # forgot --email
20
+ # ... full `user create` help (every option) ...
21
+ # Error: Missing option '--email' / '-e'.
22
+ ```
23
+
11
24
  #### Scaffold a new service
12
25
 
13
26
  ```bash
@@ -135,7 +148,7 @@ Seed and list users using the project's concrete ``UserModel`` (default ``src.db
135
148
 
136
149
  ```bash
137
150
  # Create a regular user
138
- tempest user create --email ana@example.com --password strong-pass-12
151
+ tempest user create --email ana@example.com --password strong-pass-12 --no-admin
139
152
 
140
153
  # Create an admin (can log into /admin)
141
154
  tempest user create --email admin@local --password admin-pass-12 --admin
@@ -146,11 +159,25 @@ tempest user create --email admin@local --admin
146
159
  # Custom model outside the scaffolded layout — MUST be a BaseUserModel subclass
147
160
  tempest user create --email x@y --password pass-12-chars --model myapp.models.user:UserModel
148
161
 
162
+ # Promote / demote an existing user (toggles is_admin)
163
+ tempest user promote --email ana@example.com # becomes admin
164
+ tempest user revoke --email ana@example.com # back to a regular account
165
+
149
166
  # List
150
167
  tempest user list # everyone
151
168
  tempest user list --admin # admins only
152
169
  ```
153
170
 
171
+ !!! tip "Without `--admin`/`--no-admin`, create asks"
172
+ When you pass **neither** `--admin` nor `--no-admin` in an
173
+ interactive terminal, `tempest user create` prompts
174
+ `Should this user be an administrator? [y/N]`. Non-interactive runs
175
+ (CI, pipes, scripts) skip the prompt and create a regular user
176
+ (`is_admin=False`) — pass `--admin` explicitly to create an admin
177
+ without a TTY.
178
+
179
+ `tempest user promote` / `tempest user revoke` find the user by email (case-insensitive) and only flip `is_admin`. When no user matches the email they exit with code 1 and a `no user found` message.
180
+
154
181
  ``DATABASE_URL`` resolves the same way as ``tempest db`` (env var > settings > alembic.ini).
155
182
 
156
183
  ### Regenerating `docker-compose.yaml` in an existing project
@@ -166,6 +193,31 @@ tempest generate --docker --force # overwrite an existing compose
166
193
 
167
194
  The command reads ``[project] name`` + extras from the current directory's `pyproject.toml` (pass `--path` for another). It refuses to overwrite without `--force` so hand edits don't get clobbered. The `.env.example` addendum is idempotent — re-running does not duplicate service blocks.
168
195
 
196
+ ### Generating the `src` layers from extras — `tempest generate --src`
197
+
198
+ The always-present layers (`api`, `controllers`, `services`, `schemas`, `db`, `core`, `utils`) ship in the scaffold. The layers that only make sense with a specific extra — `[queue]` (FastStream) and `[tasks]` (TaskIQ) — are **not** part of the base skeleton: dropping empty placeholder packages in every service contradicts the layout rules. When you add one of those extras to an existing project (`uv add "tempest-fastapi-sdk[queue]"`), generate the matching layer with:
199
+
200
+ ```bash
201
+ tempest generate --src # read extras from local pyproject.toml
202
+ tempest generate --src --extras tasks # force explicit extras
203
+ tempest generate --src --force # overwrite existing files
204
+ tempest generate --docker --src # compose + layers in one shot
205
+ ```
206
+
207
+ Extra → generated layer mapping:
208
+
209
+ | Extra | Files created (under `src/` or `app/`) |
210
+ |-------|------------------------------------------|
211
+ | `[queue]` | `queue/__init__.py` (broker + `AsyncBrokerManager` + `get_broker`), `queue/handlers.py` (example subscriber) |
212
+ | `[tasks]` | `tasks/__init__.py` (broker + `AsyncTaskBrokerManager` + `get_task_manager`), `tasks/jobs.py` (example task) |
213
+
214
+ The source root (`src` or `app`) is auto-detected, and generated imports (`from src.queue import broker`) already point at it. The operation is **idempotent**: existing files are **kept** unless you pass `--force`, so a hand-edited handler is never clobbered silently — a sibling file that doesn't exist yet is still written. Extras with no associated layer (e.g. just `[cache]`) generate nothing and the command says so.
215
+
216
+ !!! note "`tempest new` already generates the chosen extras' layers"
217
+ A `tempest new my_service --extras auth,queue` already ships
218
+ `src/queue/` — `generate --src` is for when you add the extra
219
+ **after** creating the project.
220
+
169
221
  After scaffolding:
170
222
 
171
223
  ```bash
@@ -8,6 +8,19 @@ tempest --help # lista todos os comandos
8
8
  tempest --version # mostra a versão do SDK
9
9
  ```
10
10
 
11
+ !!! tip "Erro de uso? O help completo aparece junto"
12
+ Quando você digita um comando inexistente, uma opção inválida ou
13
+ esquece um argumento obrigatório, o `tempest` imprime o `--help`
14
+ **completo** daquele comando (todos os parâmetros, defaults e
15
+ descrições) **antes** da linha de erro — em vez do `Try '... --help'`
16
+ enxuto do Click. Você corrige na hora, sem reexecutar com `--help`.
17
+
18
+ ```bash
19
+ tempest user create # esqueceu --email
20
+ # ... help completo do `user create` (todas as opções) ...
21
+ # Error: Missing option '--email' / '-e'.
22
+ ```
23
+
11
24
  #### Gerar um novo serviço
12
25
 
13
26
  ```bash
@@ -118,6 +131,31 @@ tempest generate --docker --force # sobrescreve compose existente
118
131
 
119
132
  O comando lê o `[project] name` + extras do `pyproject.toml` do diretório atual (use `--path` pra outro). Recusa overwrite sem `--force` pra não pisar em edits manuais. O `.env.example` é atualizado de forma idempotente — re-rodar não duplica blocos.
120
133
 
134
+ ### Gerar as camadas `src` dos extras — `tempest generate --src`
135
+
136
+ As camadas sempre presentes (`api`, `controllers`, `services`, `schemas`, `db`, `core`, `utils`) já vêm no scaffold. As camadas que só fazem sentido com um extra específico — `[queue]` (FastStream) e `[tasks]` (TaskIQ) — **não** entram no esqueleto base: deixar pacotes placeholder vazios em todo serviço contraria as regras de layout. Quando você adiciona um desses extras a um projeto existente (`uv add "tempest-fastapi-sdk[queue]"`), gere a camada correspondente com:
137
+
138
+ ```bash
139
+ tempest generate --src # lê extras do pyproject.toml local
140
+ tempest generate --src --extras tasks # força extras explícitos
141
+ tempest generate --src --force # sobrescreve arquivos existentes
142
+ tempest generate --docker --src # compose + camadas numa tacada
143
+ ```
144
+
145
+ Mapeamento extra → camada gerada:
146
+
147
+ | Extra | Arquivos criados (sob `src/` ou `app/`) |
148
+ |-------|------------------------------------------|
149
+ | `[queue]` | `queue/__init__.py` (broker + `AsyncBrokerManager` + `get_broker`), `queue/handlers.py` (subscriber de exemplo) |
150
+ | `[tasks]` | `tasks/__init__.py` (broker + `AsyncTaskBrokerManager` + `get_task_manager`), `tasks/jobs.py` (task de exemplo) |
151
+
152
+ A raiz (`src` ou `app`) é detectada automaticamente, e os imports gerados (`from src.queue import broker`) já apontam pra ela. A operação é **idempotente**: arquivos existentes são **mantidos** a menos que você passe `--force`, então um handler editado à mão nunca é sobrescrito silenciosamente — o arquivo irmão que ainda não existe é criado normalmente. Extras sem camada associada (ex.: só `[cache]`) não geram nada e o comando avisa.
153
+
154
+ !!! note "`tempest new` já gera as camadas dos extras escolhidos"
155
+ Um `tempest new my_service --extras auth,queue` já entrega
156
+ `src/queue/` pronto — o `generate --src` é pra quando você adiciona
157
+ o extra **depois** de criar o projeto.
158
+
121
159
  Depois de gerar:
122
160
 
123
161
  ```bash
@@ -158,7 +196,7 @@ Insere/lista usuários direto no banco usando o `UserModel` concreto do projeto
158
196
 
159
197
  ```bash
160
198
  # Cria usuário comum
161
- tempest user create --email ana@example.com --password senha-forte-12
199
+ tempest user create --email ana@example.com --password senha-forte-12 --no-admin
162
200
 
163
201
  # Cria admin (pode logar no /admin)
164
202
  tempest user create --email admin@local --password admin-pass-12 --admin
@@ -169,11 +207,25 @@ tempest user create --email admin@local --admin
169
207
  # Modelo customizado fora do layout scaffoldado — DEVE ser subclasse de BaseUserModel
170
208
  tempest user create --email x@y --password pass-12-chars --model myapp.models.user:UserModel
171
209
 
210
+ # Promove/rebaixa um usuário existente (liga/desliga is_admin)
211
+ tempest user promote --email ana@example.com # vira admin
212
+ tempest user revoke --email ana@example.com # volta a ser comum
213
+
172
214
  # Lista
173
215
  tempest user list # todos
174
216
  tempest user list --admin # só admins
175
217
  ```
176
218
 
219
+ !!! tip "Sem `--admin`/`--no-admin`, o create pergunta"
220
+ Quando você **não** passa nem `--admin` nem `--no-admin` num
221
+ terminal interativo, o `tempest user create` pergunta
222
+ `Should this user be an administrator? [y/N]`. Em execuções
223
+ não-interativas (CI, pipes, scripts) o prompt é pulado e o usuário
224
+ nasce comum (`is_admin=False`) — passe `--admin` explicitamente pra
225
+ criar admin sem TTY.
226
+
227
+ `tempest user promote` / `tempest user revoke` localizam o usuário por email (case-insensitive) e só alternam `is_admin`. Quando nenhum usuário casa com o email, saem com código 1 e a mensagem `no user found`.
228
+
177
229
  Resolução do `DATABASE_URL` igual ao `tempest db` (env var > settings > alembic.ini).
178
230
 
179
231
  #### Gates de qualidade
@@ -19,6 +19,7 @@ Bite-sized "I want to wire X" walkthroughs. Each page starts with **what problem
19
19
  | **[Web Push »](webpush.md)** | `WebPushDispatcher`, VAPID schemas, broadcast with pruning |
20
20
  | **[Logging »](logging.md)** | `LogUtils`, structured JSON logging, request-ID propagation |
21
21
  | **[Metrics »](metrics.md)** | `MetricsUtils` — CPU / RAM / disk / GPU snapshots |
22
+ | **[Observability (tracing) »](observability.md)** | `setup_tracing` (OpenTelemetry), `SlowQueryLogger` |
22
23
  | **[Admin site »](admin.md)** | `AdminSite`, `AdminModel`, `make_admin_router`, `BaseUserModel` |
23
24
  | **[Downloads »](downloads.md)** | `DownloadUtils` — `file_response`, `stream`, `build_content_disposition`, path-traversal safe |
24
25
  | **[Utilities »](utilities.md)** | `utcnow`/`to_utc`, `modify_dict`, `get_client_ip`, opaque tokens (`generate_opaque_token`) |
@@ -19,6 +19,7 @@ Passo a passo curtos no estilo "quero conectar X". Cada página começa com **qu
19
19
  | **[Web Push »](webpush.md)** | `WebPushDispatcher`, schemas VAPID, broadcast com poda |
20
20
  | **[Logging »](logging.md)** | `LogUtils`, logging JSON estruturado, propagação de request-ID |
21
21
  | **[Métricas »](metrics.md)** | `MetricsUtils` — snapshots de CPU / RAM / disco / GPU |
22
+ | **[Observabilidade (tracing) »](observability.md)** | `setup_tracing` (OpenTelemetry), `SlowQueryLogger` |
22
23
  | **[Painel admin »](admin.md)** | `AdminSite`, `AdminModel`, `make_admin_router`, `BaseUserModel` |
23
24
  | **[Downloads »](downloads.md)** | `DownloadUtils` — `file_response`, `stream`, `build_content_disposition`, anti path-traversal |
24
25
  | **[Utilitários »](utilities.md)** | `utcnow`/`to_utc`, `modify_dict`, `get_client_ip`, tokens opacos (`generate_opaque_token`) |
@@ -0,0 +1,163 @@
1
+ # Observability (tracing + slow queries)
2
+
3
+ Logs tell you **what** happened in a service; distributed tracing tells you
4
+ **where** the time went on a request that crosses several services, and the
5
+ `SlowQueryLogger` points at **which** query is dragging your p99. This
6
+ recipe covers both.
7
+
8
+ !!! info "Where this fits"
9
+ The [`RequestIDMiddleware`](http.md) correlates **logs** per request;
10
+ OpenTelemetry correlates **spans** across services. They complement each
11
+ other — use them together.
12
+
13
+ ## Distributed tracing with OpenTelemetry
14
+
15
+ `setup_tracing` installs an OpenTelemetry provider and auto-instruments the
16
+ common layers of a Tempest service: FastAPI (incoming requests), SQLAlchemy
17
+ (queries), and httpx (outbound calls). Requires the `[otel]` extra:
18
+
19
+ ```bash
20
+ pip install "tempest-fastapi-sdk[otel]"
21
+ ```
22
+
23
+ Call it once at startup, after the app exists and (when you want to trace
24
+ queries) after the database has connected:
25
+
26
+ ```python
27
+ from fastapi import FastAPI
28
+
29
+ from tempest_fastapi_sdk import AsyncDatabaseManager, setup_tracing
30
+
31
+ app: FastAPI = FastAPI()
32
+ db: AsyncDatabaseManager = AsyncDatabaseManager("postgresql+asyncpg://...")
33
+
34
+
35
+ @app.on_event("startup")
36
+ async def _startup() -> None:
37
+ """Connect the database and turn tracing on."""
38
+ await db.connect()
39
+ setup_tracing(
40
+ app,
41
+ service_name="orders-api",
42
+ otlp_endpoint="http://otel-collector:4317",
43
+ sqlalchemy_engine=db.engine,
44
+ )
45
+ ```
46
+
47
+ That's it: every request becomes a parent span, every query and every httpx
48
+ call becomes a child span, and the whole trace shows up in Jaeger / Tempo /
49
+ Honeycomb under the name `orders-api`.
50
+
51
+ ### No collector (local debugging)
52
+
53
+ Pass `otlp_endpoint=None` to install a console exporter — spans print to
54
+ stdout, no collector required:
55
+
56
+ ```python
57
+ from fastapi import FastAPI
58
+
59
+ from tempest_fastapi_sdk import setup_tracing
60
+
61
+ app: FastAPI = FastAPI()
62
+ setup_tracing(app, service_name="orders-api", otlp_endpoint=None)
63
+ ```
64
+
65
+ ### Sampling
66
+
67
+ In high-traffic production, tracing 100% of requests is expensive. Pass
68
+ `sample_ratio` to sample a fraction (a head-based decision propagated to
69
+ child spans):
70
+
71
+ ```python
72
+ from fastapi import FastAPI
73
+
74
+ from tempest_fastapi_sdk import setup_tracing
75
+
76
+ app: FastAPI = FastAPI()
77
+ setup_tracing(
78
+ app,
79
+ service_name="orders-api",
80
+ otlp_endpoint="http://otel-collector:4317",
81
+ sample_ratio=0.1, # ~10% of requests
82
+ resource_attributes={"deployment.environment": "prod"},
83
+ )
84
+ ```
85
+
86
+ !!! tip "Arguments, not env vars"
87
+ The endpoint, the sampling and the attributes come from the function
88
+ **arguments** — the call site is the single source of truth. No
89
+ configuring half in code and half in `OTEL_*` env vars.
90
+
91
+ !!! note "Best-effort instrumentation"
92
+ SQLAlchemy and httpx are only instrumented when the
93
+ `opentelemetry-instrumentation-sqlalchemy` / `...-httpx` packages are
94
+ installed (the `[otel]` extra ships both). If they are missing,
95
+ instrumentation is silently skipped instead of breaking boot.
96
+
97
+ ## Slow query logger
98
+
99
+ `SlowQueryLogger` registers a listener on the SQLAlchemy engine events and
100
+ emits a log line whenever a statement exceeds a configurable threshold. It
101
+ is the cheapest way to find the N+1 or the missing index. **No extra
102
+ needed** — it uses only SQLAlchemy.
103
+
104
+ ```python
105
+ import logging
106
+
107
+ from tempest_fastapi_sdk import AsyncDatabaseManager, SlowQueryLogger
108
+
109
+ db: AsyncDatabaseManager = AsyncDatabaseManager("postgresql+asyncpg://...")
110
+
111
+
112
+ async def wire_slow_query_log() -> None:
113
+ """Turn slow-query logging on at startup."""
114
+ await db.connect()
115
+ slow: SlowQueryLogger = SlowQueryLogger(
116
+ db.engine,
117
+ threshold_ms=200.0, # logs queries >= 200ms
118
+ level=logging.WARNING,
119
+ )
120
+ slow.attach()
121
+ ```
122
+
123
+ Each slow query becomes a line like:
124
+
125
+ ```text
126
+ WARNING ... slow query: 312.4ms >= 200.0ms threshold | SELECT users.id, ...
127
+ ```
128
+
129
+ ### Parameters and EXPLAIN (dev only)
130
+
131
+ By default, bind parameters are **not** logged (they often carry
132
+ PII/secrets). In development, turn on `log_parameters=True` and/or
133
+ `explain=True` to see the execution plan:
134
+
135
+ ```python
136
+ import logging
137
+
138
+ from tempest_fastapi_sdk import SlowQueryLogger
139
+
140
+ slow: SlowQueryLogger = SlowQueryLogger(
141
+ db.engine,
142
+ threshold_ms=50.0,
143
+ log_parameters=True, # include the binds — dev only
144
+ explain=True, # run EXPLAIN and append the plan — costs 1 round-trip
145
+ )
146
+ slow.attach()
147
+ ```
148
+
149
+ !!! warning "EXPLAIN costs a round-trip"
150
+ With `explain=True` every slow query fires an extra `EXPLAIN`. Keep it
151
+ off in production, turn it on only while hunting a bad plan.
152
+
153
+ To turn it off (e.g. on shutdown or in a test), call `slow.detach()`.
154
+
155
+ ## Recap
156
+
157
+ - `setup_tracing(app, service_name=..., otlp_endpoint=...)` turns on
158
+ distributed tracing with FastAPI/SQLAlchemy/httpx auto-instrumentation —
159
+ `[otel]` extra.
160
+ - `otlp_endpoint=None` exports spans to the console (local debugging);
161
+ `sample_ratio` controls sampling.
162
+ - `SlowQueryLogger(engine, threshold_ms=...).attach()` logs slow queries
163
+ with no extra at all; parameters and `EXPLAIN` sit behind opt-in flags.