FastAPI-fastkit 1.2.1__py3-none-any.whl → 1.4.0__py3-none-any.whl

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 (356) hide show
  1. fastapi_fastkit/__init__.py +1 -1
  2. fastapi_fastkit/backend/inspection/__init__.py +26 -0
  3. fastapi_fastkit/backend/inspection/checks.py +349 -0
  4. fastapi_fastkit/backend/inspection/consistency.py +125 -0
  5. fastapi_fastkit/backend/inspection/context.py +67 -0
  6. fastapi_fastkit/backend/inspection/core.py +347 -0
  7. fastapi_fastkit/backend/inspection/docker.py +185 -0
  8. fastapi_fastkit/backend/inspection/freshness.py +145 -0
  9. fastapi_fastkit/backend/inspection/fsutils.py +139 -0
  10. fastapi_fastkit/backend/inspection/lint.py +89 -0
  11. fastapi_fastkit/backend/inspection/report.py +58 -0
  12. fastapi_fastkit/backend/inspection/smoke.py +327 -0
  13. fastapi_fastkit/backend/inspection/strategies.py +336 -0
  14. fastapi_fastkit/backend/inspector.py +18 -1279
  15. fastapi_fastkit/backend/interactive/__init__.py +8 -0
  16. fastapi_fastkit/backend/interactive/config_builder.py +66 -65
  17. fastapi_fastkit/backend/interactive/prompts.py +205 -5
  18. fastapi_fastkit/backend/interactive/selectors.py +28 -2
  19. fastapi_fastkit/backend/main.py +956 -95
  20. fastapi_fastkit/backend/package_managers/base.py +172 -0
  21. fastapi_fastkit/backend/package_managers/factory.py +6 -5
  22. fastapi_fastkit/backend/package_managers/pdm_manager.py +32 -85
  23. fastapi_fastkit/backend/package_managers/pip_manager.py +31 -85
  24. fastapi_fastkit/backend/package_managers/poetry_manager.py +73 -113
  25. fastapi_fastkit/backend/package_managers/uv_manager.py +46 -115
  26. fastapi_fastkit/backend/project_builder/__init__.py +10 -0
  27. fastapi_fastkit/backend/project_builder/config_generator.py +813 -450
  28. fastapi_fastkit/backend/project_builder/config_schema.py +384 -0
  29. fastapi_fastkit/backend/project_builder/dependency_collector.py +105 -66
  30. fastapi_fastkit/backend/project_builder/preset_layout.py +429 -0
  31. fastapi_fastkit/backend/scaffolder.py +578 -0
  32. fastapi_fastkit/backend/transducer.py +54 -22
  33. fastapi_fastkit/cli.py +452 -284
  34. fastapi_fastkit/core/settings.py +248 -43
  35. fastapi_fastkit/fastapi_project_template/README.md +88 -23
  36. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/README.md-tpl +3 -0
  37. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/pyproject.toml-tpl +25 -23
  38. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/requirements.txt-tpl +39 -36
  39. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/api/api.py-tpl +3 -0
  40. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/api/routes/items.py-tpl +1 -2
  41. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/core/config.py-tpl +5 -6
  42. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/crud/items.py-tpl +1 -2
  43. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/main.py-tpl +9 -1
  44. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/schemas/items.py-tpl +1 -2
  45. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/tests/conftest.py-tpl +0 -1
  46. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/.env-tpl +21 -0
  47. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/.gitignore-tpl +33 -0
  48. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/Dockerfile-tpl +18 -0
  49. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/README.md-tpl +210 -0
  50. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/alembic.ini-tpl +119 -0
  51. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/pyproject.toml-tpl +86 -0
  52. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/requirements.txt-tpl +23 -0
  53. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/scripts/format.sh-tpl +5 -0
  54. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/scripts/lint.sh-tpl +6 -0
  55. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/scripts/run-server.sh-tpl +8 -0
  56. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/scripts/test.sh-tpl +6 -0
  57. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/__init__.py-tpl +0 -0
  58. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/__init__.py-tpl +0 -0
  59. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/alembic/README-tpl +1 -0
  60. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/alembic/env.py-tpl +51 -0
  61. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/alembic/script.py.mako-tpl +26 -0
  62. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/alembic/versions/0001_initial_auth_schema.py-tpl +62 -0
  63. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/api/__init__.py-tpl +0 -0
  64. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/api/deps.py-tpl +91 -0
  65. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/api/health.py-tpl +11 -0
  66. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/api/router.py-tpl +17 -0
  67. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/core/__init__.py-tpl +0 -0
  68. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/core/config.py-tpl +64 -0
  69. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/core/security.py-tpl +100 -0
  70. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/db/__init__.py-tpl +0 -0
  71. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/db/session.py-tpl +36 -0
  72. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/domains/__init__.py-tpl +0 -0
  73. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/domains/auth/__init__.py-tpl +0 -0
  74. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/domains/auth/models.py-tpl +25 -0
  75. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/domains/auth/repository.py-tpl +41 -0
  76. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/domains/auth/router.py-tpl +82 -0
  77. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/domains/auth/schemas.py-tpl +14 -0
  78. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/domains/auth/service.py-tpl +65 -0
  79. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/domains/users/__init__.py-tpl +0 -0
  80. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/domains/users/models.py-tpl +35 -0
  81. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/domains/users/repository.py-tpl +33 -0
  82. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/domains/users/router.py-tpl +71 -0
  83. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/domains/users/schemas.py-tpl +29 -0
  84. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/domains/users/service.py-tpl +55 -0
  85. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/main.py-tpl +69 -0
  86. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/template-config.yml-tpl +16 -0
  87. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/tests/__init__.py-tpl +0 -0
  88. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/tests/conftest.py-tpl +73 -0
  89. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/tests/test_auth.py-tpl +201 -0
  90. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/tests/test_health.py-tpl +15 -0
  91. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/tests/test_users.py-tpl +77 -0
  92. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/pyproject.toml-tpl +25 -23
  93. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/requirements.txt-tpl +39 -36
  94. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/api/api.py-tpl +3 -0
  95. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/api/routes/items.py-tpl +3 -3
  96. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/core/config.py-tpl +5 -6
  97. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/crud/items.py-tpl +1 -2
  98. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/helper/pagination.py-tpl +8 -8
  99. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/main.py-tpl +9 -0
  100. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/schemas/base.py-tpl +1 -1
  101. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/schemas/items.py-tpl +1 -2
  102. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/tests/conftest.py-tpl +0 -1
  103. fastapi_fastkit/fastapi_project_template/fastapi-default/pyproject.toml-tpl +22 -20
  104. fastapi_fastkit/fastapi_project_template/fastapi-default/requirements.txt-tpl +37 -34
  105. fastapi_fastkit/fastapi_project_template/fastapi-default/src/api/api.py-tpl +3 -0
  106. fastapi_fastkit/fastapi_project_template/fastapi-default/src/api/routes/items.py-tpl +1 -2
  107. fastapi_fastkit/fastapi_project_template/fastapi-default/src/core/config.py-tpl +5 -6
  108. fastapi_fastkit/fastapi_project_template/fastapi-default/src/crud/items.py-tpl +1 -2
  109. fastapi_fastkit/fastapi_project_template/fastapi-default/src/main.py-tpl +9 -1
  110. fastapi_fastkit/fastapi_project_template/fastapi-default/src/schemas/items.py-tpl +1 -2
  111. fastapi_fastkit/fastapi_project_template/fastapi-default/tests/conftest.py-tpl +2 -3
  112. fastapi_fastkit/fastapi_project_template/fastapi-default/tests/test_items.py-tpl +0 -2
  113. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/Dockerfile-tpl +1 -1
  114. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/README.md-tpl +3 -0
  115. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/pyproject.toml-tpl +25 -23
  116. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/requirements.txt-tpl +41 -36
  117. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/api/api.py-tpl +3 -0
  118. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/api/routes/items.py-tpl +1 -2
  119. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/core/config.py-tpl +5 -6
  120. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/crud/items.py-tpl +1 -2
  121. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/main.py-tpl +9 -1
  122. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/schemas/items.py-tpl +1 -2
  123. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/tests/conftest.py-tpl +2 -3
  124. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/tests/test_items.py-tpl +0 -2
  125. fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/.env-tpl +2 -0
  126. fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/.gitignore-tpl +31 -0
  127. fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/README.md-tpl +128 -0
  128. fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/pyproject.toml-tpl +69 -0
  129. fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/requirements.txt-tpl +37 -0
  130. fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/scripts/format.sh-tpl +5 -0
  131. fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/scripts/lint.sh-tpl +6 -0
  132. fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/scripts/run-server.sh-tpl +8 -0
  133. fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/scripts/test.sh-tpl +6 -0
  134. fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/src/__init__.py-tpl +0 -0
  135. fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/src/app/__init__.py-tpl +0 -0
  136. fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/src/app/api/__init__.py-tpl +0 -0
  137. fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/src/app/api/health.py-tpl +11 -0
  138. fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/src/app/api/router.py-tpl +15 -0
  139. fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/src/app/core/__init__.py-tpl +0 -0
  140. fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/src/app/core/config.py-tpl +49 -0
  141. fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/src/app/db/__init__.py-tpl +0 -0
  142. fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/src/app/db/memory.py-tpl +49 -0
  143. fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/src/app/domains/__init__.py-tpl +0 -0
  144. fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/src/app/domains/items/__init__.py-tpl +9 -0
  145. fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/src/app/domains/items/models.py-tpl +17 -0
  146. fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/src/app/domains/items/repository.py-tpl +47 -0
  147. fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/src/app/domains/items/router.py-tpl +58 -0
  148. fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/src/app/domains/items/schemas.py-tpl +23 -0
  149. fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/src/app/domains/items/service.py-tpl +51 -0
  150. fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/src/app/main.py-tpl +28 -0
  151. fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/tests/__init__.py-tpl +0 -0
  152. fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/tests/conftest.py-tpl +23 -0
  153. fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/tests/test_health.py-tpl +11 -0
  154. fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/tests/test_items.py-tpl +77 -0
  155. fastapi_fastkit/fastapi_project_template/fastapi-empty/README.md-tpl +2 -2
  156. fastapi_fastkit/fastapi_project_template/fastapi-empty/pyproject.toml-tpl +18 -16
  157. fastapi_fastkit/fastapi_project_template/fastapi-empty/requirements.txt-tpl +36 -10
  158. fastapi_fastkit/fastapi_project_template/fastapi-empty/src/core/config.py-tpl +5 -6
  159. fastapi_fastkit/fastapi_project_template/fastapi-empty/src/main.py-tpl +3 -1
  160. fastapi_fastkit/fastapi_project_template/fastapi-empty/tests/conftest.py-tpl +0 -1
  161. fastapi_fastkit/fastapi_project_template/fastapi-empty/tests/test_main.py-tpl +0 -1
  162. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/.env-tpl +15 -0
  163. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/.gitignore-tpl +31 -0
  164. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/Dockerfile-tpl +18 -0
  165. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/README.md-tpl +193 -0
  166. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/pyproject.toml-tpl +76 -0
  167. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/requirements.txt-tpl +15 -0
  168. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/scripts/chat.sh-tpl +10 -0
  169. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/scripts/format.sh-tpl +5 -0
  170. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/scripts/lint.sh-tpl +6 -0
  171. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/scripts/run-server.sh-tpl +8 -0
  172. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/scripts/test.sh-tpl +6 -0
  173. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/__init__.py-tpl +0 -0
  174. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/__init__.py-tpl +0 -0
  175. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/api/__init__.py-tpl +0 -0
  176. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/api/chat.py-tpl +62 -0
  177. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/api/deps.py-tpl +23 -0
  178. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/api/health.py-tpl +11 -0
  179. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/api/router.py-tpl +13 -0
  180. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/core/__init__.py-tpl +0 -0
  181. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/core/config.py-tpl +67 -0
  182. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/llm/__init__.py-tpl +0 -0
  183. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/llm/agent.py-tpl +136 -0
  184. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/llm/client.py-tpl +30 -0
  185. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/llm/tools.py-tpl +131 -0
  186. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/main.py-tpl +53 -0
  187. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/memory/__init__.py-tpl +0 -0
  188. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/memory/base.py-tpl +27 -0
  189. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/memory/in_memory.py-tpl +32 -0
  190. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/schemas/__init__.py-tpl +0 -0
  191. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/schemas/chat.py-tpl +46 -0
  192. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/template-config.yml-tpl +16 -0
  193. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/tests/__init__.py-tpl +0 -0
  194. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/tests/conftest.py-tpl +158 -0
  195. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/tests/test_chat.py-tpl +160 -0
  196. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/tests/test_health.py-tpl +12 -0
  197. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/tests/test_memory.py-tpl +38 -0
  198. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/tests/test_tools.py-tpl +37 -0
  199. fastapi_fastkit/fastapi_project_template/fastapi-mcp/README.md-tpl +1 -1
  200. fastapi_fastkit/fastapi_project_template/fastapi-mcp/pyproject.toml-tpl +29 -26
  201. fastapi_fastkit/fastapi_project_template/fastapi-mcp/requirements.txt-tpl +68 -39
  202. fastapi_fastkit/fastapi_project_template/fastapi-mcp/src/api/api.py-tpl +3 -0
  203. fastapi_fastkit/fastapi_project_template/fastapi-mcp/src/api/routes/auth.py-tpl +4 -5
  204. fastapi_fastkit/fastapi_project_template/fastapi-mcp/src/api/routes/items.py-tpl +3 -4
  205. fastapi_fastkit/fastapi_project_template/fastapi-mcp/src/auth/dependencies.py-tpl +4 -5
  206. fastapi_fastkit/fastapi_project_template/fastapi-mcp/src/core/config.py-tpl +4 -5
  207. fastapi_fastkit/fastapi_project_template/fastapi-mcp/src/main.py-tpl +4 -1
  208. fastapi_fastkit/fastapi_project_template/fastapi-mcp/src/{mcp → mcp_server}/router.py-tpl +3 -5
  209. fastapi_fastkit/fastapi_project_template/fastapi-mcp/src/schemas/items.py-tpl +6 -7
  210. fastapi_fastkit/fastapi_project_template/fastapi-mcp/tests/conftest.py-tpl +1 -1
  211. fastapi_fastkit/fastapi_project_template/fastapi-mcp/tests/test_auth.py-tpl +0 -1
  212. fastapi_fastkit/fastapi_project_template/fastapi-mcp/tests/test_items.py-tpl +0 -1
  213. fastapi_fastkit/fastapi_project_template/fastapi-mcp/tests/test_mcp.py-tpl +0 -1
  214. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/Dockerfile-tpl +1 -1
  215. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/pyproject.toml-tpl +26 -24
  216. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/requirements.txt-tpl +44 -41
  217. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/alembic/env.py-tpl +1 -3
  218. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/alembic/versions/bedcdc35b64a_first_alembic.py-tpl +5 -6
  219. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/api/api.py-tpl +2 -0
  220. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/api/routes/items.py-tpl +2 -4
  221. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/core/config.py-tpl +1 -2
  222. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/core/db.py-tpl +1 -1
  223. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/crud/items.py-tpl +4 -6
  224. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/main.py-tpl +9 -0
  225. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/schemas/items.py-tpl +4 -5
  226. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/tests/conftest.py-tpl +1 -5
  227. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/tests/test_items.py-tpl +0 -2
  228. fastapi_fastkit/fastapi_project_template/fastapi-single-module/.env-tpl +1 -0
  229. fastapi_fastkit/fastapi_project_template/fastapi-single-module/.gitignore-tpl +30 -0
  230. fastapi_fastkit/fastapi_project_template/fastapi-single-module/pyproject.toml-tpl +7 -5
  231. fastapi_fastkit/fastapi_project_template/fastapi-single-module/requirements.txt-tpl +26 -6
  232. fastapi_fastkit/fastapi_project_template/fastapi-single-module/src/main.py-tpl +3 -0
  233. fastapi_fastkit/fastapi_project_template/fastapi-single-module/tests/__init__.py-tpl +0 -0
  234. fastapi_fastkit/fastapi_project_template/fastapi-single-module/tests/conftest.py-tpl +0 -1
  235. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/.env-tpl +7 -0
  236. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/.gitignore-tpl +35 -0
  237. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/Dockerfile-tpl +18 -0
  238. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/README.md-tpl +166 -0
  239. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/alembic.ini-tpl +44 -0
  240. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/pyproject.toml-tpl +82 -0
  241. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/requirements.txt-tpl +21 -0
  242. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/scripts/format.sh-tpl +5 -0
  243. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/scripts/lint.sh-tpl +6 -0
  244. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/scripts/migrate.sh-tpl +7 -0
  245. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/scripts/run-server.sh-tpl +8 -0
  246. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/scripts/test.sh-tpl +6 -0
  247. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/__init__.py-tpl +0 -0
  248. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/__init__.py-tpl +0 -0
  249. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/alembic/README-tpl +9 -0
  250. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/alembic/env.py-tpl +72 -0
  251. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/alembic/script.py.mako-tpl +27 -0
  252. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/alembic/versions/0001_create_items_table.py-tpl +38 -0
  253. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/api/__init__.py-tpl +0 -0
  254. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/api/health.py-tpl +11 -0
  255. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/api/router.py-tpl +15 -0
  256. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/core/__init__.py-tpl +0 -0
  257. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/core/config.py-tpl +62 -0
  258. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/crud/__init__.py-tpl +0 -0
  259. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/crud/base.py-tpl +62 -0
  260. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/crud/pagination.py-tpl +21 -0
  261. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/db/__init__.py-tpl +0 -0
  262. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/db/base.py-tpl +12 -0
  263. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/db/session.py-tpl +50 -0
  264. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/domains/__init__.py-tpl +0 -0
  265. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/domains/items/__init__.py-tpl +0 -0
  266. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/domains/items/crud.py-tpl +26 -0
  267. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/domains/items/models.py-tpl +70 -0
  268. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/domains/items/router.py-tpl +69 -0
  269. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/main.py-tpl +43 -0
  270. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/template-config.yml-tpl +16 -0
  271. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/tests/__init__.py-tpl +0 -0
  272. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/tests/conftest.py-tpl +60 -0
  273. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/tests/test_crud_base.py-tpl +43 -0
  274. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/tests/test_health.py-tpl +12 -0
  275. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/tests/test_items.py-tpl +110 -0
  276. fastapi_fastkit/fastapi_project_template/modules/api/routes/new_route.py-tpl +2 -2
  277. fastapi_fastkit/fragments/README.md +90 -0
  278. fastapi_fastkit/fragments/auth/fastapi_users.py.j2 +8 -0
  279. fastapi_fastkit/fragments/auth/jwt.py.j2 +44 -0
  280. fastapi_fastkit/fragments/auth/oauth2.py.j2 +105 -0
  281. fastapi_fastkit/fragments/auth/session.py.j2 +67 -0
  282. fastapi_fastkit/fragments/db/mongodb.py.j2 +19 -0
  283. fastapi_fastkit/fragments/db/redis.py.j2 +26 -0
  284. fastapi_fastkit/fragments/db/sqlalchemy.py.j2 +45 -0
  285. fastapi_fastkit/fragments/docker/docker_compose.j2 +84 -0
  286. fastapi_fastkit/fragments/docker/dockerfile.j2 +19 -0
  287. fastapi_fastkit/fragments/features/cache.py.j2 +26 -0
  288. fastapi_fastkit/fragments/features/pagination.py.j2 +31 -0
  289. fastapi_fastkit/fragments/features/tasks_celery.py.j2 +50 -0
  290. fastapi_fastkit/fragments/features/tasks_dramatiq.py.j2 +59 -0
  291. fastapi_fastkit/fragments/features/websocket.py.j2 +66 -0
  292. fastapi_fastkit/fragments/header.j2 +4 -0
  293. fastapi_fastkit/fragments/logging/structured.py.j2 +88 -0
  294. fastapi_fastkit/fragments/main/imports/async_tasks.j2 +1 -0
  295. fastapi_fastkit/fragments/main/imports/caching.j2 +5 -0
  296. fastapi_fastkit/fragments/main/imports/fastapi_users.j2 +1 -0
  297. fastapi_fastkit/fragments/main/imports/jwt.j2 +1 -0
  298. fastapi_fastkit/fragments/main/imports/loguru.j2 +1 -0
  299. fastapi_fastkit/fragments/main/imports/mongodb.j2 +1 -0
  300. fastapi_fastkit/fragments/main/imports/oauth2.j2 +4 -0
  301. fastapi_fastkit/fragments/main/imports/opentelemetry.j2 +6 -0
  302. fastapi_fastkit/fragments/main/imports/pagination.j2 +3 -0
  303. fastapi_fastkit/fragments/main/imports/prometheus.j2 +1 -0
  304. fastapi_fastkit/fragments/main/imports/rate_limiting.j2 +3 -0
  305. fastapi_fastkit/fragments/main/imports/session_auth.j2 +4 -0
  306. fastapi_fastkit/fragments/main/imports/sqlalchemy.j2 +2 -0
  307. fastapi_fastkit/fragments/main/imports/structured_logging.j2 +1 -0
  308. fastapi_fastkit/fragments/main/imports/websocket.j2 +1 -0
  309. fastapi_fastkit/fragments/main/lifespan/caching.j2 +7 -0
  310. fastapi_fastkit/fragments/main/lifespan/mongodb.j2 +2 -0
  311. fastapi_fastkit/fragments/main/lifespan/prometheus.j2 +2 -0
  312. fastapi_fastkit/fragments/main/lifespan/sqlalchemy.j2 +2 -0
  313. fastapi_fastkit/fragments/main/setup/async_tasks.j2 +1 -0
  314. fastapi_fastkit/fragments/main/setup/caching.j2 +1 -0
  315. fastapi_fastkit/fragments/main/setup/cors.j2 +8 -0
  316. fastapi_fastkit/fragments/main/setup/oauth2.j2 +3 -0
  317. fastapi_fastkit/fragments/main/setup/opentelemetry.j2 +19 -0
  318. fastapi_fastkit/fragments/main/setup/pagination.j2 +2 -0
  319. fastapi_fastkit/fragments/main/setup/rate_limiting.j2 +3 -0
  320. fastapi_fastkit/fragments/main/setup/session_auth.j2 +6 -0
  321. fastapi_fastkit/fragments/main/setup/structured_logging.j2 +2 -0
  322. fastapi_fastkit/fragments/main/setup/websocket.j2 +1 -0
  323. fastapi_fastkit/fragments/main.py.j2 +57 -0
  324. fastapi_fastkit/fragments/migrations/alembic_ini.j2 +42 -0
  325. fastapi_fastkit/fragments/migrations/env.py.j2 +76 -0
  326. fastapi_fastkit/fragments/migrations/initial_revision.py.j2 +27 -0
  327. fastapi_fastkit/fragments/migrations/migrate_sh.j2 +34 -0
  328. fastapi_fastkit/fragments/migrations/script.py.mako.j2 +26 -0
  329. fastapi_fastkit/fragments/tasks/celery_worker.py.j2 +49 -0
  330. fastapi_fastkit/fragments/tasks/dramatiq_worker.py.j2 +41 -0
  331. fastapi_fastkit/fragments/test/factories.py.j2 +68 -0
  332. fastapi_fastkit/fragments/test/pytest_ini.j2 +16 -0
  333. fastapi_fastkit/fragments/test/test_factories.py.j2 +27 -0
  334. fastapi_fastkit/fragments/test/test_main.py.j2 +46 -0
  335. fastapi_fastkit/fragments/tooling/devcontainer.j2 +26 -0
  336. fastapi_fastkit/fragments/tooling/github_actions.j2 +37 -0
  337. fastapi_fastkit/fragments/tooling/makefile.j2 +40 -0
  338. fastapi_fastkit/fragments/tooling/pre_commit.j2 +36 -0
  339. fastapi_fastkit/fragments/tooling/ruff_toml.j2 +16 -0
  340. fastapi_fastkit/utils/config_file.py +263 -0
  341. fastapi_fastkit/utils/main.py +111 -6
  342. {fastapi_fastkit-1.2.1.dist-info → fastapi_fastkit-1.4.0.dist-info}/METADATA +33 -6
  343. fastapi_fastkit-1.4.0.dist-info/RECORD +484 -0
  344. {fastapi_fastkit-1.2.1.dist-info → fastapi_fastkit-1.4.0.dist-info}/WHEEL +1 -1
  345. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/setup.py-tpl +0 -25
  346. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/setup.py-tpl +0 -27
  347. fastapi_fastkit/fastapi_project_template/fastapi-default/setup.py-tpl +0 -22
  348. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/setup.py-tpl +0 -22
  349. fastapi_fastkit/fastapi_project_template/fastapi-empty/setup.py-tpl +0 -22
  350. fastapi_fastkit/fastapi_project_template/fastapi-mcp/setup.py-tpl +0 -51
  351. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/setup.py-tpl +0 -25
  352. fastapi_fastkit/fastapi_project_template/fastapi-single-module/setup.py-tpl +0 -17
  353. fastapi_fastkit-1.2.1.dist-info/RECORD +0 -256
  354. /fastapi_fastkit/fastapi_project_template/fastapi-mcp/src/{mcp → mcp_server}/__init__.py-tpl +0 -0
  355. {fastapi_fastkit-1.2.1.dist-info → fastapi_fastkit-1.4.0.dist-info}/entry_points.txt +0 -0
  356. {fastapi_fastkit-1.2.1.dist-info → fastapi_fastkit-1.4.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,263 @@
1
+ # --------------------------------------------------------------------------
2
+ # Project configuration file (de)serialization for non-interactive ``init``.
3
+ #
4
+ # ``fastkit init --interactive`` builds a plain configuration dict; this
5
+ # module lets that same dict travel through a file so a project can be
6
+ # reproduced without answering a single prompt (``--config``), and so an
7
+ # interactive session can be captured for later reuse (``--save-config``).
8
+ #
9
+ # Supported formats are picked from the file extension: JSON and TOML are
10
+ # always available (both ship with the stdlib on Python 3.12), YAML only
11
+ # when PyYAML happens to be installed — fastkit deliberately does not add it
12
+ # as a runtime dependency.
13
+ #
14
+ # @author bnbong bbbong9@gmail.com
15
+ # --------------------------------------------------------------------------
16
+ import importlib
17
+ import json
18
+ import os
19
+ import tomllib
20
+ from typing import Any, Dict, List, Tuple
21
+
22
+ from fastapi_fastkit.backend.interactive.validators import (
23
+ validate_email_format,
24
+ validate_project_name,
25
+ )
26
+ from fastapi_fastkit.backend.project_builder.config_schema import (
27
+ ConfigSchemaError,
28
+ normalize_project_config,
29
+ validate_project_config_schema,
30
+ )
31
+
32
+ JSON_EXTENSIONS: Tuple[str, ...] = (".json",)
33
+ TOML_EXTENSIONS: Tuple[str, ...] = (".toml",)
34
+ YAML_EXTENSIONS: Tuple[str, ...] = (".yaml", ".yml")
35
+
36
+ SUPPORTED_EXTENSIONS: Tuple[str, ...] = (
37
+ JSON_EXTENSIONS + TOML_EXTENSIONS + YAML_EXTENSIONS
38
+ )
39
+
40
+ # Keys the scaffolder needs; everything else in the file is passed through
41
+ # untouched so feature blocks stay forward-compatible.
42
+ REQUIRED_KEYS: Tuple[str, ...] = ("project_name", "author", "author_email")
43
+
44
+
45
+ class ConfigFileError(Exception):
46
+ """Raised when a project config file cannot be read, parsed or trusted."""
47
+
48
+
49
+ def _yaml_module() -> Any:
50
+ """Return the optional PyYAML module, or None when it isn't installed."""
51
+ try:
52
+ # Imported dynamically: PyYAML is optional, so a static import would
53
+ # make it look like a hard dependency to type checkers and readers.
54
+ return importlib.import_module("yaml")
55
+ except ImportError:
56
+ return None
57
+
58
+
59
+ def load_project_config(path: str) -> Dict[str, Any]:
60
+ """
61
+ Load a project configuration dict from a JSON / TOML / YAML file.
62
+
63
+ :param path: Path to the configuration file
64
+ :return: Configuration dictionary equivalent to the interactive builder's
65
+ :raises ConfigFileError: If the file is missing, of an unsupported format,
66
+ unparsable, or does not describe a mapping.
67
+ """
68
+ if not os.path.exists(path):
69
+ raise ConfigFileError(f"Config file not found: {path}")
70
+
71
+ extension = os.path.splitext(path)[1].lower()
72
+
73
+ if extension in JSON_EXTENSIONS:
74
+ raw = _load_json(path)
75
+ elif extension in TOML_EXTENSIONS:
76
+ raw = _load_toml(path)
77
+ elif extension in YAML_EXTENSIONS:
78
+ raw = _load_yaml(path)
79
+ else:
80
+ raise ConfigFileError(
81
+ f"Unsupported config file extension '{extension or path}'. "
82
+ f"Supported extensions: {', '.join(SUPPORTED_EXTENSIONS)}"
83
+ )
84
+
85
+ if not isinstance(raw, dict):
86
+ raise ConfigFileError(
87
+ f"Config file '{path}' must contain a mapping at its top level."
88
+ )
89
+
90
+ return raw
91
+
92
+
93
+ def _load_json(path: str) -> Any:
94
+ try:
95
+ with open(path, "r", encoding="utf-8") as f:
96
+ return json.load(f)
97
+ except (OSError, UnicodeDecodeError, json.JSONDecodeError) as e:
98
+ raise ConfigFileError(f"Could not parse JSON config '{path}': {e}")
99
+
100
+
101
+ def _load_toml(path: str) -> Any:
102
+ try:
103
+ with open(path, "rb") as f:
104
+ return tomllib.load(f)
105
+ except (OSError, tomllib.TOMLDecodeError) as e:
106
+ raise ConfigFileError(f"Could not parse TOML config '{path}': {e}")
107
+
108
+
109
+ def _load_yaml(path: str) -> Any:
110
+ yaml = _yaml_module()
111
+ if yaml is None:
112
+ raise ConfigFileError(
113
+ "YAML config files need PyYAML, which is not installed. "
114
+ "Install it (pip install pyyaml) or use a .json / .toml config file instead."
115
+ )
116
+ try:
117
+ with open(path, "r", encoding="utf-8") as f:
118
+ return yaml.safe_load(f)
119
+ except Exception as e:
120
+ # PyYAML raises its own YAMLError hierarchy; catching broadly keeps
121
+ # this import-optional module free of a yaml type import.
122
+ raise ConfigFileError(f"Could not parse YAML config '{path}': {e}")
123
+
124
+
125
+ def validate_project_config(config: Dict[str, Any]) -> List[str]:
126
+ """
127
+ Validate a loaded configuration against the interactive-mode rules.
128
+
129
+ Reuses ``interactive.validators`` so a file-driven run is held to exactly
130
+ the same standard as an answered prompt.
131
+
132
+ :param config: Configuration dictionary
133
+ :return: List of human-readable error messages (empty when the config is valid)
134
+ """
135
+ errors: List[str] = []
136
+
137
+ for key in REQUIRED_KEYS:
138
+ if not config.get(key):
139
+ errors.append(f"Missing required config key: '{key}'")
140
+
141
+ project_name = config.get("project_name")
142
+ if isinstance(project_name, str) and project_name:
143
+ is_valid, message = validate_project_name(project_name)
144
+ if not is_valid and message:
145
+ errors.append(message)
146
+
147
+ author_email = config.get("author_email")
148
+ if isinstance(author_email, str) and author_email:
149
+ if not validate_email_format(author_email):
150
+ errors.append(f"Invalid author email format: '{author_email}'")
151
+
152
+ # Feature selections are held to the catalog: an axis spelled in a shape
153
+ # the pipeline cannot read used to reach generation and produce a project
154
+ # whose ``main.py`` imported modules nobody wrote.
155
+ errors.extend(validate_project_config_schema(config))
156
+
157
+ return errors
158
+
159
+
160
+ def load_normalized_project_config(path: str) -> Dict[str, Any]:
161
+ """
162
+ Load a config file and return it in the canonical pipeline shape.
163
+
164
+ ``load_project_config`` deliberately hands back exactly what the file
165
+ said (so ``--save-config`` round-trips byte for byte); this wrapper is
166
+ what the generation pipeline consumes, because every consumer of a
167
+ configuration must see the same normalised selections.
168
+
169
+ :param path: Path to the configuration file
170
+ :return: Normalised configuration dictionary
171
+ :raises ConfigFileError: If the file cannot be read, parsed or trusted
172
+ """
173
+ raw = load_project_config(path)
174
+ try:
175
+ return normalize_project_config(raw)
176
+ except ConfigSchemaError as e:
177
+ raise ConfigFileError(f"Invalid project config '{path}': {e}")
178
+
179
+
180
+ def save_project_config(config: Dict[str, Any], path: str) -> None:
181
+ """
182
+ Write a configuration dict to a JSON / TOML / YAML file.
183
+
184
+ :param config: Configuration dictionary produced by the interactive builder
185
+ :param path: Destination path; the extension selects the format
186
+ :raises ConfigFileError: If the format is unsupported or the write fails
187
+ """
188
+ extension = os.path.splitext(path)[1].lower()
189
+
190
+ if extension in JSON_EXTENSIONS:
191
+ content = (
192
+ json.dumps(config, indent=2, sort_keys=True, ensure_ascii=False) + "\n"
193
+ )
194
+ elif extension in TOML_EXTENSIONS:
195
+ content = _dump_toml(config)
196
+ elif extension in YAML_EXTENSIONS:
197
+ yaml = _yaml_module()
198
+ if yaml is None:
199
+ raise ConfigFileError(
200
+ "Saving YAML config files needs PyYAML, which is not installed. "
201
+ "Use a .json / .toml path instead."
202
+ )
203
+ content = str(yaml.safe_dump(config, sort_keys=True, allow_unicode=True))
204
+ else:
205
+ raise ConfigFileError(
206
+ f"Unsupported config file extension '{extension or path}'. "
207
+ f"Supported extensions: {', '.join(SUPPORTED_EXTENSIONS)}"
208
+ )
209
+
210
+ try:
211
+ parent = os.path.dirname(os.path.abspath(path))
212
+ os.makedirs(parent, exist_ok=True)
213
+ with open(path, "w", encoding="utf-8") as f:
214
+ f.write(content)
215
+ except OSError as e:
216
+ raise ConfigFileError(f"Could not write config file '{path}': {e}")
217
+
218
+
219
+ def _dump_toml(config: Dict[str, Any]) -> str:
220
+ """
221
+ Serialize a configuration dict to TOML.
222
+
223
+ Python 3.12 ships a TOML reader but no writer, and fastkit may not add a
224
+ runtime dependency for one. The interactive config only ever holds
225
+ strings, booleans, numbers, string lists and one level of nested tables
226
+ (``database``), which this covers.
227
+ """
228
+ scalars: List[str] = []
229
+ tables: List[str] = []
230
+
231
+ for key in sorted(config):
232
+ value = config[key]
233
+ if isinstance(value, dict):
234
+ table_lines = [f"[{key}]"]
235
+ for sub_key in sorted(value):
236
+ table_lines.append(f"{sub_key} = {format_toml_value(value[sub_key])}")
237
+ tables.append("\n".join(table_lines))
238
+ else:
239
+ scalars.append(f"{key} = {format_toml_value(value)}")
240
+
241
+ sections = ["\n".join(scalars)] if scalars else []
242
+ sections.extend(tables)
243
+ return "\n\n".join(section for section in sections if section) + "\n"
244
+
245
+
246
+ def format_toml_value(value: Any) -> str:
247
+ """
248
+ Render a Python value as a TOML literal.
249
+
250
+ Shared with pyproject metadata injection so both writers escape and
251
+ quote values identically.
252
+
253
+ :param value: Value to render (bool / int / float / list / str)
254
+ :return: TOML literal string
255
+ """
256
+ if isinstance(value, bool):
257
+ return "true" if value else "false"
258
+ if isinstance(value, (int, float)):
259
+ return str(value)
260
+ if isinstance(value, (list, tuple)):
261
+ return "[" + ", ".join(format_toml_value(item) for item in value) + "]"
262
+ escaped = str(value).replace("\\", "\\\\").replace('"', '\\"')
263
+ return f'"{escaped}"'
@@ -5,6 +5,7 @@
5
5
  # --------------------------------------------------------------------------
6
6
  import os
7
7
  import re
8
+ import tomllib
8
9
  import traceback
9
10
  from typing import Any, Dict, Optional
10
11
 
@@ -24,6 +25,14 @@ logger = get_logger(__name__)
24
25
  REGEX = r"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,7}\b"
25
26
 
26
27
 
28
+ # Canonical identity markers used to distinguish FastAPI-fastkit-managed
29
+ # projects from unrelated FastAPI projects in the user workspace. Kept as
30
+ # module-level constants so templates, metadata injection, and detection
31
+ # logic all reference the same strings.
32
+ FASTKIT_DESCRIPTION_MARKER = "[FastAPI-fastkit templated]"
33
+ FASTKIT_TOOL_SECTION = "fastapi-fastkit" # the [tool.<this>] table key
34
+
35
+
27
36
  def get_optimal_console_size() -> tuple[int, int]:
28
37
  """
29
38
  Get optimal console size based on terminal dimensions.
@@ -273,19 +282,115 @@ def validate_email(ctx: Context, param: Any, value: Any) -> Any:
273
282
 
274
283
  def is_fastkit_project(project_dir: str) -> bool:
275
284
  """
276
- Check if the project was created with fastkit.
277
- Inspects the contents of the setup.py file for FastAPI-fastkit markers.
285
+ Check if the project was created/managed by FastAPI-fastkit.
286
+
287
+ Detection precedence (any single match is sufficient):
288
+
289
+ 1. ``pyproject.toml`` with ``[tool.fastapi-fastkit].managed = true``
290
+ (machine-readable marker; set by ``fastkit`` during project generation).
291
+ 2. ``pyproject.toml`` ``[project].description`` contains the
292
+ ``[FastAPI-fastkit templated]`` marker (case-insensitive).
293
+ 3. ``setup.py`` contains ``fastapi-fastkit`` (case-insensitive) — preserves
294
+ the legacy detection path for projects generated before the pyproject
295
+ marker existed.
278
296
 
279
297
  :param project_dir: Path to the project directory
280
298
  :return: True if the project was created with fastkit, False otherwise
281
299
  """
300
+ if _pyproject_marks_fastkit(os.path.join(project_dir, "pyproject.toml")):
301
+ return True
302
+
282
303
  setup_py = os.path.join(project_dir, "setup.py")
283
- if not os.path.exists(setup_py):
304
+ if os.path.exists(setup_py):
305
+ try:
306
+ with open(setup_py, "r", encoding="utf-8") as f:
307
+ content = f.read()
308
+ if FASTKIT_TOOL_SECTION in content.lower():
309
+ return True
310
+ except (OSError, UnicodeDecodeError):
311
+ pass
312
+
313
+ return False
314
+
315
+
316
+ def _pyproject_marks_fastkit(pyproject_path: str) -> bool:
317
+ """Return True if ``pyproject.toml`` carries a FastAPI-fastkit marker.
318
+
319
+ Tries structured TOML parsing first (authoritative), falling back to a
320
+ plain-text scan if the file is malformed so detection still works on
321
+ hand-edited or partially written pyproject files.
322
+ """
323
+ if not os.path.exists(pyproject_path):
284
324
  return False
285
325
 
286
326
  try:
287
- with open(setup_py, "r", encoding="utf-8") as f:
288
- content = f.read()
289
- return "FastAPI-fastkit" in content
327
+ with open(pyproject_path, "rb") as f:
328
+ data = tomllib.load(f)
329
+ except (OSError, tomllib.TOMLDecodeError, UnicodeDecodeError):
330
+ return _pyproject_text_marks_fastkit(pyproject_path)
331
+
332
+ tool_section = data.get("tool", {}).get(FASTKIT_TOOL_SECTION, {})
333
+ if isinstance(tool_section, dict) and tool_section.get("managed") is True:
334
+ return True
335
+
336
+ description = data.get("project", {}).get("description", "")
337
+ if (
338
+ isinstance(description, str)
339
+ and FASTKIT_DESCRIPTION_MARKER.lower() in description.lower()
340
+ ):
341
+ return True
342
+
343
+ return False
344
+
345
+
346
+ def _pyproject_text_marks_fastkit(pyproject_path: str) -> bool:
347
+ """Fallback plain-text scan for malformed pyproject files."""
348
+ try:
349
+ with open(pyproject_path, "r", encoding="utf-8") as f:
350
+ content = f.read().lower()
290
351
  except (OSError, UnicodeDecodeError):
291
352
  return False
353
+
354
+ if f"[tool.{FASTKIT_TOOL_SECTION}]" in content:
355
+ return True
356
+ if FASTKIT_DESCRIPTION_MARKER.lower() in content:
357
+ return True
358
+ return False
359
+
360
+
361
+ def read_fastkit_metadata(project_dir: str) -> Dict[str, Any]:
362
+ """Read the ``[tool.fastapi-fastkit]`` block of a generated project.
363
+
364
+ The block is the shared contract between generation (``init`` /
365
+ ``startdemo``) and the commands that operate on an existing project
366
+ (``runserver``, ``addroute``): it records the template, preset,
367
+ package manager, selected features and — most importantly — the
368
+ ``app_module`` entrypoint, so those commands no longer have to
369
+ re-derive the layout heuristically.
370
+
371
+ :param project_dir: Path to the generated project directory
372
+ :return: The metadata mapping, or an empty dict when the project has no
373
+ readable ``pyproject.toml`` / no fastkit block.
374
+ """
375
+ pyproject_path = os.path.join(project_dir, "pyproject.toml")
376
+ if not os.path.exists(pyproject_path):
377
+ return {}
378
+
379
+ try:
380
+ with open(pyproject_path, "rb") as f:
381
+ data = tomllib.load(f)
382
+ except (OSError, tomllib.TOMLDecodeError, UnicodeDecodeError) as e:
383
+ debug_log(
384
+ f"Could not read fastkit metadata from {pyproject_path}: {e}", "warning"
385
+ )
386
+ return {}
387
+
388
+ tool_section = data.get("tool", {})
389
+ if not isinstance(tool_section, dict):
390
+ return {}
391
+
392
+ metadata = tool_section.get(FASTKIT_TOOL_SECTION, {})
393
+ if not isinstance(metadata, dict):
394
+ return {}
395
+
396
+ return dict(metadata)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: FastAPI-fastkit
3
- Version: 1.2.1
3
+ Version: 1.4.0
4
4
  Summary: Fast, easy-to-use starter kit for new users of Python and FastAPI
5
5
  Author-Email: bnbong <bbbong9@gmail.com>
6
6
  License: MIT
@@ -11,6 +11,7 @@ Project-URL: Changelog, https://bnbong.github.io/FastAPI-fastkit/changelog/
11
11
  Requires-Python: >=3.12
12
12
  Requires-Dist: click>=8.1.7
13
13
  Requires-Dist: rich>=13.9.2
14
+ Requires-Dist: jinja2>=3.1
14
15
  Provides-Extra: dev
15
16
  Requires-Dist: pytest>=9.0.3; extra == "dev"
16
17
  Requires-Dist: pytest-cov>=6.2.1; extra == "dev"
@@ -19,10 +20,11 @@ Requires-Dist: pre-commit>=4.0.1; extra == "dev"
19
20
  Requires-Dist: mypy>=1.12.0; extra == "dev"
20
21
  Requires-Dist: isort>=5.13.2; extra == "dev"
21
22
  Requires-Dist: pygments>=2.20.0; extra == "dev"
23
+ Requires-Dist: types-pyyaml>=6.0.12.20260408; extra == "dev"
22
24
  Description-Content-Type: text/markdown
23
25
 
24
26
  <p align="center">
25
- <img align="top" width="70%" src="https://bnbong.github.io/projects/img/fastkit_general_logo.png" alt="FastAPI-fastkit"/>
27
+ <img align="top" width="70%" src=".github/fastkit_general_logo.png" alt="FastAPI-fastkit"/>
26
28
  </p>
27
29
  <p align="center">
28
30
  <em><b>FastAPI-fastkit</b>: Fast, easy-to-use starter kit for new users of Python and FastAPI</em>
@@ -57,6 +59,8 @@ This project was inspired by the `SpringBoot initializer` & Python Django's `dja
57
59
  - **🔍 Automated template quality assurance** : Weekly automated testing ensures all templates remain functional and up-to-date
58
60
  - **🚀 Multiple project templates** : Choose from various pre-configured templates for different use cases (async CRUD, Docker, PostgreSQL, etc.)
59
61
  - **📦 Multiple package manager support** : Choose your preferred Python package manager (pip, uv, pdm, poetry) for dependency management
62
+ - **🧾 Reproducible project configs** : Save an interactive session to a `.json` / `.toml` / `.yaml` file and replay it with `fastkit init --config`
63
+ - **🏷️ Self-describing projects** : Every generated project records its template, preset, package manager, entrypoint and selected features in a `[tool.fastapi-fastkit]` block that `runserver` and `addroute` read back
60
64
 
61
65
  ## Installation
62
66
 
@@ -82,6 +86,12 @@ fastkit init [OPTIONS]
82
86
  - Key options:
83
87
  - `--project-name`, `--author`, `--author-email`, `--description`
84
88
  - `--package-manager` [pip|uv|pdm|poetry]
89
+ - `--config <path>`: create the project from a saved config file (`.json` / `.toml`, and `.yaml` when PyYAML is installed) with no prompts
90
+ - `--save-config <path>`: with `--interactive`, record the answers for later reuse
91
+ - `--dry-run`: print the files and packages that would be created, write nothing
92
+ - `--no-venv`: skip virtual environment creation (implies `--no-install`)
93
+ - `--no-install`: skip dependency installation
94
+ - `--yes` / `-y`: skip the "Overwrite these files?" confirmation when deploying in place
85
95
  - Stack selection: `minimal` | `standard` | `full` (interactive)
86
96
 
87
97
  ### Create a project with interactive mode
@@ -90,6 +100,7 @@ fastkit init --interactive
90
100
  ```
91
101
  - What it does: Guided step-by-step project setup with intelligent feature selection
92
102
  - Features:
103
+ - **Architecture preset**: `minimal` | `single-module` | `classic-layered` | `domain-starter` (default)
93
104
  - **Database selection**: PostgreSQL, MySQL, MongoDB, Redis, SQLite
94
105
  - **Authentication**: JWT, OAuth2, FastAPI-Users, Session-based
95
106
  - **Background tasks**: Celery, Dramatiq
@@ -97,14 +108,20 @@ fastkit init --interactive
97
108
  - **Monitoring**: Loguru, OpenTelemetry, Prometheus
98
109
  - **Testing**: Basic (pytest), Coverage, Advanced (with faker, factory-boy)
99
110
  - **Utilities**: CORS, Rate-Limiting, Pagination, WebSocket
111
+ - **Logging**: structured JSON logging with a request-id middleware
112
+ - **Migrations**: Alembic (async env, baseline revision)
113
+ - **Tooling**: ruff, pre-commit, GitHub Actions, devcontainer, Makefile (multi-select)
100
114
  - **Deployment**: Docker, docker-compose with auto-generated configs
101
115
  - **Package manager**: pip, uv, pdm, poetry
102
116
  - **Custom packages**: Add your own dependencies
103
- - Auto-generates:
104
- - `main.py` with selected features integrated
105
- - Database and authentication configuration files
106
- - Docker deployment files (Dockerfile, docker-compose.yml)
117
+ - Auto-generates (varies by preset — see [the matrix](https://bnbong.github.io/FastAPI-fastkit/reference/preset-feature-matrix/) for details):
118
+ - `main.py` regenerated from selected features for `minimal` / `single-module`; preserved as-shipped for `classic-layered` / `domain-starter`
119
+ - Database and authentication configuration files at preset-specific paths
120
+ - Docker deployment files (`Dockerfile`, `docker-compose.yml`) with the preset's correct uvicorn entrypoint
107
121
  - Test configuration (pytest with coverage)
122
+ - `/health` and `/ready` endpoints on every generated project
123
+ - Real working code — not just installed packages — for background tasks, caching, WebSocket, pagination, OpenTelemetry, OAuth2 and session-based auth
124
+ - `--dry-run` previews the exact file tree a run would create, including logging/migrations/tooling artifacts
108
125
 
109
126
  ### Create a project from a template
110
127
  ```console
@@ -114,8 +131,16 @@ fastkit startdemo [TEMPLATE] [OPTIONS]
114
131
  - Key options:
115
132
  - `--project-name`, `--author`, `--author-email`, `--description`
116
133
  - `--package-manager` [pip|uv|pdm|poetry]
134
+ - `--dry-run`, `--no-venv`, `--no-install`, `--yes`/`-y` — same meaning as on `init`
135
+ - Refuses to run if the target project directory already exists (`--dry-run` excepted)
117
136
  - Tip: List available templates with `fastkit list-templates`
118
137
 
138
+ New in v1.4.0: `fastapi-auth-jwt` (JWT auth with refresh rotation),
139
+ `fastapi-sqlmodel` (async SQLModel + Alembic + generic CRUD), and
140
+ `fastapi-llm-agent` (streaming Claude agent with a tool loop).
141
+ `fastapi-dockerized` and `fastapi-async-crud` are deprecated — they still
142
+ work, but are no longer recommended starting points.
143
+
119
144
  ### Add a new route
120
145
  ```console
121
146
  fastkit addroute <project_name> <route_name>
@@ -144,9 +169,11 @@ fastkit deleteproject <project_name>
144
169
 
145
170
  For comprehensive guides and detailed usage instructions, visit our documentation:
146
171
 
172
+ - 🧭 **[Which starter should I choose?](https://bnbong.github.io/FastAPI-fastkit/user-guide/choosing-a-starter/)** - Beginner decision guide for `startdemo` templates and interactive presets
147
173
  - 📚 **[User Guide](https://bnbong.github.io/FastAPI-fastkit/user-guide/quick-start/)** - Detailed installation and usage guides
148
174
  - 🎯 **[Tutorial](https://bnbong.github.io/FastAPI-fastkit/tutorial/getting-started/)** - Step-by-step tutorials for beginners
149
175
  - 📖 **[CLI Reference](https://bnbong.github.io/FastAPI-fastkit/user-guide/cli-reference/)** - Complete command reference
176
+ - 🧱 **[Architecture Preset Matrix](https://bnbong.github.io/FastAPI-fastkit/reference/preset-feature-matrix/)** - Per-preset / per-feature contract for interactive generation
150
177
  - 🔍 **[Template Quality Assurance](https://bnbong.github.io/FastAPI-fastkit/reference/template-quality-assurance/)** - Automated testing and quality standards
151
178
 
152
179
  ## Contributing