FastAPI-fastkit 0.1.0__py3-none-any.whl → 1.0.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 (200) hide show
  1. fastapi_fastkit/__init__.py +1 -10
  2. fastapi_fastkit/backend/inspector.py +203 -0
  3. fastapi_fastkit/backend/main.py +482 -0
  4. fastapi_fastkit/{utils → backend}/transducer.py +36 -0
  5. fastapi_fastkit/cli.py +286 -87
  6. fastapi_fastkit/core/settings.py +48 -0
  7. fastapi_fastkit/fastapi_project_template/README.md +74 -4
  8. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/.env-tpl +1 -0
  9. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/.gitignore-tpl +30 -0
  10. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/README.md-tpl +107 -0
  11. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/requirements.txt-tpl +36 -0
  12. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/scripts/format.sh-tpl +5 -0
  13. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/scripts/lint.sh-tpl +5 -0
  14. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/scripts/run-server.sh-tpl +8 -0
  15. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/scripts/test.sh-tpl +6 -0
  16. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/setup.cfg-tpl +14 -0
  17. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/setup.py-tpl +25 -0
  18. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/api/api.py-tpl +9 -0
  19. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/api/routes/items.py-tpl +57 -0
  20. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/core/config.py-tpl +64 -0
  21. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/crud/items.py-tpl +21 -0
  22. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/main.py-tpl +26 -0
  23. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/mocks/__init__.py-tpl +0 -0
  24. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/mocks/mock_items.json-tpl +8 -0
  25. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/schemas/__init__.py-tpl +0 -0
  26. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/schemas/items.py-tpl +22 -0
  27. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/tests/__init__.py-tpl +0 -0
  28. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/tests/conftest.py-tpl +42 -0
  29. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/tests/test_items.py-tpl +48 -0
  30. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/.env-tpl +1 -0
  31. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/.gitignore-tpl +191 -0
  32. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/README.md-tpl +156 -0
  33. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/requirements.txt-tpl +36 -0
  34. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/scripts/format.sh-tpl +5 -0
  35. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/scripts/lint.sh-tpl +5 -0
  36. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/scripts/run-server.sh-tpl +8 -0
  37. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/scripts/test.sh-tpl +6 -0
  38. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/setup.cfg-tpl +12 -0
  39. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/setup.py-tpl +27 -0
  40. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/__init__.py-tpl +0 -0
  41. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/api/__init__.py-tpl +0 -0
  42. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/api/api.py-tpl +9 -0
  43. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/api/routes/__init__.py-tpl +0 -0
  44. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/api/routes/items.py-tpl +172 -0
  45. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/core/__init__.py-tpl +0 -0
  46. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/core/config.py-tpl +64 -0
  47. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/crud/__init__.py-tpl +0 -0
  48. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/crud/items.py-tpl +21 -0
  49. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/helper/__init__.py-tpl +0 -0
  50. fastapi_fastkit/fastapi_project_template/{fastapi-default → fastapi-custom-response}/src/helper/exceptions.py-tpl +12 -3
  51. fastapi_fastkit/fastapi_project_template/{fastapi-default → fastapi-custom-response}/src/helper/pagination.py-tpl +3 -2
  52. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/main.py-tpl +39 -0
  53. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/mocks/__init__.py-tpl +0 -0
  54. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/mocks/mock_items.json-tpl +8 -0
  55. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/schemas/__init__.py-tpl +0 -0
  56. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/schemas/base.py-tpl +49 -0
  57. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/schemas/items.py-tpl +22 -0
  58. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/utils/__init__.py-tpl +0 -0
  59. fastapi_fastkit/fastapi_project_template/{fastapi-default → fastapi-custom-response}/src/utils/documents.py-tpl +1 -1
  60. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/tests/__init__.py-tpl +0 -0
  61. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/tests/conftest.py-tpl +42 -0
  62. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/tests/test_items.py-tpl +61 -0
  63. fastapi_fastkit/fastapi_project_template/fastapi-default/.env-tpl +1 -0
  64. fastapi_fastkit/fastapi_project_template/fastapi-default/.gitignore-tpl +28 -189
  65. fastapi_fastkit/fastapi_project_template/fastapi-default/README.md-tpl +95 -11
  66. fastapi_fastkit/fastapi_project_template/fastapi-default/requirements.txt-tpl +25 -38
  67. fastapi_fastkit/fastapi_project_template/fastapi-default/scripts/format.sh-tpl +5 -0
  68. fastapi_fastkit/fastapi_project_template/fastapi-default/scripts/lint.sh-tpl +5 -0
  69. fastapi_fastkit/fastapi_project_template/fastapi-default/scripts/run-server.sh-tpl +8 -0
  70. fastapi_fastkit/fastapi_project_template/fastapi-default/scripts/test.sh-tpl +6 -0
  71. fastapi_fastkit/fastapi_project_template/fastapi-default/setup.cfg-tpl +5 -5
  72. fastapi_fastkit/fastapi_project_template/fastapi-default/setup.py-tpl +10 -23
  73. fastapi_fastkit/fastapi_project_template/fastapi-default/src/__init__.py-tpl +0 -88
  74. fastapi_fastkit/fastapi_project_template/fastapi-default/src/api/__init__.py-tpl +0 -0
  75. fastapi_fastkit/fastapi_project_template/fastapi-default/src/api/api.py-tpl +9 -0
  76. fastapi_fastkit/fastapi_project_template/fastapi-default/src/api/routes/__init__.py-tpl +0 -0
  77. fastapi_fastkit/fastapi_project_template/fastapi-default/src/api/routes/items.py-tpl +57 -0
  78. fastapi_fastkit/fastapi_project_template/fastapi-default/src/core/config.py-tpl +64 -0
  79. fastapi_fastkit/fastapi_project_template/fastapi-default/src/crud/items.py-tpl +18 -0
  80. fastapi_fastkit/fastapi_project_template/fastapi-default/src/main.py-tpl +26 -0
  81. fastapi_fastkit/fastapi_project_template/fastapi-default/src/mocks/mock_items.json-tpl +8 -0
  82. fastapi_fastkit/fastapi_project_template/fastapi-default/src/schemas/__init__.py-tpl +0 -48
  83. fastapi_fastkit/fastapi_project_template/fastapi-default/src/schemas/items.py-tpl +22 -0
  84. fastapi_fastkit/fastapi_project_template/fastapi-default/tests/__init__.py-tpl +0 -0
  85. fastapi_fastkit/fastapi_project_template/fastapi-default/tests/conftest.py-tpl +30 -0
  86. fastapi_fastkit/fastapi_project_template/fastapi-default/tests/test_items.py-tpl +44 -0
  87. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/.env-tpl +1 -0
  88. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/.gitignore-tpl +30 -0
  89. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/Dockerfile-tpl +23 -0
  90. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/README.md-tpl +119 -0
  91. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/requirements.txt-tpl +36 -0
  92. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/scripts/format.sh-tpl +5 -0
  93. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/scripts/lint.sh-tpl +5 -0
  94. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/scripts/run-server.sh-tpl +8 -0
  95. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/scripts/test.sh-tpl +6 -0
  96. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/setup.cfg-tpl +13 -0
  97. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/setup.py-tpl +22 -0
  98. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/__init__.py-tpl +0 -0
  99. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/api/__init__.py-tpl +0 -0
  100. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/api/api.py-tpl +6 -0
  101. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/api/routes/__init__.py-tpl +0 -0
  102. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/api/routes/items.py-tpl +54 -0
  103. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/core/__init__.py-tpl +0 -0
  104. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/core/config.py-tpl +64 -0
  105. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/crud/__init__.py-tpl +0 -0
  106. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/crud/items.py-tpl +15 -0
  107. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/main.py-tpl +26 -0
  108. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/mocks/__init__.py-tpl +0 -0
  109. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/mocks/mock_items.json-tpl +8 -0
  110. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/schemas/__init__.py-tpl +0 -0
  111. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/schemas/items.py-tpl +19 -0
  112. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/tests/__init__.py-tpl +0 -0
  113. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/tests/conftest.py-tpl +30 -0
  114. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/tests/test_items.py-tpl +44 -0
  115. fastapi_fastkit/fastapi_project_template/fastapi-empty/.env-tpl +1 -0
  116. fastapi_fastkit/fastapi_project_template/fastapi-empty/setup.py-tpl +22 -0
  117. fastapi_fastkit/fastapi_project_template/fastapi-empty/src/__init__.py-tpl +0 -0
  118. fastapi_fastkit/fastapi_project_template/fastapi-empty/src/core/__init__.py-tpl +0 -0
  119. fastapi_fastkit/fastapi_project_template/fastapi-empty/src/core/config.py-tpl +75 -0
  120. fastapi_fastkit/fastapi_project_template/fastapi-empty/src/main.py-tpl +36 -0
  121. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/.env-tpl +9 -0
  122. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/.gitignore-tpl +30 -0
  123. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/Dockerfile-tpl +23 -0
  124. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/README.md-tpl +144 -0
  125. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/alembic.ini-tpl +119 -0
  126. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/docker-compose.yml-tpl +44 -0
  127. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/requirements.txt-tpl +41 -0
  128. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/scripts/format.sh-tpl +5 -0
  129. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/scripts/lint.sh-tpl +5 -0
  130. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/scripts/pre-start.sh-tpl +16 -0
  131. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/scripts/run-server.sh-tpl +8 -0
  132. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/scripts/test.sh-tpl +10 -0
  133. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/setup.cfg-tpl +13 -0
  134. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/setup.py-tpl +25 -0
  135. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/__init__.py-tpl +0 -0
  136. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/alembic/README-tpl +1 -0
  137. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/alembic/env.py-tpl +85 -0
  138. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/alembic/script.py.mako-tpl +26 -0
  139. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/alembic/versions/bedcdc35b64a_first_alembic.py-tpl +37 -0
  140. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/api/__init__.py-tpl +0 -0
  141. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/api/api.py-tpl +11 -0
  142. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/api/deps.py-tpl +19 -0
  143. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/api/routes/__init__.py-tpl +0 -0
  144. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/api/routes/items.py-tpl +109 -0
  145. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/core/__init__.py-tpl +0 -0
  146. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/core/config.py-tpl +88 -0
  147. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/core/db.py-tpl +53 -0
  148. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/crud/__init__.py-tpl +0 -0
  149. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/crud/items.py-tpl +102 -0
  150. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/main.py-tpl +45 -0
  151. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/schemas/__init__.py-tpl +0 -0
  152. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/schemas/items.py-tpl +54 -0
  153. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/utils/__init__.py-tpl +0 -0
  154. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/utils/backend_pre_start.py-tpl +39 -0
  155. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/utils/init_data.py-tpl +23 -0
  156. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/utils/tests_pre_start.py-tpl +39 -0
  157. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/tests/__init__.py-tpl +0 -0
  158. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/tests/conftest.py-tpl +63 -0
  159. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/tests/test_items.py-tpl +44 -0
  160. fastapi_fastkit/fastapi_project_template/modules/api/__init__.py-tpl +0 -0
  161. fastapi_fastkit/fastapi_project_template/modules/api/routes/__init__.py-tpl +0 -0
  162. fastapi_fastkit/fastapi_project_template/modules/api/routes/new_route.py-tpl +64 -0
  163. fastapi_fastkit/fastapi_project_template/modules/crud/__init__.py-tpl +0 -0
  164. fastapi_fastkit/fastapi_project_template/modules/crud/new_route.py-tpl +29 -0
  165. fastapi_fastkit/fastapi_project_template/modules/schemas/__init__.py-tpl +0 -0
  166. fastapi_fastkit/fastapi_project_template/modules/schemas/new_route.py-tpl +23 -0
  167. fastapi_fastkit/utils/logging.py +4 -1
  168. fastapi_fastkit/utils/main.py +129 -0
  169. fastapi_fastkit-1.0.0.dist-info/METADATA +208 -0
  170. fastapi_fastkit-1.0.0.dist-info/RECORD +189 -0
  171. {fastapi_fastkit-0.1.0.dist-info → fastapi_fastkit-1.0.0.dist-info}/licenses/LICENSE +21 -21
  172. fastapi_fastkit/backend.py +0 -112
  173. fastapi_fastkit/fastapi_project_template/fastapi-default/.env.test-tpl +0 -3
  174. fastapi_fastkit/fastapi_project_template/fastapi-default/main.py-tpl +0 -21
  175. fastapi_fastkit/fastapi_project_template/fastapi-default/script/run-server.sh-tpl +0 -2
  176. fastapi_fastkit/fastapi_project_template/fastapi-default/script/run-test.sh-tpl +0 -2
  177. fastapi_fastkit/fastapi_project_template/fastapi-default/src/.DS_Store +0 -0
  178. fastapi_fastkit/fastapi_project_template/fastapi-default/src/core/settings.py-tpl +0 -96
  179. fastapi_fastkit/fastapi_project_template/fastapi-default/src/crud/_base.py-tpl +0 -92
  180. fastapi_fastkit/fastapi_project_template/fastapi-default/src/crud/user.py-tpl +0 -44
  181. fastapi_fastkit/fastapi_project_template/fastapi-default/src/helper/global_data.py-tpl +0 -33
  182. fastapi_fastkit/fastapi_project_template/fastapi-default/src/helper/logging.py-tpl +0 -25
  183. fastapi_fastkit/fastapi_project_template/fastapi-default/src/mocks/mock_users.json-tpl +0 -17
  184. fastapi_fastkit/fastapi_project_template/fastapi-default/src/router/__init__.py-tpl +0 -48
  185. fastapi_fastkit/fastapi_project_template/fastapi-default/src/router/user.py-tpl +0 -126
  186. fastapi_fastkit/fastapi_project_template/fastapi-default/src/schemas/user.py-tpl +0 -81
  187. fastapi_fastkit/fastapi_project_template/fastapi-default/src/templates/index.html-tpl +0 -27
  188. fastapi_fastkit/fastapi_project_template/fastapi-default/test/conftest.py-tpl +0 -22
  189. fastapi_fastkit/fastapi_project_template/fastapi-default/test/routes/test_user.py-tpl +0 -112
  190. fastapi_fastkit/utils/inspector.py +0 -15
  191. fastapi_fastkit-0.1.0.dist-info/METADATA +0 -46
  192. fastapi_fastkit-0.1.0.dist-info/RECORD +0 -56
  193. /fastapi_fastkit/{fastapi_project_template/fastapi-default/src/helper/__init__.py-tpl → backend/__init__.py} +0 -0
  194. /fastapi_fastkit/fastapi_project_template/{fastapi-default/src/utils → fastapi-async-crud/src}/__init__.py-tpl +0 -0
  195. /fastapi_fastkit/fastapi_project_template/{fastapi-default/test → fastapi-async-crud/src/api}/__init__.py-tpl +0 -0
  196. /fastapi_fastkit/fastapi_project_template/{fastapi-default/test → fastapi-async-crud/src/api}/routes/__init__.py-tpl +0 -0
  197. /fastapi_fastkit/fastapi_project_template/{fastapi-dockerized → fastapi-async-crud/src/core}/__init__.py-tpl +0 -0
  198. /fastapi_fastkit/fastapi_project_template/{fastapi-psql-orm → fastapi-async-crud/src/crud}/__init__.py-tpl +0 -0
  199. {fastapi_fastkit-0.1.0.dist-info → fastapi_fastkit-1.0.0.dist-info}/WHEEL +0 -0
  200. {fastapi_fastkit-0.1.0.dist-info → fastapi_fastkit-1.0.0.dist-info}/entry_points.txt +0 -0
@@ -1,10 +1 @@
1
- __version__ = "0.0.1"
2
-
3
- import os
4
-
5
- from rich.console import Console
6
-
7
- if "PYTEST_CURRENT_TEST" in os.environ:
8
- console = Console(no_color=True)
9
- else:
10
- console = Console()
1
+ __version__ = 'v1.0.0'
@@ -0,0 +1,203 @@
1
+ # --------------------------------------------------------------------------
2
+ # The Module inspect FastAPI template is appropriate
3
+ #
4
+ # This module will be read by Github Action when contributor
5
+ # makes a PR of adding new FastAPI template.
6
+ #
7
+ # First, check a FastAPI template is formed a valid template form with .py-tpl extension
8
+ # & dependencies requirements.
9
+ # Second, check a FastAPI template has a proper FastAPI server implementation.
10
+ # main.py module must have a FastAPI app creation. like `app = FastAPI()`
11
+ # Third, check a FastAPI template has passed all the tests.
12
+ #
13
+ # This module create temporary named 'temp' directory at src/fastapi_fastkit/backend
14
+ # and copy a template to Funtional FastAPI application into the temp directory.
15
+ # After the inspection, it will be deleted.
16
+ #
17
+ # This module include virtual environment creation & installation of dependencies.
18
+ # Depending on the volume in which the template is implemented and the number of dependencies,
19
+ # it may take some time to complete the inspection.
20
+ #
21
+ # @author bnbong
22
+ # --------------------------------------------------------------------------
23
+ import os
24
+ import shutil
25
+ import subprocess
26
+ import sys
27
+ from pathlib import Path
28
+ from typing import Any, Dict, List
29
+
30
+ from fastapi_fastkit.backend.main import (
31
+ create_venv,
32
+ find_template_core_modules,
33
+ install_dependencies,
34
+ )
35
+ from fastapi_fastkit.backend.transducer import copy_and_convert_template
36
+ from fastapi_fastkit.utils.main import print_error, print_success, print_warning
37
+
38
+
39
+ class TemplateInspector:
40
+ def __init__(self, template_path: str):
41
+ self.template_path = Path(template_path)
42
+ self.errors: List[str] = []
43
+ self.warnings: List[str] = []
44
+ self.temp_dir = os.path.join(os.path.dirname(__file__), "temp")
45
+
46
+ # Create temp directory and copy template
47
+ os.makedirs(self.temp_dir, exist_ok=True)
48
+ copy_and_convert_template(str(self.template_path), self.temp_dir)
49
+
50
+ def __del__(self) -> None:
51
+ """Cleanup temp directory when inspector is destroyed."""
52
+ if os.path.exists(self.temp_dir):
53
+ shutil.rmtree(self.temp_dir)
54
+
55
+ def inspect_template(self) -> bool:
56
+ """Inspect the template is valid FastAPI application."""
57
+ checks = [
58
+ self._check_file_structure,
59
+ self._check_file_extensions,
60
+ self._check_dependencies,
61
+ self._check_fastapi_implementation,
62
+ self._test_template,
63
+ ]
64
+
65
+ for check in checks:
66
+ if not check():
67
+ return False
68
+ return True
69
+
70
+ def _check_file_structure(self) -> bool:
71
+ """Check the required file and directory structure."""
72
+ required_paths = [
73
+ "tests",
74
+ "requirements.txt-tpl",
75
+ "setup.py-tpl",
76
+ "README.md-tpl",
77
+ ]
78
+
79
+ for path in required_paths:
80
+ if not (self.template_path / path).exists():
81
+ self.errors.append(f"Missing required path: {path}")
82
+ return False
83
+ return True
84
+
85
+ def _check_file_extensions(self) -> bool:
86
+ """Check all Python files have .py-tpl extension."""
87
+ for path in self.template_path.rglob("*"):
88
+ if path.is_file() and path.suffix == ".py":
89
+ self.errors.append(f"Found .py file instead of .py-tpl: {path}")
90
+ return False
91
+ return True
92
+
93
+ def _check_dependencies(self) -> bool:
94
+ """Check the dependencies in both setup.py-tpl and requirements.txt-tpl."""
95
+ req_path = self.template_path / "requirements.txt-tpl"
96
+ setup_path = self.template_path / "setup.py-tpl"
97
+
98
+ if not req_path.exists():
99
+ self.errors.append("requirements.txt-tpl not found")
100
+ return False
101
+ if not setup_path.exists():
102
+ self.errors.append("setup.py-tpl not found")
103
+ return False
104
+
105
+ with open(req_path) as f:
106
+ deps = f.read().splitlines()
107
+ package_names = [dep.split("==")[0] for dep in deps if dep]
108
+ if "fastapi" not in package_names:
109
+ self.errors.append(
110
+ "FastAPI dependency not found in requirements.txt-tpl"
111
+ )
112
+ return False
113
+ return True
114
+
115
+ def _check_fastapi_implementation(self) -> bool:
116
+ """Check if the template has a proper FastAPI server implementation."""
117
+ core_modules = find_template_core_modules(self.temp_dir)
118
+
119
+ if not core_modules["main"]:
120
+ self.errors.append("main.py not found in template")
121
+ return False
122
+
123
+ with open(core_modules["main"]) as f:
124
+ content = f.read()
125
+ if "FastAPI" not in content or "app" not in content:
126
+ self.errors.append("FastAPI app creation not found in main.py")
127
+ return False
128
+ return True
129
+
130
+ def _test_template(self) -> bool:
131
+ """Run the tests in the converted template directory."""
132
+ test_dir = Path(self.temp_dir) / "tests"
133
+ if not test_dir.exists():
134
+ self.errors.append("Tests directory not found")
135
+ return False
136
+
137
+ try:
138
+ # Create virtual environment
139
+ venv_path = create_venv(self.temp_dir)
140
+
141
+ # Install dependencies
142
+ install_dependencies(self.temp_dir, venv_path)
143
+
144
+ # Run tests using the venv's pytest
145
+ if os.name == "nt": # Windows
146
+ pytest_path = os.path.join(venv_path, "Scripts", "pytest")
147
+ else: # Linux/Mac
148
+ pytest_path = os.path.join(venv_path, "bin", "pytest")
149
+
150
+ result = subprocess.run(
151
+ [pytest_path, str(test_dir)],
152
+ capture_output=True,
153
+ text=True,
154
+ cwd=self.temp_dir,
155
+ )
156
+
157
+ if result.returncode != 0:
158
+ self.errors.append(f"Tests failed: {result.stderr}")
159
+ return False
160
+
161
+ except Exception as e:
162
+ self.errors.append(f"Error running tests: {e}")
163
+ return False
164
+
165
+ return True
166
+
167
+
168
+ def inspect_template(template_path: str) -> Dict[str, Any]:
169
+ """Run the template inspection and return the result."""
170
+ inspector = TemplateInspector(template_path)
171
+ is_valid = inspector.inspect_template()
172
+ result: dict[str, Any] = {
173
+ "valid": is_valid,
174
+ "errors": inspector.errors,
175
+ "warnings": inspector.warnings,
176
+ }
177
+
178
+ if result["valid"]:
179
+ print_success("Template inspection passed successfully! ✨")
180
+ elif result["errors"]:
181
+ error_messages = [str(error) for error in result["errors"]]
182
+ print_error(
183
+ "Template inspection failed with following errors:\n"
184
+ + "\n".join(f"- {error}" for error in error_messages)
185
+ )
186
+
187
+ if result["warnings"]:
188
+ warning_messages = [str(warning) for warning in result["warnings"]]
189
+ print_warning(
190
+ "Template has following warnings:\n"
191
+ + "\n".join(f"- {warning}" for warning in warning_messages)
192
+ )
193
+
194
+ return result
195
+
196
+
197
+ if __name__ == "__main__":
198
+ if len(sys.argv) != 2:
199
+ print("Usage: python inspector.py <template_dir>")
200
+ sys.exit(1)
201
+
202
+ template_dir = sys.argv[1]
203
+ inspect_template(template_dir)
@@ -0,0 +1,482 @@
1
+ # --------------------------------------------------------------------------
2
+ # The Module defines backend operations for FastAPI-fastkit CLI.
3
+ #
4
+ # @author bnbong bbbong9@gmail.com
5
+ # --------------------------------------------------------------------------
6
+ import os
7
+ import subprocess
8
+ from typing import Dict, List
9
+
10
+ from fastapi_fastkit import console
11
+ from fastapi_fastkit.backend.transducer import copy_and_convert_template_file
12
+ from fastapi_fastkit.core.exceptions import BackendExceptions, TemplateExceptions
13
+ from fastapi_fastkit.core.settings import settings
14
+ from fastapi_fastkit.utils.main import (
15
+ handle_exception,
16
+ print_error,
17
+ print_info,
18
+ print_success,
19
+ print_warning,
20
+ )
21
+
22
+ # ------------------------------------------------------------
23
+ # Template Discovery Functions
24
+ # ------------------------------------------------------------
25
+
26
+
27
+ def find_template_core_modules(project_dir: str) -> Dict[str, str]:
28
+ """
29
+ Find core module files in the template project structure.
30
+ Returns a dictionary with paths to main.py, setup.py, and config files.
31
+
32
+ :param project_dir: Path to the project directory
33
+ :return: Dictionary with paths to core modules
34
+ """
35
+ core_modules = {"main": "", "setup": "", "config": ""}
36
+ template_config = settings.TEMPLATE_PATHS["config"]
37
+
38
+ # Find main.py
39
+ for path in settings.TEMPLATE_PATHS["main"]:
40
+ full_path = os.path.join(project_dir, path)
41
+ if os.path.exists(full_path):
42
+ core_modules["main"] = full_path
43
+ break
44
+
45
+ # Find setup.py
46
+ for path in settings.TEMPLATE_PATHS["setup"]:
47
+ full_path = os.path.join(project_dir, path)
48
+ if os.path.exists(full_path):
49
+ core_modules["setup"] = full_path
50
+ break
51
+
52
+ # Find config files
53
+ if isinstance(template_config, dict):
54
+ for config_file in template_config.get("files", []):
55
+ for base_path in template_config.get("paths", []):
56
+ full_path = os.path.join(project_dir, base_path, config_file)
57
+ if os.path.exists(full_path):
58
+ core_modules["config"] = full_path
59
+ break
60
+ if core_modules["config"]:
61
+ break
62
+
63
+ return core_modules
64
+
65
+
66
+ def read_template_stack(template_path: str) -> List[str]:
67
+ """
68
+ Read the install_requires from setup.py-tpl in the template directory.
69
+ Returns a list of required packages.
70
+
71
+ :param template_path: Path to the template directory
72
+ :return: List of required packages
73
+ """
74
+ setup_path = os.path.join(template_path, "setup.py-tpl")
75
+ if not os.path.exists(setup_path):
76
+ return []
77
+
78
+ try:
79
+ with open(setup_path, "r") as f:
80
+ content = f.read()
81
+ # Find the install_requires section using proper string matching
82
+ if "install_requires: list[str] = [" in content:
83
+ start_idx = content.find("install_requires: list[str] = [") + len(
84
+ "install_requires: list[str] = ["
85
+ )
86
+ end_idx = content.find("]", start_idx)
87
+ if start_idx != -1 and end_idx != -1:
88
+ deps_str = content[start_idx:end_idx]
89
+ # Clean and parse the dependencies
90
+ deps = [
91
+ dep.strip().strip("'").strip('"')
92
+ for dep in deps_str.split(",")
93
+ if dep.strip() and not dep.isspace()
94
+ ]
95
+ return [dep for dep in deps if dep] # Remove empty strings
96
+ except Exception as e:
97
+ handle_exception(e, "Error reading template dependencies")
98
+ return []
99
+
100
+ return []
101
+
102
+
103
+ # ------------------------------------------------------------
104
+ # Project Setup Functions
105
+ # ------------------------------------------------------------
106
+
107
+
108
+ def inject_project_metadata(
109
+ target_dir: str,
110
+ project_name: str,
111
+ author: str,
112
+ author_email: str,
113
+ description: str,
114
+ ) -> None:
115
+ """
116
+ Inject project metadata into template files after template conversion.
117
+ """
118
+ try:
119
+ core_modules = find_template_core_modules(target_dir)
120
+ setup_py = core_modules.get("setup", "")
121
+ config_py = core_modules.get("config", "")
122
+
123
+ if setup_py and os.path.exists(setup_py):
124
+ with open(setup_py, "r") as f:
125
+ content = f.read()
126
+
127
+ # Replace placeholders
128
+ content = content.replace("<project_name>", project_name)
129
+ content = content.replace("<author>", author)
130
+ content = content.replace("<author_email>", author_email)
131
+ content = content.replace("<description>", description)
132
+
133
+ with open(setup_py, "w") as f:
134
+ f.write(content)
135
+ print_info("Injected metadata into setup.py")
136
+
137
+ if config_py and os.path.exists(config_py):
138
+ with open(config_py, "r") as f:
139
+ content = f.read()
140
+
141
+ content = content.replace("<project_name>", project_name)
142
+
143
+ with open(config_py, "w") as f:
144
+ f.write(content)
145
+ print_info("Injected metadata into config file")
146
+
147
+ # Try to find the readme file
148
+ readme_files = ["README.md", "Readme.md", "readme.md"]
149
+ for readme in readme_files:
150
+ readme_path = os.path.join(target_dir, readme)
151
+ if os.path.exists(readme_path):
152
+ with open(readme_path, "r") as f:
153
+ content = f.read()
154
+
155
+ content = content.replace(
156
+ "{FASTAPI TEMPLATE PROJECT NAME}", project_name
157
+ )
158
+ content = content.replace("{fill here}", author)
159
+
160
+ with open(readme_path, "w") as f:
161
+ f.write(content)
162
+ print_info("Injected metadata into README.md")
163
+ break
164
+
165
+ except Exception as e:
166
+ handle_exception(e, "Failed to inject project metadata")
167
+ raise BackendExceptions("Failed to inject project metadata")
168
+
169
+
170
+ def create_venv(project_dir: str) -> str:
171
+ """Create a virtual environment."""
172
+ try:
173
+ with console.status("[bold green]Setting up project environment..."):
174
+ console.print("[yellow]Creating virtual environment...[/yellow]")
175
+ venv_path = os.path.join(project_dir, ".venv")
176
+ subprocess.run(["python", "-m", "venv", venv_path], check=True)
177
+
178
+ if os.name == "nt":
179
+ activate_venv = f" {os.path.join(venv_path, 'Scripts', 'activate.bat')}"
180
+ else:
181
+ activate_venv = f" source {os.path.join(venv_path, 'bin', 'activate')}"
182
+
183
+ print_info(
184
+ "venv created at "
185
+ + venv_path
186
+ + "\nTo activate the virtual environment, run:\n\n"
187
+ + activate_venv,
188
+ )
189
+ return venv_path
190
+
191
+ except Exception as e:
192
+ print_error(f"Error during venv creation: {e}")
193
+ raise BackendExceptions("Failed to create venv")
194
+
195
+
196
+ def install_dependencies(project_dir: str, venv_path: str) -> None:
197
+ """
198
+ Install project dependencies into the virtual environment.
199
+
200
+ :param project_dir: Path to the project directory
201
+ :param venv_path: Path to the virtual environment
202
+ :return: None
203
+ """
204
+ try:
205
+ if not os.path.exists(venv_path):
206
+ print_error("Virtual environment does not exist. Creating it first.")
207
+ venv_path = create_venv(project_dir)
208
+ if not venv_path:
209
+ raise BackendExceptions("Failed to create virtual environment")
210
+
211
+ requirements_path = os.path.join(project_dir, "requirements.txt")
212
+ if not os.path.exists(requirements_path):
213
+ print_error(f"Requirements file not found at {requirements_path}")
214
+ raise BackendExceptions("Requirements file not found")
215
+
216
+ if os.name == "nt": # Windows
217
+ pip_path = os.path.join(venv_path, "Scripts", "pip")
218
+ else: # Unix-based
219
+ pip_path = os.path.join(venv_path, "bin", "pip")
220
+
221
+ # Upgrade pip
222
+ subprocess.run(
223
+ [pip_path, "install", "--upgrade", "pip"],
224
+ check=True,
225
+ capture_output=True,
226
+ text=True,
227
+ )
228
+
229
+ with console.status("[bold green]Installing dependencies..."):
230
+ subprocess.run(
231
+ [pip_path, "install", "-r", "requirements.txt"],
232
+ cwd=project_dir,
233
+ check=True,
234
+ )
235
+
236
+ print_success("Dependencies installed successfully")
237
+
238
+ except subprocess.CalledProcessError as e:
239
+ handle_exception(e, f"Error during dependency installation: {str(e)}")
240
+ if hasattr(e, "stderr"):
241
+ print_error(f"Error details: {e.stderr}")
242
+ raise BackendExceptions("Failed to install dependencies")
243
+ except Exception as e:
244
+ handle_exception(e, f"Error during dependency installation: {str(e)}")
245
+ raise BackendExceptions(f"Failed to install dependencies: {str(e)}")
246
+
247
+
248
+ # ------------------------------------------------------------
249
+ # Add Route Functions
250
+ # ------------------------------------------------------------
251
+
252
+
253
+ def _ensure_project_structure(src_dir: str) -> Dict[str, str]:
254
+ """
255
+ Ensure the project structure exists for adding a new route.
256
+ Creates necessary directories if they don't exist.
257
+
258
+ :param src_dir: Source directory of the project
259
+ :return: Dictionary with paths to target directories
260
+ """
261
+ if not os.path.exists(src_dir):
262
+ raise BackendExceptions(f"Source directory not found at {src_dir}")
263
+
264
+ # Define target directories
265
+ target_dirs = {
266
+ "api": os.path.join(src_dir, "api"),
267
+ "api_routes": os.path.join(src_dir, "api", "routes"),
268
+ "crud": os.path.join(src_dir, "crud"),
269
+ "schemas": os.path.join(src_dir, "schemas"),
270
+ }
271
+
272
+ # Create directories and __init__.py files if needed
273
+ for dir_name, dir_path in target_dirs.items():
274
+ if not os.path.exists(dir_path):
275
+ os.makedirs(dir_path)
276
+
277
+ # Create __init__.py if it doesn't exist
278
+ init_file = os.path.join(dir_path, "__init__.py")
279
+ if not os.path.exists(init_file):
280
+ with open(init_file, "w") as f:
281
+ pass
282
+
283
+ return target_dirs
284
+
285
+
286
+ def _create_route_files(
287
+ modules_dir: str, target_dirs: Dict[str, str], route_name: str
288
+ ) -> None:
289
+ """
290
+ Create route files from templates.
291
+
292
+ :param modules_dir: Path to the modules directory
293
+ :param target_dirs: Dictionary with paths to target directories
294
+ :param route_name: Name of the route to create
295
+ """
296
+ replacements = {"<new_route>": route_name}
297
+ module_types = ["api/routes", "crud", "schemas"]
298
+
299
+ for module_type in module_types:
300
+ # Source template
301
+ source = os.path.join(modules_dir, module_type, "new_route.py-tpl")
302
+
303
+ # Target directory
304
+ if module_type == "api/routes":
305
+ target_dir = target_dirs["api_routes"]
306
+ else:
307
+ target_dir = target_dirs[module_type.split("/")[-1]]
308
+
309
+ # Target file
310
+ target = os.path.join(target_dir, f"{route_name}.py")
311
+
312
+ if os.path.exists(target):
313
+ print_warning(f"File {target} already exists, skipping...")
314
+ continue
315
+
316
+ if not copy_and_convert_template_file(source, target, replacements):
317
+ print_warning(f"Failed to copy template file {source} to {target}")
318
+
319
+
320
+ def _handle_api_router_file(
321
+ target_dirs: Dict[str, str], modules_dir: str, route_name: str
322
+ ) -> None:
323
+ """
324
+ Handle the API router file - create or update.
325
+
326
+ :param target_dirs: Dictionary with paths to target directories
327
+ :param modules_dir: Path to the modules directory
328
+ :param route_name: Name of the route to add
329
+ """
330
+ api_py_target = os.path.join(target_dirs["api"], "api.py")
331
+
332
+ if os.path.exists(api_py_target):
333
+ # Update existing api.py
334
+ with open(api_py_target, "r") as f:
335
+ api_content = f.read()
336
+
337
+ # Check if router is already included
338
+ router_import = f"from src.api.routes import {route_name}"
339
+ if router_import not in api_content:
340
+ with open(api_py_target, "a") as f:
341
+ f.write(f"\n{router_import}\n")
342
+ f.write(f"api_router.include_router({route_name}.router)\n")
343
+ print_info(f"Added route {route_name} to existing api.py")
344
+ else:
345
+ # Create new api.py
346
+ router_code = f"""
347
+ # --------------------------------------------------------------------------
348
+ # API router connector module
349
+ # --------------------------------------------------------------------------
350
+ from fastapi import APIRouter
351
+
352
+ from src.api.routes import {route_name}
353
+
354
+ api_router = APIRouter()
355
+ api_router.include_router({route_name}.router)
356
+
357
+ """
358
+ with open(api_py_target, "w") as tgt_file:
359
+ tgt_file.write(router_code)
360
+
361
+
362
+ def _process_init_files(
363
+ modules_dir: str, target_dirs: Dict[str, str], module_types: List[str]
364
+ ) -> None:
365
+ """
366
+ Process __init__.py files if they don't exist.
367
+
368
+ :param modules_dir: Path to the modules directory
369
+ :param target_dirs: Dictionary with paths to target directories
370
+ :param module_types: List of module types to process
371
+ """
372
+ for module_type in module_types:
373
+ module_base = module_type.split("/")[0]
374
+ init_source = os.path.join(modules_dir, module_base, "__init__.py-tpl")
375
+
376
+ if os.path.exists(init_source):
377
+ init_target_dir = target_dirs.get(module_base, None) or target_dirs.get(
378
+ f"{module_base}_routes"
379
+ )
380
+ if init_target_dir:
381
+ init_target = os.path.join(init_target_dir, "__init__.py")
382
+ if not os.path.exists(init_target):
383
+ copy_and_convert_template_file(init_source, init_target)
384
+
385
+
386
+ def _update_main_app(src_dir: str, route_name: str) -> None:
387
+ """
388
+ Update the main application file to include the API router.
389
+ Adds the router import and include statement at the end of the file.
390
+
391
+ :param src_dir: Source directory of the project
392
+ :param route_name: Name of the route to add
393
+ """
394
+ main_py_path = os.path.join(src_dir, "main.py")
395
+ if not os.path.exists(main_py_path):
396
+ print_warning("main.py not found. Please manually add the API router.")
397
+ return
398
+
399
+ with open(main_py_path, "r") as f:
400
+ main_content = f.read()
401
+
402
+ # Check if router is already imported or included
403
+ router_import = "from src.api.api import api_router"
404
+ router_include = "app.include_router(api_router"
405
+
406
+ if router_import in main_content and router_include in main_content:
407
+ # Router already fully configured, nothing to do
408
+ return
409
+
410
+ # Check if FastAPI app is defined
411
+ if "app = FastAPI" not in main_content:
412
+ print_warning(
413
+ "FastAPI app instance not found in main.py. Please manually add router."
414
+ )
415
+ return
416
+
417
+ # Add the router import if needed
418
+ if router_import not in main_content:
419
+ # Add import at the end of imports section or beginning of file
420
+ lines = main_content.split("\n")
421
+
422
+ # Find last import line
423
+ last_import_idx = -1
424
+ for i, line in enumerate(lines):
425
+ if line.startswith("import ") or line.startswith("from "):
426
+ last_import_idx = i
427
+
428
+ if last_import_idx >= 0:
429
+ # Insert after the last import
430
+ lines.insert(last_import_idx + 1, router_import)
431
+ else:
432
+ # Insert at the beginning
433
+ lines.insert(0, router_import)
434
+
435
+ main_content = "\n".join(lines)
436
+
437
+ # Add the router include
438
+ if router_include not in main_content:
439
+ if not main_content.endswith("\n"):
440
+ main_content += "\n"
441
+
442
+ main_content += f"\n# Include API router\napp.include_router(api_router)\n"
443
+
444
+ # Write the updated content back to the file
445
+ with open(main_py_path, "w") as f:
446
+ f.write(main_content)
447
+
448
+ print_info("Updated main.py to include the API router")
449
+
450
+
451
+ def add_new_route(project_dir: str, route_name: str) -> None:
452
+ """
453
+ Add a new API route to an existing FastAPI project.
454
+
455
+ :param project_dir: Path to the project directory
456
+ :param route_name: Name of the new route to add
457
+ :return: None
458
+ """
459
+ try:
460
+ # Setup paths
461
+ modules_dir = os.path.join(settings.FASTKIT_TEMPLATE_ROOT, "modules")
462
+ src_dir = os.path.join(project_dir, "src")
463
+
464
+ # Ensure project structure exists
465
+ target_dirs = _ensure_project_structure(src_dir)
466
+
467
+ # Create route files
468
+ _create_route_files(modules_dir, target_dirs, route_name)
469
+
470
+ # Handle API router file
471
+ _handle_api_router_file(target_dirs, modules_dir, route_name)
472
+
473
+ # Process init files
474
+ module_types = ["api/routes", "crud", "schemas"]
475
+ _process_init_files(modules_dir, target_dirs, module_types)
476
+
477
+ # Update main application
478
+ _update_main_app(src_dir, route_name)
479
+
480
+ except Exception as e:
481
+ handle_exception(e, f"Error adding new route: {str(e)}")
482
+ raise BackendExceptions(f"Failed to add new route: {str(e)}")