FastAPI-fastkit 1.1.4__py3-none-any.whl → 1.2.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/inspector.py +170 -12
- fastapi_fastkit/backend/interactive/__init__.py +51 -0
- fastapi_fastkit/backend/interactive/config_builder.py +186 -0
- fastapi_fastkit/backend/interactive/prompts.py +528 -0
- fastapi_fastkit/backend/interactive/selectors.py +241 -0
- fastapi_fastkit/backend/interactive/validators.py +163 -0
- fastapi_fastkit/backend/main.py +77 -0
- fastapi_fastkit/backend/package_managers/pdm_manager.py +6 -2
- fastapi_fastkit/backend/package_managers/pip_manager.py +6 -2
- fastapi_fastkit/backend/package_managers/poetry_manager.py +6 -2
- fastapi_fastkit/backend/package_managers/uv_manager.py +6 -2
- fastapi_fastkit/backend/project_builder/__init__.py +17 -0
- fastapi_fastkit/backend/project_builder/config_generator.py +594 -0
- fastapi_fastkit/backend/project_builder/dependency_collector.py +210 -0
- fastapi_fastkit/cli.py +218 -20
- fastapi_fastkit/core/settings.py +74 -0
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/pyproject.toml-tpl +2 -1
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/requirements.txt-tpl +1 -0
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/pyproject.toml-tpl +2 -1
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/requirements.txt-tpl +1 -0
- fastapi_fastkit/fastapi_project_template/fastapi-default/pyproject.toml-tpl +2 -1
- fastapi_fastkit/fastapi_project_template/fastapi-default/requirements.txt-tpl +1 -0
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/pyproject.toml-tpl +2 -1
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/requirements.txt-tpl +1 -0
- fastapi_fastkit/fastapi_project_template/fastapi-empty/pyproject.toml-tpl +2 -1
- fastapi_fastkit/fastapi_project_template/fastapi-empty/requirements.txt-tpl +1 -0
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/pyproject.toml-tpl +2 -1
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/requirements.txt-tpl +1 -0
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/pyproject.toml-tpl +2 -1
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/requirements.txt-tpl +1 -0
- fastapi_fastkit/fastapi_project_template/fastapi-single-module/pyproject.toml-tpl +2 -1
- fastapi_fastkit/fastapi_project_template/fastapi-single-module/requirements.txt-tpl +1 -0
- fastapi_fastkit/utils/main.py +121 -10
- {fastapi_fastkit-1.1.4.dist-info → fastapi_fastkit-1.2.0.dist-info}/METADATA +9 -6
- {fastapi_fastkit-1.1.4.dist-info → fastapi_fastkit-1.2.0.dist-info}/RECORD +39 -31
- {fastapi_fastkit-1.1.4.dist-info → fastapi_fastkit-1.2.0.dist-info}/WHEEL +1 -1
- {fastapi_fastkit-1.1.4.dist-info → fastapi_fastkit-1.2.0.dist-info}/entry_points.txt +0 -0
- {fastapi_fastkit-1.1.4.dist-info → fastapi_fastkit-1.2.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
# --------------------------------------------------------------------------
|
|
2
|
+
# Dependency collection and management
|
|
3
|
+
#
|
|
4
|
+
# Collects dependencies from:
|
|
5
|
+
# - Base template (if selected)
|
|
6
|
+
# - Database choice
|
|
7
|
+
# - Authentication method
|
|
8
|
+
# - Additional features
|
|
9
|
+
# - Custom packages
|
|
10
|
+
#
|
|
11
|
+
# Handles deduplication and version conflict detection.
|
|
12
|
+
#
|
|
13
|
+
# @author bnbong bbbong9@gmail.com
|
|
14
|
+
# --------------------------------------------------------------------------
|
|
15
|
+
from typing import Any, Dict, List, Set
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class DependencyCollector:
|
|
19
|
+
"""
|
|
20
|
+
Collects and manages project dependencies.
|
|
21
|
+
|
|
22
|
+
This class is responsible for gathering all dependencies from
|
|
23
|
+
various sources and ensuring they are properly deduplicated.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def __init__(self, settings: Any) -> None:
|
|
27
|
+
"""
|
|
28
|
+
Initialize dependency collector.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
settings: FastkitConfig instance
|
|
32
|
+
"""
|
|
33
|
+
self.settings = settings
|
|
34
|
+
self.dependencies: Set[str] = set()
|
|
35
|
+
|
|
36
|
+
def collect_from_config(self, config: Dict[str, Any]) -> List[str]:
|
|
37
|
+
"""
|
|
38
|
+
Collect all dependencies from configuration.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
config: Project configuration dictionary
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
Sorted list of all dependencies
|
|
45
|
+
"""
|
|
46
|
+
# Reset dependencies
|
|
47
|
+
self.dependencies = set()
|
|
48
|
+
|
|
49
|
+
# Add base dependencies
|
|
50
|
+
self.add_base_dependencies()
|
|
51
|
+
|
|
52
|
+
# Add database dependencies
|
|
53
|
+
db_info = config.get("database", {})
|
|
54
|
+
if isinstance(db_info, dict) and db_info.get("type") != "None":
|
|
55
|
+
self.add_database_dependencies(db_info.get("type", ""))
|
|
56
|
+
|
|
57
|
+
# Add authentication dependencies
|
|
58
|
+
auth_type = config.get("authentication", "None")
|
|
59
|
+
if auth_type != "None":
|
|
60
|
+
self.add_authentication_dependencies(auth_type)
|
|
61
|
+
|
|
62
|
+
# Add async tasks dependencies
|
|
63
|
+
tasks_type = config.get("async_tasks", "None")
|
|
64
|
+
if tasks_type != "None":
|
|
65
|
+
self.add_async_tasks_dependencies(tasks_type)
|
|
66
|
+
|
|
67
|
+
# Add caching dependencies
|
|
68
|
+
cache_type = config.get("caching", "None")
|
|
69
|
+
if cache_type != "None":
|
|
70
|
+
self.add_caching_dependencies(cache_type)
|
|
71
|
+
|
|
72
|
+
# Add monitoring dependencies
|
|
73
|
+
monitoring_type = config.get("monitoring", "None")
|
|
74
|
+
if monitoring_type != "None":
|
|
75
|
+
self.add_monitoring_dependencies(monitoring_type)
|
|
76
|
+
|
|
77
|
+
# Add testing dependencies
|
|
78
|
+
testing_type = config.get("testing", "None")
|
|
79
|
+
if testing_type != "None":
|
|
80
|
+
self.add_testing_dependencies(testing_type)
|
|
81
|
+
|
|
82
|
+
# Add utilities dependencies
|
|
83
|
+
utilities = config.get("utilities", [])
|
|
84
|
+
for util in utilities:
|
|
85
|
+
self.add_utility_dependencies(util)
|
|
86
|
+
|
|
87
|
+
# Add custom packages
|
|
88
|
+
custom = config.get("custom_packages", [])
|
|
89
|
+
if custom:
|
|
90
|
+
self.dependencies.update(custom)
|
|
91
|
+
|
|
92
|
+
return self.get_final_dependencies()
|
|
93
|
+
|
|
94
|
+
def add_base_dependencies(self) -> None:
|
|
95
|
+
"""Add core FastAPI dependencies."""
|
|
96
|
+
self.dependencies.update(
|
|
97
|
+
[
|
|
98
|
+
"fastapi",
|
|
99
|
+
"uvicorn",
|
|
100
|
+
"pydantic",
|
|
101
|
+
"pydantic-settings",
|
|
102
|
+
]
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
def add_database_dependencies(self, db_type: str) -> None:
|
|
106
|
+
"""
|
|
107
|
+
Add database-specific dependencies.
|
|
108
|
+
|
|
109
|
+
Args:
|
|
110
|
+
db_type: Database type name
|
|
111
|
+
"""
|
|
112
|
+
catalog = self.settings.PACKAGE_CATALOG.get("database", {})
|
|
113
|
+
packages = catalog.get(db_type, [])
|
|
114
|
+
self.dependencies.update(packages)
|
|
115
|
+
|
|
116
|
+
def add_authentication_dependencies(self, auth_type: str) -> None:
|
|
117
|
+
"""
|
|
118
|
+
Add authentication dependencies.
|
|
119
|
+
|
|
120
|
+
Args:
|
|
121
|
+
auth_type: Authentication type name
|
|
122
|
+
"""
|
|
123
|
+
catalog = self.settings.PACKAGE_CATALOG.get("authentication", {})
|
|
124
|
+
packages = catalog.get(auth_type, [])
|
|
125
|
+
self.dependencies.update(packages)
|
|
126
|
+
|
|
127
|
+
def add_async_tasks_dependencies(self, tasks_type: str) -> None:
|
|
128
|
+
"""
|
|
129
|
+
Add async tasks dependencies.
|
|
130
|
+
|
|
131
|
+
Args:
|
|
132
|
+
tasks_type: Task queue type name
|
|
133
|
+
"""
|
|
134
|
+
catalog = self.settings.PACKAGE_CATALOG.get("async_tasks", {})
|
|
135
|
+
packages = catalog.get(tasks_type, [])
|
|
136
|
+
self.dependencies.update(packages)
|
|
137
|
+
|
|
138
|
+
def add_caching_dependencies(self, cache_type: str) -> None:
|
|
139
|
+
"""
|
|
140
|
+
Add caching dependencies.
|
|
141
|
+
|
|
142
|
+
Args:
|
|
143
|
+
cache_type: Caching type name
|
|
144
|
+
"""
|
|
145
|
+
catalog = self.settings.PACKAGE_CATALOG.get("caching", {})
|
|
146
|
+
packages = catalog.get(cache_type, [])
|
|
147
|
+
self.dependencies.update(packages)
|
|
148
|
+
|
|
149
|
+
def add_monitoring_dependencies(self, monitoring_type: str) -> None:
|
|
150
|
+
"""
|
|
151
|
+
Add monitoring dependencies.
|
|
152
|
+
|
|
153
|
+
Args:
|
|
154
|
+
monitoring_type: Monitoring type name
|
|
155
|
+
"""
|
|
156
|
+
catalog = self.settings.PACKAGE_CATALOG.get("monitoring", {})
|
|
157
|
+
packages = catalog.get(monitoring_type, [])
|
|
158
|
+
self.dependencies.update(packages)
|
|
159
|
+
|
|
160
|
+
def add_testing_dependencies(self, testing_type: str) -> None:
|
|
161
|
+
"""
|
|
162
|
+
Add testing dependencies.
|
|
163
|
+
|
|
164
|
+
Args:
|
|
165
|
+
testing_type: Testing framework type name
|
|
166
|
+
"""
|
|
167
|
+
catalog = self.settings.PACKAGE_CATALOG.get("testing", {})
|
|
168
|
+
packages = catalog.get(testing_type, [])
|
|
169
|
+
self.dependencies.update(packages)
|
|
170
|
+
|
|
171
|
+
def add_utility_dependencies(self, utility: str) -> None:
|
|
172
|
+
"""
|
|
173
|
+
Add utility dependencies.
|
|
174
|
+
|
|
175
|
+
Args:
|
|
176
|
+
utility: Utility name
|
|
177
|
+
"""
|
|
178
|
+
catalog = self.settings.PACKAGE_CATALOG.get("utilities", {})
|
|
179
|
+
packages = catalog.get(utility, [])
|
|
180
|
+
self.dependencies.update(packages)
|
|
181
|
+
|
|
182
|
+
def add_feature_dependencies(self, features: List[str]) -> None:
|
|
183
|
+
"""
|
|
184
|
+
Add dependencies for selected features.
|
|
185
|
+
|
|
186
|
+
Args:
|
|
187
|
+
features: List of feature names
|
|
188
|
+
"""
|
|
189
|
+
for feature in features:
|
|
190
|
+
# This is a generic method that can be extended
|
|
191
|
+
# Currently handled by specific methods above
|
|
192
|
+
pass
|
|
193
|
+
|
|
194
|
+
def get_final_dependencies(self) -> List[str]:
|
|
195
|
+
"""
|
|
196
|
+
Return deduplicated, sorted dependency list.
|
|
197
|
+
|
|
198
|
+
Returns:
|
|
199
|
+
Sorted list of all dependencies
|
|
200
|
+
"""
|
|
201
|
+
return sorted(list(self.dependencies))
|
|
202
|
+
|
|
203
|
+
def get_dependency_count(self) -> int:
|
|
204
|
+
"""
|
|
205
|
+
Get the total number of dependencies.
|
|
206
|
+
|
|
207
|
+
Returns:
|
|
208
|
+
Count of unique dependencies
|
|
209
|
+
"""
|
|
210
|
+
return len(self.dependencies)
|
fastapi_fastkit/cli.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# TODO : add a feature to automatically fix appropriate fastkit output console size
|
|
2
1
|
# --------------------------------------------------------------------------
|
|
3
2
|
# The Module defines main and core CLI operations for FastAPI-fastkit.
|
|
4
3
|
#
|
|
@@ -9,13 +8,15 @@ import os
|
|
|
9
8
|
import shutil
|
|
10
9
|
import subprocess
|
|
11
10
|
import sys
|
|
12
|
-
from typing import Union
|
|
11
|
+
from typing import Union, cast
|
|
13
12
|
|
|
14
13
|
import click
|
|
15
|
-
from click
|
|
14
|
+
from click import Command, Context
|
|
16
15
|
from rich import print
|
|
17
16
|
from rich.panel import Panel
|
|
18
17
|
|
|
18
|
+
from fastapi_fastkit.backend.interactive import InteractiveConfigBuilder
|
|
19
|
+
from fastapi_fastkit.backend.interactive.selectors import display_feature_catalog
|
|
19
20
|
from fastapi_fastkit.backend.main import (
|
|
20
21
|
add_new_route,
|
|
21
22
|
ask_create_project_folder,
|
|
@@ -31,6 +32,7 @@ from fastapi_fastkit.backend.main import (
|
|
|
31
32
|
from fastapi_fastkit.core.exceptions import CLIExceptions
|
|
32
33
|
from fastapi_fastkit.core.settings import FastkitConfig
|
|
33
34
|
from fastapi_fastkit.utils.logging import get_logger, setup_logging
|
|
35
|
+
from fastapi_fastkit.utils.main import console as utils_console
|
|
34
36
|
from fastapi_fastkit.utils.main import (
|
|
35
37
|
create_info_table,
|
|
36
38
|
is_fastkit_project,
|
|
@@ -41,14 +43,16 @@ from fastapi_fastkit.utils.main import (
|
|
|
41
43
|
validate_email,
|
|
42
44
|
)
|
|
43
45
|
|
|
44
|
-
|
|
46
|
+
console = utils_console
|
|
47
|
+
|
|
48
|
+
from . import __version__
|
|
45
49
|
|
|
46
50
|
|
|
47
51
|
@click.group()
|
|
48
52
|
@click.option("--debug/--no-debug", default=False)
|
|
49
53
|
@click.version_option(__version__, prog_name="fastapi-fastkit")
|
|
50
54
|
@click.pass_context
|
|
51
|
-
def fastkit_cli(ctx: Context, debug: bool) -> Union["
|
|
55
|
+
def fastkit_cli(ctx: Context, debug: bool) -> Union["Command", None]:
|
|
52
56
|
"""
|
|
53
57
|
main FastAPI-fastkit CLI operation group
|
|
54
58
|
"""
|
|
@@ -97,6 +101,7 @@ def echo(ctx: Context) -> None:
|
|
|
97
101
|
Deploy FastAPI app foundation instantly at your local!
|
|
98
102
|
|
|
99
103
|
---
|
|
104
|
+
|
|
100
105
|
- Project Maintainer : [link=mailto:bbbong9@gmail.com]bnbong(JunHyeok Lee)[/link]
|
|
101
106
|
- Current Version : {__version__}
|
|
102
107
|
- Github : [link]https://github.com/bnbong/FastAPI-fastkit[/link]
|
|
@@ -135,8 +140,7 @@ def list_templates(ctx: Context) -> None:
|
|
|
135
140
|
print_warning("No available templates.")
|
|
136
141
|
return
|
|
137
142
|
|
|
138
|
-
|
|
139
|
-
|
|
143
|
+
template_data = {}
|
|
140
144
|
for template in templates:
|
|
141
145
|
template_path = os.path.join(template_dir, template)
|
|
142
146
|
readme_path = os.path.join(template_path, "README.md-tpl")
|
|
@@ -148,11 +152,26 @@ def list_templates(ctx: Context) -> None:
|
|
|
148
152
|
if first_line.startswith("# "):
|
|
149
153
|
description = first_line[2:]
|
|
150
154
|
|
|
151
|
-
|
|
155
|
+
template_data[template] = description
|
|
152
156
|
|
|
157
|
+
table = create_info_table("Available Templates", template_data)
|
|
153
158
|
console.print(table)
|
|
154
159
|
|
|
155
160
|
|
|
161
|
+
@fastkit_cli.command()
|
|
162
|
+
@click.pass_context
|
|
163
|
+
def list_features(ctx: Context) -> None:
|
|
164
|
+
"""
|
|
165
|
+
Display the list of available features and packages in the catalog.
|
|
166
|
+
|
|
167
|
+
Shows all available features that can be selected during interactive
|
|
168
|
+
project creation, along with their associated packages.
|
|
169
|
+
"""
|
|
170
|
+
settings = ctx.obj["settings"]
|
|
171
|
+
|
|
172
|
+
display_feature_catalog(settings.PACKAGE_CATALOG, settings.FEATURE_DESCRIPTIONS)
|
|
173
|
+
|
|
174
|
+
|
|
156
175
|
@fastkit_cli.command(context_settings={"ignore_unknown_options": True})
|
|
157
176
|
@click.argument("template", default="fastapi-default")
|
|
158
177
|
@click.option(
|
|
@@ -293,23 +312,26 @@ def startdemo(
|
|
|
293
312
|
|
|
294
313
|
@fastkit_cli.command(context_settings={"ignore_unknown_options": True})
|
|
295
314
|
@click.option(
|
|
296
|
-
"--
|
|
297
|
-
|
|
298
|
-
|
|
315
|
+
"--interactive",
|
|
316
|
+
is_flag=True,
|
|
317
|
+
default=False,
|
|
318
|
+
help="Enable interactive mode for guided project setup with feature selection.",
|
|
299
319
|
)
|
|
300
320
|
@click.option(
|
|
301
|
-
"--
|
|
321
|
+
"--project-name",
|
|
322
|
+
default=None,
|
|
323
|
+
help="The name of the new FastAPI project.",
|
|
302
324
|
)
|
|
325
|
+
@click.option("--author", default=None, help="The name of the project author.")
|
|
303
326
|
@click.option(
|
|
304
327
|
"--author-email",
|
|
305
|
-
|
|
328
|
+
default=None,
|
|
306
329
|
help="The email of the project author.",
|
|
307
330
|
type=str,
|
|
308
|
-
callback=validate_email,
|
|
309
331
|
)
|
|
310
332
|
@click.option(
|
|
311
333
|
"--description",
|
|
312
|
-
|
|
334
|
+
default=None,
|
|
313
335
|
help="The description of the new FastAPI project.",
|
|
314
336
|
)
|
|
315
337
|
@click.option(
|
|
@@ -321,6 +343,7 @@ def startdemo(
|
|
|
321
343
|
@click.pass_context
|
|
322
344
|
def init(
|
|
323
345
|
ctx: Context,
|
|
346
|
+
interactive: bool,
|
|
324
347
|
project_name: str,
|
|
325
348
|
author: str,
|
|
326
349
|
author_email: str,
|
|
@@ -328,15 +351,190 @@ def init(
|
|
|
328
351
|
package_manager: str,
|
|
329
352
|
) -> None:
|
|
330
353
|
"""
|
|
331
|
-
Start a
|
|
332
|
-
|
|
333
|
-
This command will automatically create a new FastAPI project directory and a python virtual environment.
|
|
354
|
+
Start a FastAPI project setup.
|
|
334
355
|
|
|
335
|
-
|
|
356
|
+
Use --interactive for guided setup with dynamic feature selection.
|
|
357
|
+
Without --interactive, creates an empty project with predefined stacks.
|
|
336
358
|
|
|
337
|
-
|
|
359
|
+
This command will automatically create a new FastAPI project directory
|
|
360
|
+
and a python virtual environment. Dependencies will be automatically
|
|
361
|
+
installed based on the selected features or stack.
|
|
338
362
|
"""
|
|
339
363
|
settings = ctx.obj["settings"]
|
|
364
|
+
|
|
365
|
+
# Interactive mode - use InteractiveConfigBuilder
|
|
366
|
+
if interactive:
|
|
367
|
+
print_info("Starting interactive project setup...")
|
|
368
|
+
|
|
369
|
+
builder = InteractiveConfigBuilder(settings)
|
|
370
|
+
config = builder.run_interactive_flow()
|
|
371
|
+
|
|
372
|
+
# User cancelled
|
|
373
|
+
if not config:
|
|
374
|
+
return
|
|
375
|
+
|
|
376
|
+
# Extract configuration
|
|
377
|
+
project_name = cast(str, config.get("project_name", ""))
|
|
378
|
+
author = cast(str, config.get("author", ""))
|
|
379
|
+
author_email = cast(str, config.get("author_email", ""))
|
|
380
|
+
description = cast(str, config.get("description", ""))
|
|
381
|
+
package_manager = config.get(
|
|
382
|
+
"package_manager", settings.DEFAULT_PACKAGE_MANAGER
|
|
383
|
+
)
|
|
384
|
+
all_dependencies = config.get("all_dependencies", [])
|
|
385
|
+
|
|
386
|
+
# Check if project already exists
|
|
387
|
+
project_dir = os.path.join(settings.USER_WORKSPACE, project_name)
|
|
388
|
+
if os.path.exists(project_dir):
|
|
389
|
+
print_error(f"Error: Project '{project_name}' already exists.")
|
|
390
|
+
return
|
|
391
|
+
|
|
392
|
+
# Ask user whether to create a new project folder
|
|
393
|
+
create_project_folder = ask_create_project_folder(project_name)
|
|
394
|
+
|
|
395
|
+
try:
|
|
396
|
+
user_local = settings.USER_WORKSPACE
|
|
397
|
+
|
|
398
|
+
# Use fastapi-empty template as base
|
|
399
|
+
template = "fastapi-empty"
|
|
400
|
+
template_dir = settings.FASTKIT_TEMPLATE_ROOT
|
|
401
|
+
target_template = os.path.join(template_dir, template)
|
|
402
|
+
|
|
403
|
+
if not os.path.exists(target_template):
|
|
404
|
+
print_error(
|
|
405
|
+
f"Template '{template}' does not exist in '{template_dir}'."
|
|
406
|
+
)
|
|
407
|
+
raise CLIExceptions(
|
|
408
|
+
f"Template '{template}' does not exist in '{template_dir}'."
|
|
409
|
+
)
|
|
410
|
+
|
|
411
|
+
# Deploy template
|
|
412
|
+
project_dir, _ = deploy_template_with_folder_option(
|
|
413
|
+
target_template, user_local, project_name, create_project_folder
|
|
414
|
+
)
|
|
415
|
+
|
|
416
|
+
# Inject project metadata
|
|
417
|
+
inject_project_metadata(
|
|
418
|
+
project_dir, project_name, author, author_email, description
|
|
419
|
+
)
|
|
420
|
+
|
|
421
|
+
# Generate dependency file with collected dependencies
|
|
422
|
+
generate_dependency_file_with_manager(
|
|
423
|
+
project_dir,
|
|
424
|
+
all_dependencies,
|
|
425
|
+
package_manager,
|
|
426
|
+
project_name,
|
|
427
|
+
author,
|
|
428
|
+
author_email,
|
|
429
|
+
description,
|
|
430
|
+
)
|
|
431
|
+
|
|
432
|
+
# Update setup.py install_requires with selected dependencies
|
|
433
|
+
from fastapi_fastkit.backend.main import update_setup_py_dependencies
|
|
434
|
+
|
|
435
|
+
update_setup_py_dependencies(project_dir, all_dependencies)
|
|
436
|
+
|
|
437
|
+
print_success(
|
|
438
|
+
f"Generated dependency file with {len(all_dependencies)} packages"
|
|
439
|
+
)
|
|
440
|
+
|
|
441
|
+
# Generate stack-specific code and configurations
|
|
442
|
+
from fastapi_fastkit.backend.project_builder.config_generator import (
|
|
443
|
+
DynamicConfigGenerator,
|
|
444
|
+
)
|
|
445
|
+
|
|
446
|
+
generator = DynamicConfigGenerator(config, project_dir)
|
|
447
|
+
|
|
448
|
+
# Generate main.py with selected features
|
|
449
|
+
main_py_content = generator.generate_main_py()
|
|
450
|
+
main_py_path = os.path.join(project_dir, "src", "main.py")
|
|
451
|
+
if not os.path.exists(main_py_path):
|
|
452
|
+
main_py_path = os.path.join(project_dir, "main.py")
|
|
453
|
+
|
|
454
|
+
with open(main_py_path, "w") as f:
|
|
455
|
+
f.write(main_py_content)
|
|
456
|
+
|
|
457
|
+
# Generate database configuration if selected
|
|
458
|
+
db_info = config.get("database", {})
|
|
459
|
+
if isinstance(db_info, dict) and db_info.get("type") != "None":
|
|
460
|
+
db_config_content = generator.generate_database_config()
|
|
461
|
+
if db_config_content:
|
|
462
|
+
db_config_path = os.path.join(
|
|
463
|
+
project_dir, "src", "config", "database.py"
|
|
464
|
+
)
|
|
465
|
+
os.makedirs(os.path.dirname(db_config_path), exist_ok=True)
|
|
466
|
+
with open(db_config_path, "w") as f:
|
|
467
|
+
f.write(db_config_content)
|
|
468
|
+
|
|
469
|
+
# Generate auth configuration if selected
|
|
470
|
+
auth_type = config.get("authentication", "None")
|
|
471
|
+
if auth_type != "None":
|
|
472
|
+
auth_config_content = generator.generate_auth_config()
|
|
473
|
+
if auth_config_content:
|
|
474
|
+
auth_config_path = os.path.join(
|
|
475
|
+
project_dir, "src", "config", "auth.py"
|
|
476
|
+
)
|
|
477
|
+
os.makedirs(os.path.dirname(auth_config_path), exist_ok=True)
|
|
478
|
+
with open(auth_config_path, "w") as f:
|
|
479
|
+
f.write(auth_config_content)
|
|
480
|
+
|
|
481
|
+
# Generate test configuration if testing selected
|
|
482
|
+
testing_type = config.get("testing", "None")
|
|
483
|
+
if testing_type != "None":
|
|
484
|
+
test_config_content = generator.generate_test_config()
|
|
485
|
+
if test_config_content:
|
|
486
|
+
test_config_path = os.path.join(project_dir, "tests", "conftest.py")
|
|
487
|
+
os.makedirs(os.path.dirname(test_config_path), exist_ok=True)
|
|
488
|
+
with open(test_config_path, "w") as f:
|
|
489
|
+
f.write(test_config_content)
|
|
490
|
+
|
|
491
|
+
# Generate Docker files if deployment selected
|
|
492
|
+
deployment = config.get("deployment", [])
|
|
493
|
+
if deployment and deployment != ["None"]:
|
|
494
|
+
generator.generate_docker_files()
|
|
495
|
+
print_success(f"Generated Docker deployment files")
|
|
496
|
+
|
|
497
|
+
print_success(f"Generated configuration files for selected stack")
|
|
498
|
+
|
|
499
|
+
# Create virtual environment and install dependencies
|
|
500
|
+
venv_path = create_venv_with_manager(project_dir, package_manager)
|
|
501
|
+
install_dependencies_with_manager(project_dir, venv_path, package_manager)
|
|
502
|
+
|
|
503
|
+
success_message = get_deployment_success_message(
|
|
504
|
+
template, project_name, user_local, create_project_folder
|
|
505
|
+
)
|
|
506
|
+
print_success(success_message)
|
|
507
|
+
|
|
508
|
+
print_info(
|
|
509
|
+
"To start your project, run 'fastkit runserver' at newly created FastAPI project directory"
|
|
510
|
+
)
|
|
511
|
+
|
|
512
|
+
except Exception as e:
|
|
513
|
+
if settings.DEBUG_MODE:
|
|
514
|
+
logger = get_logger()
|
|
515
|
+
logger.exception(f"Error during project creation in init: {str(e)}")
|
|
516
|
+
print_error(f"Error during project creation: {str(e)}")
|
|
517
|
+
if os.path.exists(project_dir):
|
|
518
|
+
shutil.rmtree(project_dir, ignore_errors=True)
|
|
519
|
+
|
|
520
|
+
return
|
|
521
|
+
|
|
522
|
+
# Non-interactive mode (original behavior)
|
|
523
|
+
# Require parameters if not interactive
|
|
524
|
+
if not project_name:
|
|
525
|
+
project_name = click.prompt("Enter the project name", type=str)
|
|
526
|
+
if not author:
|
|
527
|
+
author = click.prompt("Enter the author name", type=str)
|
|
528
|
+
if not author_email:
|
|
529
|
+
while True:
|
|
530
|
+
author_email = click.prompt("Enter the author email", type=str)
|
|
531
|
+
# Simple validation
|
|
532
|
+
if "@" in author_email and "." in author_email:
|
|
533
|
+
break
|
|
534
|
+
print_error("Invalid email format. Please try again.")
|
|
535
|
+
if not description:
|
|
536
|
+
description = click.prompt("Enter the project description", type=str)
|
|
537
|
+
|
|
340
538
|
project_dir = os.path.join(settings.USER_WORKSPACE, project_name)
|
|
341
539
|
|
|
342
540
|
if os.path.exists(project_dir):
|
fastapi_fastkit/core/settings.py
CHANGED
|
@@ -94,6 +94,80 @@ class FastkitConfig:
|
|
|
94
94
|
},
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
+
# Package Catalog for Interactive Mode (v1.2.0+)
|
|
98
|
+
# Based on recommendations from: https://github.com/mjhea0/awesome-fastapi
|
|
99
|
+
PACKAGE_CATALOG: dict[str, dict[str, list[str]]] = {
|
|
100
|
+
"database": {
|
|
101
|
+
"PostgreSQL": ["psycopg2-binary", "asyncpg", "sqlalchemy", "alembic"],
|
|
102
|
+
"MySQL": ["pymysql", "aiomysql", "sqlalchemy", "alembic"],
|
|
103
|
+
"MongoDB": ["motor", "beanie"],
|
|
104
|
+
"Redis": ["redis[hiredis]", "aioredis"],
|
|
105
|
+
"SQLite": ["sqlalchemy", "alembic"],
|
|
106
|
+
"None": [],
|
|
107
|
+
},
|
|
108
|
+
"authentication": {
|
|
109
|
+
"JWT": ["python-jose[cryptography]", "passlib[bcrypt]"],
|
|
110
|
+
"OAuth2": ["authlib"],
|
|
111
|
+
"FastAPI-Users": [
|
|
112
|
+
"fastapi-users[sqlalchemy]",
|
|
113
|
+
"python-jose[cryptography]",
|
|
114
|
+
"passlib[bcrypt]",
|
|
115
|
+
],
|
|
116
|
+
"Session-based": ["itsdangerous"],
|
|
117
|
+
"None": [],
|
|
118
|
+
},
|
|
119
|
+
"async_tasks": {
|
|
120
|
+
"Celery": ["celery[redis]", "redis"],
|
|
121
|
+
"Dramatiq": ["dramatiq[redis]", "redis"],
|
|
122
|
+
"None": [],
|
|
123
|
+
},
|
|
124
|
+
"testing": {
|
|
125
|
+
"Basic": ["pytest", "pytest-asyncio", "httpx"],
|
|
126
|
+
"Coverage": ["pytest", "pytest-asyncio", "pytest-cov", "httpx"],
|
|
127
|
+
"Advanced": [
|
|
128
|
+
"pytest",
|
|
129
|
+
"pytest-asyncio",
|
|
130
|
+
"pytest-cov",
|
|
131
|
+
"httpx",
|
|
132
|
+
"faker",
|
|
133
|
+
"factory-boy",
|
|
134
|
+
],
|
|
135
|
+
"None": [],
|
|
136
|
+
},
|
|
137
|
+
"caching": {
|
|
138
|
+
"Redis": ["redis[hiredis]", "fastapi-cache2"],
|
|
139
|
+
"None": [],
|
|
140
|
+
},
|
|
141
|
+
"monitoring": {
|
|
142
|
+
"Loguru": ["loguru"],
|
|
143
|
+
"OpenTelemetry": [
|
|
144
|
+
"opentelemetry-api",
|
|
145
|
+
"opentelemetry-sdk",
|
|
146
|
+
"opentelemetry-instrumentation-fastapi",
|
|
147
|
+
],
|
|
148
|
+
"Prometheus": ["prometheus-client", "prometheus-fastapi-instrumentator"],
|
|
149
|
+
"None": [],
|
|
150
|
+
},
|
|
151
|
+
"utilities": {
|
|
152
|
+
"CORS": [], # Built-in to FastAPI
|
|
153
|
+
"Rate-Limiting": ["slowapi"],
|
|
154
|
+
"Pagination": ["fastapi-pagination"],
|
|
155
|
+
"WebSocket": [], # Built-in to FastAPI
|
|
156
|
+
"None": [],
|
|
157
|
+
},
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
# Feature descriptions for display in interactive mode
|
|
161
|
+
FEATURE_DESCRIPTIONS: dict[str, str] = {
|
|
162
|
+
"database": "Database and ORM selection",
|
|
163
|
+
"authentication": "User authentication and authorization",
|
|
164
|
+
"async_tasks": "Background task processing",
|
|
165
|
+
"testing": "Testing framework and tools",
|
|
166
|
+
"caching": "Response and data caching",
|
|
167
|
+
"monitoring": "Application monitoring and logging",
|
|
168
|
+
"utilities": "Additional utilities and middleware",
|
|
169
|
+
}
|
|
170
|
+
|
|
97
171
|
# Testing Options
|
|
98
172
|
TEST_SERVER_PORT: int = 8000
|
|
99
173
|
TEST_DEFAULT_TERMINAL_WIDTH: int = 80
|
|
@@ -7,7 +7,7 @@ authors = [
|
|
|
7
7
|
]
|
|
8
8
|
readme = "README.md"
|
|
9
9
|
license = "MIT"
|
|
10
|
-
requires-python = ">=3.
|
|
10
|
+
requires-python = ">=3.12"
|
|
11
11
|
dependencies = [
|
|
12
12
|
"fastapi>=0.115.8",
|
|
13
13
|
"uvicorn[standard]>=0.34.0",
|
|
@@ -16,6 +16,7 @@ dependencies = [
|
|
|
16
16
|
"SQLAlchemy>=2.0.38",
|
|
17
17
|
"python-dotenv>=1.0.1",
|
|
18
18
|
"aiofiles>=24.1.0",
|
|
19
|
+
"fastapi-fastkit>=1.1.5",
|
|
19
20
|
]
|
|
20
21
|
|
|
21
22
|
[project.optional-dependencies]
|
|
@@ -7,7 +7,7 @@ authors = [
|
|
|
7
7
|
]
|
|
8
8
|
readme = "README.md"
|
|
9
9
|
license = "MIT"
|
|
10
|
-
requires-python = ">=3.
|
|
10
|
+
requires-python = ">=3.12"
|
|
11
11
|
dependencies = [
|
|
12
12
|
"fastapi>=0.115.8",
|
|
13
13
|
"uvicorn[standard]>=0.34.0",
|
|
@@ -16,6 +16,7 @@ dependencies = [
|
|
|
16
16
|
"SQLAlchemy>=2.0.38",
|
|
17
17
|
"python-dotenv>=1.0.1",
|
|
18
18
|
"aiofiles>=24.1.0",
|
|
19
|
+
"fastapi-fastkit>=1.1.5",
|
|
19
20
|
]
|
|
20
21
|
|
|
21
22
|
[project.optional-dependencies]
|
|
@@ -7,7 +7,7 @@ authors = [
|
|
|
7
7
|
]
|
|
8
8
|
readme = "README.md"
|
|
9
9
|
license = "MIT"
|
|
10
|
-
requires-python = ">=3.
|
|
10
|
+
requires-python = ">=3.12"
|
|
11
11
|
dependencies = [
|
|
12
12
|
"fastapi>=0.115.8",
|
|
13
13
|
"uvicorn[standard]>=0.34.0",
|
|
@@ -15,6 +15,7 @@ dependencies = [
|
|
|
15
15
|
"pydantic-settings>=2.7.1",
|
|
16
16
|
"SQLAlchemy>=2.0.38",
|
|
17
17
|
"python-dotenv>=1.0.1",
|
|
18
|
+
"fastapi-fastkit>=1.1.5",
|
|
18
19
|
]
|
|
19
20
|
|
|
20
21
|
[project.optional-dependencies]
|