FastAPI-fastkit 1.0.2__py3-none-any.whl → 1.1.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 +933 -83
- fastapi_fastkit/backend/main.py +640 -482
- fastapi_fastkit/backend/package_managers/__init__.py +22 -0
- fastapi_fastkit/backend/package_managers/base.py +150 -0
- fastapi_fastkit/backend/package_managers/factory.py +151 -0
- fastapi_fastkit/backend/package_managers/pdm_manager.py +275 -0
- fastapi_fastkit/backend/package_managers/pip_manager.py +205 -0
- fastapi_fastkit/backend/package_managers/poetry_manager.py +378 -0
- fastapi_fastkit/backend/package_managers/uv_manager.py +327 -0
- fastapi_fastkit/backend/transducer.py +210 -106
- fastapi_fastkit/cli.py +702 -664
- fastapi_fastkit/core/exceptions.py +14 -3
- fastapi_fastkit/core/settings.py +181 -155
- fastapi_fastkit/fastapi_project_template/README.md +90 -90
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/.env-tpl +1 -1
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/.gitignore-tpl +30 -30
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/README.md-tpl +107 -107
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/requirements.txt-tpl +36 -36
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/scripts/format.sh-tpl +5 -5
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/scripts/lint.sh-tpl +5 -5
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/scripts/run-server.sh-tpl +8 -8
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/scripts/test.sh-tpl +6 -6
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/setup.cfg-tpl +14 -14
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/setup.py-tpl +25 -25
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/api/api.py-tpl +9 -9
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/api/routes/items.py-tpl +57 -57
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/core/config.py-tpl +64 -64
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/crud/items.py-tpl +21 -21
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/main.py-tpl +26 -26
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/mocks/mock_items.json-tpl +8 -8
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/schemas/items.py-tpl +22 -22
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/tests/conftest.py-tpl +42 -42
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/tests/test_items.py-tpl +48 -48
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/.env-tpl +1 -1
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/.gitignore-tpl +191 -191
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/README.md-tpl +156 -156
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/requirements.txt-tpl +36 -36
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/scripts/format.sh-tpl +5 -5
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/scripts/lint.sh-tpl +5 -5
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/scripts/run-server.sh-tpl +8 -8
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/scripts/test.sh-tpl +6 -6
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/setup.cfg-tpl +12 -12
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/setup.py-tpl +27 -27
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/api/api.py-tpl +9 -9
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/api/routes/items.py-tpl +172 -172
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/core/config.py-tpl +64 -64
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/crud/items.py-tpl +21 -21
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/helper/exceptions.py-tpl +103 -103
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/helper/pagination.py-tpl +72 -72
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/main.py-tpl +39 -39
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/mocks/mock_items.json-tpl +8 -8
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/schemas/base.py-tpl +49 -49
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/schemas/items.py-tpl +22 -22
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/utils/documents.py-tpl +20 -20
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/tests/conftest.py-tpl +42 -42
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/tests/test_items.py-tpl +61 -61
- fastapi_fastkit/fastapi_project_template/fastapi-default/README.md-tpl +101 -101
- fastapi_fastkit/fastapi_project_template/fastapi-default/scripts/run-server.sh-tpl +8 -8
- fastapi_fastkit/fastapi_project_template/fastapi-default/setup.py-tpl +22 -22
- fastapi_fastkit/fastapi_project_template/fastapi-default/src/mocks/mock_items.json-tpl +8 -8
- fastapi_fastkit/fastapi_project_template/fastapi-default/tests/conftest.py-tpl +30 -30
- fastapi_fastkit/fastapi_project_template/fastapi-default/tests/test_items.py-tpl +44 -44
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/.env-tpl +1 -1
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/.gitignore-tpl +30 -30
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/Dockerfile-tpl +23 -23
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/README.md-tpl +119 -119
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/requirements.txt-tpl +36 -36
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/scripts/format.sh-tpl +5 -5
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/scripts/lint.sh-tpl +5 -5
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/scripts/run-server.sh-tpl +8 -8
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/scripts/test.sh-tpl +6 -6
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/setup.cfg-tpl +13 -13
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/setup.py-tpl +22 -22
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/api/api.py-tpl +6 -6
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/api/routes/items.py-tpl +54 -54
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/core/config.py-tpl +64 -64
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/crud/items.py-tpl +15 -15
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/main.py-tpl +26 -26
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/mocks/mock_items.json-tpl +8 -8
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/schemas/items.py-tpl +19 -19
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/tests/conftest.py-tpl +30 -30
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/tests/test_items.py-tpl +44 -44
- fastapi_fastkit/fastapi_project_template/fastapi-empty/.env-tpl +1 -1
- fastapi_fastkit/fastapi_project_template/fastapi-empty/.gitignore-tpl +30 -0
- fastapi_fastkit/fastapi_project_template/fastapi-empty/README.md-tpl +85 -0
- fastapi_fastkit/fastapi_project_template/fastapi-empty/requirements.txt-tpl +9 -0
- fastapi_fastkit/fastapi_project_template/fastapi-empty/setup.cfg-tpl +13 -0
- fastapi_fastkit/fastapi_project_template/fastapi-empty/setup.py-tpl +22 -22
- fastapi_fastkit/fastapi_project_template/fastapi-empty/src/core/config.py-tpl +75 -75
- fastapi_fastkit/fastapi_project_template/fastapi-empty/src/main.py-tpl +48 -36
- fastapi_fastkit/fastapi_project_template/fastapi-empty/tests/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-empty/tests/conftest.py-tpl +16 -0
- fastapi_fastkit/fastapi_project_template/fastapi-empty/tests/test_main.py-tpl +37 -0
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/.env-tpl +29 -0
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/README.md-tpl +249 -0
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/requirements.txt-tpl +40 -0
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/scripts/format.sh-tpl +12 -0
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/scripts/lint.sh-tpl +18 -0
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/scripts/run-server.sh-tpl +9 -0
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/scripts/test.sh-tpl +9 -0
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/setup.cfg-tpl +90 -0
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/setup.py-tpl +51 -0
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/src/__init__.py-tpl +4 -0
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/src/api/__init__.py-tpl +3 -0
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/src/api/api.py-tpl +14 -0
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/src/api/routes/__init__.py-tpl +3 -0
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/src/api/routes/auth.py-tpl +134 -0
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/src/api/routes/items.py-tpl +189 -0
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/src/auth/__init__.py-tpl +3 -0
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/src/auth/dependencies.py-tpl +88 -0
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/src/core/__init__.py-tpl +3 -0
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/src/core/config.py-tpl +60 -0
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/src/main.py-tpl +66 -0
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/src/mcp/__init__.py-tpl +3 -0
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/src/mcp/router.py-tpl +100 -0
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/src/schemas/__init__.py-tpl +3 -0
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/src/schemas/items.py-tpl +67 -0
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/tests/__init__.py-tpl +3 -0
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/tests/conftest.py-tpl +49 -0
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/tests/test_auth.py-tpl +101 -0
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/tests/test_items.py-tpl +96 -0
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/tests/test_mcp.py-tpl +81 -0
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/.env-tpl +9 -9
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/.gitignore-tpl +30 -30
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/Dockerfile-tpl +23 -23
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/README.md-tpl +144 -144
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/alembic.ini-tpl +119 -119
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/docker-compose.yml-tpl +44 -44
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/requirements.txt-tpl +41 -41
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/scripts/format.sh-tpl +5 -5
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/scripts/lint.sh-tpl +5 -5
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/scripts/pre-start.sh-tpl +16 -16
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/scripts/run-server.sh-tpl +8 -8
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/scripts/test.sh-tpl +10 -10
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/setup.cfg-tpl +13 -13
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/setup.py-tpl +25 -25
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/alembic/README-tpl +1 -1
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/alembic/env.py-tpl +85 -85
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/alembic/script.py.mako-tpl +26 -26
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/alembic/versions/bedcdc35b64a_first_alembic.py-tpl +37 -37
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/api/api.py-tpl +11 -11
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/api/deps.py-tpl +19 -19
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/api/routes/items.py-tpl +109 -109
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/core/config.py-tpl +88 -88
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/core/db.py-tpl +53 -53
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/crud/items.py-tpl +102 -102
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/main.py-tpl +45 -45
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/schemas/items.py-tpl +54 -54
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/utils/backend_pre_start.py-tpl +39 -39
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/utils/init_data.py-tpl +23 -23
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/utils/tests_pre_start.py-tpl +39 -39
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/template-config.yml-tpl +24 -0
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/tests/conftest.py-tpl +63 -63
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/tests/test_items.py-tpl +44 -44
- fastapi_fastkit/fastapi_project_template/modules/api/routes/new_route.py-tpl +64 -64
- fastapi_fastkit/fastapi_project_template/modules/crud/new_route.py-tpl +29 -29
- fastapi_fastkit/fastapi_project_template/modules/schemas/new_route.py-tpl +23 -23
- fastapi_fastkit/utils/logging.py +64 -28
- fastapi_fastkit/utils/main.py +180 -140
- fastapi_fastkit-1.1.0.dist-info/METADATA +182 -0
- {fastapi_fastkit-1.0.2.dist-info → fastapi_fastkit-1.1.0.dist-info}/RECORD +165 -129
- {fastapi_fastkit-1.0.2.dist-info → fastapi_fastkit-1.1.0.dist-info}/WHEEL +1 -1
- {fastapi_fastkit-1.0.2.dist-info → fastapi_fastkit-1.1.0.dist-info}/licenses/LICENSE +21 -21
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/.DS_Store +0 -0
- fastapi_fastkit/logs/fastkit_debug_20250702_161423.log +0 -21
- fastapi_fastkit/logs/fastkit_debug_20250702_162706.log +0 -20
- fastapi_fastkit/logs/fastkit_debug_20250702_163010.log +0 -21
- fastapi_fastkit/logs/fastkit_debug_20250702_163526.log +0 -21
- fastapi_fastkit/logs/fastkit_debug_20250702_164053.log +0 -21
- fastapi_fastkit/logs/fastkit_debug_20250702_165220.log +0 -21
- fastapi_fastkit/logs/fastkit_debug_20250702_165647.log +0 -21
- fastapi_fastkit-1.0.2.dist-info/METADATA +0 -320
- {fastapi_fastkit-1.0.2.dist-info → fastapi_fastkit-1.1.0.dist-info}/entry_points.txt +0 -0
fastapi_fastkit/cli.py
CHANGED
|
@@ -1,664 +1,702 @@
|
|
|
1
|
-
# --------------------------------------------------------------------------
|
|
2
|
-
# The Module defines main and core CLI operations for FastAPI-fastkit.
|
|
3
|
-
#
|
|
4
|
-
# @author bnbong bbbong9@gmail.com
|
|
5
|
-
# --------------------------------------------------------------------------
|
|
6
|
-
import atexit
|
|
7
|
-
import os
|
|
8
|
-
import shutil
|
|
9
|
-
import subprocess
|
|
10
|
-
import sys
|
|
11
|
-
from typing import Union
|
|
12
|
-
|
|
13
|
-
import click
|
|
14
|
-
from click.core import BaseCommand, Context
|
|
15
|
-
from rich import print
|
|
16
|
-
from rich.panel import Panel
|
|
17
|
-
|
|
18
|
-
from fastapi_fastkit.backend.main import (
|
|
19
|
-
add_new_route,
|
|
20
|
-
|
|
21
|
-
find_template_core_modules,
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
from fastapi_fastkit.
|
|
28
|
-
from fastapi_fastkit.core.
|
|
29
|
-
from fastapi_fastkit.
|
|
30
|
-
from fastapi_fastkit.utils.
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
@click.
|
|
45
|
-
@click.
|
|
46
|
-
@click.
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
:
|
|
98
|
-
:
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
@click.
|
|
164
|
-
|
|
165
|
-
"
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
"
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
)
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
"""
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
)
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
deps_table
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
console.print("\n")
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
)
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
)
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
)
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
)
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
:
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
"
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
)
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
if
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
"
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
1
|
+
# --------------------------------------------------------------------------
|
|
2
|
+
# The Module defines main and core CLI operations for FastAPI-fastkit.
|
|
3
|
+
#
|
|
4
|
+
# @author bnbong bbbong9@gmail.com
|
|
5
|
+
# --------------------------------------------------------------------------
|
|
6
|
+
import atexit
|
|
7
|
+
import os
|
|
8
|
+
import shutil
|
|
9
|
+
import subprocess
|
|
10
|
+
import sys
|
|
11
|
+
from typing import Union
|
|
12
|
+
|
|
13
|
+
import click
|
|
14
|
+
from click.core import BaseCommand, Context
|
|
15
|
+
from rich import print
|
|
16
|
+
from rich.panel import Panel
|
|
17
|
+
|
|
18
|
+
from fastapi_fastkit.backend.main import (
|
|
19
|
+
add_new_route,
|
|
20
|
+
create_venv_with_manager,
|
|
21
|
+
find_template_core_modules,
|
|
22
|
+
generate_dependency_file_with_manager,
|
|
23
|
+
inject_project_metadata,
|
|
24
|
+
install_dependencies_with_manager,
|
|
25
|
+
read_template_stack,
|
|
26
|
+
)
|
|
27
|
+
from fastapi_fastkit.backend.transducer import copy_and_convert_template
|
|
28
|
+
from fastapi_fastkit.core.exceptions import CLIExceptions
|
|
29
|
+
from fastapi_fastkit.core.settings import FastkitConfig
|
|
30
|
+
from fastapi_fastkit.utils.logging import get_logger, setup_logging
|
|
31
|
+
from fastapi_fastkit.utils.main import (
|
|
32
|
+
create_info_table,
|
|
33
|
+
is_fastkit_project,
|
|
34
|
+
print_error,
|
|
35
|
+
print_info,
|
|
36
|
+
print_success,
|
|
37
|
+
print_warning,
|
|
38
|
+
validate_email,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
from . import __version__, console
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@click.group()
|
|
45
|
+
@click.option("--debug/--no-debug", default=False)
|
|
46
|
+
@click.version_option(__version__, prog_name="fastapi-fastkit")
|
|
47
|
+
@click.pass_context
|
|
48
|
+
def fastkit_cli(ctx: Context, debug: bool) -> Union["BaseCommand", None]:
|
|
49
|
+
"""
|
|
50
|
+
main FastAPI-fastkit CLI operation group
|
|
51
|
+
"""
|
|
52
|
+
settings = FastkitConfig()
|
|
53
|
+
ctx.ensure_object(dict)
|
|
54
|
+
|
|
55
|
+
if debug:
|
|
56
|
+
print_warning("running at debugging mode!!")
|
|
57
|
+
settings.set_debug_mode()
|
|
58
|
+
|
|
59
|
+
ctx.obj["settings"] = settings
|
|
60
|
+
|
|
61
|
+
# Setup logging and get debug capture if debug mode is enabled
|
|
62
|
+
debug_capture = setup_logging(settings=settings)
|
|
63
|
+
ctx.obj["debug_capture"] = debug_capture
|
|
64
|
+
|
|
65
|
+
# If debug mode is enabled, start capturing output
|
|
66
|
+
if debug_capture:
|
|
67
|
+
debug_capture.__enter__()
|
|
68
|
+
# Log CLI invocation
|
|
69
|
+
logger = get_logger()
|
|
70
|
+
logger.info(f"CLI invoked with debug mode: {' '.join(sys.argv)}")
|
|
71
|
+
|
|
72
|
+
# Register cleanup function for when the CLI exits
|
|
73
|
+
def cleanup_debug_capture() -> None:
|
|
74
|
+
try:
|
|
75
|
+
debug_capture.__exit__(None, None, None)
|
|
76
|
+
logger.info("FastAPI-fastkit CLI session ended")
|
|
77
|
+
except Exception:
|
|
78
|
+
pass # Fail silently during cleanup
|
|
79
|
+
|
|
80
|
+
atexit.register(cleanup_debug_capture)
|
|
81
|
+
|
|
82
|
+
return None
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
@fastkit_cli.command()
|
|
86
|
+
@click.pass_context
|
|
87
|
+
def echo(ctx: Context) -> None:
|
|
88
|
+
"""
|
|
89
|
+
About FastAPI-fastkit
|
|
90
|
+
"""
|
|
91
|
+
fastkit_info = f"""
|
|
92
|
+
⚡️ FastAPI fastkit - fastest [bold]FastAPI[/bold] initializer. ⚡️
|
|
93
|
+
|
|
94
|
+
Deploy FastAPI app foundation instantly at your local!
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
- Project Maintainer : [link=mailto:bbbong9@gmail.com]bnbong(JunHyeok Lee)[/link]
|
|
98
|
+
- Current Version : {__version__}
|
|
99
|
+
- Github : [link]https://github.com/bnbong/FastAPI-fastkit[/link]
|
|
100
|
+
"""
|
|
101
|
+
settings = ctx.obj["settings"]
|
|
102
|
+
description_panel = Panel(fastkit_info, title="About FastAPI-fastkit")
|
|
103
|
+
click.echo(print(description_panel))
|
|
104
|
+
|
|
105
|
+
if settings.DEBUG_MODE:
|
|
106
|
+
debug_output = f"FASTKIT_PROJECT_ROOT: {settings.FASTKIT_PROJECT_ROOT}\nUSER_WORKSPACE: {settings.USER_WORKSPACE}"
|
|
107
|
+
|
|
108
|
+
click.echo(debug_output)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
@fastkit_cli.command()
|
|
112
|
+
@click.pass_context
|
|
113
|
+
def list_templates(ctx: Context) -> None:
|
|
114
|
+
"""
|
|
115
|
+
Display the list of available templates.
|
|
116
|
+
"""
|
|
117
|
+
settings = ctx.obj["settings"]
|
|
118
|
+
template_dir = settings.FASTKIT_TEMPLATE_ROOT
|
|
119
|
+
|
|
120
|
+
if not os.path.exists(template_dir):
|
|
121
|
+
print_error("Template directory not found.")
|
|
122
|
+
return
|
|
123
|
+
|
|
124
|
+
excluded_dirs = ["__pycache__", "modules"]
|
|
125
|
+
templates = [
|
|
126
|
+
d
|
|
127
|
+
for d in os.listdir(template_dir)
|
|
128
|
+
if os.path.isdir(os.path.join(template_dir, d)) and d not in excluded_dirs
|
|
129
|
+
]
|
|
130
|
+
|
|
131
|
+
if not templates:
|
|
132
|
+
print_warning("No available templates.")
|
|
133
|
+
return
|
|
134
|
+
|
|
135
|
+
table = create_info_table("Available Templates")
|
|
136
|
+
|
|
137
|
+
for template in templates:
|
|
138
|
+
template_path = os.path.join(template_dir, template)
|
|
139
|
+
readme_path = os.path.join(template_path, "README.md-tpl")
|
|
140
|
+
|
|
141
|
+
description = "No description"
|
|
142
|
+
if os.path.exists(readme_path):
|
|
143
|
+
with open(readme_path, "r") as f:
|
|
144
|
+
first_line = f.readline().strip()
|
|
145
|
+
if first_line.startswith("# "):
|
|
146
|
+
description = first_line[2:]
|
|
147
|
+
|
|
148
|
+
table.add_row(template, description)
|
|
149
|
+
|
|
150
|
+
console.print(table)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
@fastkit_cli.command(context_settings={"ignore_unknown_options": True})
|
|
154
|
+
@click.argument("template", default="fastapi-default")
|
|
155
|
+
@click.option(
|
|
156
|
+
"--project-name",
|
|
157
|
+
prompt="Enter the project name",
|
|
158
|
+
help="The name of the new FastAPI project.",
|
|
159
|
+
)
|
|
160
|
+
@click.option(
|
|
161
|
+
"--author", prompt="Enter the author name", help="The name of the project author."
|
|
162
|
+
)
|
|
163
|
+
@click.option(
|
|
164
|
+
"--author-email",
|
|
165
|
+
prompt="Enter the author email",
|
|
166
|
+
help="The email of the project author.",
|
|
167
|
+
type=str,
|
|
168
|
+
callback=validate_email,
|
|
169
|
+
)
|
|
170
|
+
@click.option(
|
|
171
|
+
"--description",
|
|
172
|
+
prompt="Enter the project description",
|
|
173
|
+
help="The description of the new FastAPI project.",
|
|
174
|
+
)
|
|
175
|
+
@click.option(
|
|
176
|
+
"--package-manager",
|
|
177
|
+
help="Package manager to use for the project.",
|
|
178
|
+
type=click.Choice(["pip", "uv", "pdm", "poetry"]),
|
|
179
|
+
default=None,
|
|
180
|
+
)
|
|
181
|
+
@click.pass_context
|
|
182
|
+
def startdemo(
|
|
183
|
+
ctx: Context,
|
|
184
|
+
template: str,
|
|
185
|
+
project_name: str,
|
|
186
|
+
author: str,
|
|
187
|
+
author_email: str,
|
|
188
|
+
description: str,
|
|
189
|
+
package_manager: str,
|
|
190
|
+
) -> None:
|
|
191
|
+
"""
|
|
192
|
+
Create a new FastAPI project from templates and inject metadata.
|
|
193
|
+
"""
|
|
194
|
+
settings = ctx.obj["settings"]
|
|
195
|
+
|
|
196
|
+
template_dir = settings.FASTKIT_TEMPLATE_ROOT
|
|
197
|
+
click.echo(f"Deploying FastAPI project using '{template}' template")
|
|
198
|
+
target_template = os.path.join(template_dir, template)
|
|
199
|
+
|
|
200
|
+
if settings.DEBUG_MODE:
|
|
201
|
+
logger = get_logger()
|
|
202
|
+
logger.info(f"Template path: {target_template}")
|
|
203
|
+
|
|
204
|
+
click.echo(f"Template path: {target_template}")
|
|
205
|
+
|
|
206
|
+
if not os.path.exists(target_template):
|
|
207
|
+
print_error(f"Template '{template}' does not exist in '{template_dir}'.")
|
|
208
|
+
raise CLIExceptions(
|
|
209
|
+
f"Template '{template}' does not exist in '{template_dir}'."
|
|
210
|
+
)
|
|
211
|
+
table = create_info_table(
|
|
212
|
+
"Project Information",
|
|
213
|
+
{
|
|
214
|
+
"Project Name": project_name,
|
|
215
|
+
"Author": author,
|
|
216
|
+
"Author Email": author_email,
|
|
217
|
+
"Description": description,
|
|
218
|
+
},
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
console.print("\n")
|
|
222
|
+
console.print(table)
|
|
223
|
+
|
|
224
|
+
template_deps = read_template_stack(target_template)
|
|
225
|
+
if template_deps:
|
|
226
|
+
deps_table = create_info_table(
|
|
227
|
+
"Template Dependencies",
|
|
228
|
+
{f"Dependency {i+1}": dep for i, dep in enumerate(template_deps)},
|
|
229
|
+
)
|
|
230
|
+
console.print("\n")
|
|
231
|
+
console.print(deps_table)
|
|
232
|
+
|
|
233
|
+
# Package manager selection
|
|
234
|
+
if not package_manager:
|
|
235
|
+
console.print("\n[bold]Available Package Managers:[/bold]")
|
|
236
|
+
package_manager_table = create_info_table(
|
|
237
|
+
"Package Managers",
|
|
238
|
+
{
|
|
239
|
+
f"{manager.upper()}": config["description"]
|
|
240
|
+
for manager, config in settings.PACKAGE_MANAGER_CONFIG.items()
|
|
241
|
+
},
|
|
242
|
+
)
|
|
243
|
+
console.print(package_manager_table)
|
|
244
|
+
console.print("\n")
|
|
245
|
+
|
|
246
|
+
package_manager = click.prompt(
|
|
247
|
+
"Select package manager",
|
|
248
|
+
type=click.Choice(settings.SUPPORTED_PACKAGE_MANAGERS),
|
|
249
|
+
default=settings.DEFAULT_PACKAGE_MANAGER,
|
|
250
|
+
show_choices=True,
|
|
251
|
+
show_default=True,
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
confirm = click.confirm(
|
|
255
|
+
"\nDo you want to proceed with project creation?", default=False
|
|
256
|
+
)
|
|
257
|
+
if not confirm:
|
|
258
|
+
print_error("Project creation aborted!")
|
|
259
|
+
return
|
|
260
|
+
|
|
261
|
+
try:
|
|
262
|
+
user_local = settings.USER_WORKSPACE
|
|
263
|
+
project_dir = os.path.join(user_local, project_name)
|
|
264
|
+
|
|
265
|
+
click.echo(f"FastAPI template project will deploy at '{user_local}'")
|
|
266
|
+
|
|
267
|
+
copy_and_convert_template(target_template, user_local, project_name)
|
|
268
|
+
|
|
269
|
+
inject_project_metadata(
|
|
270
|
+
project_dir, project_name, author, author_email, description
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
# Create virtual environment and install dependencies with selected package manager
|
|
274
|
+
venv_path = create_venv_with_manager(project_dir, package_manager)
|
|
275
|
+
install_dependencies_with_manager(project_dir, venv_path, package_manager)
|
|
276
|
+
|
|
277
|
+
print_success(
|
|
278
|
+
f"FastAPI project '{project_name}' from '{template}' has been created and saved to {user_local}!"
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
except Exception as e:
|
|
282
|
+
if settings.DEBUG_MODE:
|
|
283
|
+
logger = get_logger()
|
|
284
|
+
logger.exception(f"Error during project creation in startdemo: {str(e)}")
|
|
285
|
+
print_error(f"Error during project creation: {str(e)}")
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
@fastkit_cli.command(context_settings={"ignore_unknown_options": True})
|
|
289
|
+
@click.option(
|
|
290
|
+
"--project-name",
|
|
291
|
+
prompt="Enter the project name",
|
|
292
|
+
help="The name of the new FastAPI project.",
|
|
293
|
+
)
|
|
294
|
+
@click.option(
|
|
295
|
+
"--author", prompt="Enter the author name", help="The name of the project author."
|
|
296
|
+
)
|
|
297
|
+
@click.option(
|
|
298
|
+
"--author-email",
|
|
299
|
+
prompt="Enter the author email",
|
|
300
|
+
help="The email of the project author.",
|
|
301
|
+
type=str,
|
|
302
|
+
callback=validate_email,
|
|
303
|
+
)
|
|
304
|
+
@click.option(
|
|
305
|
+
"--description",
|
|
306
|
+
prompt="Enter the project description",
|
|
307
|
+
help="The description of the new FastAPI project.",
|
|
308
|
+
)
|
|
309
|
+
@click.option(
|
|
310
|
+
"--package-manager",
|
|
311
|
+
help="Package manager to use for the project.",
|
|
312
|
+
type=click.Choice(["pip", "uv", "pdm", "poetry"]),
|
|
313
|
+
default=None,
|
|
314
|
+
)
|
|
315
|
+
@click.pass_context
|
|
316
|
+
def init(
|
|
317
|
+
ctx: Context,
|
|
318
|
+
project_name: str,
|
|
319
|
+
author: str,
|
|
320
|
+
author_email: str,
|
|
321
|
+
description: str,
|
|
322
|
+
package_manager: str,
|
|
323
|
+
) -> None:
|
|
324
|
+
"""
|
|
325
|
+
Start a empty FastAPI project setup.
|
|
326
|
+
This command will automatically create a new FastAPI project directory and a python virtual environment.
|
|
327
|
+
Dependencies will be automatically installed based on the selected stack at venv.
|
|
328
|
+
Project metadata will be injected to the project files.
|
|
329
|
+
"""
|
|
330
|
+
settings = ctx.obj["settings"]
|
|
331
|
+
project_dir = os.path.join(settings.USER_WORKSPACE, project_name)
|
|
332
|
+
|
|
333
|
+
if os.path.exists(project_dir):
|
|
334
|
+
print_error(f"Error: Project '{project_name}' already exists.")
|
|
335
|
+
return
|
|
336
|
+
|
|
337
|
+
# Display project information
|
|
338
|
+
project_info_table = create_info_table(
|
|
339
|
+
"Project Information",
|
|
340
|
+
{
|
|
341
|
+
"Project Name": project_name,
|
|
342
|
+
"Author": author,
|
|
343
|
+
"Author Email": author_email,
|
|
344
|
+
"Description": description,
|
|
345
|
+
},
|
|
346
|
+
)
|
|
347
|
+
console.print("\n")
|
|
348
|
+
console.print(project_info_table)
|
|
349
|
+
|
|
350
|
+
# Display available stacks
|
|
351
|
+
console.print("\n[bold]Available Stacks and Dependencies:[/bold]")
|
|
352
|
+
|
|
353
|
+
for stack_name, deps in settings.PROJECT_STACKS.items():
|
|
354
|
+
table = create_info_table(
|
|
355
|
+
f"{stack_name.upper()} Stack",
|
|
356
|
+
{f"Dependency {i+1}": dep for i, dep in enumerate(deps)},
|
|
357
|
+
)
|
|
358
|
+
console.print(table)
|
|
359
|
+
console.print("\n")
|
|
360
|
+
|
|
361
|
+
stack = click.prompt(
|
|
362
|
+
"Select stack",
|
|
363
|
+
type=click.Choice(list(settings.PROJECT_STACKS.keys())),
|
|
364
|
+
show_choices=True,
|
|
365
|
+
)
|
|
366
|
+
|
|
367
|
+
# Package manager selection
|
|
368
|
+
if not package_manager:
|
|
369
|
+
console.print("\n[bold]Available Package Managers:[/bold]")
|
|
370
|
+
package_manager_table = create_info_table(
|
|
371
|
+
"Package Managers",
|
|
372
|
+
{
|
|
373
|
+
f"{manager.upper()}": config["description"]
|
|
374
|
+
for manager, config in settings.PACKAGE_MANAGER_CONFIG.items()
|
|
375
|
+
},
|
|
376
|
+
)
|
|
377
|
+
console.print(package_manager_table)
|
|
378
|
+
console.print("\n")
|
|
379
|
+
|
|
380
|
+
package_manager = click.prompt(
|
|
381
|
+
"Select package manager",
|
|
382
|
+
type=click.Choice(settings.SUPPORTED_PACKAGE_MANAGERS),
|
|
383
|
+
default=settings.DEFAULT_PACKAGE_MANAGER,
|
|
384
|
+
show_choices=True,
|
|
385
|
+
show_default=True,
|
|
386
|
+
)
|
|
387
|
+
|
|
388
|
+
template = "fastapi-empty"
|
|
389
|
+
template_dir = settings.FASTKIT_TEMPLATE_ROOT
|
|
390
|
+
target_template = os.path.join(template_dir, template)
|
|
391
|
+
|
|
392
|
+
if not os.path.exists(target_template):
|
|
393
|
+
print_error(f"Template '{template}' does not exist in '{template_dir}'.")
|
|
394
|
+
raise CLIExceptions(
|
|
395
|
+
f"Template '{template}' does not exist in '{template_dir}'."
|
|
396
|
+
)
|
|
397
|
+
|
|
398
|
+
confirm = click.confirm(
|
|
399
|
+
"\nDo you want to proceed with project creation?", default=False
|
|
400
|
+
)
|
|
401
|
+
if not confirm:
|
|
402
|
+
print_error("Project creation aborted!")
|
|
403
|
+
return
|
|
404
|
+
|
|
405
|
+
try:
|
|
406
|
+
user_local = settings.USER_WORKSPACE
|
|
407
|
+
project_dir = os.path.join(user_local, project_name)
|
|
408
|
+
|
|
409
|
+
click.echo(f"FastAPI project will deploy at '{user_local}'")
|
|
410
|
+
|
|
411
|
+
copy_and_convert_template(target_template, user_local, project_name)
|
|
412
|
+
|
|
413
|
+
inject_project_metadata(
|
|
414
|
+
project_dir, project_name, author, author_email, description
|
|
415
|
+
)
|
|
416
|
+
|
|
417
|
+
deps_table = create_info_table(
|
|
418
|
+
f"Creating Project: {project_name}", {"Component": "Collected"}
|
|
419
|
+
)
|
|
420
|
+
|
|
421
|
+
# Generate dependency file using selected package manager
|
|
422
|
+
dependencies = settings.PROJECT_STACKS[stack]
|
|
423
|
+
generate_dependency_file_with_manager(
|
|
424
|
+
project_dir,
|
|
425
|
+
dependencies,
|
|
426
|
+
package_manager,
|
|
427
|
+
project_name,
|
|
428
|
+
author,
|
|
429
|
+
author_email,
|
|
430
|
+
description,
|
|
431
|
+
)
|
|
432
|
+
|
|
433
|
+
for dep in dependencies:
|
|
434
|
+
deps_table.add_row(dep, "✓")
|
|
435
|
+
|
|
436
|
+
console.print(deps_table)
|
|
437
|
+
|
|
438
|
+
# Create virtual environment and install dependencies with selected package manager
|
|
439
|
+
venv_path = create_venv_with_manager(project_dir, package_manager)
|
|
440
|
+
install_dependencies_with_manager(project_dir, venv_path, package_manager)
|
|
441
|
+
|
|
442
|
+
print_success(
|
|
443
|
+
f"FastAPI project '{project_name}' has been created successfully and saved to {user_local}!"
|
|
444
|
+
)
|
|
445
|
+
|
|
446
|
+
print_info(
|
|
447
|
+
"To start your project, run 'fastkit runserver' at newly created FastAPI project directory"
|
|
448
|
+
)
|
|
449
|
+
|
|
450
|
+
except Exception as e:
|
|
451
|
+
if settings.DEBUG_MODE:
|
|
452
|
+
logger = get_logger()
|
|
453
|
+
logger.exception(f"Error during project creation in init: {str(e)}")
|
|
454
|
+
print_error(f"Error during project creation: {str(e)}")
|
|
455
|
+
if os.path.exists(project_dir):
|
|
456
|
+
shutil.rmtree(project_dir, ignore_errors=True)
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
@fastkit_cli.command()
|
|
460
|
+
@click.argument("project_name")
|
|
461
|
+
@click.argument("route_name")
|
|
462
|
+
@click.pass_context
|
|
463
|
+
def addroute(ctx: Context, project_name: str, route_name: str) -> None:
|
|
464
|
+
"""
|
|
465
|
+
Add a new route to the FastAPI project.
|
|
466
|
+
"""
|
|
467
|
+
settings = ctx.obj["settings"]
|
|
468
|
+
user_local = settings.USER_WORKSPACE
|
|
469
|
+
project_dir = os.path.join(user_local, project_name)
|
|
470
|
+
|
|
471
|
+
# Check if project exists
|
|
472
|
+
if not os.path.exists(project_dir):
|
|
473
|
+
print_error(f"Project '{project_name}' does not exist in '{user_local}'.")
|
|
474
|
+
return
|
|
475
|
+
|
|
476
|
+
# Verify it's a fastkit project
|
|
477
|
+
if not is_fastkit_project(project_dir):
|
|
478
|
+
print_error(f"'{project_name}' is not a FastAPI-fastkit project.")
|
|
479
|
+
return
|
|
480
|
+
|
|
481
|
+
# Validate route name
|
|
482
|
+
if not route_name.isidentifier():
|
|
483
|
+
print_error(f"Route name '{route_name}' is not a valid Python identifier.")
|
|
484
|
+
return
|
|
485
|
+
|
|
486
|
+
# Route name shouldn't match reserved keywords
|
|
487
|
+
import keyword
|
|
488
|
+
|
|
489
|
+
if keyword.iskeyword(route_name):
|
|
490
|
+
print_error(
|
|
491
|
+
f"Route name '{route_name}' is a Python keyword and cannot be used."
|
|
492
|
+
)
|
|
493
|
+
return
|
|
494
|
+
|
|
495
|
+
try:
|
|
496
|
+
# Show information about the operation
|
|
497
|
+
table = create_info_table(
|
|
498
|
+
"Adding New Route",
|
|
499
|
+
{
|
|
500
|
+
"Project": project_name,
|
|
501
|
+
"Route Name": route_name,
|
|
502
|
+
"Target Directory": project_dir,
|
|
503
|
+
},
|
|
504
|
+
)
|
|
505
|
+
console.print(table)
|
|
506
|
+
|
|
507
|
+
# Confirm before proceeding
|
|
508
|
+
confirm = click.confirm(
|
|
509
|
+
f"\nDo you want to add route '{route_name}' to project '{project_name}'?",
|
|
510
|
+
default=True,
|
|
511
|
+
)
|
|
512
|
+
if not confirm:
|
|
513
|
+
print_error("Operation cancelled!")
|
|
514
|
+
return
|
|
515
|
+
|
|
516
|
+
# Add the new route
|
|
517
|
+
add_new_route(project_dir, route_name)
|
|
518
|
+
|
|
519
|
+
print_success(
|
|
520
|
+
f"Successfully added new route '{route_name}' to project `{project_name}`"
|
|
521
|
+
)
|
|
522
|
+
|
|
523
|
+
except Exception as e:
|
|
524
|
+
logger = get_logger()
|
|
525
|
+
logger.exception(f"Error during route addition: {str(e)}")
|
|
526
|
+
print_error(f"Error during route addition: {str(e)}")
|
|
527
|
+
|
|
528
|
+
|
|
529
|
+
@fastkit_cli.command()
|
|
530
|
+
@click.argument("project_name")
|
|
531
|
+
@click.pass_context
|
|
532
|
+
def deleteproject(ctx: Context, project_name: str) -> None:
|
|
533
|
+
"""
|
|
534
|
+
Delete a FastAPI project.
|
|
535
|
+
"""
|
|
536
|
+
settings = ctx.obj["settings"]
|
|
537
|
+
user_local = settings.USER_WORKSPACE
|
|
538
|
+
project_dir = os.path.join(user_local, project_name)
|
|
539
|
+
|
|
540
|
+
if not os.path.exists(project_dir):
|
|
541
|
+
print_error(f"Project '{project_name}' does not exist in '{user_local}'.")
|
|
542
|
+
return
|
|
543
|
+
|
|
544
|
+
if not is_fastkit_project(project_dir):
|
|
545
|
+
print_error(f"'{project_name}' is not a FastAPI-fastkit project.")
|
|
546
|
+
return
|
|
547
|
+
|
|
548
|
+
confirm = click.confirm(
|
|
549
|
+
f"\nDo you want to delete project '{project_name}' at '{project_dir}'?",
|
|
550
|
+
default=False,
|
|
551
|
+
)
|
|
552
|
+
if not confirm:
|
|
553
|
+
print_error("Project deletion cancelled!")
|
|
554
|
+
return
|
|
555
|
+
|
|
556
|
+
try:
|
|
557
|
+
shutil.rmtree(project_dir)
|
|
558
|
+
print_success(f"Project '{project_name}' has been deleted successfully!")
|
|
559
|
+
|
|
560
|
+
except Exception as e:
|
|
561
|
+
logger = get_logger()
|
|
562
|
+
logger.exception(f"Error during project deletion: {e}")
|
|
563
|
+
print_error(f"Error during project deletion: {e}")
|
|
564
|
+
|
|
565
|
+
|
|
566
|
+
@fastkit_cli.command()
|
|
567
|
+
@click.option(
|
|
568
|
+
"--host",
|
|
569
|
+
default="127.0.0.1",
|
|
570
|
+
show_default=True,
|
|
571
|
+
help="Host to bind the server",
|
|
572
|
+
)
|
|
573
|
+
@click.option(
|
|
574
|
+
"--port",
|
|
575
|
+
default=8000,
|
|
576
|
+
show_default=True,
|
|
577
|
+
help="Port to bind the server",
|
|
578
|
+
)
|
|
579
|
+
@click.option(
|
|
580
|
+
"--reload/--no-reload",
|
|
581
|
+
default=True,
|
|
582
|
+
show_default=True,
|
|
583
|
+
help="Enable/disable auto-reload on code changes",
|
|
584
|
+
)
|
|
585
|
+
@click.option(
|
|
586
|
+
"--workers",
|
|
587
|
+
default=1,
|
|
588
|
+
show_default=True,
|
|
589
|
+
help="Number of worker processes",
|
|
590
|
+
)
|
|
591
|
+
@click.pass_context
|
|
592
|
+
def runserver(
|
|
593
|
+
ctx: Context,
|
|
594
|
+
host: str = "127.0.0.1",
|
|
595
|
+
port: int = 8000,
|
|
596
|
+
reload: bool = True,
|
|
597
|
+
workers: int = 1,
|
|
598
|
+
) -> None:
|
|
599
|
+
"""
|
|
600
|
+
Run the FastAPI server for the current project.
|
|
601
|
+
"""
|
|
602
|
+
settings = ctx.obj["settings"]
|
|
603
|
+
project_dir = settings.USER_WORKSPACE
|
|
604
|
+
|
|
605
|
+
# Check for virtual environment
|
|
606
|
+
venv_path = os.path.join(project_dir, ".venv")
|
|
607
|
+
if not os.path.exists(venv_path) or not os.path.isdir(venv_path):
|
|
608
|
+
print_error(
|
|
609
|
+
"Virtual environment not found. Is this a project deployed with Fastkit?"
|
|
610
|
+
)
|
|
611
|
+
confirm = click.confirm(
|
|
612
|
+
"Do you want to continue with system Python?", default=False
|
|
613
|
+
)
|
|
614
|
+
if not confirm:
|
|
615
|
+
return
|
|
616
|
+
venv_python = None
|
|
617
|
+
else:
|
|
618
|
+
if os.name == "nt": # Windows
|
|
619
|
+
venv_python = os.path.join(venv_path, "Scripts", "python.exe")
|
|
620
|
+
else: # Unix/Linux/Mac
|
|
621
|
+
venv_python = os.path.join(venv_path, "bin", "python")
|
|
622
|
+
|
|
623
|
+
if not os.path.exists(venv_python):
|
|
624
|
+
print_error(
|
|
625
|
+
f"Python interpreter not found in virtual environment: {venv_python}"
|
|
626
|
+
)
|
|
627
|
+
confirm = click.confirm(
|
|
628
|
+
"Do you want to continue with system Python?", default=False
|
|
629
|
+
)
|
|
630
|
+
if not confirm:
|
|
631
|
+
return
|
|
632
|
+
venv_python = None
|
|
633
|
+
|
|
634
|
+
core_modules = find_template_core_modules(project_dir)
|
|
635
|
+
if not core_modules["main"]:
|
|
636
|
+
print_error(f"Could not find 'main.py' in '{project_dir}'.")
|
|
637
|
+
return
|
|
638
|
+
|
|
639
|
+
main_path = core_modules["main"]
|
|
640
|
+
if "src/" in main_path:
|
|
641
|
+
app_module = "src.main:app"
|
|
642
|
+
else:
|
|
643
|
+
app_module = "main:app"
|
|
644
|
+
|
|
645
|
+
if venv_python:
|
|
646
|
+
print_info(f"Using Python from virtual environment: {venv_python}")
|
|
647
|
+
command = [
|
|
648
|
+
venv_python,
|
|
649
|
+
"-m",
|
|
650
|
+
"uvicorn",
|
|
651
|
+
app_module,
|
|
652
|
+
"--host",
|
|
653
|
+
host,
|
|
654
|
+
"--port",
|
|
655
|
+
str(port),
|
|
656
|
+
"--workers",
|
|
657
|
+
str(workers),
|
|
658
|
+
]
|
|
659
|
+
else:
|
|
660
|
+
command = [
|
|
661
|
+
"uvicorn",
|
|
662
|
+
app_module,
|
|
663
|
+
"--host",
|
|
664
|
+
host,
|
|
665
|
+
"--port",
|
|
666
|
+
str(port),
|
|
667
|
+
"--workers",
|
|
668
|
+
str(workers),
|
|
669
|
+
]
|
|
670
|
+
|
|
671
|
+
if reload:
|
|
672
|
+
command.append("--reload")
|
|
673
|
+
|
|
674
|
+
try:
|
|
675
|
+
print_success(f"Starting FastAPI server at {host}:{port}...")
|
|
676
|
+
|
|
677
|
+
# Set up environment variables for the subprocess
|
|
678
|
+
env = os.environ.copy()
|
|
679
|
+
if venv_python:
|
|
680
|
+
python_path = os.path.dirname(os.path.dirname(venv_python))
|
|
681
|
+
if "PYTHONPATH" in env:
|
|
682
|
+
env["PYTHONPATH"] = f"{python_path}:{env['PYTHONPATH']}"
|
|
683
|
+
else:
|
|
684
|
+
env["PYTHONPATH"] = python_path
|
|
685
|
+
|
|
686
|
+
# Run the server with the configured environment
|
|
687
|
+
subprocess.run(command, check=True, env=env)
|
|
688
|
+
except subprocess.CalledProcessError as e:
|
|
689
|
+
logger = get_logger()
|
|
690
|
+
logger.exception(f"Failed to start FastAPI server: {e}")
|
|
691
|
+
print_error(f"Failed to start FastAPI server.\n{e}")
|
|
692
|
+
except FileNotFoundError as e:
|
|
693
|
+
logger = get_logger()
|
|
694
|
+
logger.exception(f"FileNotFoundError when starting server: {e}")
|
|
695
|
+
if venv_python:
|
|
696
|
+
print_error(
|
|
697
|
+
f"Failed to run Python from the virtual environment. Make sure uvicorn is installed in the project's virtual environment."
|
|
698
|
+
)
|
|
699
|
+
else:
|
|
700
|
+
print_error(
|
|
701
|
+
f"uvicorn not found. Make sure it's installed in your system Python."
|
|
702
|
+
)
|