FastAPI-fastkit 0.1.1__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 -1
- fastapi_fastkit/backend/main.py +363 -72
- fastapi_fastkit/backend/transducer.py +36 -0
- fastapi_fastkit/cli.py +230 -43
- fastapi_fastkit/core/settings.py +12 -2
- fastapi_fastkit/fastapi_project_template/README.md +20 -1
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/.env-tpl +1 -0
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/.gitignore-tpl +28 -189
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/README.md-tpl +102 -12
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/requirements.txt-tpl +27 -38
- 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 +7 -6
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/setup.py-tpl +13 -23
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/__init__.py-tpl +0 -88
- 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/mock_items.json-tpl +8 -0
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/schemas/__init__.py-tpl +0 -48
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/schemas/items.py-tpl +22 -0
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/tests/conftest.py-tpl +33 -13
- 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/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-async-crud → fastapi-custom-response}/src/helper/exceptions.py-tpl +12 -3
- fastapi_fastkit/fastapi_project_template/{fastapi-async-crud → 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-async-crud → 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/README.md-tpl +85 -9
- fastapi_fastkit/fastapi_project_template/fastapi-default/scripts/run-server.sh-tpl +8 -0
- fastapi_fastkit/fastapi_project_template/fastapi-default/setup.py-tpl +1 -1
- fastapi_fastkit/fastapi_project_template/fastapi-default/src/mocks/mock_items.json-tpl +2 -2
- fastapi_fastkit/fastapi_project_template/fastapi-default/tests/conftest.py-tpl +15 -0
- fastapi_fastkit/fastapi_project_template/fastapi-default/tests/test_items.py-tpl +6 -24
- 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/main.py +51 -5
- fastapi_fastkit-1.0.0.dist-info/METADATA +208 -0
- fastapi_fastkit-1.0.0.dist-info/RECORD +189 -0
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/.env.test-tpl +0 -3
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/main.py-tpl +0 -21
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/script/run-server.sh-tpl +0 -2
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/script/run-test.sh-tpl +0 -2
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/core/settings.py-tpl +0 -96
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/crud/_base.py-tpl +0 -92
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/crud/user.py-tpl +0 -44
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/helper/global_data.py-tpl +0 -33
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/helper/logging.py-tpl +0 -25
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/mocks/mock_users.json-tpl +0 -17
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/router/__init__.py-tpl +0 -48
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/router/user.py-tpl +0 -126
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/schemas/user.py-tpl +0 -81
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/templates/index.html-tpl +0 -27
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/tests/routes/test_user.py-tpl +0 -112
- fastapi_fastkit-0.1.1.dist-info/METADATA +0 -173
- fastapi_fastkit-0.1.1.dist-info/RECORD +0 -84
- /fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/{helper → api}/__init__.py-tpl +0 -0
- /fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/{utils → api/routes}/__init__.py-tpl +0 -0
- /fastapi_fastkit/fastapi_project_template/{fastapi-async-crud/tests/routes → fastapi-custom-response/src}/__init__.py-tpl +0 -0
- /fastapi_fastkit/fastapi_project_template/{fastapi-customized-response/README.md-tpl → fastapi-custom-response/src/api/__init__.py-tpl} +0 -0
- {fastapi_fastkit-0.1.1.dist-info → fastapi_fastkit-1.0.0.dist-info}/WHEEL +0 -0
- {fastapi_fastkit-0.1.1.dist-info → fastapi_fastkit-1.0.0.dist-info}/entry_points.txt +0 -0
- {fastapi_fastkit-0.1.1.dist-info → fastapi_fastkit-1.0.0.dist-info}/licenses/LICENSE +0 -0
fastapi_fastkit/__init__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = '
|
|
1
|
+
__version__ = 'v1.0.0'
|
fastapi_fastkit/backend/main.py
CHANGED
|
@@ -5,17 +5,32 @@
|
|
|
5
5
|
# --------------------------------------------------------------------------
|
|
6
6
|
import os
|
|
7
7
|
import subprocess
|
|
8
|
+
from typing import Dict, List
|
|
8
9
|
|
|
9
10
|
from fastapi_fastkit import console
|
|
11
|
+
from fastapi_fastkit.backend.transducer import copy_and_convert_template_file
|
|
10
12
|
from fastapi_fastkit.core.exceptions import BackendExceptions, TemplateExceptions
|
|
11
13
|
from fastapi_fastkit.core.settings import settings
|
|
12
|
-
from fastapi_fastkit.utils.main import
|
|
14
|
+
from fastapi_fastkit.utils.main import (
|
|
15
|
+
handle_exception,
|
|
16
|
+
print_error,
|
|
17
|
+
print_info,
|
|
18
|
+
print_success,
|
|
19
|
+
print_warning,
|
|
20
|
+
)
|
|
13
21
|
|
|
22
|
+
# ------------------------------------------------------------
|
|
23
|
+
# Template Discovery Functions
|
|
24
|
+
# ------------------------------------------------------------
|
|
14
25
|
|
|
15
|
-
|
|
26
|
+
|
|
27
|
+
def find_template_core_modules(project_dir: str) -> Dict[str, str]:
|
|
16
28
|
"""
|
|
17
29
|
Find core module files in the template project structure.
|
|
18
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
|
|
19
34
|
"""
|
|
20
35
|
core_modules = {"main": "", "setup": "", "config": ""}
|
|
21
36
|
template_config = settings.TEMPLATE_PATHS["config"]
|
|
@@ -34,7 +49,7 @@ def find_template_core_modules(project_dir: str) -> dict[str, str]:
|
|
|
34
49
|
core_modules["setup"] = full_path
|
|
35
50
|
break
|
|
36
51
|
|
|
37
|
-
# Find config files
|
|
52
|
+
# Find config files
|
|
38
53
|
if isinstance(template_config, dict):
|
|
39
54
|
for config_file in template_config.get("files", []):
|
|
40
55
|
for base_path in template_config.get("paths", []):
|
|
@@ -48,6 +63,48 @@ def find_template_core_modules(project_dir: str) -> dict[str, str]:
|
|
|
48
63
|
return core_modules
|
|
49
64
|
|
|
50
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
|
+
|
|
51
108
|
def inject_project_metadata(
|
|
52
109
|
target_dir: str,
|
|
53
110
|
project_name: str,
|
|
@@ -60,42 +117,54 @@ def inject_project_metadata(
|
|
|
60
117
|
"""
|
|
61
118
|
try:
|
|
62
119
|
core_modules = find_template_core_modules(target_dir)
|
|
120
|
+
setup_py = core_modules.get("setup", "")
|
|
121
|
+
config_py = core_modules.get("config", "")
|
|
63
122
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
with open(core_modules["main"], "r+") as f:
|
|
123
|
+
if setup_py and os.path.exists(setup_py):
|
|
124
|
+
with open(setup_py, "r") as f:
|
|
67
125
|
content = f.read()
|
|
68
|
-
content = content.replace("app_title", f'"{project_name}"')
|
|
69
|
-
content = content.replace("app_description", f'"{description}"')
|
|
70
|
-
f.seek(0)
|
|
71
|
-
f.write(content)
|
|
72
|
-
f.truncate()
|
|
73
126
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
content = content.replace("<author_email>", author_email, 1)
|
|
82
|
-
f.seek(0)
|
|
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:
|
|
83
134
|
f.write(content)
|
|
84
|
-
|
|
135
|
+
print_info("Injected metadata into setup.py")
|
|
85
136
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
with open(core_modules["config"], "r+") as f:
|
|
137
|
+
if config_py and os.path.exists(config_py):
|
|
138
|
+
with open(config_py, "r") as f:
|
|
89
139
|
content = f.read()
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
140
|
+
|
|
141
|
+
content = content.replace("<project_name>", project_name)
|
|
142
|
+
|
|
143
|
+
with open(config_py, "w") as f:
|
|
93
144
|
f.write(content)
|
|
94
|
-
|
|
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
|
|
95
164
|
|
|
96
165
|
except Exception as e:
|
|
97
|
-
|
|
98
|
-
raise
|
|
166
|
+
handle_exception(e, "Failed to inject project metadata")
|
|
167
|
+
raise BackendExceptions("Failed to inject project metadata")
|
|
99
168
|
|
|
100
169
|
|
|
101
170
|
def create_venv(project_dir: str) -> str:
|
|
@@ -125,67 +194,289 @@ def create_venv(project_dir: str) -> str:
|
|
|
125
194
|
|
|
126
195
|
|
|
127
196
|
def install_dependencies(project_dir: str, venv_path: str) -> None:
|
|
128
|
-
"""
|
|
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
|
+
"""
|
|
129
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
|
+
|
|
130
216
|
if os.name == "nt": # Windows
|
|
131
217
|
pip_path = os.path.join(venv_path, "Scripts", "pip")
|
|
132
|
-
else: #
|
|
218
|
+
else: # Unix-based
|
|
133
219
|
pip_path = os.path.join(venv_path, "bin", "pip")
|
|
134
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
|
+
|
|
135
229
|
with console.status("[bold green]Installing dependencies..."):
|
|
136
230
|
subprocess.run(
|
|
137
231
|
[pip_path, "install", "-r", "requirements.txt"],
|
|
138
232
|
cwd=project_dir,
|
|
139
233
|
check=True,
|
|
140
234
|
)
|
|
141
|
-
if os.name == "nt":
|
|
142
|
-
activate_venv = f" {os.path.join(venv_path, 'Scripts', 'activate.bat')}"
|
|
143
|
-
else:
|
|
144
|
-
activate_venv = f" source {os.path.join(venv_path, 'bin', 'activate')}"
|
|
145
235
|
|
|
146
|
-
|
|
147
|
-
"Dependencies installed successfully."
|
|
148
|
-
+ "\nTo activate the virtual environment, run:\n\n"
|
|
149
|
-
+ activate_venv,
|
|
150
|
-
)
|
|
236
|
+
print_success("Dependencies installed successfully")
|
|
151
237
|
|
|
152
|
-
except
|
|
153
|
-
|
|
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}")
|
|
154
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)}")
|
|
155
246
|
|
|
156
247
|
|
|
157
|
-
|
|
248
|
+
# ------------------------------------------------------------
|
|
249
|
+
# Add Route Functions
|
|
250
|
+
# ------------------------------------------------------------
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def _ensure_project_structure(src_dir: str) -> Dict[str, str]:
|
|
158
254
|
"""
|
|
159
|
-
|
|
160
|
-
|
|
255
|
+
Ensure the project structure exists for adding a new route.
|
|
256
|
+
Creates necessary directories if they don't exist.
|
|
161
257
|
|
|
162
|
-
:param
|
|
163
|
-
:return:
|
|
258
|
+
:param src_dir: Source directory of the project
|
|
259
|
+
:return: Dictionary with paths to target directories
|
|
164
260
|
"""
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
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
|
+
}
|
|
168
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
|
+
"""
|
|
169
459
|
try:
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
if "install_requires: list[str] = [" in content:
|
|
174
|
-
start_idx = content.find("install_requires: list[str] = [") + len(
|
|
175
|
-
"install_requires: list[str] = ["
|
|
176
|
-
)
|
|
177
|
-
end_idx = content.find("]", start_idx)
|
|
178
|
-
if start_idx != -1 and end_idx != -1:
|
|
179
|
-
deps_str = content[start_idx:end_idx]
|
|
180
|
-
# Clean and parse the dependencies
|
|
181
|
-
deps = [
|
|
182
|
-
dep.strip().strip("'").strip('"')
|
|
183
|
-
for dep in deps_str.split(",")
|
|
184
|
-
if dep.strip() and not dep.isspace()
|
|
185
|
-
]
|
|
186
|
-
return [dep for dep in deps if dep] # Remove empty strings
|
|
187
|
-
except Exception as e:
|
|
188
|
-
print_error(f"Error reading template dependencies: {e}")
|
|
189
|
-
return []
|
|
460
|
+
# Setup paths
|
|
461
|
+
modules_dir = os.path.join(settings.FASTKIT_TEMPLATE_ROOT, "modules")
|
|
462
|
+
src_dir = os.path.join(project_dir, "src")
|
|
190
463
|
|
|
191
|
-
|
|
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)}")
|
|
@@ -64,6 +64,42 @@ def copy_and_convert_template(
|
|
|
64
64
|
shutil.copy2(src_file, dst_file)
|
|
65
65
|
|
|
66
66
|
|
|
67
|
+
def copy_and_convert_template_file(
|
|
68
|
+
source_file: str, target_file: str, replacements: dict = None # type: ignore
|
|
69
|
+
) -> bool:
|
|
70
|
+
"""
|
|
71
|
+
Copies a single template file to the target location, converting it from .*-tpl
|
|
72
|
+
to its proper extension and replacing any placeholders with provided values.
|
|
73
|
+
|
|
74
|
+
:param source_file: Path to the source template file (with -tpl extension)
|
|
75
|
+
:param target_file: Path to target destination file (without -tpl extension)
|
|
76
|
+
:param replacements: Dictionary of placeholder replacements {placeholder: value}
|
|
77
|
+
:return: True if successful, False otherwise
|
|
78
|
+
"""
|
|
79
|
+
try:
|
|
80
|
+
if not os.path.exists(source_file):
|
|
81
|
+
return False
|
|
82
|
+
|
|
83
|
+
# Read a single source content (with .py-tpl extension)
|
|
84
|
+
with open(source_file, "r") as src_file:
|
|
85
|
+
content = src_file.read()
|
|
86
|
+
|
|
87
|
+
if replacements and isinstance(replacements, dict):
|
|
88
|
+
for placeholder, value in replacements.items():
|
|
89
|
+
content = content.replace(placeholder, value)
|
|
90
|
+
|
|
91
|
+
target_dir = os.path.dirname(target_file)
|
|
92
|
+
os.makedirs(target_dir, exist_ok=True)
|
|
93
|
+
|
|
94
|
+
with open(target_file, "w") as tgt_file:
|
|
95
|
+
tgt_file.write(content)
|
|
96
|
+
|
|
97
|
+
return True
|
|
98
|
+
except Exception as e:
|
|
99
|
+
print(f"Error copying template file: {e}")
|
|
100
|
+
return False
|
|
101
|
+
|
|
102
|
+
|
|
67
103
|
def _convert_real_extension_to_tpl() -> None:
|
|
68
104
|
# TODO : impl this for converting runnable FastAPI app code to template - debugging operation for contributors
|
|
69
105
|
# this will be used at inspector module, not package user's runtime.
|