fastapi-rtk 2.1.1__tar.gz → 2.1.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (299) hide show
  1. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/PKG-INFO +1 -1
  2. fastapi_rtk-2.1.3/fastapi_rtk/_version.py +1 -0
  3. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/api/base_api.py +20 -12
  4. fastapi_rtk-2.1.3/fastapi_rtk/cli/decorators.py +80 -0
  5. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/conftest.py +3 -0
  6. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/api/test_base_api.py +23 -0
  7. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/cli/commands/test_db.py +1 -3
  8. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/cli/commands/test_export.py +9 -4
  9. fastapi_rtk-2.1.3/tests/unit/cli/conftest.py +30 -0
  10. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/cli/test_decorators.py +41 -24
  11. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/test_fastapi_react_toolkit.py +32 -7
  12. fastapi_rtk-2.1.1/fastapi_rtk/_version.py +0 -1
  13. fastapi_rtk-2.1.1/fastapi_rtk/cli/decorators.py +0 -87
  14. fastapi_rtk-2.1.1/tests/unit/cli/conftest.py +0 -15
  15. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/.gitignore +0 -0
  16. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/LICENSE +0 -0
  17. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/README.md +0 -0
  18. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/__init__.py +0 -0
  19. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/api/__init__.py +0 -0
  20. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/api/model_rest_api/__init__.py +0 -0
  21. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/api/model_rest_api/_add_mixin.py +0 -0
  22. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/api/model_rest_api/_bulk_mixin.py +0 -0
  23. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/api/model_rest_api/_columns.py +0 -0
  24. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/api/model_rest_api/_delete_mixin.py +0 -0
  25. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/api/model_rest_api/_download_mixin.py +0 -0
  26. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/api/model_rest_api/_edit_mixin.py +0 -0
  27. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/api/model_rest_api/_file_mixin.py +0 -0
  28. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/api/model_rest_api/_info_mixin.py +0 -0
  29. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/api/model_rest_api/_list_mixin.py +0 -0
  30. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/api/model_rest_api/_params.py +0 -0
  31. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/api/model_rest_api/_show_mixin.py +0 -0
  32. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/api/model_rest_api/_upload_mixin.py +0 -0
  33. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/apis/__init__.py +0 -0
  34. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/apis/info.py +0 -0
  35. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/apis/license.py +0 -0
  36. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/auth/__init__.py +0 -0
  37. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/auth/auth.py +0 -0
  38. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/auth/hashers/__init__.py +0 -0
  39. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/auth/hashers/pbkdf2.py +0 -0
  40. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/auth/hashers/scrypt.py +0 -0
  41. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/auth/ldap.py +0 -0
  42. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/auth/password_helpers/__init__.py +0 -0
  43. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/auth/password_helpers/fab.py +0 -0
  44. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/auth/strategies/__init__.py +0 -0
  45. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/auth/strategies/config.py +0 -0
  46. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/auth/strategies/db.py +0 -0
  47. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/auth/strategies/jwt.py +0 -0
  48. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/backends/__init__.py +0 -0
  49. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/backends/generic/__init__.py +0 -0
  50. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/backends/generic/column.py +0 -0
  51. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/backends/generic/db.py +0 -0
  52. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/backends/generic/exceptions.py +0 -0
  53. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/backends/generic/filters.py +0 -0
  54. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/backends/generic/interface.py +0 -0
  55. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/backends/generic/model.py +0 -0
  56. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/backends/generic/session.py +0 -0
  57. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/backends/sqla/__init__.py +0 -0
  58. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/backends/sqla/column.py +0 -0
  59. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/backends/sqla/db.py +0 -0
  60. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/backends/sqla/exceptions.py +0 -0
  61. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/backends/sqla/extensions/__init__.py +0 -0
  62. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/backends/sqla/extensions/audit/__init__.py +0 -0
  63. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/backends/sqla/extensions/audit/_decorators_mixin.py +0 -0
  64. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/backends/sqla/extensions/audit/_lifecycle_mixin.py +0 -0
  65. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/backends/sqla/extensions/audit/_logger.py +0 -0
  66. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/backends/sqla/extensions/audit/_processing_mixin.py +0 -0
  67. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/backends/sqla/extensions/audit/audit.py +0 -0
  68. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/backends/sqla/extensions/audit/types.py +0 -0
  69. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/backends/sqla/extensions/geoalchemy2/__init__.py +0 -0
  70. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/backends/sqla/extensions/geoalchemy2/filters.py +0 -0
  71. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/backends/sqla/extensions/geoalchemy2/geometry_converter.py +0 -0
  72. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/backends/sqla/filters.py +0 -0
  73. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/backends/sqla/interface.py +0 -0
  74. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/backends/sqla/model.py +0 -0
  75. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/backends/sqla/session.py +0 -0
  76. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/bases/__init__.py +0 -0
  77. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/bases/db.py +0 -0
  78. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/bases/file_manager.py +0 -0
  79. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/bases/filter.py +0 -0
  80. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/bases/interface.py +0 -0
  81. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/bases/model.py +0 -0
  82. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/bases/session.py +0 -0
  83. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/cli/__init__.py +0 -0
  84. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/cli/cli.py +0 -0
  85. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/cli/commands/__init__.py +0 -0
  86. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/cli/commands/_security_crypto.py +0 -0
  87. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/cli/commands/db/__init__.py +0 -0
  88. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/cli/commands/db/templates/fastapi/README +0 -0
  89. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/cli/commands/db/templates/fastapi/alembic.ini.mako +0 -0
  90. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/cli/commands/db/templates/fastapi/env.py +0 -0
  91. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/cli/commands/db/templates/fastapi/script.py.mako +0 -0
  92. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/cli/commands/db/templates/fastapi-multidb/README +0 -0
  93. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/cli/commands/db/templates/fastapi-multidb/alembic.ini.mako +0 -0
  94. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/cli/commands/db/templates/fastapi-multidb/env.py +0 -0
  95. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/cli/commands/db/templates/fastapi-multidb/script.py.mako +0 -0
  96. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/cli/commands/export.py +0 -0
  97. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/cli/commands/security.py +0 -0
  98. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/cli/commands/translate.py +0 -0
  99. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/cli/const.py +0 -0
  100. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/cli/types.py +0 -0
  101. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/cli/utils.py +0 -0
  102. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/config.py +0 -0
  103. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/const.py +0 -0
  104. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/db.py +0 -0
  105. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/decorators.py +0 -0
  106. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/dependencies.py +0 -0
  107. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/exceptions.py +0 -0
  108. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/fastapi_react_toolkit.py +0 -0
  109. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/file_managers/__init__.py +0 -0
  110. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/file_managers/file_manager.py +0 -0
  111. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/file_managers/image_manager.py +0 -0
  112. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/file_managers/s3_file_manager.py +0 -0
  113. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/file_managers/s3_image_manager.py +0 -0
  114. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/filters.py +0 -0
  115. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/globals.py +0 -0
  116. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/lang/__init__.py +0 -0
  117. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/lang/babel/__init__.py +0 -0
  118. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/lang/babel/cli.py +0 -0
  119. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/lang/babel/config.py +0 -0
  120. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/lang/babel.cfg +0 -0
  121. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/lang/lazy_text.py +0 -0
  122. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/lang/messages.pot +0 -0
  123. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/lang/translations/de/LC_MESSAGES/messages.mo +0 -0
  124. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/lang/translations/de/LC_MESSAGES/messages.po +0 -0
  125. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/lang/translations/en/LC_MESSAGES/messages.mo +0 -0
  126. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/lang/translations/en/LC_MESSAGES/messages.po +0 -0
  127. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/manager.py +0 -0
  128. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/middlewares.py +0 -0
  129. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/mixins.py +0 -0
  130. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/models.py +0 -0
  131. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/py.typed +0 -0
  132. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/registry.py +0 -0
  133. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/routers.py +0 -0
  134. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/schemas.py +0 -0
  135. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/security/__init__.py +0 -0
  136. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/security/sqla/__init__.py +0 -0
  137. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/security/sqla/apis.py +0 -0
  138. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/security/sqla/models.py +0 -0
  139. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/security/sqla/security_manager/__init__.py +0 -0
  140. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/security/sqla/security_manager/_association_mixin.py +0 -0
  141. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/security/sqla/security_manager/_builtin_role_mixin.py +0 -0
  142. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/security/sqla/security_manager/_cleanup_mixin.py +0 -0
  143. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/security/sqla/security_manager/_exception_filters.py +0 -0
  144. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/security/sqla/security_manager/_export.py +0 -0
  145. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/security/sqla/security_manager/_import.py +0 -0
  146. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/security/sqla/security_manager/_role_mixin.py +0 -0
  147. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/security/sqla/security_manager/_user_mixin.py +0 -0
  148. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/setting.py +0 -0
  149. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/types.py +0 -0
  150. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/utils/__init__.py +0 -0
  151. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/utils/async_task_runner.py +0 -0
  152. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/utils/class_factory.py +0 -0
  153. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/utils/csv_json_converter.py +0 -0
  154. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/utils/deep_merge.py +0 -0
  155. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/utils/extender_mixin.py +0 -0
  156. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/utils/flask_appbuilder_utils.py +0 -0
  157. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/utils/formatter.py +0 -0
  158. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/utils/hooks.py +0 -0
  159. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/utils/lazy.py +0 -0
  160. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/utils/merge_schema.py +0 -0
  161. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/utils/multiple_async_contexts.py +0 -0
  162. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/utils/pydantic.py +0 -0
  163. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/utils/run_utils.py +0 -0
  164. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/utils/self_dependencies.py +0 -0
  165. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/utils/smartdefaultdict.py +0 -0
  166. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/utils/sqla.py +0 -0
  167. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/utils/timezone.py +0 -0
  168. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/utils/update_signature.py +0 -0
  169. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/utils/use_default_when_none.py +0 -0
  170. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/fastapi_rtk/version.py +0 -0
  171. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/pyproject.toml +0 -0
  172. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/docker-compose.gis.yml +0 -0
  173. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/integration/__init__.py +0 -0
  174. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/integration/api/__init__.py +0 -0
  175. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/integration/api/test_model_rest_api.py +0 -0
  176. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/integration/apis/__init__.py +0 -0
  177. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/integration/apis/test_info_contract.py +0 -0
  178. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/integration/auth/__init__.py +0 -0
  179. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/integration/auth/test_auth_flow.py +0 -0
  180. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/integration/auth/test_oauth.py +0 -0
  181. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/integration/conftest.py +0 -0
  182. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/integration/file_managers/__init__.py +0 -0
  183. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/integration/file_managers/test_file_routes.py +0 -0
  184. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/integration/security/__init__.py +0 -0
  185. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/integration/security/sqla/__init__.py +0 -0
  186. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/integration/security/sqla/test_security_manager.py +0 -0
  187. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/integration/test_app_smoke.py +0 -0
  188. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/__init__.py +0 -0
  189. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/api/__init__.py +0 -0
  190. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/api/conftest.py +0 -0
  191. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/api/model_rest_api/__init__.py +0 -0
  192. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/api/model_rest_api/test_columns.py +0 -0
  193. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/api/model_rest_api/test_file_mixin.py +0 -0
  194. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/api/model_rest_api/test_init.py +0 -0
  195. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/apis/__init__.py +0 -0
  196. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/apis/test_info.py +0 -0
  197. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/apis/test_license.py +0 -0
  198. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/auth/__init__.py +0 -0
  199. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/auth/hashers/__init__.py +0 -0
  200. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/auth/hashers/test_pbkdf2.py +0 -0
  201. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/auth/hashers/test_scrypt.py +0 -0
  202. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/auth/password_helpers/__init__.py +0 -0
  203. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/auth/password_helpers/test_fab.py +0 -0
  204. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/auth/strategies/__init__.py +0 -0
  205. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/auth/strategies/test_config.py +0 -0
  206. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/auth/strategies/test_db.py +0 -0
  207. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/auth/strategies/test_jwt.py +0 -0
  208. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/auth/test_auth.py +0 -0
  209. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/backends/__init__.py +0 -0
  210. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/backends/generic/__init__.py +0 -0
  211. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/backends/generic/test_column.py +0 -0
  212. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/backends/generic/test_db.py +0 -0
  213. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/backends/generic/test_exceptions.py +0 -0
  214. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/backends/generic/test_filters.py +0 -0
  215. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/backends/generic/test_interface.py +0 -0
  216. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/backends/generic/test_model.py +0 -0
  217. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/backends/generic/test_session.py +0 -0
  218. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/backends/sqla/__init__.py +0 -0
  219. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/backends/sqla/conftest.py +0 -0
  220. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/backends/sqla/test_audit.py +0 -0
  221. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/backends/sqla/test_audit_types.py +0 -0
  222. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/backends/sqla/test_column.py +0 -0
  223. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/backends/sqla/test_db.py +0 -0
  224. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/backends/sqla/test_filters.py +0 -0
  225. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/backends/sqla/test_geoalchemy2.py +0 -0
  226. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/backends/sqla/test_interface.py +0 -0
  227. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/backends/sqla/test_model.py +0 -0
  228. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/backends/sqla/test_session.py +0 -0
  229. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/bases/__init__.py +0 -0
  230. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/bases/test_db.py +0 -0
  231. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/bases/test_file_manager.py +0 -0
  232. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/bases/test_filter.py +0 -0
  233. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/bases/test_interface.py +0 -0
  234. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/bases/test_model.py +0 -0
  235. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/bases/test_session.py +0 -0
  236. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/cli/__init__.py +0 -0
  237. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/cli/commands/__init__.py +0 -0
  238. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/cli/commands/conftest.py +0 -0
  239. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/cli/commands/test_security.py +0 -0
  240. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/cli/commands/test_security_crypto.py +0 -0
  241. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/cli/commands/test_translate.py +0 -0
  242. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/cli/test_cli.py +0 -0
  243. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/cli/test_types.py +0 -0
  244. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/cli/test_utils.py +0 -0
  245. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/file_managers/__init__.py +0 -0
  246. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/file_managers/conftest.py +0 -0
  247. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/file_managers/test_file_manager.py +0 -0
  248. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/file_managers/test_image_manager.py +0 -0
  249. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/file_managers/test_s3_file_manager.py +0 -0
  250. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/file_managers/test_s3_image_manager.py +0 -0
  251. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/lang/__init__.py +0 -0
  252. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/lang/test_babel_cli.py +0 -0
  253. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/lang/test_babel_config.py +0 -0
  254. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/lang/test_lazy_text.py +0 -0
  255. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/security/__init__.py +0 -0
  256. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/security/sqla/__init__.py +0 -0
  257. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/security/sqla/conftest.py +0 -0
  258. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/security/sqla/test_apis.py +0 -0
  259. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/security/sqla/test_models.py +0 -0
  260. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/security/sqla/test_security_manager.py +0 -0
  261. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/test_config.py +0 -0
  262. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/test_const.py +0 -0
  263. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/test_db.py +0 -0
  264. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/test_decorators.py +0 -0
  265. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/test_dependencies.py +0 -0
  266. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/test_exceptions.py +0 -0
  267. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/test_filters.py +0 -0
  268. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/test_globals.py +0 -0
  269. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/test_manager.py +0 -0
  270. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/test_middlewares.py +0 -0
  271. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/test_mixins.py +0 -0
  272. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/test_models.py +0 -0
  273. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/test_registry.py +0 -0
  274. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/test_routers.py +0 -0
  275. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/test_schemas.py +0 -0
  276. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/test_setting.py +0 -0
  277. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/test_types.py +0 -0
  278. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/test_version.py +0 -0
  279. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/utils/__init__.py +0 -0
  280. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/utils/test_async_task_runner.py +0 -0
  281. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/utils/test_class_factory.py +0 -0
  282. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/utils/test_csv_json_converter.py +0 -0
  283. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/utils/test_deep_merge.py +0 -0
  284. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/utils/test_extender_mixin.py +0 -0
  285. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/utils/test_flask_appbuilder_utils.py +0 -0
  286. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/utils/test_formatter.py +0 -0
  287. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/utils/test_hooks.py +0 -0
  288. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/utils/test_lazy.py +0 -0
  289. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/utils/test_merge_schema.py +0 -0
  290. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/utils/test_multiple_async_contexts.py +0 -0
  291. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/utils/test_pydantic.py +0 -0
  292. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/utils/test_run_utils.py +0 -0
  293. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/utils/test_self_dependencies.py +0 -0
  294. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/utils/test_smartdefaultdict.py +0 -0
  295. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/utils/test_sqla.py +0 -0
  296. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/utils/test_timezone.py +0 -0
  297. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/utils/test_update_signature.py +0 -0
  298. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/tests/unit/utils/test_use_default_when_none.py +0 -0
  299. {fastapi_rtk-2.1.1 → fastapi_rtk-2.1.3}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastapi-rtk
3
- Version: 2.1.1
3
+ Version: 2.1.3
4
4
  Summary: A package that provides a set of tools to build a FastAPI application with a Class-Based CRUD API.
5
5
  Project-URL: Homepage, https://codeberg.org/datatactics/fastapi-rtk
6
6
  Project-URL: Issues, https://codeberg.org/datatactics/fastapi-rtk/issues
@@ -0,0 +1 @@
1
+ __version__ = "2.1.3"
@@ -201,24 +201,27 @@ class BaseApi:
201
201
  self, metadata["response_model_str"]
202
202
  )
203
203
 
204
- extra_dependencies = []
205
- if metadata.get("dependencies"):
206
- extra_dependencies = metadata["dependencies"]
207
- if extra_dependencies and not data.get("dependencies"):
208
- data["dependencies"] = []
209
- for dep in extra_dependencies:
204
+ resolved_dependencies = []
205
+ for dep in metadata.get("dependencies") or []:
210
206
  func, kwargs = dep
211
207
  if kwargs:
208
+ # Resolve into a fresh dict; the source kwargs live in
209
+ # the shared registry and must stay un-mutated so other
210
+ # instances of the same Api class can resolve them too.
211
+ resolved_kwargs = {}
212
212
  for key, val in kwargs.items():
213
213
  if val == ":self":
214
- kwargs[key] = self
215
- elif val.startswith(":f"):
214
+ resolved_kwargs[key] = self
215
+ elif isinstance(val, str) and val.startswith(":f"):
216
216
  prop = val.split(".")[1]
217
- kwargs[key] = metadata[prop]
218
- func = Depends(func(**kwargs))
217
+ resolved_kwargs[key] = metadata[prop]
218
+ else:
219
+ resolved_kwargs[key] = val
220
+ resolved_dependencies.append(
221
+ Depends(func(**resolved_kwargs))
222
+ )
219
223
  else:
220
- func = Depends(func)
221
- data["dependencies"].append(func)
224
+ resolved_dependencies.append(Depends(func))
222
225
 
223
226
  path, methods, rest_data = (
224
227
  data["path"],
@@ -226,6 +229,11 @@ class BaseApi:
226
229
  {k: v for k, v in data.items() if k != "methods"},
227
230
  )
228
231
 
232
+ if resolved_dependencies:
233
+ rest_data["dependencies"] = (
234
+ list(data.get("dependencies") or []) + resolved_dependencies
235
+ )
236
+
229
237
  self.messages.append(
230
238
  f"Registering route {self.router.prefix}{path} {methods}"
231
239
  )
@@ -0,0 +1,80 @@
1
+ import inspect
2
+ from functools import wraps
3
+
4
+ import typer
5
+ from fastapi_cli.discover import get_import_data
6
+ from fastapi_cli.exceptions import FastAPICLIException
7
+
8
+ from ..db import db
9
+ from ..globals import g
10
+ from .const import logger
11
+ from .utils import run_in_current_event_loop
12
+
13
+
14
+ def ensure_app_loaded(f):
15
+ """Ensure a FastAPI app is loaded before running `f`.
16
+
17
+ Only commands that read models or config (not the database) need this.
18
+ """
19
+ return _check_existing_app(f)
20
+
21
+
22
+ def ensure_fastapi_rtk_tables_exist(f):
23
+ """Ensure the fastapi-rtk tables exist before running `f`.
24
+
25
+ Implies :func:`ensure_app_loaded`. Use on commands that touch the database.
26
+
27
+ Table-init only runs in CLI mode; an in-process caller (e.g. the lifespan)
28
+ already created the tables on the running loop, and re-running it here on a
29
+ worker-thread loop would crash async drivers (cross-loop connection reuse).
30
+
31
+ For the CLI path, init and body share one loop via
32
+ :func:`run_in_current_event_loop`: an `async def` command (a
33
+ :func:`make_sync` wrapper with `f.__wrapped__`) awaits init, body, and
34
+ `db.close()` in one call; a sync command inits on its own loop then runs.
35
+ """
36
+
37
+ body = getattr(f, "__wrapped__", None)
38
+
39
+ @wraps(f)
40
+ def wrapper(*args, **kwargs):
41
+ if not g.is_cli:
42
+ return f(*args, **kwargs)
43
+
44
+ if body is not None and inspect.iscoroutinefunction(body):
45
+
46
+ async def run():
47
+ await db.init_fastapi_rtk_tables()
48
+ try:
49
+ return await body(*args, **kwargs)
50
+ finally:
51
+ await db.close()
52
+
53
+ return run_in_current_event_loop(run())
54
+
55
+ run_in_current_event_loop(db.init_fastapi_rtk_tables())
56
+ return f(*args, **kwargs)
57
+
58
+ return ensure_app_loaded(wrapper)
59
+
60
+
61
+ def _check_existing_app(f, *, silent=False):
62
+ @wraps(f)
63
+ def wrapper(*args, **kwargs):
64
+ # No app loaded -> CLI invocation: flag cli (before import, so the
65
+ # toolkit skips the lifespan) and import from path. Else reuse it.
66
+ if g.current_app is None:
67
+ g.is_cli = True
68
+ try:
69
+ get_import_data(path=g.path)
70
+ except FastAPICLIException as e:
71
+ if not silent:
72
+ logger.error(str(e))
73
+ raise typer.Exit(code=1) from None
74
+ return f(*args, **kwargs)
75
+
76
+ return wrapper
77
+
78
+
79
+ def check_existing_app_silent(f):
80
+ return _check_existing_app(f, silent=True)
@@ -130,6 +130,7 @@ def make_toolkit_app(tmp_path, config_setter):
130
130
  extra_apis: optional list of API classes to register via add_api.
131
131
  extra_lifespans: optional list of async context managers.
132
132
  config_overrides: optional dict of additional config values.
133
+ upgrade_db: run the alembic upgrade step in the lifespan.
133
134
 
134
135
  Returns:
135
136
  FastAPI app instance with toolkit initialized.
@@ -144,6 +145,7 @@ def make_toolkit_app(tmp_path, config_setter):
144
145
  extra_apis: Iterable[Any] | None = None,
145
146
  extra_lifespans: Iterable[Any] | None = None,
146
147
  config_overrides: dict | None = None,
148
+ upgrade_db: bool = False,
147
149
  ):
148
150
  db_path = tmp_path / "test.db"
149
151
  config_setter("SQLALCHEMY_DATABASE_URI", f"sqlite+aiosqlite:///{db_path}")
@@ -187,6 +189,7 @@ def make_toolkit_app(tmp_path, config_setter):
187
189
 
188
190
  toolkit = FastAPIReactToolkit(
189
191
  create_tables=False,
192
+ upgrade_db=upgrade_db,
190
193
  exclude_apis=["LicenseApi"],
191
194
  lifespans=list(extra_lifespans or []),
192
195
  auth={"secret_key": "tier-integration-secret-32-bytes!!"},
@@ -130,6 +130,29 @@ class TestExposedRoutes:
130
130
  api = TierMsgApi()
131
131
  assert any("Registering route" in m for m in api.messages)
132
132
 
133
+ def test_protect_dependency_resolved_per_instance(self):
134
+ # Regression: resolving @protect's ":self" / ":f" placeholders must not
135
+ # mutate the shared registry metadata. Otherwise a second instance of
136
+ # the same class crashes ("... object has no attribute 'startswith'")
137
+ # and dependencies accumulate across registrations.
138
+ class TierSharedApi(BaseApi):
139
+ base_permissions = [f"{PERMISSION_PREFIX}read"]
140
+
141
+ @expose("/shared", methods=["GET"])
142
+ @protect()
143
+ @permission_name("read")
144
+ async def shared(self):
145
+ return {}
146
+
147
+ for _ in range(2):
148
+ api = TierSharedApi()
149
+ deps = [
150
+ rest_data.get("dependencies")
151
+ for _, rest_data, _, _ in api.routes_to_register
152
+ if rest_data["path"] == "/shared"
153
+ ]
154
+ assert deps and len(deps[0]) == 1
155
+
133
156
 
134
157
  class TestPriorityRoutes:
135
158
  def test_priority_routes_reordered(self):
@@ -219,9 +219,7 @@ class TestAppCheckPartition:
219
219
  neutralize_app_check.get_import_data.assert_called_once()
220
220
  neutralize_app_check.run_in_current_event_loop.assert_called_once()
221
221
 
222
- def test_migrate_checks_once_via_revision(
223
- self, monkeypatch, neutralize_app_check
224
- ):
222
+ def test_migrate_checks_once_via_revision(self, monkeypatch, neutralize_app_check):
225
223
  from fastapi_rtk.cli.commands.db import migrate
226
224
 
227
225
  self._patch_alembic(monkeypatch, "revision")
@@ -29,17 +29,22 @@ class TestAppCheckPartition:
29
29
  neutralize_app_check.get_import_data.assert_called_once()
30
30
  neutralize_app_check.run_in_current_event_loop.assert_not_called()
31
31
 
32
- def test_api_docs_is_import_only(
33
- self, tmp_path, monkeypatch, global_setter, neutralize_app_check
34
- ):
32
+ def test_api_docs_is_import_only(self, tmp_path, monkeypatch, neutralize_app_check):
35
33
  from unittest.mock import MagicMock
36
34
 
37
35
  from fastapi_rtk.cli.commands import export as ex_mod
36
+ from fastapi_rtk.globals import g
38
37
 
39
38
  app_mock = MagicMock()
40
39
  app_mock.apis = []
41
40
  app_mock.app.openapi.return_value = {"paths": {}, "components": {}}
42
- global_setter("current_app", app_mock)
41
+
42
+ # No app loaded yet -> CLI (from-path) branch: importing the app is what
43
+ # populates `g.current_app`, so the mock mirrors that side effect.
44
+ def _load(*args, **kwargs):
45
+ g.current_app = app_mock
46
+
47
+ neutralize_app_check.get_import_data.side_effect = _load
43
48
 
44
49
  ex_mod.api_docs(filename=str(tmp_path / "out.md"))
45
50
  neutralize_app_check.get_import_data.assert_called_once()
@@ -0,0 +1,30 @@
1
+ """Shared fixtures for tier 14 cli/ tests.
2
+
3
+ Commands decorated with `@ensure_app_loaded` / `@ensure_fastapi_rtk_tables_exist`
4
+ discriminate CLI from in-process by `g.current_app`: when it is unset they import
5
+ the app from path and flag `g.is_cli = True`. Both flags leak into later tests,
6
+ so isolate them. `current_app` is cleared *before* each test so the CLI
7
+ (from-path) branch is exercised, and both are restored afterwards.
8
+ """
9
+
10
+ import pytest
11
+
12
+ from fastapi_rtk.globals import g
13
+
14
+ _MISSING = object()
15
+
16
+
17
+ @pytest.fixture(autouse=True)
18
+ def _reset_cli_globals():
19
+ saved_boot = g._bootstrap_values.pop("current_app", _MISSING)
20
+ saved_var = g._vars.pop("current_app", _MISSING)
21
+ yield
22
+ g.is_cli = False
23
+ if saved_boot is _MISSING:
24
+ g._bootstrap_values.pop("current_app", None)
25
+ else:
26
+ g._bootstrap_values["current_app"] = saved_boot
27
+ if saved_var is _MISSING:
28
+ g._vars.pop("current_app", None)
29
+ else:
30
+ g._vars["current_app"] = saved_var
@@ -8,7 +8,6 @@ import typer
8
8
 
9
9
  from fastapi_rtk.cli.decorators import (
10
10
  _check_existing_app,
11
- _set_cli_mode,
12
11
  check_existing_app_silent,
13
12
  ensure_app_loaded,
14
13
  ensure_fastapi_rtk_tables_exist,
@@ -16,29 +15,6 @@ from fastapi_rtk.cli.decorators import (
16
15
  from fastapi_rtk.cli.utils import make_sync
17
16
 
18
17
 
19
- class TestSetCliMode:
20
- def test_sets_cli_flag(self, global_setter):
21
- global_setter("is_cli", False)
22
-
23
- from fastapi_rtk.globals import g
24
-
25
- captured = []
26
-
27
- @_set_cli_mode
28
- def fn():
29
- captured.append(g.is_cli)
30
- return "ok"
31
-
32
- try:
33
- result = fn()
34
- assert result == "ok"
35
- assert captured == [True]
36
- finally:
37
- # Restore the default - the decorator writes to g._vars which
38
- # bypasses the global_setter fixture's restore semantics.
39
- g.is_cli = False
40
-
41
-
42
18
  class TestCheckExistingApp:
43
19
  def test_runs_when_app_exists(self):
44
20
  with patch("fastapi_rtk.cli.decorators.get_import_data"):
@@ -125,6 +101,47 @@ class TestEnsureAppLoaded:
125
101
  g.is_cli = False
126
102
 
127
103
 
104
+ class TestInProcessReusesLoadedApp:
105
+ """When `g.current_app` is set (in-process, e.g. the app lifespan) the
106
+ decorators reuse the loaded app: no import, no CLI flag, no table-init.
107
+ """
108
+
109
+ def test_check_existing_app_skips_import_when_app_loaded(self):
110
+ from fastapi_rtk.globals import g
111
+
112
+ g.current_app = object()
113
+ with patch("fastapi_rtk.cli.decorators.get_import_data") as mock_import:
114
+
115
+ @_check_existing_app
116
+ def fn():
117
+ return "result"
118
+
119
+ assert fn() == "result"
120
+
121
+ mock_import.assert_not_called()
122
+ assert g.is_cli is False
123
+
124
+ def test_tables_exist_skips_init_when_app_loaded(self):
125
+ from fastapi_rtk.globals import g
126
+
127
+ g.current_app = object()
128
+ with (
129
+ patch("fastapi_rtk.cli.decorators.get_import_data") as mock_import,
130
+ patch("fastapi_rtk.cli.decorators.run_in_current_event_loop") as mock_run,
131
+ ):
132
+
133
+ @ensure_fastapi_rtk_tables_exist
134
+ def fn():
135
+ return "done"
136
+
137
+ assert fn() == "done"
138
+
139
+ # In-process: no app import and no table-init (the foreign-loop touch).
140
+ mock_import.assert_not_called()
141
+ mock_run.assert_not_called()
142
+ assert g.is_cli is False
143
+
144
+
128
145
  class TestEnsureFastapiRtkTablesExist:
129
146
  def test_initializes_tables(self):
130
147
  with (
@@ -133,7 +133,9 @@ class TestInitializeWithFeatures:
133
133
  assert "SecWebPatchDocsMiddleware" in names
134
134
  assert "SecWebPatchReDocMiddleware" in names
135
135
 
136
- def test_profiler_enabled_adds_middleware(self, config_setter, tmp_path, monkeypatch):
136
+ def test_profiler_enabled_adds_middleware(
137
+ self, config_setter, tmp_path, monkeypatch
138
+ ):
137
139
  import sys
138
140
  from unittest.mock import MagicMock
139
141
 
@@ -239,16 +241,12 @@ class TestTemplateFolderRoute:
239
241
  # Without index.html we hit the TemplateNotFound -> 404
240
242
  assert r.status_code == 404
241
243
 
242
- def test_template_folder_index_renders_when_present(
243
- self, tmp_path, config_setter
244
- ):
244
+ def test_template_folder_index_renders_when_present(self, tmp_path, config_setter):
245
245
  from starlette.testclient import TestClient
246
246
 
247
247
  tmpl_dir = tmp_path / "tmpl"
248
248
  tmpl_dir.mkdir()
249
- (tmpl_dir / "index.html").write_text(
250
- "<html>{{ app_name }}</html>"
251
- )
249
+ (tmpl_dir / "index.html").write_text("<html>{{ app_name }}</html>")
252
250
  config_setter("TEMPLATE_FOLDER", str(tmpl_dir))
253
251
  config_setter("APP_NAME", "MyApp")
254
252
 
@@ -616,6 +614,33 @@ class TestToolkitLifespanSmoke:
616
614
  assert app is not None
617
615
 
618
616
 
617
+ class TestToolkitLifespanUpgradeDb:
618
+ """Regression: `upgrade_db=True` must not crash on async drivers.
619
+
620
+ The lifespan creates the fastapi-rtk tables on the running loop and then
621
+ runs the alembic upgrade. Routing that upgrade through the CLI
622
+ `ensure_fastapi_rtk_tables_exist` decorator re-touches the shared async
623
+ engine on a fresh event loop in a worker thread, which asyncpg / aiosqlite
624
+ reject with "got Future ... attached to a different loop". The upgrade must
625
+ run without re-entering the async table-init.
626
+ """
627
+
628
+ @pytest.mark.asyncio
629
+ async def test_upgrade_db_lifespan_no_cross_loop(self, make_toolkit_app):
630
+ from unittest.mock import MagicMock
631
+
632
+ from fastapi_rtk.cli.commands import db as db_mod
633
+
634
+ with patch.object(db_mod.alembic.command, "upgrade", MagicMock()) as upgrade:
635
+ app = make_toolkit_app(upgrade_db=True)
636
+ async with app.router.lifespan_context(app):
637
+ pass
638
+
639
+ # Alembic ran (on its own sync engine), and the lifespan completed
640
+ # without the cross-loop RuntimeError.
641
+ upgrade.assert_called_once()
642
+
643
+
619
644
  class TestToolkitDebugLogLevel:
620
645
  """Line 634: DEBUG=True sets logger level to DEBUG."""
621
646
 
@@ -1 +0,0 @@
1
- __version__ = "2.1.1"
@@ -1,87 +0,0 @@
1
- import inspect
2
- from functools import wraps
3
-
4
- import typer
5
- from fastapi_cli.discover import get_import_data
6
- from fastapi_cli.exceptions import FastAPICLIException
7
-
8
- from ..db import db
9
- from ..globals import g
10
- from .const import logger
11
- from .utils import run_in_current_event_loop
12
-
13
-
14
- def ensure_app_loaded(f):
15
- """Load the app for the CLI: set `g.is_cli`, then import the app.
16
-
17
- Importing the app is what registers the models and populates `g.config`,
18
- so any command that reads models or config (but does not touch the
19
- database) only needs this.
20
- """
21
- return _set_cli_mode(_check_existing_app(f))
22
-
23
-
24
- def ensure_fastapi_rtk_tables_exist(f):
25
- """Ensure the fastapi-rtk tables exist before running `f`.
26
-
27
- Creating the tables reads config and reflects the registered models, so it
28
- implies :func:`ensure_app_loaded`. Use this on commands that touch the
29
- database; use :func:`ensure_app_loaded` on the rest.
30
-
31
- The table-creation and the command body must run on the **same** event
32
- loop: the async engine pools a connection bound to whichever loop opened
33
- it, and asyncpg / aiosqlite raise when that connection is reused from a
34
- second loop. `f` is normally a :func:`fastapi_rtk.cli.utils.make_sync`
35
- wrapper whose original coroutine is exposed as ``f.__wrapped__``; when so,
36
- the table init and the body are awaited inside one
37
- :func:`run_in_current_event_loop` call and the engine is disposed before
38
- that loop closes. A plain synchronous `f` cannot share the loop (it has no
39
- coroutine), so the init runs on its own loop and `f` is called directly.
40
- """
41
-
42
- body = getattr(f, "__wrapped__", None)
43
-
44
- @wraps(f)
45
- def wrapper(*args, **kwargs):
46
- if body is not None and inspect.iscoroutinefunction(body):
47
-
48
- async def run():
49
- await db.init_fastapi_rtk_tables()
50
- try:
51
- return await body(*args, **kwargs)
52
- finally:
53
- await db.close()
54
-
55
- return run_in_current_event_loop(run())
56
-
57
- run_in_current_event_loop(db.init_fastapi_rtk_tables())
58
- return f(*args, **kwargs)
59
-
60
- return ensure_app_loaded(wrapper)
61
-
62
-
63
- def _check_existing_app(f, *, silent=False):
64
- @wraps(f)
65
- def wrapper(*args, **kwargs):
66
- try:
67
- get_import_data(path=g.path)
68
- except FastAPICLIException as e:
69
- if not silent:
70
- logger.error(str(e))
71
- raise typer.Exit(code=1) from None
72
- return f(*args, **kwargs)
73
-
74
- return wrapper
75
-
76
-
77
- def check_existing_app_silent(f):
78
- return _check_existing_app(f, silent=True)
79
-
80
-
81
- def _set_cli_mode(f):
82
- @wraps(f)
83
- def wrapper(*args, **kwargs):
84
- g.is_cli = True
85
- return f(*args, **kwargs)
86
-
87
- return wrapper
@@ -1,15 +0,0 @@
1
- """Shared fixtures for tier 14 cli/ tests.
2
-
3
- Commands decorated with `@ensure_app_loaded` / `@ensure_fastapi_rtk_tables_exist`
4
- set `g.is_cli = True`. The flag leaks into later tests, so reset it after each.
5
- """
6
-
7
- import pytest
8
-
9
- from fastapi_rtk.globals import g
10
-
11
-
12
- @pytest.fixture(autouse=True)
13
- def _reset_is_cli():
14
- yield
15
- g.is_cli = False
File without changes
File without changes
File without changes