fastapi-gen-newone 0.1.1__tar.gz

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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mouad
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,95 @@
1
+ Metadata-Version: 2.4
2
+ Name: fastapi-gen-newone
3
+ Version: 0.1.1
4
+ Summary: ⚡ Scaffold production-ready FastAPI projects instantly
5
+ Author: Mouad Sadik
6
+ License: MIT
7
+ Keywords: fastapi,cli,generator,backend,python
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.11
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENCE
14
+ Requires-Dist: typer>=0.12
15
+ Requires-Dist: rich>=13
16
+ Dynamic: license-file
17
+
18
+ # fastapi-gen ⚡
19
+
20
+ > Create production-ready FastAPI projects in seconds.
21
+
22
+ ## Install
23
+ ```bash
24
+ pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ fastapi-gen-newone
25
+ ```
26
+
27
+ Or run directly with `pipx`:
28
+ ```bash
29
+ pipx run fastapi-gen-newone my-app
30
+ ```
31
+
32
+ ## Usage
33
+
34
+ ### Interactive (recommended)
35
+ ```bash
36
+ fastapi-gen my-app
37
+ ```
38
+
39
+ You'll be prompted to select features:
40
+ ```
41
+ ⚡ FastAPI Project Generator
42
+ Scaffold a production-ready FastAPI app in seconds
43
+
44
+ ? Project name: my-app
45
+ ? Include SQLAlchemy (database models): Yes
46
+ ? Include Alembic (database migrations): Yes
47
+ ? Include JWT Auth (login/register routes): Yes
48
+ ? Include Docker (Dockerfile + docker-compose): Yes
49
+ ? Include Pytest (test suite): Yes
50
+ ```
51
+
52
+ ### With flags (non-interactive)
53
+ ```bash
54
+ fastapi-gen my-app --db --auth --docker --alembic --tests
55
+ ```
56
+
57
+ ### Skip prompts entirely
58
+ ```bash
59
+ fastapi-gen my-app -y # bare project, no extras
60
+ fastapi-gen my-app -y --auth # just auth, no prompts
61
+ ```
62
+
63
+ ## Generated structure
64
+ ```
65
+ my-app/
66
+ ├── src/
67
+ │ ├── main.py ← FastAPI app entrypoint
68
+ │ ├── core/
69
+ │ │ └── config.py ← pydantic-settings
70
+ │ ├── api/v1/
71
+ │ │ ├── router.py
72
+ │ │ └── endpoints/
73
+ │ │ └── health.py
74
+ │ ├── db/ ← (if --db)
75
+ │ │ └── session.py
76
+ │ ├── models/ ← (if --db)
77
+ │ └── schemas/ ← (if --db)
78
+ ├── alembic/ ← (if --alembic)
79
+ ├── tests/ ← (if --tests)
80
+ ├── Dockerfile ← (if --docker)
81
+ ├── docker-compose.yml ← (if --docker)
82
+ ├── pyproject.toml
83
+ ├── .env.example
84
+ └── README.md
85
+ ```
86
+
87
+ ## Options
88
+
89
+ | Flag | Description |
90
+ |------|-------------|
91
+ | `--db` | SQLAlchemy async ORM + aiosqlite |
92
+ | `--alembic` | Alembic migration setup |
93
+ | `--docker` | Dockerfile + docker-compose |
94
+ | `--tests` | pytest + httpx async test suite |
95
+ | `-y / --no-interactive` | Skip all prompts |
@@ -0,0 +1,78 @@
1
+ # fastapi-gen ⚡
2
+
3
+ > Create production-ready FastAPI projects in seconds.
4
+
5
+ ## Install
6
+ ```bash
7
+ pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ fastapi-gen-newone
8
+ ```
9
+
10
+ Or run directly with `pipx`:
11
+ ```bash
12
+ pipx run fastapi-gen-newone my-app
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ ### Interactive (recommended)
18
+ ```bash
19
+ fastapi-gen my-app
20
+ ```
21
+
22
+ You'll be prompted to select features:
23
+ ```
24
+ ⚡ FastAPI Project Generator
25
+ Scaffold a production-ready FastAPI app in seconds
26
+
27
+ ? Project name: my-app
28
+ ? Include SQLAlchemy (database models): Yes
29
+ ? Include Alembic (database migrations): Yes
30
+ ? Include JWT Auth (login/register routes): Yes
31
+ ? Include Docker (Dockerfile + docker-compose): Yes
32
+ ? Include Pytest (test suite): Yes
33
+ ```
34
+
35
+ ### With flags (non-interactive)
36
+ ```bash
37
+ fastapi-gen my-app --db --auth --docker --alembic --tests
38
+ ```
39
+
40
+ ### Skip prompts entirely
41
+ ```bash
42
+ fastapi-gen my-app -y # bare project, no extras
43
+ fastapi-gen my-app -y --auth # just auth, no prompts
44
+ ```
45
+
46
+ ## Generated structure
47
+ ```
48
+ my-app/
49
+ ├── src/
50
+ │ ├── main.py ← FastAPI app entrypoint
51
+ │ ├── core/
52
+ │ │ └── config.py ← pydantic-settings
53
+ │ ├── api/v1/
54
+ │ │ ├── router.py
55
+ │ │ └── endpoints/
56
+ │ │ └── health.py
57
+ │ ├── db/ ← (if --db)
58
+ │ │ └── session.py
59
+ │ ├── models/ ← (if --db)
60
+ │ └── schemas/ ← (if --db)
61
+ ├── alembic/ ← (if --alembic)
62
+ ├── tests/ ← (if --tests)
63
+ ├── Dockerfile ← (if --docker)
64
+ ├── docker-compose.yml ← (if --docker)
65
+ ├── pyproject.toml
66
+ ├── .env.example
67
+ └── README.md
68
+ ```
69
+
70
+ ## Options
71
+
72
+ | Flag | Description |
73
+ |------|-------------|
74
+ | `--db` | SQLAlchemy async ORM + aiosqlite |
75
+ | `--alembic` | Alembic migration setup |
76
+ | `--docker` | Dockerfile + docker-compose |
77
+ | `--tests` | pytest + httpx async test suite |
78
+ | `-y / --no-interactive` | Skip all prompts |
File without changes
@@ -0,0 +1,82 @@
1
+ import typer
2
+ from rich.console import Console
3
+ from rich.prompt import Prompt, Confirm
4
+ from rich.panel import Panel
5
+ from rich.text import Text
6
+ from rich import print as rprint
7
+ import re
8
+
9
+ from .generator import generate_project
10
+ from .config import ProjectConfig
11
+
12
+ app = typer.Typer(add_completion=False)
13
+ console = Console()
14
+
15
+
16
+ def validate_name(name: str) -> str:
17
+ if not re.match(r'^[a-z][a-z0-9_-]*$', name):
18
+ raise typer.BadParameter(
19
+ "Project name must be lowercase, start with a letter, and contain only letters, numbers, hyphens, or underscores."
20
+ )
21
+ return name
22
+
23
+
24
+ @app.command()
25
+ def create(
26
+ project_name: str = typer.Argument(None, help="Name of the project to create"),
27
+ db: bool = typer.Option(False, "--db", help="Add SQLAlchemy + database support"),
28
+ docker: bool = typer.Option(False, "--docker", help="Add Dockerfile & docker-compose"),
29
+ alembic: bool = typer.Option(False, "--alembic", help="Add Alembic migrations"),
30
+ tests: bool = typer.Option(False, "--tests", help="Add pytest test suite"),
31
+ no_interactive: bool = typer.Option(False, "--no-interactive", "-y", help="Skip prompts, use defaults/flags"),
32
+ ):
33
+ """
34
+ ⚡ Create a new FastAPI project.
35
+ """
36
+ console.print()
37
+ console.print(Panel.fit(
38
+ Text.from_markup(
39
+ "[bold cyan]⚡ FastAPI Project Generator[/bold cyan]\n"
40
+ "[dim]Scaffold a production-ready FastAPI app in seconds[/dim]"
41
+ ),
42
+ border_style="cyan",
43
+ padding=(0, 2),
44
+ ))
45
+ console.print()
46
+
47
+ # --- Project name ---
48
+ if project_name is None:
49
+ project_name = Prompt.ask("[bold]? Project name[/bold]", default="my-fastapi-app")
50
+ try:
51
+ validate_name(project_name.replace("-", "_").replace(" ", "_"))
52
+ except typer.BadParameter as e:
53
+ console.print(f"[red]✗ {e}[/red]")
54
+ raise typer.Exit(1)
55
+
56
+ # --- Interactive prompts (unless -y) ---
57
+ if not no_interactive:
58
+ console.print()
59
+ console.print("[dim]Select features to include:[/dim]")
60
+ if not db:
61
+ db = Confirm.ask(" [bold]? Include SQLAlchemy[/bold] (database models)", default=False)
62
+ if db and not alembic:
63
+ alembic = Confirm.ask(" [bold]? Include Alembic[/bold] (database migrations)", default=False)
64
+ if not docker:
65
+ docker = Confirm.ask(" [bold]? Include Docker[/bold] (Dockerfile + docker-compose)", default=False)
66
+ if not tests:
67
+ tests = Confirm.ask(" [bold]? Include Pytest[/bold] (test suite)", default=False)
68
+
69
+ config = ProjectConfig(
70
+ name=project_name,
71
+ db=db,
72
+ docker=docker,
73
+ alembic=alembic,
74
+ tests=tests,
75
+ )
76
+
77
+ console.print()
78
+ generate_project(config, console)
79
+
80
+
81
+ if __name__ == "__main__":
82
+ app()
@@ -0,0 +1,15 @@
1
+ from dataclasses import dataclass, field
2
+
3
+
4
+ @dataclass
5
+ class ProjectConfig:
6
+ name: str
7
+ db: bool = False
8
+ docker: bool = False
9
+ alembic: bool = False
10
+ tests: bool = False
11
+
12
+ @property
13
+ def slug(self) -> str:
14
+ """Snake_case version of the project name for Python modules."""
15
+ return self.name.replace("-", "_").lower()
@@ -0,0 +1,148 @@
1
+ import os
2
+ from pathlib import Path
3
+ from rich.console import Console
4
+ from rich.progress import Progress, SpinnerColumn, TextColumn
5
+ from rich.tree import Tree
6
+ from rich import print as rprint
7
+ import time
8
+
9
+ from .config import ProjectConfig
10
+ from . import templates
11
+
12
+
13
+ def write(path: Path, content: str):
14
+ path.parent.mkdir(parents=True, exist_ok=True)
15
+ path.write_text(content, encoding="utf-8")
16
+
17
+
18
+ def generate_project(config: ProjectConfig, console: Console):
19
+ base = Path(config.name)
20
+
21
+ if base.exists():
22
+ console.print(f"[red]✗ Directory '{config.name}' already exists.[/red]")
23
+ raise SystemExit(1)
24
+
25
+ files: dict[str, str] = {}
26
+
27
+ # --- Core app files ---
28
+ files["src/main.py"] = templates.main_py(config)
29
+ files["src/core/__init__.py"] = ""
30
+ files["src/core/config.py"] = templates.core_config(config)
31
+ files["src/api/__init__.py"] = ""
32
+ files["src/api/v1/__init__.py"] = ""
33
+ files["src/api/v1/router.py"] = templates.api_router(config)
34
+ files["src/api/v1/endpoints/__init__.py"] = ""
35
+ files["src/api/v1/endpoints/health.py"] = templates.health_endpoint()
36
+
37
+ # --- DB / models ---
38
+ if config.db:
39
+ files["src/db/__init__.py"] = ""
40
+ files["src/db/session.py"] = templates.db_session(config)
41
+ files["src/db/base.py"] = templates.db_base()
42
+ files["src/models/__init__.py"] = ""
43
+ files["src/models/base.py"] = templates.model_base()
44
+ files["src/schemas/__init__.py"] = ""
45
+
46
+ # --- Alembic ---
47
+ if config.alembic:
48
+ files["alembic.ini"] = templates.alembic_ini(config)
49
+ files["alembic/env.py"] = templates.alembic_env(config)
50
+ files["alembic/versions/.gitkeep"] = ""
51
+
52
+ # --- Tests ---
53
+ if config.tests:
54
+ files["tests/__init__.py"] = ""
55
+ files["tests/conftest.py"] = templates.conftest(config)
56
+ files["tests/test_health.py"] = templates.test_health()
57
+
58
+ # --- Docker ---
59
+ if config.docker:
60
+ files["Dockerfile"] = templates.dockerfile(config)
61
+ files["docker-compose.yml"] = templates.docker_compose(config)
62
+ files[".dockerignore"] = templates.dockerignore()
63
+
64
+ # --- Project root ---
65
+ files["pyproject.toml"] = templates.pyproject_toml(config)
66
+ files[".env.example"] = templates.env_example(config)
67
+ files[".gitignore"] = templates.gitignore()
68
+ files["README.md"] = templates.readme(config)
69
+ files["src/__init__.py"] = ""
70
+
71
+ # --- Write files with progress ---
72
+ with Progress(
73
+ SpinnerColumn(spinner_name="dots", style="cyan"),
74
+ TextColumn("[progress.description]{task.description}"),
75
+ console=console,
76
+ transient=True,
77
+ ) as progress:
78
+ task = progress.add_task("Creating project...", total=len(files))
79
+ for rel_path, content in files.items():
80
+ write(base / rel_path, content)
81
+ progress.advance(task)
82
+ time.sleep(0.015)
83
+
84
+ # --- Print file tree ---
85
+ console.print(_build_tree(config))
86
+ console.print()
87
+
88
+ # --- Next steps ---
89
+ console.print("[bold green]✓ Project created successfully![/bold green]")
90
+ console.print()
91
+ console.print("[bold]Next steps:[/bold]")
92
+ console.print(f" [cyan]cd {config.name}[/cyan]")
93
+ console.print(f" [cyan]python -m venv .venv && source .venv/bin/activate[/cyan]")
94
+ console.print(f" [cyan]pip install -e .[/cyan]")
95
+ if config.alembic:
96
+ console.print(f" [cyan]alembic upgrade head[/cyan]")
97
+ if config.docker:
98
+ console.print(f" [cyan]docker-compose up --build[/cyan]")
99
+ else:
100
+ console.print(f" [cyan]uvicorn src.main:app --reload[/cyan]")
101
+ console.print()
102
+ console.print(f" Docs -> http://localhost:8000/docs")
103
+ console.print()
104
+
105
+
106
+ def _build_tree(config: ProjectConfig) -> Tree:
107
+ tree = Tree(f"[bold cyan]{config.name}/[/bold cyan]")
108
+
109
+ src = tree.add("[bold yellow]src/[/bold yellow]")
110
+ src.add("[dim]__init__.py[/dim]")
111
+ src.add("[green]main.py[/green] [dim]<- app entrypoint[/dim]")
112
+
113
+ core = src.add("[bold yellow]core/[/bold yellow]")
114
+ core.add("config.py [dim]<- settings[/dim]")
115
+
116
+ api = src.add("[bold yellow]api/v1/[/bold yellow]")
117
+ api.add("router.py")
118
+ ep = api.add("[bold yellow]endpoints/[/bold yellow]")
119
+ ep.add("health.py")
120
+
121
+ if config.db:
122
+ db = src.add("[bold yellow]db/[/bold yellow]")
123
+ db.add("session.py [dim]<- DB engine[/dim]")
124
+ db.add("base.py")
125
+ src.add("[bold yellow]models/[/bold yellow]").add("[dim](add models here)[/dim]")
126
+ src.add("[bold yellow]schemas/[/bold yellow]").add("[dim](add schemas here)[/dim]")
127
+
128
+ if config.alembic:
129
+ alembic = tree.add("[bold yellow]alembic/[/bold yellow]")
130
+ alembic.add("env.py")
131
+ alembic.add("[bold yellow]versions/[/bold yellow]")
132
+ tree.add("alembic.ini")
133
+
134
+ if config.tests:
135
+ tests = tree.add("[bold yellow]tests/[/bold yellow]")
136
+ tests.add("conftest.py")
137
+ tests.add("test_health.py")
138
+
139
+ if config.docker:
140
+ tree.add("Dockerfile")
141
+ tree.add("docker-compose.yml")
142
+ tree.add(".dockerignore")
143
+
144
+ tree.add("pyproject.toml [dim]<- deps & metadata[/dim]")
145
+ tree.add(".env.example")
146
+ tree.add(".gitignore")
147
+ tree.add("README.md")
148
+ return tree
@@ -0,0 +1,412 @@
1
+ """
2
+ All file content templates for generated projects.
3
+ """
4
+ from .config import ProjectConfig
5
+
6
+
7
+ # -- Core ---------------------------------------------------------------------
8
+
9
+ def main_py(c: ProjectConfig) -> str:
10
+ router_import = "from src.api.v1.router import router as api_router"
11
+ db_lifespan = ""
12
+ if c.db:
13
+ db_lifespan = """
14
+ from contextlib import asynccontextmanager
15
+ from src.db.session import engine
16
+ from src.db.base import Base
17
+
18
+ @asynccontextmanager
19
+ async def lifespan(app: FastAPI):
20
+ async with engine.begin() as conn:
21
+ await conn.run_sync(Base.metadata.create_all)
22
+ yield
23
+ """
24
+ lifespan_arg = "lifespan=lifespan" if c.db else ""
25
+
26
+ return f'''from fastapi import FastAPI
27
+ from fastapi.middleware.cors import CORSMiddleware
28
+ from src.core.config import settings
29
+ {router_import}
30
+ {db_lifespan}
31
+ app = FastAPI(
32
+ title=settings.PROJECT_NAME,
33
+ version=settings.VERSION,
34
+ docs_url="/docs",
35
+ redoc_url="/redoc",
36
+ {lifespan_arg}
37
+ )
38
+
39
+ app.add_middleware(
40
+ CORSMiddleware,
41
+ allow_origins=settings.ALLOWED_ORIGINS,
42
+ allow_credentials=True,
43
+ allow_methods=["*"],
44
+ allow_headers=["*"],
45
+ )
46
+
47
+ app.include_router(api_router, prefix="/api/v1")
48
+
49
+
50
+ @app.get("/", tags=["root"])
51
+ async def root():
52
+ return {{"message": f"Welcome to {{settings.PROJECT_NAME}}"}}
53
+ '''
54
+
55
+
56
+ def core_config(c: ProjectConfig) -> str:
57
+ db_field = '\n DATABASE_URL: str = "sqlite+aiosqlite:///./dev.db"' if c.db else ""
58
+ return f'''from pydantic_settings import BaseSettings
59
+ from typing import List
60
+
61
+
62
+ class Settings(BaseSettings):
63
+ PROJECT_NAME: str = "{c.name}"
64
+ VERSION: str = "0.1.0"
65
+ ALLOWED_ORIGINS: List[str] = ["http://localhost:3000", "http://localhost:8000"]{db_field}
66
+
67
+ class Config:
68
+ env_file = ".env"
69
+
70
+
71
+ settings = Settings()
72
+ '''
73
+
74
+
75
+ def api_router(c: ProjectConfig) -> str:
76
+ return '''from fastapi import APIRouter
77
+ from src.api.v1.endpoints.health import router as health_router
78
+
79
+ router = APIRouter()
80
+ router.include_router(health_router, prefix="/health", tags=["health"])
81
+ '''
82
+
83
+
84
+ def health_endpoint() -> str:
85
+ return '''from fastapi import APIRouter
86
+
87
+ router = APIRouter()
88
+
89
+
90
+ @router.get("")
91
+ async def health_check():
92
+ return {"status": "ok"}
93
+ '''
94
+
95
+
96
+ # -- Database -----------------------------------------------------------------
97
+
98
+ def db_session(c: ProjectConfig) -> str:
99
+ return '''from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker, AsyncSession
100
+ from src.core.config import settings
101
+
102
+ engine = create_async_engine(settings.DATABASE_URL, echo=False)
103
+ AsyncSessionLocal = async_sessionmaker(engine, expire_on_commit=False)
104
+
105
+
106
+ async def get_db() -> AsyncSession:
107
+ async with AsyncSessionLocal() as session:
108
+ yield session
109
+ '''
110
+
111
+
112
+ def db_base() -> str:
113
+ return '''from src.models.base import Base
114
+
115
+ __all__ = ["Base"]
116
+ '''
117
+
118
+
119
+ def model_base() -> str:
120
+ return '''from sqlalchemy.orm import DeclarativeBase
121
+
122
+
123
+ class Base(DeclarativeBase):
124
+ pass
125
+ '''
126
+
127
+
128
+ # -- Alembic ------------------------------------------------------------------
129
+
130
+ def alembic_ini(c: ProjectConfig) -> str:
131
+ return f'''[alembic]
132
+ script_location = alembic
133
+ sqlalchemy.url = sqlite:///./dev.db
134
+
135
+ [loggers]
136
+ keys = root,sqlalchemy,alembic
137
+
138
+ [handlers]
139
+ keys = console
140
+
141
+ [formatters]
142
+ keys = generic
143
+
144
+ [logger_root]
145
+ level = WARN
146
+ handlers = console
147
+ qualname =
148
+
149
+ [logger_sqlalchemy]
150
+ level = WARN
151
+ handlers =
152
+ qualname = sqlalchemy.engine
153
+
154
+ [logger_alembic]
155
+ level = INFO
156
+ handlers =
157
+ qualname = alembic
158
+
159
+ [handler_console]
160
+ class = StreamHandler
161
+ args = (sys.stderr,)
162
+ level = NOTSET
163
+ formatter = generic
164
+
165
+ [formatter_generic]
166
+ format = %(levelname)-5.5s [%(name)s] %(message)s
167
+ datefmt = %H:%M:%S
168
+ '''
169
+
170
+
171
+ def alembic_env(c: ProjectConfig) -> str:
172
+ return '''from alembic import context
173
+ from sqlalchemy import engine_from_config, pool
174
+ from src.db.base import Base
175
+ from src.core.config import settings
176
+
177
+ config = context.config
178
+ config.set_main_option("sqlalchemy.url", settings.DATABASE_URL.replace("+aiosqlite", ""))
179
+ target_metadata = Base.metadata
180
+
181
+
182
+ def run_migrations_offline():
183
+ context.configure(
184
+ url=config.get_main_option("sqlalchemy.url"),
185
+ target_metadata=target_metadata,
186
+ literal_binds=True,
187
+ )
188
+ with context.begin_transaction():
189
+ context.run_migrations()
190
+
191
+
192
+ def run_migrations_online():
193
+ connectable = engine_from_config(
194
+ config.get_section(config.config_ini_section),
195
+ prefix="sqlalchemy.",
196
+ poolclass=pool.NullPool,
197
+ )
198
+ with connectable.connect() as connection:
199
+ context.configure(connection=connection, target_metadata=target_metadata)
200
+ with context.begin_transaction():
201
+ context.run_migrations()
202
+
203
+
204
+ if context.is_offline_mode():
205
+ run_migrations_offline()
206
+ else:
207
+ run_migrations_online()
208
+ '''
209
+
210
+
211
+ # -- Tests --------------------------------------------------------------------
212
+
213
+ def conftest(c: ProjectConfig) -> str:
214
+ return '''import pytest
215
+ from httpx import AsyncClient, ASGITransport
216
+ from src.main import app
217
+
218
+
219
+ @pytest.fixture
220
+ async def client():
221
+ async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as ac:
222
+ yield ac
223
+ '''
224
+
225
+
226
+ def test_health() -> str:
227
+ return '''import pytest
228
+
229
+
230
+ @pytest.mark.anyio
231
+ async def test_health(client):
232
+ response = await client.get("/api/v1/health")
233
+ assert response.status_code == 200
234
+ assert response.json() == {"status": "ok"}
235
+ '''
236
+
237
+
238
+ # -- Docker -------------------------------------------------------------------
239
+
240
+ def dockerfile(c: ProjectConfig) -> str:
241
+ return '''FROM python:3.12-slim
242
+
243
+ WORKDIR /app
244
+
245
+ COPY pyproject.toml .
246
+ RUN pip install --no-cache-dir -e .
247
+
248
+ COPY . .
249
+
250
+ EXPOSE 8000
251
+
252
+ CMD ["uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "8000"]
253
+ '''
254
+
255
+
256
+ def docker_compose(c: ProjectConfig) -> str:
257
+ db_service = """
258
+ postgres:
259
+ image: postgres:16-alpine
260
+ environment:
261
+ POSTGRES_USER: postgres
262
+ POSTGRES_PASSWORD: postgres
263
+ POSTGRES_DB: appdb
264
+ ports:
265
+ - "5432:5432"
266
+ volumes:
267
+ - pgdata:/var/lib/postgresql/data
268
+
269
+ volumes:
270
+ pgdata:
271
+ """ if c.db else ""
272
+
273
+ db_depends = "\n depends_on:\n - postgres" if c.db else ""
274
+
275
+ return f'''version: "3.9"
276
+
277
+ services:
278
+ api:
279
+ build: .
280
+ ports:
281
+ - "8000:8000"
282
+ env_file:
283
+ - .env
284
+ volumes:
285
+ - .:/app{db_depends}
286
+ {db_service}'''
287
+
288
+
289
+ def dockerignore() -> str:
290
+ return '''.venv
291
+ __pycache__
292
+ *.pyc
293
+ *.pyo
294
+ .git
295
+ .env
296
+ *.egg-info
297
+ dist
298
+ build
299
+ .pytest_cache
300
+ '''
301
+
302
+
303
+ # -- Project root -------------------------------------------------------------
304
+
305
+ def pyproject_toml(c: ProjectConfig) -> str:
306
+ extras = [
307
+ "fastapi[standard]",
308
+ "pydantic-settings",
309
+ "uvicorn[standard]",
310
+ ]
311
+ if c.db:
312
+ extras += ["sqlalchemy[asyncio]", "aiosqlite"]
313
+ if c.alembic:
314
+ extras.append("alembic")
315
+ if c.tests:
316
+ extras += ["pytest", "pytest-anyio", "httpx"]
317
+
318
+ deps = "\n".join(f' "{dep}",' for dep in extras)
319
+
320
+ return f'''[build-system]
321
+ requires = ["setuptools>=68", "wheel"]
322
+ build-backend = "setuptools.build_meta"
323
+
324
+ [project]
325
+ name = "{c.name}"
326
+ version = "0.1.0"
327
+ description = "A FastAPI application"
328
+ requires-python = ">=3.11"
329
+ dependencies = [
330
+ {deps}
331
+ ]
332
+
333
+ [tool.setuptools.packages.find]
334
+ where = ["."]
335
+ include = ["src*"]
336
+
337
+ [tool.pytest.ini_options]
338
+ asyncio_mode = "auto"
339
+ '''
340
+
341
+
342
+ def env_example(c: ProjectConfig) -> str:
343
+ lines = ['PROJECT_NAME="My FastAPI App"']
344
+ if c.db:
345
+ lines.append('DATABASE_URL="sqlite+aiosqlite:///./dev.db"')
346
+ return "\n".join(lines) + "\n"
347
+
348
+
349
+ def gitignore() -> str:
350
+ return '''.venv/
351
+ __pycache__/
352
+ *.pyc
353
+ *.pyo
354
+ *.pyd
355
+ .env
356
+ *.db
357
+ *.sqlite3
358
+ dist/
359
+ build/
360
+ *.egg-info/
361
+ .pytest_cache/
362
+ .mypy_cache/
363
+ .ruff_cache/
364
+ '''
365
+
366
+
367
+ def readme(c: ProjectConfig) -> str:
368
+ features = ["- FastAPI with async support"]
369
+ if c.db:
370
+ features.append("- SQLAlchemy async ORM")
371
+ if c.alembic:
372
+ features.append("- Alembic migrations")
373
+ if c.docker:
374
+ features.append("- Docker + docker-compose")
375
+ if c.tests:
376
+ features.append("- Pytest async test suite")
377
+
378
+ feature_block = "\n".join(features)
379
+ run_cmd = "docker-compose up --build" if c.docker else "uvicorn src.main:app --reload"
380
+
381
+ return f'''# {c.name}
382
+
383
+ ## Features
384
+
385
+ {feature_block}
386
+
387
+ ## Getting started
388
+
389
+ ```bash
390
+ python -m venv .venv
391
+ source .venv/bin/activate
392
+ pip install -e .
393
+ cp .env.example .env
394
+ {"alembic upgrade head" + chr(10) if c.alembic else ""}{run_cmd}
395
+ ```
396
+
397
+ Open http://localhost:8000/docs for the interactive API docs.
398
+
399
+ ## Project structure
400
+
401
+ ```
402
+ src/
403
+ main.py # App entrypoint
404
+ core/
405
+ config.py # Settings (pydantic-settings)
406
+ api/v1/
407
+ router.py
408
+ endpoints/
409
+ health.py
410
+ {" db/" + chr(10) + " session.py" + chr(10) + " models/" + chr(10) + " schemas/" if c.db else ""}
411
+ ```
412
+ '''
@@ -0,0 +1,95 @@
1
+ Metadata-Version: 2.4
2
+ Name: fastapi-gen-newone
3
+ Version: 0.1.1
4
+ Summary: ⚡ Scaffold production-ready FastAPI projects instantly
5
+ Author: Mouad Sadik
6
+ License: MIT
7
+ Keywords: fastapi,cli,generator,backend,python
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.11
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENCE
14
+ Requires-Dist: typer>=0.12
15
+ Requires-Dist: rich>=13
16
+ Dynamic: license-file
17
+
18
+ # fastapi-gen ⚡
19
+
20
+ > Create production-ready FastAPI projects in seconds.
21
+
22
+ ## Install
23
+ ```bash
24
+ pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ fastapi-gen-newone
25
+ ```
26
+
27
+ Or run directly with `pipx`:
28
+ ```bash
29
+ pipx run fastapi-gen-newone my-app
30
+ ```
31
+
32
+ ## Usage
33
+
34
+ ### Interactive (recommended)
35
+ ```bash
36
+ fastapi-gen my-app
37
+ ```
38
+
39
+ You'll be prompted to select features:
40
+ ```
41
+ ⚡ FastAPI Project Generator
42
+ Scaffold a production-ready FastAPI app in seconds
43
+
44
+ ? Project name: my-app
45
+ ? Include SQLAlchemy (database models): Yes
46
+ ? Include Alembic (database migrations): Yes
47
+ ? Include JWT Auth (login/register routes): Yes
48
+ ? Include Docker (Dockerfile + docker-compose): Yes
49
+ ? Include Pytest (test suite): Yes
50
+ ```
51
+
52
+ ### With flags (non-interactive)
53
+ ```bash
54
+ fastapi-gen my-app --db --auth --docker --alembic --tests
55
+ ```
56
+
57
+ ### Skip prompts entirely
58
+ ```bash
59
+ fastapi-gen my-app -y # bare project, no extras
60
+ fastapi-gen my-app -y --auth # just auth, no prompts
61
+ ```
62
+
63
+ ## Generated structure
64
+ ```
65
+ my-app/
66
+ ├── src/
67
+ │ ├── main.py ← FastAPI app entrypoint
68
+ │ ├── core/
69
+ │ │ └── config.py ← pydantic-settings
70
+ │ ├── api/v1/
71
+ │ │ ├── router.py
72
+ │ │ └── endpoints/
73
+ │ │ └── health.py
74
+ │ ├── db/ ← (if --db)
75
+ │ │ └── session.py
76
+ │ ├── models/ ← (if --db)
77
+ │ └── schemas/ ← (if --db)
78
+ ├── alembic/ ← (if --alembic)
79
+ ├── tests/ ← (if --tests)
80
+ ├── Dockerfile ← (if --docker)
81
+ ├── docker-compose.yml ← (if --docker)
82
+ ├── pyproject.toml
83
+ ├── .env.example
84
+ └── README.md
85
+ ```
86
+
87
+ ## Options
88
+
89
+ | Flag | Description |
90
+ |------|-------------|
91
+ | `--db` | SQLAlchemy async ORM + aiosqlite |
92
+ | `--alembic` | Alembic migration setup |
93
+ | `--docker` | Dockerfile + docker-compose |
94
+ | `--tests` | pytest + httpx async test suite |
95
+ | `-y / --no-interactive` | Skip all prompts |
@@ -0,0 +1,14 @@
1
+ LICENCE
2
+ README.md
3
+ pyproject.toml
4
+ fastapi_gen/__init__.py
5
+ fastapi_gen/cli.py
6
+ fastapi_gen/config.py
7
+ fastapi_gen/generator.py
8
+ fastapi_gen/templates.py
9
+ fastapi_gen_newone.egg-info/PKG-INFO
10
+ fastapi_gen_newone.egg-info/SOURCES.txt
11
+ fastapi_gen_newone.egg-info/dependency_links.txt
12
+ fastapi_gen_newone.egg-info/entry_points.txt
13
+ fastapi_gen_newone.egg-info/requires.txt
14
+ fastapi_gen_newone.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ fastapi-gen = fastapi_gen.cli:app
@@ -0,0 +1,2 @@
1
+ typer>=0.12
2
+ rich>=13
@@ -0,0 +1,29 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "fastapi-gen-newone"
7
+ version = "0.1.1"
8
+ description = "⚡ Scaffold production-ready FastAPI projects instantly"
9
+ readme = "README.md"
10
+ requires-python = ">=3.11"
11
+ license = {text = "MIT"}
12
+ dependencies = [
13
+ "typer>=0.12",
14
+ "rich>=13",
15
+ ]
16
+ authors = [{name = "Mouad Sadik"}]
17
+ keywords = ["fastapi", "cli", "generator", "backend", "python"]
18
+ classifiers = [
19
+ "Programming Language :: Python :: 3",
20
+ "License :: OSI Approved :: MIT License",
21
+ "Operating System :: OS Independent",
22
+ ]
23
+
24
+ [project.scripts]
25
+ fastapi-gen = "fastapi_gen.cli:app"
26
+
27
+ [tool.setuptools.packages.find]
28
+ where = ["."]
29
+ include = ["fastapi_gen*"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+