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.
- fastapi_fastkit/__init__.py +1 -10
- fastapi_fastkit/backend/inspector.py +203 -0
- fastapi_fastkit/backend/main.py +482 -0
- fastapi_fastkit/{utils → backend}/transducer.py +36 -0
- fastapi_fastkit/cli.py +286 -87
- fastapi_fastkit/core/settings.py +48 -0
- fastapi_fastkit/fastapi_project_template/README.md +74 -4
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/.env-tpl +1 -0
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/.gitignore-tpl +30 -0
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/README.md-tpl +107 -0
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/requirements.txt-tpl +36 -0
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/scripts/format.sh-tpl +5 -0
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/scripts/lint.sh-tpl +5 -0
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/scripts/run-server.sh-tpl +8 -0
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/scripts/test.sh-tpl +6 -0
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/setup.cfg-tpl +14 -0
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/setup.py-tpl +25 -0
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/api/api.py-tpl +9 -0
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/api/routes/items.py-tpl +57 -0
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/core/config.py-tpl +64 -0
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/crud/items.py-tpl +21 -0
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/main.py-tpl +26 -0
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/mocks/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/mocks/mock_items.json-tpl +8 -0
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/schemas/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/schemas/items.py-tpl +22 -0
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/tests/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/tests/conftest.py-tpl +42 -0
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/tests/test_items.py-tpl +48 -0
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/.env-tpl +1 -0
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/.gitignore-tpl +191 -0
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/README.md-tpl +156 -0
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/requirements.txt-tpl +36 -0
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/scripts/format.sh-tpl +5 -0
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/scripts/lint.sh-tpl +5 -0
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/scripts/run-server.sh-tpl +8 -0
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/scripts/test.sh-tpl +6 -0
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/setup.cfg-tpl +12 -0
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/setup.py-tpl +27 -0
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/api/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/api/api.py-tpl +9 -0
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/api/routes/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/api/routes/items.py-tpl +172 -0
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/core/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/core/config.py-tpl +64 -0
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/crud/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/crud/items.py-tpl +21 -0
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/helper/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/{fastapi-default → fastapi-custom-response}/src/helper/exceptions.py-tpl +12 -3
- fastapi_fastkit/fastapi_project_template/{fastapi-default → fastapi-custom-response}/src/helper/pagination.py-tpl +3 -2
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/main.py-tpl +39 -0
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/mocks/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/mocks/mock_items.json-tpl +8 -0
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/schemas/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/schemas/base.py-tpl +49 -0
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/schemas/items.py-tpl +22 -0
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/utils/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/{fastapi-default → fastapi-custom-response}/src/utils/documents.py-tpl +1 -1
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/tests/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/tests/conftest.py-tpl +42 -0
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/tests/test_items.py-tpl +61 -0
- fastapi_fastkit/fastapi_project_template/fastapi-default/.env-tpl +1 -0
- fastapi_fastkit/fastapi_project_template/fastapi-default/.gitignore-tpl +28 -189
- fastapi_fastkit/fastapi_project_template/fastapi-default/README.md-tpl +95 -11
- fastapi_fastkit/fastapi_project_template/fastapi-default/requirements.txt-tpl +25 -38
- fastapi_fastkit/fastapi_project_template/fastapi-default/scripts/format.sh-tpl +5 -0
- fastapi_fastkit/fastapi_project_template/fastapi-default/scripts/lint.sh-tpl +5 -0
- fastapi_fastkit/fastapi_project_template/fastapi-default/scripts/run-server.sh-tpl +8 -0
- fastapi_fastkit/fastapi_project_template/fastapi-default/scripts/test.sh-tpl +6 -0
- fastapi_fastkit/fastapi_project_template/fastapi-default/setup.cfg-tpl +5 -5
- fastapi_fastkit/fastapi_project_template/fastapi-default/setup.py-tpl +10 -23
- fastapi_fastkit/fastapi_project_template/fastapi-default/src/__init__.py-tpl +0 -88
- fastapi_fastkit/fastapi_project_template/fastapi-default/src/api/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-default/src/api/api.py-tpl +9 -0
- fastapi_fastkit/fastapi_project_template/fastapi-default/src/api/routes/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-default/src/api/routes/items.py-tpl +57 -0
- fastapi_fastkit/fastapi_project_template/fastapi-default/src/core/config.py-tpl +64 -0
- fastapi_fastkit/fastapi_project_template/fastapi-default/src/crud/items.py-tpl +18 -0
- fastapi_fastkit/fastapi_project_template/fastapi-default/src/main.py-tpl +26 -0
- fastapi_fastkit/fastapi_project_template/fastapi-default/src/mocks/mock_items.json-tpl +8 -0
- fastapi_fastkit/fastapi_project_template/fastapi-default/src/schemas/__init__.py-tpl +0 -48
- fastapi_fastkit/fastapi_project_template/fastapi-default/src/schemas/items.py-tpl +22 -0
- fastapi_fastkit/fastapi_project_template/fastapi-default/tests/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-default/tests/conftest.py-tpl +30 -0
- fastapi_fastkit/fastapi_project_template/fastapi-default/tests/test_items.py-tpl +44 -0
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/.env-tpl +1 -0
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/.gitignore-tpl +30 -0
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/Dockerfile-tpl +23 -0
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/README.md-tpl +119 -0
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/requirements.txt-tpl +36 -0
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/scripts/format.sh-tpl +5 -0
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/scripts/lint.sh-tpl +5 -0
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/scripts/run-server.sh-tpl +8 -0
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/scripts/test.sh-tpl +6 -0
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/setup.cfg-tpl +13 -0
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/setup.py-tpl +22 -0
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/api/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/api/api.py-tpl +6 -0
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/api/routes/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/api/routes/items.py-tpl +54 -0
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/core/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/core/config.py-tpl +64 -0
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/crud/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/crud/items.py-tpl +15 -0
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/main.py-tpl +26 -0
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/mocks/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/mocks/mock_items.json-tpl +8 -0
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/schemas/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/schemas/items.py-tpl +19 -0
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/tests/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/tests/conftest.py-tpl +30 -0
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/tests/test_items.py-tpl +44 -0
- fastapi_fastkit/fastapi_project_template/fastapi-empty/.env-tpl +1 -0
- fastapi_fastkit/fastapi_project_template/fastapi-empty/setup.py-tpl +22 -0
- fastapi_fastkit/fastapi_project_template/fastapi-empty/src/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-empty/src/core/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-empty/src/core/config.py-tpl +75 -0
- fastapi_fastkit/fastapi_project_template/fastapi-empty/src/main.py-tpl +36 -0
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/.env-tpl +9 -0
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/.gitignore-tpl +30 -0
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/Dockerfile-tpl +23 -0
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/README.md-tpl +144 -0
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/alembic.ini-tpl +119 -0
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/docker-compose.yml-tpl +44 -0
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/requirements.txt-tpl +41 -0
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/scripts/format.sh-tpl +5 -0
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/scripts/lint.sh-tpl +5 -0
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/scripts/pre-start.sh-tpl +16 -0
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/scripts/run-server.sh-tpl +8 -0
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/scripts/test.sh-tpl +10 -0
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/setup.cfg-tpl +13 -0
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/setup.py-tpl +25 -0
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/alembic/README-tpl +1 -0
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/alembic/env.py-tpl +85 -0
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/alembic/script.py.mako-tpl +26 -0
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/alembic/versions/bedcdc35b64a_first_alembic.py-tpl +37 -0
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/api/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/api/api.py-tpl +11 -0
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/api/deps.py-tpl +19 -0
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/api/routes/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/api/routes/items.py-tpl +109 -0
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/core/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/core/config.py-tpl +88 -0
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/core/db.py-tpl +53 -0
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/crud/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/crud/items.py-tpl +102 -0
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/main.py-tpl +45 -0
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/schemas/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/schemas/items.py-tpl +54 -0
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/utils/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/utils/backend_pre_start.py-tpl +39 -0
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/utils/init_data.py-tpl +23 -0
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/utils/tests_pre_start.py-tpl +39 -0
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/tests/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/tests/conftest.py-tpl +63 -0
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/tests/test_items.py-tpl +44 -0
- fastapi_fastkit/fastapi_project_template/modules/api/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/modules/api/routes/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/modules/api/routes/new_route.py-tpl +64 -0
- fastapi_fastkit/fastapi_project_template/modules/crud/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/modules/crud/new_route.py-tpl +29 -0
- fastapi_fastkit/fastapi_project_template/modules/schemas/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/modules/schemas/new_route.py-tpl +23 -0
- fastapi_fastkit/utils/logging.py +4 -1
- fastapi_fastkit/utils/main.py +129 -0
- fastapi_fastkit-1.0.0.dist-info/METADATA +208 -0
- fastapi_fastkit-1.0.0.dist-info/RECORD +189 -0
- {fastapi_fastkit-0.1.0.dist-info → fastapi_fastkit-1.0.0.dist-info}/licenses/LICENSE +21 -21
- fastapi_fastkit/backend.py +0 -112
- fastapi_fastkit/fastapi_project_template/fastapi-default/.env.test-tpl +0 -3
- fastapi_fastkit/fastapi_project_template/fastapi-default/main.py-tpl +0 -21
- fastapi_fastkit/fastapi_project_template/fastapi-default/script/run-server.sh-tpl +0 -2
- fastapi_fastkit/fastapi_project_template/fastapi-default/script/run-test.sh-tpl +0 -2
- fastapi_fastkit/fastapi_project_template/fastapi-default/src/.DS_Store +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-default/src/core/settings.py-tpl +0 -96
- fastapi_fastkit/fastapi_project_template/fastapi-default/src/crud/_base.py-tpl +0 -92
- fastapi_fastkit/fastapi_project_template/fastapi-default/src/crud/user.py-tpl +0 -44
- fastapi_fastkit/fastapi_project_template/fastapi-default/src/helper/global_data.py-tpl +0 -33
- fastapi_fastkit/fastapi_project_template/fastapi-default/src/helper/logging.py-tpl +0 -25
- fastapi_fastkit/fastapi_project_template/fastapi-default/src/mocks/mock_users.json-tpl +0 -17
- fastapi_fastkit/fastapi_project_template/fastapi-default/src/router/__init__.py-tpl +0 -48
- fastapi_fastkit/fastapi_project_template/fastapi-default/src/router/user.py-tpl +0 -126
- fastapi_fastkit/fastapi_project_template/fastapi-default/src/schemas/user.py-tpl +0 -81
- fastapi_fastkit/fastapi_project_template/fastapi-default/src/templates/index.html-tpl +0 -27
- fastapi_fastkit/fastapi_project_template/fastapi-default/test/conftest.py-tpl +0 -22
- fastapi_fastkit/fastapi_project_template/fastapi-default/test/routes/test_user.py-tpl +0 -112
- fastapi_fastkit/utils/inspector.py +0 -15
- fastapi_fastkit-0.1.0.dist-info/METADATA +0 -46
- fastapi_fastkit-0.1.0.dist-info/RECORD +0 -56
- /fastapi_fastkit/{fastapi_project_template/fastapi-default/src/helper/__init__.py-tpl → backend/__init__.py} +0 -0
- /fastapi_fastkit/fastapi_project_template/{fastapi-default/src/utils → fastapi-async-crud/src}/__init__.py-tpl +0 -0
- /fastapi_fastkit/fastapi_project_template/{fastapi-default/test → fastapi-async-crud/src/api}/__init__.py-tpl +0 -0
- /fastapi_fastkit/fastapi_project_template/{fastapi-default/test → fastapi-async-crud/src/api}/routes/__init__.py-tpl +0 -0
- /fastapi_fastkit/fastapi_project_template/{fastapi-dockerized → fastapi-async-crud/src/core}/__init__.py-tpl +0 -0
- /fastapi_fastkit/fastapi_project_template/{fastapi-psql-orm → fastapi-async-crud/src/crud}/__init__.py-tpl +0 -0
- {fastapi_fastkit-0.1.0.dist-info → fastapi_fastkit-1.0.0.dist-info}/WHEEL +0 -0
- {fastapi_fastkit-0.1.0.dist-info → fastapi_fastkit-1.0.0.dist-info}/entry_points.txt +0 -0
fastapi_fastkit/__init__.py
CHANGED
|
@@ -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)}")
|