fastapp-cli 0.1.0__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.
- fastapp_cli-0.1.0/.gitignore +19 -0
- fastapp_cli-0.1.0/PKG-INFO +102 -0
- fastapp_cli-0.1.0/PLAN.md +311 -0
- fastapp_cli-0.1.0/README.md +82 -0
- fastapp_cli-0.1.0/pyproject.toml +94 -0
- fastapp_cli-0.1.0/src/fastapp_cli/__init__.py +3 -0
- fastapp_cli-0.1.0/src/fastapp_cli/create.py +157 -0
- fastapp_cli-0.1.0/src/fastapp_cli/main.py +33 -0
- fastapp_cli-0.1.0/src/fastapp_cli/naming.py +39 -0
- fastapp_cli-0.1.0/src/fastapp_cli/prompts.py +35 -0
- fastapp_cli-0.1.0/src/fastapp_cli/render.py +130 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/__init__.py +1 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/.env.development.example.j2 +21 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/.env.example.j2 +29 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/.env.j2 +27 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/.gitignore +178 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/.pre-commit-config.yaml.j2 +80 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/.python-version.j2 +1 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/Dockerfile.j2 +17 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/Makefile.j2 +31 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/README.md.j2 +68 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/alembic/env.py.j2 +84 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/alembic/script.py.mako +28 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/alembic/versions/.gitkeep +0 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/alembic.ini.j2 +50 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/app/__init__.py.j2 +1 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/app/api/__init__.py.j2 +1 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/app/api/deps.py.j2 +33 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/app/api/v1/__init__.py.j2 +1 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/app/api/v1/endpoints/__init__.py.j2 +1 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/app/api/v1/endpoints/health.py.j2 +33 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/app/api/v1/endpoints/items.py.j2 +90 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/app/api/v1/router.py.j2 +9 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/app/core/__init__.py.j2 +1 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/app/core/celery_app.py.j2 +62 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/app/core/config.py.j2 +105 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/app/core/context_var.py.j2 +13 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/app/core/database.py.j2 +50 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/app/core/exceptions.py.j2 +175 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/app/core/logging.py.j2 +125 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/app/core/middleware.py.j2 +39 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/app/crud/__init__.py.j2 +1 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/app/crud/base.py.j2 +229 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/app/crud/item.py.j2 +10 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/app/main.py.j2 +118 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/app/models/__init__.py.j2 +10 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/app/models/base.py.j2 +59 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/app/models/item.py.j2 +22 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/app/schemas/__init__.py.j2 +1 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/app/schemas/common.py.j2 +81 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/app/schemas/item.py.j2 +35 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/app/services/__init__.py.j2 +1 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/app/services/base.py.j2 +79 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/app/services/item_service.py.j2 +10 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/app/tasks/__init__.py.j2 +1 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/app/tasks/sample_tasks.py.j2 +28 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/app/utils/__init__.py.j2 +1 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/docs/SQLModel/345/256/232/344/271/211/347/244/272/344/276/213.md +400 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/pm2.config.json.j2 +47 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/pyproject.toml.j2 +195 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/scripts/celery_beat.sh.j2 +9 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/scripts/celery_flower.sh.j2 +22 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/scripts/celery_worker.sh.j2 +15 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/scripts/start.sh.j2 +17 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/tests/api/test_health.py.j2 +15 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/tests/api/test_items.py.j2 +61 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/tests/conftest.py.j2 +61 -0
- fastapp_cli-0.1.0/src/fastapp_cli/templates/project/tests/services/test_item_service.py.j2 +44 -0
- fastapp_cli-0.1.0/tests/test_create.py +116 -0
- fastapp_cli-0.1.0/tests/test_naming.py +41 -0
- fastapp_cli-0.1.0/tests/test_render.py +98 -0
- fastapp_cli-0.1.0/uv.lock +642 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: fastapp-cli
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: FastAPI 项目脚手架:一条命令生成完整可运行的 FastAPI 工程
|
|
5
|
+
Author: aidenmo
|
|
6
|
+
License: MIT
|
|
7
|
+
Keywords: cli,fastapi,scaffold,sqlmodel,template
|
|
8
|
+
Classifier: Development Status :: 4 - Beta
|
|
9
|
+
Classifier: Environment :: Console
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Topic :: Software Development :: Code Generators
|
|
16
|
+
Requires-Python: >=3.10
|
|
17
|
+
Requires-Dist: jinja2>=3.1.0
|
|
18
|
+
Requires-Dist: typer>=0.12.0
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+
# fastapp-cli
|
|
22
|
+
|
|
23
|
+
FastAPI 项目脚手架:一条命令生成**完整、可直接运行**的 FastAPI 工程。
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
fastapp create my-server
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## 特性
|
|
30
|
+
|
|
31
|
+
- **分层架构**:`api / schemas / crud / services / models` 分层,内置泛型 CRUD / Service 基类
|
|
32
|
+
- **开箱即用的工程能力**:统一响应 / 异常体系、TraceID 中间件、loguru 日志、pydantic-settings 多环境配置
|
|
33
|
+
- **分页 CRUD + 过滤**:基于 fastapi-pagination 与 fastapi-filter 的完整示例(`/api/v1/items`)
|
|
34
|
+
- **Celery 骨架**:默认 redis broker,本地无 redis 时启动自动降级 `memory://` 并告警
|
|
35
|
+
- **Alembic 迁移**:接入 SQLModel.metadata,含 autogenerate 过滤钩子
|
|
36
|
+
- **优雅降级**:MySQL 缺席不阻塞启动,`/api/v1/health` 返回 `database: up/down`
|
|
37
|
+
- **工程化配套**:Makefile、scripts/、pre-commit、ruff + mypy + pytest 配置全套
|
|
38
|
+
- **可选部署文件**:`--pm2` / `--docker` 按需生成
|
|
39
|
+
|
|
40
|
+
## 安装
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# uv tool(推荐)
|
|
44
|
+
uv tool install fastapp-cli
|
|
45
|
+
|
|
46
|
+
# 或 pipx
|
|
47
|
+
pipx install fastapp-cli
|
|
48
|
+
|
|
49
|
+
# 或一次性使用
|
|
50
|
+
uvx fastapp create demo
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## 使用
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
fastapp create <project_name> [options]
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
| 参数 | 默认 | 说明 |
|
|
60
|
+
|---|---|---|
|
|
61
|
+
| `project_name` | 必填 | 项目名;小写字母/数字/连字符,如 `my-server` |
|
|
62
|
+
| `--description` | 交互提问 | 项目描述 |
|
|
63
|
+
| `--pm2 / --no-pm2` | 交互提问 | 是否生成 `pm2.config.json` |
|
|
64
|
+
| `--docker / --no-docker` | 交互提问 | 是否生成 `Dockerfile` |
|
|
65
|
+
| `--python` | `3.12` | 目标 Python 版本(写入 `.python-version`) |
|
|
66
|
+
| `--author` | `git config user.name` | 作者署名 |
|
|
67
|
+
| `--force` | 关 | 目标目录已存在时覆盖重建 |
|
|
68
|
+
| `--no-git` | 关 | 跳过 `git init` |
|
|
69
|
+
|
|
70
|
+
全部关键项通过 flag 提供时零交互:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
fastapp create my-server --description "demo" --no-pm2 --no-docker
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
生成完成后:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
cd my-server && uv sync
|
|
80
|
+
make dev # 访问 /api/v1/docs
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## 生成项目依赖
|
|
84
|
+
|
|
85
|
+
fastapi、sqlmodel、alembic、celery[redis]、fastapi-pagination、fastapi-filter、loguru、pydantic-settings 等,dev 组含 pytest / ruff / mypy / pre-commit。
|
|
86
|
+
|
|
87
|
+
## 开发 fastapp-cli 自身
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
uv sync --group dev
|
|
91
|
+
uv run pytest # 单元 + 冒烟测试
|
|
92
|
+
uv run ruff check .
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## 发布
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
uv build # 构建 sdist + wheel(模板随包发布)
|
|
99
|
+
uv publish # 发布到 PyPI
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
版本策略:v0.1.0 起,语义化版本。
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
# fastapp-cli 项目计划(第一阶段交付物)
|
|
2
|
+
|
|
3
|
+
> 状态:**第二阶段已完成**。CLI 已实现并通过全部验证(§11 全项),`uv build` 打包校验通过。
|
|
4
|
+
> 参考架构:`/Users/aidenmo/projects/ai-lyric-server`(已完整勘察)。
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 1. 目标与范围
|
|
9
|
+
|
|
10
|
+
构建 Python CLI 工具 `fastapp-cli`(命令名 `fastapp`),执行:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
fastapp create <project_name>
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
生成一个**完整、可直接运行**的 FastAPI 项目:完整复刻参考项目的通用工程能力(分层架构、配置、日志、异常、TraceID、统一响应、分页 CRUD、过滤、Celery 骨架、Alembic、测试、Lint),剥离全部业务与腾讯内部耦合,用户基于生成物继续开发完整业务。
|
|
17
|
+
|
|
18
|
+
### 已确认的设计决策
|
|
19
|
+
|
|
20
|
+
| 决策点 | 结论 |
|
|
21
|
+
|---|---|
|
|
22
|
+
| CLI 框架 | Typer |
|
|
23
|
+
| 模板渲染 | 内置 Jinja2(模板随包发布,`importlib.resources` 加载) |
|
|
24
|
+
| 生成项目依赖管理 | uv(pyproject + uv.lock) |
|
|
25
|
+
| fastapp-cli 分发 | PyPI + `uv tool install fastapp-cli` / `pipx` |
|
|
26
|
+
| 数据层 | SQLModel + **MySQL 默认**,缺席时**降级不阻塞启动**(见 §7) |
|
|
27
|
+
| 能力集 | 参考项目的通用能力**全量纳入**:分页 CRUD(fastapi-pagination)、通用过滤(fastapi-filter)、认证占位、Celery 骨架 |
|
|
28
|
+
| 部署配套 | `scripts/` + Makefile 默认生成;**pm2、Dockerfile 由用户在 create 时选择** |
|
|
29
|
+
| 交互模式 | 混合模式:关键项交互提问,提供 flag 则跳过提问,其余全默认 |
|
|
30
|
+
| 应用包名 | 生成项目的应用包**固定位 `app/`**(与参考项目一致),`project_name` 仅用于目录名与 pyproject name |
|
|
31
|
+
| Celery 默认 broker | 默认 `redis://localhost:6379`,redis 不可达时**自动降级 `memory://`** 并告警 |
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## 2. CLI 命令设计
|
|
36
|
+
|
|
37
|
+
### 2.1 v1 命令面
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
fastapp # 显示帮助
|
|
41
|
+
fastapp --version # 版本号
|
|
42
|
+
fastapp create <project_name> # 生成脚手架项目(核心命令)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### 2.2 `fastapp create` 参数
|
|
46
|
+
|
|
47
|
+
| 参数 | 类型 | 默认 | 说明 |
|
|
48
|
+
|---|---|---|---|
|
|
49
|
+
| `project_name` | 位置参数 | 必填 | 项目名;小写字母/数字/连字符,如 `my-server`(仅用于目录名与 pyproject name,应用包固定位 `app`) |
|
|
50
|
+
| `--description` | option | `A FastAPI project created by fastapp-cli` | 项目描述;**交互提问** |
|
|
51
|
+
| `--pm2 / --no-pm2` | flag | 未指定时**交互提问** | 是否生成 `pm2.config.json` |
|
|
52
|
+
| `--docker / --no-docker` | flag | 未指定时**交互提问** | 是否生成 `Dockerfile` |
|
|
53
|
+
| `--python` | option | `3.12` | 生成项目的目标 Python 版本(写入 `.python-version` 与 pyproject) |
|
|
54
|
+
| `--author` | option | 取 `git config user.name` | 作者署名 |
|
|
55
|
+
| `--force` | flag | 关 | 目标目录已存在时覆盖重建 |
|
|
56
|
+
| `--no-git` | flag | 关 | 跳过 `git init` |
|
|
57
|
+
|
|
58
|
+
### 2.3 交互流程(混合模式)
|
|
59
|
+
|
|
60
|
+
```text
|
|
61
|
+
$ fastapp create my-server
|
|
62
|
+
? 项目描述 [A FastAPI project created by fastapp-cli]:
|
|
63
|
+
? 是否包含 pm2 配置? [y/N]
|
|
64
|
+
? 是否包含 Dockerfile? [y/N]
|
|
65
|
+
✔ 生成项目 my-server/(23 个文件)
|
|
66
|
+
✔ 已初始化 git 仓库
|
|
67
|
+
下一步:
|
|
68
|
+
cd my-server && uv sync
|
|
69
|
+
make dev # 或 uv run uvicorn app.main:app --reload
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
- 三个提问项:**描述、pm2、Dockerfile**(与决策"关键项提问、pm2/Dockerfile 用户选择"一致);全部通过 flag 提供时零交互。
|
|
73
|
+
- 数据库不提问:固定 MySQL 形态 + 降级保底(§7.1);Celery 必含,broker 默认 redis、缺席自动降级 memory(§7.3)。
|
|
74
|
+
- 参数校验:`project_name` 非法字符拒绝并提示(仅用于目录名与 pyproject name;应用包固定为 `app`,无需派生包名)。
|
|
75
|
+
- 完成后打印下一步指引(`uv sync` → `make dev` → 访问 `/api/v1/docs`)。
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## 3. fastapp-cli 自身工程结构
|
|
80
|
+
|
|
81
|
+
```text
|
|
82
|
+
fastapp-cli/
|
|
83
|
+
├── pyproject.toml # hatchling 构建;requires-python >=3.10
|
|
84
|
+
├── README.md # 使用说明(中文)
|
|
85
|
+
├── PLAN.md # 本计划文档
|
|
86
|
+
├── src/
|
|
87
|
+
│ └── fastapp_cli/
|
|
88
|
+
│ ├── __init__.py # __version__
|
|
89
|
+
│ ├── main.py # Typer 应用入口(console script: fastapp)
|
|
90
|
+
│ ├── create.py # create 命令:校验→渲染→git init→输出指引
|
|
91
|
+
│ ├── prompts.py # 混合模式交互提问(Typer prompt/confirm)
|
|
92
|
+
│ ├── naming.py # project_name 校验(目录名 / pyproject name)
|
|
93
|
+
│ ├── render.py # Jinja2 引擎:变量注入、条件文件、原样拷贝与残留自检
|
|
94
|
+
│ └── templates/
|
|
95
|
+
│ └── project/ # 生成项目模板根(清单见 §5、§6)
|
|
96
|
+
└── tests/
|
|
97
|
+
├── test_naming.py # 命名校验单元测试
|
|
98
|
+
├── test_render.py # 渲染:无 {{ }} 残留、条件文件随 flag 增减
|
|
99
|
+
└── test_create.py # 冒烟:tmp 目录 create → 断言关键文件树
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
依赖:`typer`、`jinja2`(仅两个运行时依赖);dev 组:`pytest`、`ruff`、`mypy`。
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## 4. 生成项目目录结构
|
|
107
|
+
|
|
108
|
+
以下为 `fastapp create demo-server` 的产物(应用包**固定位 `app/`**,与参考项目结构一致,便于沿用既有开发习惯):
|
|
109
|
+
|
|
110
|
+
```text
|
|
111
|
+
demo-server/
|
|
112
|
+
├── .python-version # 3.12
|
|
113
|
+
├── .env.example # 环境变量样例(MySQL 占位 + Celery redis://localhost)
|
|
114
|
+
├── .env.development.example
|
|
115
|
+
├── .env # 从 .env.example 复制,本地默认配置(gitignore)
|
|
116
|
+
├── .gitignore
|
|
117
|
+
├── .pre-commit-config.yaml
|
|
118
|
+
├── Makefile # sync / dev / test / lint / format / migrate / revision
|
|
119
|
+
├── README.md # 快速开始、目录说明、扩展指南
|
|
120
|
+
├── docs/
|
|
121
|
+
│ └── SQLModel定义示例.md # 原样拷贝自参考项目,SQLModel 建模参考手册(供开发者查阅)
|
|
122
|
+
├── pyproject.toml # 依赖 + ruff + mypy + pytest 配置
|
|
123
|
+
├── alembic.ini
|
|
124
|
+
├── alembic/
|
|
125
|
+
│ ├── env.py # 接入 settings.DATABASE_URI 与 SQLModel.metadata
|
|
126
|
+
│ ├── script.py.mako
|
|
127
|
+
│ └── versions/.gitkeep
|
|
128
|
+
├── scripts/
|
|
129
|
+
│ ├── start.sh # uvicorn 启动
|
|
130
|
+
│ ├── celery_worker.sh
|
|
131
|
+
│ ├── celery_beat.sh
|
|
132
|
+
│ └── celery_flower.sh
|
|
133
|
+
├── pm2.config.json # 条件生成(--pm2)
|
|
134
|
+
├── Dockerfile # 条件生成(--docker)
|
|
135
|
+
├── tests/
|
|
136
|
+
│ ├── conftest.py # sqlite 内存库 + 依赖覆盖(修正参考项目缺陷)
|
|
137
|
+
│ ├── api/test_health.py
|
|
138
|
+
│ ├── api/test_items.py
|
|
139
|
+
│ └── services/test_item_service.py
|
|
140
|
+
└── app/ # 应用包,固定名 app(分层与参考项目一致)
|
|
141
|
+
├── main.py # 工厂函数 create_app + lifespan(含 DB / redis 探测降级)
|
|
142
|
+
├── core/
|
|
143
|
+
│ ├── config.py # pydantic-settings,.env + .env.{APP_ENV} 分层
|
|
144
|
+
│ ├── database.py # SQLModel 引擎 + get_session(连接参数含降级探测)
|
|
145
|
+
│ ├── logging.py # loguru 配置
|
|
146
|
+
│ ├── exceptions.py # AppExceptionError 体系 + 全局处理器
|
|
147
|
+
│ ├── middleware.py # TraceIDMiddleware
|
|
148
|
+
│ ├── context_var.py # trace_id ContextVar
|
|
149
|
+
│ └── celery_app.py # Celery 实例(redis 默认,缺席降级 memory)
|
|
150
|
+
├── api/
|
|
151
|
+
│ ├── deps.py # DBSession / CurrentUser(认证占位)
|
|
152
|
+
│ └── v1/
|
|
153
|
+
│ ├── router.py
|
|
154
|
+
│ └── endpoints/
|
|
155
|
+
│ ├── health.py # /api/v1/health(含 database up/down 状态)
|
|
156
|
+
│ └── items.py # 分页 CRUD 示例(增删改查 + 过滤 + 分页)
|
|
157
|
+
├── models/
|
|
158
|
+
│ ├── base.py # IDMixin / TimestampMixin / FormattedDatetime
|
|
159
|
+
│ ├── item.py # Item 模型(demo 业务域)
|
|
160
|
+
│ └── __init__.py
|
|
161
|
+
├── schemas/
|
|
162
|
+
│ ├── common.py # Response[T] / PageParams / PageResponse[T]
|
|
163
|
+
│ ├── item.py # ItemCreate / ItemUpdate / ItemFilter
|
|
164
|
+
│ └── __init__.py
|
|
165
|
+
├── crud/
|
|
166
|
+
│ ├── base.py # CRUDBase 泛型
|
|
167
|
+
│ ├── item.py
|
|
168
|
+
│ └── __init__.py
|
|
169
|
+
├── services/
|
|
170
|
+
│ ├── base.py # ServiceBase
|
|
171
|
+
│ ├── item_service.py
|
|
172
|
+
│ └── __init__.py
|
|
173
|
+
├── tasks/
|
|
174
|
+
│ ├── __init__.py
|
|
175
|
+
│ └── sample_tasks.py # Celery 示例任务
|
|
176
|
+
└── utils/
|
|
177
|
+
└── __init__.py
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## 5. 模板文件清单
|
|
183
|
+
|
|
184
|
+
`templates/project/` 下共约 35 个文件,按两类处理:
|
|
185
|
+
|
|
186
|
+
| 类别 | 文件 | 处理方式 |
|
|
187
|
+
|---|---|---|
|
|
188
|
+
| **Jinja 渲染**(.j2) | 全部 `.py`/`.toml`/`.md`/`.json`/`.ini`/`.sh`/`.yaml`/`Makefile`/`.env*` | 注入变量(§6),如 `main.py.j2` |
|
|
189
|
+
| **原样拷贝** | `alembic/script.py.mako`、`versions/.gitkeep`、**`docs/` 整目录**(含 `SQLModel定义示例.md`) | 不渲染,原样拷贝(应用包固定位 `app/`,目录名无需模板化;`docs/` 供开发者参考) |
|
|
190
|
+
|
|
191
|
+
条件生成规则(Jinja `{% if %}` 控制):
|
|
192
|
+
|
|
193
|
+
| 文件 | 条件 |
|
|
194
|
+
|---|---|
|
|
195
|
+
| `pm2.config.json` | `use_pm2` |
|
|
196
|
+
| `Dockerfile` | `use_docker` |
|
|
197
|
+
| `scripts/celery_*.sh` | 始终生成(Celery 必含) |
|
|
198
|
+
| `tests/services/test_item_service.py` | 始终生成 |
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
## 6. 模板变量与渲染机制
|
|
203
|
+
|
|
204
|
+
| 变量 | 来源 | 示例 |
|
|
205
|
+
|---|---|---|
|
|
206
|
+
| `project_name` | CLI 参数 | `demo-server`(应用包固定 `app`,无包名变量) |
|
|
207
|
+
| `project_description` | 交互/flag | `A FastAPI project ...` |
|
|
208
|
+
| `python_version` | `--python` | `3.12` |
|
|
209
|
+
| `author_name` | `--author` / git config | `aidenmo` |
|
|
210
|
+
| `use_pm2` / `use_docker` | 交互/flag | `true` |
|
|
211
|
+
| `year` | 当前年份 | `2026` |
|
|
212
|
+
| `fastapp_cli_version` | 包内版本(写入 README 生成声明) | `0.1.0` |
|
|
213
|
+
|
|
214
|
+
渲染机制:
|
|
215
|
+
- `importlib.resources` 读取包内模板目录,发布后离线可用、模板与 CLI 版本严格同步;
|
|
216
|
+
- 渲染后统一检查输出文件中无 `{{`/`{%` 残留(自检,发现即报错);
|
|
217
|
+
- 目标目录已存在且未指定 `--force` 时拒绝执行。
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## 7. 关键行为规范
|
|
222
|
+
|
|
223
|
+
### 7.1 MySQL 缺席降级(已确认方案的具体化)
|
|
224
|
+
|
|
225
|
+
- `lifespan` 启动时用引擎执行 `SELECT 1`(带超时):成功 → `info` 日志;失败 → `warning` 日志("数据库未就绪,数据接口将返回 500,请配置 .env"),**应用正常启动**;
|
|
226
|
+
- `/api/v1/health` 返回体增加 `"database": "up" | "down"`,状态直观可查;
|
|
227
|
+
- 访问 DB 的接口在库缺席时由统一异常处理器兜底为 `{code: 50000, message: "服务器内部错误"}`,不裸抛堆栈;
|
|
228
|
+
- 测试环境(conftest)使用 sqlite 内存库,不受影响。
|
|
229
|
+
|
|
230
|
+
### 7.2 认证占位
|
|
231
|
+
|
|
232
|
+
`deps.get_current_user`:非生产环境返回 `settings.MOCK_USER`(默认 `dev`),生产环境抛 `UnauthorizedError`。参考项目中的 TOF/TME 登录逻辑不迁移,接入点保留。
|
|
233
|
+
|
|
234
|
+
### 7.3 Celery:默认 redis,缺席自动降级 memory
|
|
235
|
+
|
|
236
|
+
- `.env` 预置 `CELERY_BROKER_URL=redis://localhost:6379/0`、`CELERY_RESULT_BACKEND=redis://localhost:6379/1`;
|
|
237
|
+
- lifespan 启动时对 redis 执行 `PING` 探测(带超时):可达 → 正常使用 redis;不可达 → `warning` 日志("redis 未就绪,Celery 已降级为 memory broker"),broker 重建为 `memory://`、backend 降级为 `cache+memory://`;
|
|
238
|
+
- 降级逻辑封装在 `core/celery_app.py` 的 `build_celery_app(broker_url, backend_url)`,主应用与 worker 共用同一构造入口;
|
|
239
|
+
- README 说明:生产环境在 `.env` 配置真实 redis 地址即可,无需改代码。
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## 8. 依赖管理
|
|
244
|
+
|
|
245
|
+
### 8.1 生成项目(对标参考项目逐项裁剪)
|
|
246
|
+
|
|
247
|
+
**保留(运行时)**:`fastapi`、`uvicorn[standard]`、`sqlmodel`、`sqlalchemy`、`alembic`、`pymysql`、`pydantic`、`pydantic-settings`、`loguru`、`celery[redis]`、`flower`、`fastapi-pagination`、`fastapi-filter[sqlalchemy]`、`tenacity`、`httpx`
|
|
248
|
+
|
|
249
|
+
**裁剪(业务/腾讯内部耦合)**:`rainbow-config`、`cos-python-sdk-v5`、`jieba`、`pypinyin`、`jwcrypto`、`pycryptodome`、`python-multipart`(demo 无文件接口)、`contextvars`(Python 标准库已内置,参考项目此依赖冗余)、`setuptools` 钉版
|
|
250
|
+
|
|
251
|
+
**dev 组**:`pytest`、`pytest-asyncio`、`pytest-cov`、`pytest-mock`、`ruff`、`mypy`、`pre-commit`
|
|
252
|
+
|
|
253
|
+
- `requires-python = ">=3.12"`:模板沿用参考项目的 PEP 695 泛型语法(`class Response[T]`);
|
|
254
|
+
- ruff/mypy/pytest 配置从参考项目 pyproject 移植(target py312,移除腾讯库 override;**删除重复的 pytest.ini**,仅保留 pyproject 配置);
|
|
255
|
+
- uv 镜像源:默认 `pypi.org`,pyproject 内附**注释掉**的腾讯镜像块,内网用户取消注释即用。
|
|
256
|
+
|
|
257
|
+
### 8.2 fastapp-cli 自身
|
|
258
|
+
|
|
259
|
+
- 运行时依赖仅 `typer` + `jinja2`;
|
|
260
|
+
- `requires-python >=3.10`(CLI 工具放宽兼容面;模板渲染产物为纯文本,不受此限制)。
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
## 9. 打包与发布
|
|
265
|
+
|
|
266
|
+
- **构建后端**:hatchling;`[project.scripts] fastapp = "fastapp_cli.main:app"`;
|
|
267
|
+
- 模板目录经 hatchling 包含进 wheel(`src/fastapp_cli/templates` 随包发布);
|
|
268
|
+
- **发布流程**:`uv build` → `uv publish`(PyPI;发布凭据由维护者本地配置 / Trusted Publishing);
|
|
269
|
+
- **安装使用**:`uv tool install fastapp-cli`、`pipx install fastapp-cli`,或一次性 `uvx fastapp create demo`;
|
|
270
|
+
- 版本策略:v0.1.0 起,语义化版本。
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
## 10. 与参考项目的差异清单
|
|
275
|
+
|
|
276
|
+
| 类型 | 内容 |
|
|
277
|
+
|---|---|
|
|
278
|
+
| 剥离 | rainbow-config / TOF / TME / COS / knot / jieba / pypinyin 等业务与内部依赖;`app/utils` 业务工具 |
|
|
279
|
+
| 修正 | `conftest.py` 引用不存在的 `get_db` → 统一为 `get_session`;删除重复 pytest 配置 |
|
|
280
|
+
| 新增 | lifespan DB/redis 探测降级、health 状态字段、Makefile、`--pm2/--docker` 条件文件、命名校验 |
|
|
281
|
+
| 替换 | 业务域 lyric → 通用 demo 域 `items`;utils 业务实现 → 空扩展位 |
|
|
282
|
+
| 保留 | 分层架构与 `app/` 包名、统一响应/异常/TraceID/日志、CRUD/Service 基类、Mixin、Alembic、Celery、工程化配置全套、`docs/` 参考文档 |
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
## 11. 质量验证(第二阶段完成标准)
|
|
287
|
+
|
|
288
|
+
1. `fastapp create demo-server` 全 flag 直通 + 零 flag 交互两条路径均成功;
|
|
289
|
+
2. 生成项目内 `uv sync && uv run pytest` 全绿(无需 MySQL);
|
|
290
|
+
3. 生成项目 `make dev`(`uvicorn app.main:app --reload`)后:`/api/v1/health` 返回 `{"status":"ok","database":"down"}`(无库降级可见),配置本地 MySQL 后变为 `up`;
|
|
291
|
+
4. `/api/v1/items` 分页 CRUD + 过滤端到端可用;无 redis 时 Celery 自动降级 `memory://` 并输出告警日志,配置 redis 后任务走 redis broker;
|
|
292
|
+
5. CLI 自身 `pytest`(命名/渲染/冒烟)全绿;产物中无 Jinja 残留标记。
|
|
293
|
+
|
|
294
|
+
---
|
|
295
|
+
|
|
296
|
+
## 12. 第二阶段实施步骤(确认后执行)
|
|
297
|
+
|
|
298
|
+
1. 初始化 `fastapp-cli` 包骨架(pyproject + src 布局 + Typer 入口);
|
|
299
|
+
2. 实现 `naming` / `prompts` / `render` 三个模块;
|
|
300
|
+
3. 编写 `templates/project` 全量模板(从参考项目移植 + 裁剪 + 修正 + 参数化);
|
|
301
|
+
4. 实现 `create` 命令(校验→渲染→条件文件→git init→指引输出);
|
|
302
|
+
5. 编写 CLI 自身测试(单元 + 冒烟);
|
|
303
|
+
6. 端到端验证(§11 全项)并修复;
|
|
304
|
+
7. 补充 README(fastapp-cli 使用说明 + 发布指引)。
|
|
305
|
+
|
|
306
|
+
## 13. 路线图(v1 之后,不在本次范围)
|
|
307
|
+
|
|
308
|
+
- `fastapp check`:环境/生成项目健康自检;
|
|
309
|
+
- `fastapp add <feature>`:向已有项目追加模块(如 celery、docker);
|
|
310
|
+
- `--template`:自定义模板路径;
|
|
311
|
+
- GitHub Actions CI 模板选项。
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# fastapp-cli
|
|
2
|
+
|
|
3
|
+
FastAPI 项目脚手架:一条命令生成**完整、可直接运行**的 FastAPI 工程。
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
fastapp create my-server
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## 特性
|
|
10
|
+
|
|
11
|
+
- **分层架构**:`api / schemas / crud / services / models` 分层,内置泛型 CRUD / Service 基类
|
|
12
|
+
- **开箱即用的工程能力**:统一响应 / 异常体系、TraceID 中间件、loguru 日志、pydantic-settings 多环境配置
|
|
13
|
+
- **分页 CRUD + 过滤**:基于 fastapi-pagination 与 fastapi-filter 的完整示例(`/api/v1/items`)
|
|
14
|
+
- **Celery 骨架**:默认 redis broker,本地无 redis 时启动自动降级 `memory://` 并告警
|
|
15
|
+
- **Alembic 迁移**:接入 SQLModel.metadata,含 autogenerate 过滤钩子
|
|
16
|
+
- **优雅降级**:MySQL 缺席不阻塞启动,`/api/v1/health` 返回 `database: up/down`
|
|
17
|
+
- **工程化配套**:Makefile、scripts/、pre-commit、ruff + mypy + pytest 配置全套
|
|
18
|
+
- **可选部署文件**:`--pm2` / `--docker` 按需生成
|
|
19
|
+
|
|
20
|
+
## 安装
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
# uv tool(推荐)
|
|
24
|
+
uv tool install fastapp-cli
|
|
25
|
+
|
|
26
|
+
# 或 pipx
|
|
27
|
+
pipx install fastapp-cli
|
|
28
|
+
|
|
29
|
+
# 或一次性使用
|
|
30
|
+
uvx fastapp create demo
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## 使用
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
fastapp create <project_name> [options]
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
| 参数 | 默认 | 说明 |
|
|
40
|
+
|---|---|---|
|
|
41
|
+
| `project_name` | 必填 | 项目名;小写字母/数字/连字符,如 `my-server` |
|
|
42
|
+
| `--description` | 交互提问 | 项目描述 |
|
|
43
|
+
| `--pm2 / --no-pm2` | 交互提问 | 是否生成 `pm2.config.json` |
|
|
44
|
+
| `--docker / --no-docker` | 交互提问 | 是否生成 `Dockerfile` |
|
|
45
|
+
| `--python` | `3.12` | 目标 Python 版本(写入 `.python-version`) |
|
|
46
|
+
| `--author` | `git config user.name` | 作者署名 |
|
|
47
|
+
| `--force` | 关 | 目标目录已存在时覆盖重建 |
|
|
48
|
+
| `--no-git` | 关 | 跳过 `git init` |
|
|
49
|
+
|
|
50
|
+
全部关键项通过 flag 提供时零交互:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
fastapp create my-server --description "demo" --no-pm2 --no-docker
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
生成完成后:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
cd my-server && uv sync
|
|
60
|
+
make dev # 访问 /api/v1/docs
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## 生成项目依赖
|
|
64
|
+
|
|
65
|
+
fastapi、sqlmodel、alembic、celery[redis]、fastapi-pagination、fastapi-filter、loguru、pydantic-settings 等,dev 组含 pytest / ruff / mypy / pre-commit。
|
|
66
|
+
|
|
67
|
+
## 开发 fastapp-cli 自身
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
uv sync --group dev
|
|
71
|
+
uv run pytest # 单元 + 冒烟测试
|
|
72
|
+
uv run ruff check .
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## 发布
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
uv build # 构建 sdist + wheel(模板随包发布)
|
|
79
|
+
uv publish # 发布到 PyPI
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
版本策略:v0.1.0 起,语义化版本。
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "fastapp-cli"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "FastAPI 项目脚手架:一条命令生成完整可运行的 FastAPI 工程"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [{ name = "aidenmo" }]
|
|
13
|
+
keywords = ["fastapi", "scaffold", "cli", "template", "sqlmodel"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 4 - Beta",
|
|
16
|
+
"Environment :: Console",
|
|
17
|
+
"Intended Audience :: Developers",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Programming Language :: Python :: 3.10",
|
|
20
|
+
"Programming Language :: Python :: 3.11",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
"Topic :: Software Development :: Code Generators",
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
dependencies = [
|
|
26
|
+
"typer>=0.12.0",
|
|
27
|
+
"jinja2>=3.1.0",
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
[project.scripts]
|
|
31
|
+
fastapp = "fastapp_cli.main:app"
|
|
32
|
+
|
|
33
|
+
[dependency-groups]
|
|
34
|
+
dev = [
|
|
35
|
+
"mypy>=1.11.0",
|
|
36
|
+
"pytest>=8.0.0",
|
|
37
|
+
"ruff>=0.6.0",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
[tool.hatch.build.targets.wheel]
|
|
41
|
+
packages = ["src/fastapp_cli"]
|
|
42
|
+
|
|
43
|
+
# -----------------------------------------------------------------------------
|
|
44
|
+
# pytest
|
|
45
|
+
# -----------------------------------------------------------------------------
|
|
46
|
+
[tool.pytest.ini_options]
|
|
47
|
+
minversion = "7.0"
|
|
48
|
+
testpaths = ["tests"]
|
|
49
|
+
python_files = ["test_*.py", "*_test.py"]
|
|
50
|
+
addopts = [
|
|
51
|
+
"-ra",
|
|
52
|
+
"--strict-markers",
|
|
53
|
+
"--strict-config",
|
|
54
|
+
"--tb=short",
|
|
55
|
+
]
|
|
56
|
+
|
|
57
|
+
# -----------------------------------------------------------------------------
|
|
58
|
+
# Ruff
|
|
59
|
+
# -----------------------------------------------------------------------------
|
|
60
|
+
[tool.ruff]
|
|
61
|
+
line-length = 120
|
|
62
|
+
target-version = "py310"
|
|
63
|
+
respect-gitignore = true
|
|
64
|
+
|
|
65
|
+
[tool.ruff.lint]
|
|
66
|
+
select = ["F", "E", "W", "I", "B", "UP", "SIM", "N", "TID"]
|
|
67
|
+
ignore = ["E501"]
|
|
68
|
+
|
|
69
|
+
[tool.ruff.lint.per-file-ignores]
|
|
70
|
+
"tests/**/*.py" = ["E", "F", "I", "N", "UP"]
|
|
71
|
+
|
|
72
|
+
[tool.ruff.format]
|
|
73
|
+
quote-style = "double"
|
|
74
|
+
indent-style = "space"
|
|
75
|
+
skip-magic-trailing-comma = false
|
|
76
|
+
|
|
77
|
+
# -----------------------------------------------------------------------------
|
|
78
|
+
# mypy
|
|
79
|
+
# -----------------------------------------------------------------------------
|
|
80
|
+
[tool.mypy]
|
|
81
|
+
python_version = "3.10"
|
|
82
|
+
warn_unused_ignores = true
|
|
83
|
+
warn_unreachable = true
|
|
84
|
+
warn_redundant_casts = true
|
|
85
|
+
no_implicit_optional = true
|
|
86
|
+
strict_equality = true
|
|
87
|
+
check_untyped_defs = true
|
|
88
|
+
show_error_codes = true
|
|
89
|
+
show_column_numbers = true
|
|
90
|
+
pretty = true
|
|
91
|
+
|
|
92
|
+
[[tool.mypy.overrides]]
|
|
93
|
+
module = ["tests.*"]
|
|
94
|
+
ignore_errors = true
|