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.
- fastapi_gen_newone-0.1.1/LICENCE +21 -0
- fastapi_gen_newone-0.1.1/PKG-INFO +95 -0
- fastapi_gen_newone-0.1.1/README.md +78 -0
- fastapi_gen_newone-0.1.1/fastapi_gen/__init__.py +0 -0
- fastapi_gen_newone-0.1.1/fastapi_gen/cli.py +82 -0
- fastapi_gen_newone-0.1.1/fastapi_gen/config.py +15 -0
- fastapi_gen_newone-0.1.1/fastapi_gen/generator.py +148 -0
- fastapi_gen_newone-0.1.1/fastapi_gen/templates.py +412 -0
- fastapi_gen_newone-0.1.1/fastapi_gen_newone.egg-info/PKG-INFO +95 -0
- fastapi_gen_newone-0.1.1/fastapi_gen_newone.egg-info/SOURCES.txt +14 -0
- fastapi_gen_newone-0.1.1/fastapi_gen_newone.egg-info/dependency_links.txt +1 -0
- fastapi_gen_newone-0.1.1/fastapi_gen_newone.egg-info/entry_points.txt +2 -0
- fastapi_gen_newone-0.1.1/fastapi_gen_newone.egg-info/requires.txt +2 -0
- fastapi_gen_newone-0.1.1/fastapi_gen_newone.egg-info/top_level.txt +1 -0
- fastapi_gen_newone-0.1.1/pyproject.toml +29 -0
- fastapi_gen_newone-0.1.1/setup.cfg +4 -0
|
@@ -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 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
fastapi_gen
|
|
@@ -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*"]
|