forgeapi 0.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_forge/__init__.py +15 -0
- fastapi_forge/cli.py +125 -0
- fastapi_forge/commands/__init__.py +5 -0
- fastapi_forge/commands/create.py +107 -0
- fastapi_forge/generator.py +300 -0
- fastapi_forge/models.py +187 -0
- fastapi_forge/prompts.py +364 -0
- fastapi_forge/templates/base/.dockerignore.jinja +20 -0
- fastapi_forge/templates/base/.github/workflows/ci.yml.jinja +155 -0
- fastapi_forge/templates/base/.gitignore.jinja +68 -0
- fastapi_forge/templates/base/Dockerfile.jinja +69 -0
- fastapi_forge/templates/base/README.md.jinja +141 -0
- fastapi_forge/templates/base/alembic/README.md.jinja +43 -0
- fastapi_forge/templates/base/alembic/env.py.jinja +93 -0
- fastapi_forge/templates/base/alembic/script.py.mako.jinja +26 -0
- fastapi_forge/templates/base/alembic/versions/.gitkeep.jinja +1 -0
- fastapi_forge/templates/base/alembic.ini.jinja +70 -0
- fastapi_forge/templates/base/app/__init__.py.jinja +5 -0
- fastapi_forge/templates/base/app/api/__init__.py.jinja +3 -0
- fastapi_forge/templates/base/app/api/auth_api.py.jinja +72 -0
- fastapi_forge/templates/base/app/api/health_api.py.jinja +41 -0
- fastapi_forge/templates/base/app/config/__init__.py.jinja +31 -0
- fastapi_forge/templates/base/app/config/base.py.jinja +52 -0
- fastapi_forge/templates/base/app/config/env.py.jinja +75 -0
- fastapi_forge/templates/base/app/core/__init__.py.jinja +3 -0
- fastapi_forge/templates/base/app/core/auth.py.jinja +96 -0
- fastapi_forge/templates/base/app/core/config.py.jinja +56 -0
- fastapi_forge/templates/base/app/core/database.py.jinja +68 -0
- fastapi_forge/templates/base/app/core/deps.py.jinja +55 -0
- fastapi_forge/templates/base/app/core/redis.py.jinja +41 -0
- fastapi_forge/templates/base/app/daos/__init__.py.jinja +3 -0
- fastapi_forge/templates/base/app/exceptions/__init__.py.jinja +7 -0
- fastapi_forge/templates/base/app/exceptions/exception.py.jinja +34 -0
- fastapi_forge/templates/base/app/exceptions/handler.py.jinja +56 -0
- fastapi_forge/templates/base/app/main.py.jinja +24 -0
- fastapi_forge/templates/base/app/models/__init__.py.jinja +7 -0
- fastapi_forge/templates/base/app/models/base.py.jinja +13 -0
- fastapi_forge/templates/base/app/schemas/__init__.py.jinja +3 -0
- fastapi_forge/templates/base/app/schemas/api_schema.py.jinja +20 -0
- fastapi_forge/templates/base/app/schemas/auth_schema.py.jinja +21 -0
- fastapi_forge/templates/base/app/server.py.jinja +99 -0
- fastapi_forge/templates/base/app/services/__init__.py.jinja +3 -0
- fastapi_forge/templates/base/app/utils/__init__.py.jinja +3 -0
- fastapi_forge/templates/base/app/utils/log.py.jinja +21 -0
- fastapi_forge/templates/base/config.yaml.jinja +71 -0
- fastapi_forge/templates/base/docker-compose.yml.jinja +117 -0
- fastapi_forge/templates/base/pyproject.toml.jinja +86 -0
- fastapi_forge/templates/base/pytest.ini.jinja +10 -0
- fastapi_forge/templates/base/ruff.toml.jinja +33 -0
- fastapi_forge/templates/base/tests/__init__.py.jinja +3 -0
- fastapi_forge/templates/base/tests/conftest.py.jinja +31 -0
- fastapi_forge/templates/base/tests/test_health.py.jinja +24 -0
- forgeapi-0.1.0.dist-info/METADATA +182 -0
- forgeapi-0.1.0.dist-info/RECORD +57 -0
- forgeapi-0.1.0.dist-info/WHEEL +4 -0
- forgeapi-0.1.0.dist-info/entry_points.txt +2 -0
- forgeapi-0.1.0.dist-info/licenses/LICENSE +21 -0
fastapi_forge/models.py
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Project Configuration Models
|
|
3
|
+
|
|
4
|
+
This module defines the data structures for project configuration using Pydantic.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from enum import Enum
|
|
8
|
+
from typing import Literal
|
|
9
|
+
|
|
10
|
+
from pydantic import BaseModel, Field, field_validator
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class PackageManager(str, Enum):
|
|
14
|
+
"""Supported package managers."""
|
|
15
|
+
|
|
16
|
+
UV = "uv"
|
|
17
|
+
POETRY = "poetry"
|
|
18
|
+
PIP = "pip"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class DatabaseType(str, Enum):
|
|
22
|
+
"""Supported database types."""
|
|
23
|
+
|
|
24
|
+
POSTGRES = "postgres"
|
|
25
|
+
MYSQL = "mysql"
|
|
26
|
+
SQLITE = "sqlite"
|
|
27
|
+
NONE = "none"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class ProjectConfig(BaseModel):
|
|
31
|
+
"""
|
|
32
|
+
Project configuration model.
|
|
33
|
+
|
|
34
|
+
This model holds all the configuration options for generating a new FastAPI project.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
# Basic Information
|
|
38
|
+
project_name: str = Field(
|
|
39
|
+
...,
|
|
40
|
+
min_length=1,
|
|
41
|
+
max_length=100,
|
|
42
|
+
description="Name of the project",
|
|
43
|
+
)
|
|
44
|
+
project_slug: str = Field(
|
|
45
|
+
default="",
|
|
46
|
+
description="Project identifier in snake_case",
|
|
47
|
+
)
|
|
48
|
+
project_description: str = Field(
|
|
49
|
+
default="A FastAPI project generated by FastAPI-Forge",
|
|
50
|
+
description="Project description",
|
|
51
|
+
)
|
|
52
|
+
author_name: str = Field(
|
|
53
|
+
default="Your Name",
|
|
54
|
+
description="Author name",
|
|
55
|
+
)
|
|
56
|
+
author_email: str = Field(
|
|
57
|
+
default="your@email.com",
|
|
58
|
+
description="Author email",
|
|
59
|
+
)
|
|
60
|
+
python_version: Literal["3.10", "3.11", "3.12", "3.13"] = Field(
|
|
61
|
+
default="3.11",
|
|
62
|
+
description="Python version",
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
# Package Manager
|
|
66
|
+
package_manager: PackageManager = Field(
|
|
67
|
+
default=PackageManager.UV,
|
|
68
|
+
description="Package manager to use",
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
# Database
|
|
72
|
+
database: DatabaseType = Field(
|
|
73
|
+
default=DatabaseType.POSTGRES,
|
|
74
|
+
description="Database type",
|
|
75
|
+
)
|
|
76
|
+
use_alembic: bool = Field(
|
|
77
|
+
default=True,
|
|
78
|
+
description="Whether to use Alembic for database migrations",
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
# Features
|
|
82
|
+
use_auth: bool = Field(
|
|
83
|
+
default=True,
|
|
84
|
+
description="Whether to include JWT authentication",
|
|
85
|
+
)
|
|
86
|
+
use_redis: bool = Field(
|
|
87
|
+
default=True,
|
|
88
|
+
description="Whether to include Redis support",
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
# Docker
|
|
92
|
+
use_docker: bool = Field(
|
|
93
|
+
default=True,
|
|
94
|
+
description="Whether to generate Docker configuration",
|
|
95
|
+
)
|
|
96
|
+
use_docker_compose: bool = Field(
|
|
97
|
+
default=True,
|
|
98
|
+
description="Whether to generate docker-compose.yml",
|
|
99
|
+
)
|
|
100
|
+
docker_services: list[str] = Field(
|
|
101
|
+
default_factory=lambda: ["postgres", "redis"],
|
|
102
|
+
description="Services to include in docker-compose",
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
# Testing & Quality
|
|
106
|
+
use_pytest: bool = Field(
|
|
107
|
+
default=True,
|
|
108
|
+
description="Whether to configure Pytest",
|
|
109
|
+
)
|
|
110
|
+
use_ruff: bool = Field(
|
|
111
|
+
default=True,
|
|
112
|
+
description="Whether to configure Ruff linter/formatter",
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
# CI/CD & Editor
|
|
116
|
+
use_github_actions: bool = Field(
|
|
117
|
+
default=True,
|
|
118
|
+
description="Whether to generate GitHub Actions CI",
|
|
119
|
+
)
|
|
120
|
+
use_vscode: bool = Field(
|
|
121
|
+
default=True,
|
|
122
|
+
description="Whether to generate VS Code configuration",
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
@field_validator("project_slug", mode="before")
|
|
126
|
+
@classmethod
|
|
127
|
+
def generate_slug(cls, v: str, info) -> str:
|
|
128
|
+
"""Generate project slug from project name if not provided."""
|
|
129
|
+
if v:
|
|
130
|
+
return v
|
|
131
|
+
# Get project_name from the data being validated
|
|
132
|
+
project_name = info.data.get("project_name", "")
|
|
133
|
+
if project_name:
|
|
134
|
+
# Convert to snake_case
|
|
135
|
+
slug = project_name.lower()
|
|
136
|
+
slug = slug.replace("-", "_")
|
|
137
|
+
slug = slug.replace(" ", "_")
|
|
138
|
+
# Remove any non-alphanumeric characters except underscore
|
|
139
|
+
slug = "".join(c for c in slug if c.isalnum() or c == "_")
|
|
140
|
+
return slug
|
|
141
|
+
return v
|
|
142
|
+
|
|
143
|
+
def model_post_init(self, __context) -> None:
|
|
144
|
+
"""Post-initialization processing."""
|
|
145
|
+
# Ensure project_slug is set
|
|
146
|
+
if not self.project_slug and self.project_name:
|
|
147
|
+
slug = self.project_name.lower()
|
|
148
|
+
slug = slug.replace("-", "_")
|
|
149
|
+
slug = slug.replace(" ", "_")
|
|
150
|
+
slug = "".join(c for c in slug if c.isalnum() or c == "_")
|
|
151
|
+
object.__setattr__(self, "project_slug", slug)
|
|
152
|
+
|
|
153
|
+
# If database is none, disable alembic
|
|
154
|
+
if self.database == DatabaseType.NONE:
|
|
155
|
+
object.__setattr__(self, "use_alembic", False)
|
|
156
|
+
|
|
157
|
+
# Update docker_services based on selections
|
|
158
|
+
services = []
|
|
159
|
+
if self.database == DatabaseType.POSTGRES:
|
|
160
|
+
services.append("postgres")
|
|
161
|
+
elif self.database == DatabaseType.MYSQL:
|
|
162
|
+
services.append("mysql")
|
|
163
|
+
if self.use_redis:
|
|
164
|
+
services.append("redis")
|
|
165
|
+
if services != self.docker_services:
|
|
166
|
+
object.__setattr__(self, "docker_services", services)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
# Default configuration for quick start
|
|
170
|
+
DEFAULT_CONFIG = ProjectConfig(
|
|
171
|
+
project_name="my-fastapi-app",
|
|
172
|
+
project_description="A FastAPI project generated by FastAPI-Forge",
|
|
173
|
+
author_name="Your Name",
|
|
174
|
+
author_email="your@email.com",
|
|
175
|
+
python_version="3.11",
|
|
176
|
+
package_manager=PackageManager.UV,
|
|
177
|
+
database=DatabaseType.POSTGRES,
|
|
178
|
+
use_alembic=True,
|
|
179
|
+
use_auth=True,
|
|
180
|
+
use_redis=True,
|
|
181
|
+
use_docker=True,
|
|
182
|
+
use_docker_compose=True,
|
|
183
|
+
use_pytest=True,
|
|
184
|
+
use_ruff=True,
|
|
185
|
+
use_github_actions=True,
|
|
186
|
+
use_vscode=True,
|
|
187
|
+
)
|
fastapi_forge/prompts.py
ADDED
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Interactive Prompts Module
|
|
3
|
+
|
|
4
|
+
This module provides interactive command-line prompts using Questionary
|
|
5
|
+
for collecting project configuration from users.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import questionary
|
|
9
|
+
from questionary import Style
|
|
10
|
+
from rich.console import Console
|
|
11
|
+
|
|
12
|
+
from fastapi_forge.models import (
|
|
13
|
+
DatabaseType,
|
|
14
|
+
PackageManager,
|
|
15
|
+
ProjectConfig,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
console = Console()
|
|
19
|
+
|
|
20
|
+
# Custom style for questionary prompts
|
|
21
|
+
CUSTOM_STYLE = Style(
|
|
22
|
+
[
|
|
23
|
+
("qmark", "fg:cyan bold"),
|
|
24
|
+
("question", "fg:white bold"),
|
|
25
|
+
("answer", "fg:green bold"),
|
|
26
|
+
("pointer", "fg:cyan bold"),
|
|
27
|
+
("highlighted", "fg:cyan bold"),
|
|
28
|
+
("selected", "fg:green"),
|
|
29
|
+
("separator", "fg:gray"),
|
|
30
|
+
("instruction", "fg:gray italic"),
|
|
31
|
+
("text", "fg:white"),
|
|
32
|
+
]
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def prompt_basic_info(project_name: str | None = None) -> dict:
|
|
37
|
+
"""
|
|
38
|
+
Prompt for basic project information.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
project_name: Optional pre-filled project name
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
Dictionary with basic project info
|
|
45
|
+
"""
|
|
46
|
+
console.print("\n[bold cyan]📝 Basic Project Information[/bold cyan]\n")
|
|
47
|
+
|
|
48
|
+
# Project name
|
|
49
|
+
if project_name:
|
|
50
|
+
name = project_name
|
|
51
|
+
console.print(f" Project name: [green]{name}[/green]")
|
|
52
|
+
else:
|
|
53
|
+
name = questionary.text(
|
|
54
|
+
"Project name:",
|
|
55
|
+
default="my-fastapi-app",
|
|
56
|
+
style=CUSTOM_STYLE,
|
|
57
|
+
).ask()
|
|
58
|
+
|
|
59
|
+
if not name:
|
|
60
|
+
raise KeyboardInterrupt("Project creation cancelled.")
|
|
61
|
+
|
|
62
|
+
# Project description
|
|
63
|
+
description = questionary.text(
|
|
64
|
+
"Project description:",
|
|
65
|
+
default="A FastAPI project generated by FastAPI-Forge",
|
|
66
|
+
style=CUSTOM_STYLE,
|
|
67
|
+
).ask()
|
|
68
|
+
|
|
69
|
+
# Author name
|
|
70
|
+
author_name = questionary.text(
|
|
71
|
+
"Author name:",
|
|
72
|
+
default="Your Name",
|
|
73
|
+
style=CUSTOM_STYLE,
|
|
74
|
+
).ask()
|
|
75
|
+
|
|
76
|
+
# Author email
|
|
77
|
+
author_email = questionary.text(
|
|
78
|
+
"Author email:",
|
|
79
|
+
default="your@email.com",
|
|
80
|
+
style=CUSTOM_STYLE,
|
|
81
|
+
).ask()
|
|
82
|
+
|
|
83
|
+
# Python version
|
|
84
|
+
python_version = questionary.select(
|
|
85
|
+
"Python version:",
|
|
86
|
+
choices=["3.10", "3.11", "3.12", "3.13"],
|
|
87
|
+
default="3.11",
|
|
88
|
+
style=CUSTOM_STYLE,
|
|
89
|
+
).ask()
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
"project_name": name,
|
|
93
|
+
"project_description": description or "A FastAPI project",
|
|
94
|
+
"author_name": author_name or "Your Name",
|
|
95
|
+
"author_email": author_email or "your@email.com",
|
|
96
|
+
"python_version": python_version or "3.11",
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def prompt_package_manager() -> PackageManager:
|
|
101
|
+
"""
|
|
102
|
+
Prompt for package manager selection.
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
Selected PackageManager enum value
|
|
106
|
+
"""
|
|
107
|
+
console.print("\n[bold cyan]📦 Package Manager[/bold cyan]\n")
|
|
108
|
+
|
|
109
|
+
choice = questionary.select(
|
|
110
|
+
"Select package manager:",
|
|
111
|
+
choices=[
|
|
112
|
+
questionary.Choice("uv (recommended - faster)", value="uv"),
|
|
113
|
+
questionary.Choice("Poetry", value="poetry"),
|
|
114
|
+
questionary.Choice("pip (requirements.txt only)", value="pip"),
|
|
115
|
+
],
|
|
116
|
+
default="uv",
|
|
117
|
+
style=CUSTOM_STYLE,
|
|
118
|
+
).ask()
|
|
119
|
+
|
|
120
|
+
return PackageManager(choice) if choice else PackageManager.UV
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def prompt_database() -> tuple[DatabaseType, bool]:
|
|
124
|
+
"""
|
|
125
|
+
Prompt for database configuration.
|
|
126
|
+
|
|
127
|
+
Returns:
|
|
128
|
+
Tuple of (DatabaseType, use_alembic)
|
|
129
|
+
"""
|
|
130
|
+
console.print("\n[bold cyan]🗄️ Database Configuration[/bold cyan]\n")
|
|
131
|
+
|
|
132
|
+
db_choice = questionary.select(
|
|
133
|
+
"Select database:",
|
|
134
|
+
choices=[
|
|
135
|
+
questionary.Choice("PostgreSQL (recommended)", value="postgres"),
|
|
136
|
+
questionary.Choice("MySQL", value="mysql"),
|
|
137
|
+
questionary.Choice("SQLite (development only)", value="sqlite"),
|
|
138
|
+
questionary.Choice("None (no database)", value="none"),
|
|
139
|
+
],
|
|
140
|
+
default="postgres",
|
|
141
|
+
style=CUSTOM_STYLE,
|
|
142
|
+
).ask()
|
|
143
|
+
|
|
144
|
+
database = DatabaseType(db_choice) if db_choice else DatabaseType.POSTGRES
|
|
145
|
+
|
|
146
|
+
use_alembic = False
|
|
147
|
+
if database != DatabaseType.NONE:
|
|
148
|
+
use_alembic = questionary.confirm(
|
|
149
|
+
"Enable database migrations (Alembic)?",
|
|
150
|
+
default=True,
|
|
151
|
+
style=CUSTOM_STYLE,
|
|
152
|
+
).ask()
|
|
153
|
+
use_alembic = use_alembic if use_alembic is not None else True
|
|
154
|
+
|
|
155
|
+
return database, use_alembic
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def prompt_features() -> dict:
|
|
159
|
+
"""
|
|
160
|
+
Prompt for feature selection.
|
|
161
|
+
|
|
162
|
+
Returns:
|
|
163
|
+
Dictionary with feature flags
|
|
164
|
+
"""
|
|
165
|
+
console.print("\n[bold cyan]🔧 Features[/bold cyan]\n")
|
|
166
|
+
|
|
167
|
+
use_auth = questionary.confirm(
|
|
168
|
+
"Include JWT authentication module?",
|
|
169
|
+
default=True,
|
|
170
|
+
style=CUSTOM_STYLE,
|
|
171
|
+
).ask()
|
|
172
|
+
|
|
173
|
+
use_redis = questionary.confirm(
|
|
174
|
+
"Include Redis support?",
|
|
175
|
+
default=True,
|
|
176
|
+
style=CUSTOM_STYLE,
|
|
177
|
+
).ask()
|
|
178
|
+
|
|
179
|
+
return {
|
|
180
|
+
"use_auth": use_auth if use_auth is not None else True,
|
|
181
|
+
"use_redis": use_redis if use_redis is not None else True,
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def prompt_docker() -> dict:
|
|
186
|
+
"""
|
|
187
|
+
Prompt for Docker configuration.
|
|
188
|
+
|
|
189
|
+
Returns:
|
|
190
|
+
Dictionary with Docker settings
|
|
191
|
+
"""
|
|
192
|
+
console.print("\n[bold cyan]🐳 Docker Configuration[/bold cyan]\n")
|
|
193
|
+
|
|
194
|
+
use_docker = questionary.confirm(
|
|
195
|
+
"Generate Dockerfile?",
|
|
196
|
+
default=True,
|
|
197
|
+
style=CUSTOM_STYLE,
|
|
198
|
+
).ask()
|
|
199
|
+
use_docker = use_docker if use_docker is not None else True
|
|
200
|
+
|
|
201
|
+
use_docker_compose = False
|
|
202
|
+
docker_services: list[str] = []
|
|
203
|
+
|
|
204
|
+
if use_docker:
|
|
205
|
+
use_docker_compose = questionary.confirm(
|
|
206
|
+
"Generate docker-compose.yml?",
|
|
207
|
+
default=True,
|
|
208
|
+
style=CUSTOM_STYLE,
|
|
209
|
+
).ask()
|
|
210
|
+
use_docker_compose = use_docker_compose if use_docker_compose is not None else True
|
|
211
|
+
|
|
212
|
+
if use_docker_compose:
|
|
213
|
+
docker_services = questionary.checkbox(
|
|
214
|
+
"Select services for docker-compose:",
|
|
215
|
+
choices=[
|
|
216
|
+
questionary.Choice("PostgreSQL", value="postgres", checked=True),
|
|
217
|
+
questionary.Choice("Redis", value="redis", checked=True),
|
|
218
|
+
questionary.Choice("RabbitMQ", value="rabbitmq"),
|
|
219
|
+
questionary.Choice("MinIO (Object Storage)", value="minio"),
|
|
220
|
+
],
|
|
221
|
+
style=CUSTOM_STYLE,
|
|
222
|
+
).ask()
|
|
223
|
+
docker_services = docker_services or ["postgres", "redis"]
|
|
224
|
+
|
|
225
|
+
return {
|
|
226
|
+
"use_docker": use_docker,
|
|
227
|
+
"use_docker_compose": use_docker_compose,
|
|
228
|
+
"docker_services": docker_services,
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def prompt_extras() -> dict:
|
|
233
|
+
"""
|
|
234
|
+
Prompt for extra configuration options.
|
|
235
|
+
|
|
236
|
+
Returns:
|
|
237
|
+
Dictionary with extra settings
|
|
238
|
+
"""
|
|
239
|
+
console.print("\n[bold cyan]✨ Extra Options[/bold cyan]\n")
|
|
240
|
+
|
|
241
|
+
use_pytest = questionary.confirm(
|
|
242
|
+
"Configure Pytest for testing?",
|
|
243
|
+
default=True,
|
|
244
|
+
style=CUSTOM_STYLE,
|
|
245
|
+
).ask()
|
|
246
|
+
|
|
247
|
+
use_ruff = questionary.confirm(
|
|
248
|
+
"Configure Ruff (linter/formatter)?",
|
|
249
|
+
default=True,
|
|
250
|
+
style=CUSTOM_STYLE,
|
|
251
|
+
).ask()
|
|
252
|
+
|
|
253
|
+
use_github_actions = questionary.confirm(
|
|
254
|
+
"Generate GitHub Actions CI?",
|
|
255
|
+
default=True,
|
|
256
|
+
style=CUSTOM_STYLE,
|
|
257
|
+
).ask()
|
|
258
|
+
|
|
259
|
+
use_vscode = questionary.confirm(
|
|
260
|
+
"Generate VS Code configuration?",
|
|
261
|
+
default=True,
|
|
262
|
+
style=CUSTOM_STYLE,
|
|
263
|
+
).ask()
|
|
264
|
+
|
|
265
|
+
return {
|
|
266
|
+
"use_pytest": use_pytest if use_pytest is not None else True,
|
|
267
|
+
"use_ruff": use_ruff if use_ruff is not None else True,
|
|
268
|
+
"use_github_actions": use_github_actions if use_github_actions is not None else True,
|
|
269
|
+
"use_vscode": use_vscode if use_vscode is not None else True,
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def collect_project_config(project_name: str | None = None) -> ProjectConfig:
|
|
274
|
+
"""
|
|
275
|
+
Collect all project configuration through interactive prompts.
|
|
276
|
+
|
|
277
|
+
Args:
|
|
278
|
+
project_name: Optional pre-filled project name
|
|
279
|
+
|
|
280
|
+
Returns:
|
|
281
|
+
Complete ProjectConfig object
|
|
282
|
+
"""
|
|
283
|
+
console.print(
|
|
284
|
+
"\n[bold cyan]🚀 FastAPI-Forge[/bold cyan] - "
|
|
285
|
+
"[white]Create New Project[/white]\n"
|
|
286
|
+
)
|
|
287
|
+
console.print("[dim]Press Ctrl+C to cancel at any time.[/dim]\n")
|
|
288
|
+
|
|
289
|
+
try:
|
|
290
|
+
# Collect all configuration
|
|
291
|
+
basic_info = prompt_basic_info(project_name)
|
|
292
|
+
package_manager = prompt_package_manager()
|
|
293
|
+
database, use_alembic = prompt_database()
|
|
294
|
+
features = prompt_features()
|
|
295
|
+
docker = prompt_docker()
|
|
296
|
+
extras = prompt_extras()
|
|
297
|
+
|
|
298
|
+
# Combine all config
|
|
299
|
+
config = ProjectConfig(
|
|
300
|
+
**basic_info,
|
|
301
|
+
package_manager=package_manager,
|
|
302
|
+
database=database,
|
|
303
|
+
use_alembic=use_alembic,
|
|
304
|
+
**features,
|
|
305
|
+
**docker,
|
|
306
|
+
**extras,
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
return config
|
|
310
|
+
|
|
311
|
+
except KeyboardInterrupt:
|
|
312
|
+
console.print("\n\n[yellow]Project creation cancelled.[/yellow]")
|
|
313
|
+
raise
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
def confirm_config(config: ProjectConfig) -> bool:
|
|
317
|
+
"""
|
|
318
|
+
Display configuration summary and ask for confirmation.
|
|
319
|
+
|
|
320
|
+
Args:
|
|
321
|
+
config: ProjectConfig to display
|
|
322
|
+
|
|
323
|
+
Returns:
|
|
324
|
+
True if user confirms, False otherwise
|
|
325
|
+
"""
|
|
326
|
+
console.print("\n[bold cyan]📋 Configuration Summary[/bold cyan]\n")
|
|
327
|
+
|
|
328
|
+
console.print(f" [white]Project:[/white] [green]{config.project_name}[/green]")
|
|
329
|
+
console.print(f" [white]Description:[/white] {config.project_description}")
|
|
330
|
+
console.print(f" [white]Author:[/white] {config.author_name} <{config.author_email}>")
|
|
331
|
+
console.print(f" [white]Python:[/white] {config.python_version}")
|
|
332
|
+
console.print(f" [white]Package Manager:[/white] {config.package_manager.value}")
|
|
333
|
+
console.print(f" [white]Database:[/white] {config.database.value}")
|
|
334
|
+
|
|
335
|
+
features = []
|
|
336
|
+
if config.use_alembic:
|
|
337
|
+
features.append("Alembic")
|
|
338
|
+
if config.use_auth:
|
|
339
|
+
features.append("JWT Auth")
|
|
340
|
+
if config.use_redis:
|
|
341
|
+
features.append("Redis")
|
|
342
|
+
if config.use_docker:
|
|
343
|
+
features.append("Docker")
|
|
344
|
+
if config.use_pytest:
|
|
345
|
+
features.append("Pytest")
|
|
346
|
+
if config.use_ruff:
|
|
347
|
+
features.append("Ruff")
|
|
348
|
+
if config.use_github_actions:
|
|
349
|
+
features.append("GitHub Actions")
|
|
350
|
+
|
|
351
|
+
console.print(f" [white]Features:[/white] {', '.join(features)}")
|
|
352
|
+
|
|
353
|
+
if config.use_docker_compose and config.docker_services:
|
|
354
|
+
console.print(f" [white]Docker Services:[/white] {', '.join(config.docker_services)}")
|
|
355
|
+
|
|
356
|
+
console.print()
|
|
357
|
+
|
|
358
|
+
confirm = questionary.confirm(
|
|
359
|
+
"Create project with this configuration?",
|
|
360
|
+
default=True,
|
|
361
|
+
style=CUSTOM_STYLE,
|
|
362
|
+
).ask()
|
|
363
|
+
|
|
364
|
+
return confirm if confirm is not None else False
|