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.
Files changed (39) hide show
  1. fastapi_fastkit/__init__.py +1 -1
  2. fastapi_fastkit/backend/inspector.py +170 -12
  3. fastapi_fastkit/backend/interactive/__init__.py +51 -0
  4. fastapi_fastkit/backend/interactive/config_builder.py +186 -0
  5. fastapi_fastkit/backend/interactive/prompts.py +528 -0
  6. fastapi_fastkit/backend/interactive/selectors.py +241 -0
  7. fastapi_fastkit/backend/interactive/validators.py +163 -0
  8. fastapi_fastkit/backend/main.py +77 -0
  9. fastapi_fastkit/backend/package_managers/pdm_manager.py +6 -2
  10. fastapi_fastkit/backend/package_managers/pip_manager.py +6 -2
  11. fastapi_fastkit/backend/package_managers/poetry_manager.py +6 -2
  12. fastapi_fastkit/backend/package_managers/uv_manager.py +6 -2
  13. fastapi_fastkit/backend/project_builder/__init__.py +17 -0
  14. fastapi_fastkit/backend/project_builder/config_generator.py +594 -0
  15. fastapi_fastkit/backend/project_builder/dependency_collector.py +210 -0
  16. fastapi_fastkit/cli.py +218 -20
  17. fastapi_fastkit/core/settings.py +74 -0
  18. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/pyproject.toml-tpl +2 -1
  19. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/requirements.txt-tpl +1 -0
  20. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/pyproject.toml-tpl +2 -1
  21. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/requirements.txt-tpl +1 -0
  22. fastapi_fastkit/fastapi_project_template/fastapi-default/pyproject.toml-tpl +2 -1
  23. fastapi_fastkit/fastapi_project_template/fastapi-default/requirements.txt-tpl +1 -0
  24. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/pyproject.toml-tpl +2 -1
  25. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/requirements.txt-tpl +1 -0
  26. fastapi_fastkit/fastapi_project_template/fastapi-empty/pyproject.toml-tpl +2 -1
  27. fastapi_fastkit/fastapi_project_template/fastapi-empty/requirements.txt-tpl +1 -0
  28. fastapi_fastkit/fastapi_project_template/fastapi-mcp/pyproject.toml-tpl +2 -1
  29. fastapi_fastkit/fastapi_project_template/fastapi-mcp/requirements.txt-tpl +1 -0
  30. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/pyproject.toml-tpl +2 -1
  31. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/requirements.txt-tpl +1 -0
  32. fastapi_fastkit/fastapi_project_template/fastapi-single-module/pyproject.toml-tpl +2 -1
  33. fastapi_fastkit/fastapi_project_template/fastapi-single-module/requirements.txt-tpl +1 -0
  34. fastapi_fastkit/utils/main.py +121 -10
  35. {fastapi_fastkit-1.1.4.dist-info → fastapi_fastkit-1.2.0.dist-info}/METADATA +9 -6
  36. {fastapi_fastkit-1.1.4.dist-info → fastapi_fastkit-1.2.0.dist-info}/RECORD +39 -31
  37. {fastapi_fastkit-1.1.4.dist-info → fastapi_fastkit-1.2.0.dist-info}/WHEEL +1 -1
  38. {fastapi_fastkit-1.1.4.dist-info → fastapi_fastkit-1.2.0.dist-info}/entry_points.txt +0 -0
  39. {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.core import BaseCommand, Context
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
- from . import __version__, console
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["BaseCommand", None]:
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
- table = create_info_table("Available Templates")
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
- table.add_row(template, description)
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
- "--project-name",
297
- prompt="Enter the project name",
298
- help="The name of the new FastAPI project.",
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
- "--author", prompt="Enter the author name", help="The name of the project author."
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
- prompt="Enter the author email",
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
- prompt="Enter the project description",
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 empty FastAPI project setup.
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
- Dependencies will be automatically installed based on the selected stack at venv.
356
+ Use --interactive for guided setup with dynamic feature selection.
357
+ Without --interactive, creates an empty project with predefined stacks.
336
358
 
337
- Project metadata will be injected to the project files.
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):
@@ -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.9"
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]
@@ -34,3 +34,4 @@ uvloop==0.21.0
34
34
  watchfiles==1.0.4
35
35
  websockets==15.0
36
36
  aiofiles>=24.1.0
37
+ FastAPI-fastkit==1.1.5
@@ -7,7 +7,7 @@ authors = [
7
7
  ]
8
8
  readme = "README.md"
9
9
  license = "MIT"
10
- requires-python = ">=3.9"
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]
@@ -34,3 +34,4 @@ uvicorn==0.34.0
34
34
  uvloop==0.21.0
35
35
  watchfiles==1.0.4
36
36
  websockets==15.0
37
+ FastAPI-fastkit==1.1.5
@@ -7,7 +7,7 @@ authors = [
7
7
  ]
8
8
  readme = "README.md"
9
9
  license = "MIT"
10
- requires-python = ">=3.9"
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]
@@ -32,3 +32,4 @@ uvicorn==0.34.0
32
32
  uvloop==0.21.0
33
33
  watchfiles==1.0.4
34
34
  websockets==15.0
35
+ FastAPI-fastkit==1.1.5