toms-fast 0.2.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- toms_fast-0.2.1.dist-info/METADATA +467 -0
- toms_fast-0.2.1.dist-info/RECORD +60 -0
- toms_fast-0.2.1.dist-info/WHEEL +4 -0
- toms_fast-0.2.1.dist-info/entry_points.txt +2 -0
- tomskit/__init__.py +0 -0
- tomskit/celery/README.md +693 -0
- tomskit/celery/__init__.py +4 -0
- tomskit/celery/celery.py +306 -0
- tomskit/celery/config.py +377 -0
- tomskit/cli/__init__.py +207 -0
- tomskit/cli/__main__.py +8 -0
- tomskit/cli/scaffold.py +123 -0
- tomskit/cli/templates/__init__.py +42 -0
- tomskit/cli/templates/base.py +348 -0
- tomskit/cli/templates/celery.py +101 -0
- tomskit/cli/templates/extensions.py +213 -0
- tomskit/cli/templates/fastapi.py +400 -0
- tomskit/cli/templates/migrations.py +281 -0
- tomskit/cli/templates_config.py +122 -0
- tomskit/logger/README.md +466 -0
- tomskit/logger/__init__.py +4 -0
- tomskit/logger/config.py +106 -0
- tomskit/logger/logger.py +290 -0
- tomskit/py.typed +0 -0
- tomskit/redis/README.md +462 -0
- tomskit/redis/__init__.py +6 -0
- tomskit/redis/config.py +85 -0
- tomskit/redis/redis_pool.py +87 -0
- tomskit/redis/redis_sync.py +66 -0
- tomskit/server/__init__.py +47 -0
- tomskit/server/config.py +117 -0
- tomskit/server/exceptions.py +412 -0
- tomskit/server/middleware.py +371 -0
- tomskit/server/parser.py +312 -0
- tomskit/server/resource.py +464 -0
- tomskit/server/server.py +276 -0
- tomskit/server/type.py +263 -0
- tomskit/sqlalchemy/README.md +590 -0
- tomskit/sqlalchemy/__init__.py +20 -0
- tomskit/sqlalchemy/config.py +125 -0
- tomskit/sqlalchemy/database.py +125 -0
- tomskit/sqlalchemy/pagination.py +359 -0
- tomskit/sqlalchemy/property.py +19 -0
- tomskit/sqlalchemy/sqlalchemy.py +131 -0
- tomskit/sqlalchemy/types.py +32 -0
- tomskit/task/README.md +67 -0
- tomskit/task/__init__.py +4 -0
- tomskit/task/task_manager.py +124 -0
- tomskit/tools/README.md +63 -0
- tomskit/tools/__init__.py +18 -0
- tomskit/tools/config.py +70 -0
- tomskit/tools/warnings.py +37 -0
- tomskit/tools/woker.py +81 -0
- tomskit/utils/README.md +666 -0
- tomskit/utils/README_SERIALIZER.md +644 -0
- tomskit/utils/__init__.py +35 -0
- tomskit/utils/fields.py +434 -0
- tomskit/utils/marshal_utils.py +137 -0
- tomskit/utils/response_utils.py +13 -0
- tomskit/utils/serializers.py +447 -0
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
"""
|
|
2
|
+
基础模板模块
|
|
3
|
+
包含所有项目类型都需要的基础文件模板
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from typing import Callable
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def _get_readme_content(project_name: str, project_type: str) -> str:
|
|
10
|
+
"""根据项目类型生成 README 内容"""
|
|
11
|
+
project_type_names = {
|
|
12
|
+
"fastapi": "FastAPI",
|
|
13
|
+
"celery": "Celery",
|
|
14
|
+
"full": "FastAPI + Celery"
|
|
15
|
+
}
|
|
16
|
+
project_desc = project_type_names.get(project_type, project_type)
|
|
17
|
+
|
|
18
|
+
# 基础内容
|
|
19
|
+
content = f'''# {project_name}
|
|
20
|
+
|
|
21
|
+
基于 [toms-fast](https://github.com/tomszhou/toms-fast) 的 {project_desc} 项目脚手架。
|
|
22
|
+
|
|
23
|
+
## 🚀 快速开始
|
|
24
|
+
|
|
25
|
+
### 前置要求
|
|
26
|
+
|
|
27
|
+
- Python >= 3.11
|
|
28
|
+
- [uv](https://github.com/astral-sh/uv) (推荐使用 uv 管理依赖)
|
|
29
|
+
|
|
30
|
+
### 1. 安装依赖
|
|
31
|
+
|
|
32
|
+
使用 uv 安装项目依赖:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
# 安装 uv (如果还没有安装)
|
|
36
|
+
# macOS/Linux:
|
|
37
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
38
|
+
|
|
39
|
+
# 或使用 pip:
|
|
40
|
+
pip install uv
|
|
41
|
+
|
|
42
|
+
# 安装项目依赖
|
|
43
|
+
uv sync
|
|
44
|
+
|
|
45
|
+
# 或安装开发依赖
|
|
46
|
+
uv sync --group dev
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### 2. 配置环境变量
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
cd backend
|
|
53
|
+
cp .env.example .env
|
|
54
|
+
# 编辑 .env 文件,配置数据库和 Redis 连接信息
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
'''
|
|
58
|
+
|
|
59
|
+
# 根据项目类型添加运行说明
|
|
60
|
+
if project_type in ("fastapi", "full"):
|
|
61
|
+
content += '''### 3. 运行 FastAPI 应用
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# 确保在 backend 目录下
|
|
65
|
+
cd backend
|
|
66
|
+
|
|
67
|
+
# 使用 uv 运行(推荐)
|
|
68
|
+
uv run uvicorn main:app --reload
|
|
69
|
+
|
|
70
|
+
# 或激活虚拟环境后运行
|
|
71
|
+
source .venv/bin/activate # Windows: .venv\\Scripts\\activate
|
|
72
|
+
uvicorn main:app --reload
|
|
73
|
+
|
|
74
|
+
# 或直接运行
|
|
75
|
+
python main.py
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### 4. 访问 API
|
|
79
|
+
|
|
80
|
+
- API 文档: http://localhost:8000/docs (如果启用了文档)
|
|
81
|
+
- 健康检查: http://localhost:8000/health
|
|
82
|
+
- 用户 API: http://localhost:8000/api/v1/users
|
|
83
|
+
|
|
84
|
+
'''
|
|
85
|
+
|
|
86
|
+
if project_type in ("celery", "full"):
|
|
87
|
+
content += '''### 3. 运行 Celery Worker
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
# 确保在 backend 目录下
|
|
91
|
+
cd backend
|
|
92
|
+
|
|
93
|
+
# 使用 uv 运行(推荐)
|
|
94
|
+
uv run celery -A celery_app worker --loglevel=info
|
|
95
|
+
|
|
96
|
+
# 或激活虚拟环境后运行
|
|
97
|
+
source .venv/bin/activate # Windows: .venv\\Scripts\\activate
|
|
98
|
+
celery -A celery_app worker --loglevel=info
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### 4. 运行 Celery Beat(定时任务,可选)
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
cd backend
|
|
105
|
+
uv run celery -A celery_app beat --loglevel=info
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
'''
|
|
109
|
+
|
|
110
|
+
# 项目结构
|
|
111
|
+
content += f'''## 📁 项目结构
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
{project_name}/
|
|
115
|
+
├── backend/ # 后端代码目录
|
|
116
|
+
'''
|
|
117
|
+
|
|
118
|
+
if project_type in ("fastapi", "full"):
|
|
119
|
+
content += '''│ ├── app/
|
|
120
|
+
│ │ ├── controllers/ # 控制器层(API 路由)
|
|
121
|
+
│ │ │ └── users/ # 用户控制器示例
|
|
122
|
+
│ │ ├── models/ # 数据库模型
|
|
123
|
+
│ │ ├── schemas/ # Pydantic 模型(请求/响应)
|
|
124
|
+
│ │ ├── services/ # 业务逻辑层
|
|
125
|
+
│ │ ├── middleware/ # 中间件目录
|
|
126
|
+
│ │ │ ├── request_id.py # 请求 ID 追踪
|
|
127
|
+
│ │ │ └── resource_cleanup.py # 资源清理
|
|
128
|
+
│ │ └── utils/ # 工具函数
|
|
129
|
+
│ ├── main.py # FastAPI 应用入口
|
|
130
|
+
'''
|
|
131
|
+
|
|
132
|
+
if project_type in ("celery", "full"):
|
|
133
|
+
content += '''│ ├── celery_app.py # Celery 应用入口
|
|
134
|
+
│ ├── tasks/ # Celery 任务
|
|
135
|
+
│ │ └── example_task.py # 示例任务
|
|
136
|
+
'''
|
|
137
|
+
|
|
138
|
+
content += '''│ ├── tests/ # 测试文件
|
|
139
|
+
│ ├── logs/ # 日志目录
|
|
140
|
+
│ ├── migrations/ # 数据库迁移目录
|
|
141
|
+
│ ├── pyproject.toml # 项目配置和依赖(使用 uv 管理)
|
|
142
|
+
│ └── .env # 环境变量配置
|
|
143
|
+
├── web/ # 前端代码目录
|
|
144
|
+
└── README.md # 项目说明文档
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
'''
|
|
148
|
+
|
|
149
|
+
# 使用指南
|
|
150
|
+
if project_type in ("fastapi", "full"):
|
|
151
|
+
content += '''## 📖 使用指南
|
|
152
|
+
|
|
153
|
+
### 添加新控制器
|
|
154
|
+
|
|
155
|
+
1. 在 `app/controllers/` 下创建新控制器目录
|
|
156
|
+
2. 创建 `resources.py` 定义 Resource
|
|
157
|
+
3. 在 `app/schemas/` 中创建对应的数据模型(请求/响应)
|
|
158
|
+
4. 创建 `module.py` 定义控制器初始化函数
|
|
159
|
+
5. 在 `main.py` 中调用初始化函数
|
|
160
|
+
|
|
161
|
+
### 定义 Resource
|
|
162
|
+
|
|
163
|
+
```python
|
|
164
|
+
from tomskit.server import Resource, api_doc, register_resource
|
|
165
|
+
|
|
166
|
+
@register_resource(module="users", path="/users", tags=["用户管理"])
|
|
167
|
+
class UserResource(Resource):
|
|
168
|
+
@api_doc(
|
|
169
|
+
summary="获取用户列表",
|
|
170
|
+
response_model=list[UserResponse]
|
|
171
|
+
)
|
|
172
|
+
async def get(self, request: Request):
|
|
173
|
+
return []
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
'''
|
|
177
|
+
|
|
178
|
+
if project_type in ("celery", "full"):
|
|
179
|
+
content += '''### 定义 Celery 任务
|
|
180
|
+
|
|
181
|
+
```python
|
|
182
|
+
from celery import shared_task
|
|
183
|
+
from tomskit.celery import AsyncTaskRunner
|
|
184
|
+
|
|
185
|
+
@shared_task(name="my_task", queue="default")
|
|
186
|
+
def my_task(message: str):
|
|
187
|
+
runner = AsyncTaskRunner(async_my_task)
|
|
188
|
+
return runner.run(message)
|
|
189
|
+
|
|
190
|
+
async def async_my_task(message: str):
|
|
191
|
+
# 实现异步任务逻辑
|
|
192
|
+
return f"处理完成: {message}"
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
'''
|
|
196
|
+
|
|
197
|
+
content += '''## 🔗 相关链接
|
|
198
|
+
|
|
199
|
+
- [toms-fast 文档](https://github.com/tomszhou/toms-fast)
|
|
200
|
+
- [FastAPI 文档](https://fastapi.tiangolo.com/)
|
|
201
|
+
- [Celery 文档](https://docs.celeryq.dev/)
|
|
202
|
+
'''
|
|
203
|
+
|
|
204
|
+
return content
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def get_base_templates(project_name: str, project_type: str = "full") -> dict[str, Callable[[], str]]:
|
|
208
|
+
"""获取基础模板"""
|
|
209
|
+
return {
|
|
210
|
+
"env_example": lambda: '''# 应用配置
|
|
211
|
+
APP_NAME=my-fastapi-app
|
|
212
|
+
APP_ENV=development
|
|
213
|
+
|
|
214
|
+
# Gunicorn 配置(生产环境)
|
|
215
|
+
workers=4
|
|
216
|
+
bind=0.0.0.0:8000
|
|
217
|
+
daemon=False
|
|
218
|
+
|
|
219
|
+
# Redis 配置
|
|
220
|
+
REDIS_HOST=localhost
|
|
221
|
+
REDIS_PORT=6379
|
|
222
|
+
REDIS_DB=0
|
|
223
|
+
REDIS_PASSWORD=
|
|
224
|
+
|
|
225
|
+
# 日志配置
|
|
226
|
+
LOG_PREFIX=[MyApp]
|
|
227
|
+
LOG_LEVEL=INFO
|
|
228
|
+
LOG_DIR=logs
|
|
229
|
+
LOG_NAME=apps
|
|
230
|
+
LOG_USE_UTC=False
|
|
231
|
+
|
|
232
|
+
# 数据库配置
|
|
233
|
+
DB_HOST=localhost
|
|
234
|
+
DB_PORT=3306
|
|
235
|
+
DB_USERNAME=root
|
|
236
|
+
DB_PASSWORD=password
|
|
237
|
+
DB_DATABASE=mydb
|
|
238
|
+
DB_CHARSET=utf8mb4
|
|
239
|
+
DB_EXTRAS=
|
|
240
|
+
|
|
241
|
+
# SQLAlchemy 配置
|
|
242
|
+
SQLALCHEMY_DATABASE_URI_SCHEME=mysql+aiomysql
|
|
243
|
+
SQLALCHEMY_DATABASE_SYNC_URI_SCHEME=mysql+pymysql
|
|
244
|
+
SQLALCHEMY_POOL_SIZE=300
|
|
245
|
+
SQLALCHEMY_MAX_OVERFLOW=10
|
|
246
|
+
SQLALCHEMY_POOL_RECYCLE=3600
|
|
247
|
+
SQLALCHEMY_POOL_PRE_PING=False
|
|
248
|
+
SQLALCHEMY_ECHO=False
|
|
249
|
+
''',
|
|
250
|
+
|
|
251
|
+
"gitignore": lambda: '''# Python
|
|
252
|
+
__pycache__/
|
|
253
|
+
*.py[cod]
|
|
254
|
+
*$py.class
|
|
255
|
+
*.so
|
|
256
|
+
.Python
|
|
257
|
+
build/
|
|
258
|
+
develop-eggs/
|
|
259
|
+
dist/
|
|
260
|
+
downloads/
|
|
261
|
+
eggs/
|
|
262
|
+
.eggs/
|
|
263
|
+
lib/
|
|
264
|
+
lib64/
|
|
265
|
+
parts/
|
|
266
|
+
sdist/
|
|
267
|
+
var/
|
|
268
|
+
wheels/
|
|
269
|
+
*.egg-info/
|
|
270
|
+
.installed.cfg
|
|
271
|
+
*.egg
|
|
272
|
+
|
|
273
|
+
# Virtual Environment
|
|
274
|
+
venv/
|
|
275
|
+
env/
|
|
276
|
+
ENV/
|
|
277
|
+
.venv
|
|
278
|
+
|
|
279
|
+
# IDE
|
|
280
|
+
.vscode/
|
|
281
|
+
.idea/
|
|
282
|
+
*.swp
|
|
283
|
+
*.swo
|
|
284
|
+
*~
|
|
285
|
+
|
|
286
|
+
# Environment
|
|
287
|
+
.env
|
|
288
|
+
.env.local
|
|
289
|
+
|
|
290
|
+
# Logs
|
|
291
|
+
logs/
|
|
292
|
+
*.log
|
|
293
|
+
|
|
294
|
+
# Database
|
|
295
|
+
*.db
|
|
296
|
+
*.sqlite
|
|
297
|
+
|
|
298
|
+
# OS
|
|
299
|
+
.DS_Store
|
|
300
|
+
Thumbs.db
|
|
301
|
+
|
|
302
|
+
# Project specific
|
|
303
|
+
run/
|
|
304
|
+
*.pid
|
|
305
|
+
''',
|
|
306
|
+
|
|
307
|
+
"pyproject_toml": lambda: f'''[project]
|
|
308
|
+
name = "{project_name}"
|
|
309
|
+
version = "0.1.0"
|
|
310
|
+
description = "基于 toms-fast 的 FastAPI 应用"
|
|
311
|
+
requires-python = ">=3.11"
|
|
312
|
+
dependencies = [
|
|
313
|
+
"toms-fast>=0.1.1",
|
|
314
|
+
"python-dotenv>=1.0.0",
|
|
315
|
+
"uvicorn[standard]>=0.27.0",
|
|
316
|
+
]
|
|
317
|
+
|
|
318
|
+
[build-system]
|
|
319
|
+
requires = ["hatchling"]
|
|
320
|
+
build-backend = "hatchling.build"
|
|
321
|
+
|
|
322
|
+
[tool.uv]
|
|
323
|
+
index-url = "https://pypi.tuna.tsinghua.edu.cn/simple"
|
|
324
|
+
|
|
325
|
+
[dependency-groups]
|
|
326
|
+
dev = [
|
|
327
|
+
"pytest>=8.3.5",
|
|
328
|
+
"pytest-asyncio>=0.26.0",
|
|
329
|
+
"httpx>=0.27.0",
|
|
330
|
+
]
|
|
331
|
+
|
|
332
|
+
[tool.ruff]
|
|
333
|
+
line-length = 120
|
|
334
|
+
target-version = "py311"
|
|
335
|
+
|
|
336
|
+
[tool.mypy]
|
|
337
|
+
python_version = "3.11"
|
|
338
|
+
ignore_missing_imports = true
|
|
339
|
+
|
|
340
|
+
[tool.pytest.ini_options]
|
|
341
|
+
asyncio_mode = "auto"
|
|
342
|
+
asyncio_default_fixture_loop_scope = "function"
|
|
343
|
+
''',
|
|
344
|
+
|
|
345
|
+
"readme_md": lambda: _get_readme_content(project_name, project_type),
|
|
346
|
+
|
|
347
|
+
"tests_init_py": lambda: "",
|
|
348
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Celery 模板模块
|
|
3
|
+
包含所有 Celery 相关的文件模板
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from typing import Callable
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def get_celery_templates(project_name: str) -> dict[str, Callable[[], str]]:
|
|
10
|
+
"""获取 Celery 模板"""
|
|
11
|
+
return {
|
|
12
|
+
"celery_app_py": lambda: f'''"""
|
|
13
|
+
{project_name} Celery 应用入口
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
from dotenv import load_dotenv
|
|
18
|
+
from celery.signals import worker_process_init
|
|
19
|
+
|
|
20
|
+
from extensions.ext_celery import init_app, get_celery_app
|
|
21
|
+
from extensions import init_all_extensions
|
|
22
|
+
|
|
23
|
+
# 加载环境变量
|
|
24
|
+
env_path = Path(__file__).parent / ".env"
|
|
25
|
+
if env_path.exists():
|
|
26
|
+
load_dotenv(env_path)
|
|
27
|
+
else:
|
|
28
|
+
print("⚠️ 警告: .env 文件不存在,请从 .env.example 复制并配置")
|
|
29
|
+
|
|
30
|
+
# 初始化 Celery 应用(通过扩展)
|
|
31
|
+
celery_app = init_app()
|
|
32
|
+
|
|
33
|
+
# 统一初始化所有扩展(logger, database, redis 等)
|
|
34
|
+
# 注意:celery_app 已经初始化,ext_celery 会检测到并跳过重复初始化
|
|
35
|
+
init_all_extensions(celery_app)
|
|
36
|
+
|
|
37
|
+
# Worker 启动时的初始化(如果需要额外的 worker 初始化逻辑)
|
|
38
|
+
@worker_process_init.connect
|
|
39
|
+
def init_worker(sender=None, **kwargs):
|
|
40
|
+
"""Worker 进程启动时的初始化"""
|
|
41
|
+
# 扩展已经在 init_all_extensions 中初始化了
|
|
42
|
+
pass
|
|
43
|
+
|
|
44
|
+
# 导入任务(确保任务被注册)
|
|
45
|
+
from tasks import example_task # noqa: E402, F401
|
|
46
|
+
|
|
47
|
+
# 导出 celery_app 供其他地方使用
|
|
48
|
+
__all__ = ["celery_app"]
|
|
49
|
+
''',
|
|
50
|
+
|
|
51
|
+
"tasks_init_py": lambda: '''"""
|
|
52
|
+
Celery 任务模块
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
# 导入所有任务,确保它们被注册到 Celery 应用
|
|
56
|
+
from . import example_task # noqa: F401
|
|
57
|
+
|
|
58
|
+
__all__ = ["example_task"]
|
|
59
|
+
''',
|
|
60
|
+
|
|
61
|
+
"example_task_py": lambda: f'''"""
|
|
62
|
+
示例 Celery 任务
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
from celery import shared_task
|
|
66
|
+
from tomskit.celery import AsyncTaskRunner
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@shared_task(name="{project_name}.example_task", queue="default")
|
|
70
|
+
def example_task(message: str):
|
|
71
|
+
"""
|
|
72
|
+
示例异步任务
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
message: 要处理的消息
|
|
76
|
+
|
|
77
|
+
Returns:
|
|
78
|
+
str: 处理结果
|
|
79
|
+
"""
|
|
80
|
+
runner = AsyncTaskRunner(async_example_task)
|
|
81
|
+
return runner.run(message)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
async def async_example_task(message: str):
|
|
85
|
+
"""
|
|
86
|
+
异步任务函数
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
message: 要处理的消息
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
str: 处理结果
|
|
93
|
+
"""
|
|
94
|
+
# TODO: 实现你的异步任务逻辑
|
|
95
|
+
# 可以使用 db.session 进行数据库操作
|
|
96
|
+
# 可以使用 redis_client 进行 Redis 操作
|
|
97
|
+
|
|
98
|
+
print(f"处理消息: {{message}}")
|
|
99
|
+
return f"任务完成: {{message}}"
|
|
100
|
+
''',
|
|
101
|
+
}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
"""
|
|
2
|
+
扩展模板模块
|
|
3
|
+
包含所有扩展相关的文件模板
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from typing import Callable
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def get_extension_templates(project_name: str, project_type: str = "full") -> dict[str, Callable[[], str]]:
|
|
10
|
+
"""获取扩展模板"""
|
|
11
|
+
# 根据项目类型决定是否包含 ext_celery
|
|
12
|
+
def _get_extensions_init_py():
|
|
13
|
+
celery_import = ""
|
|
14
|
+
celery_in_list = ""
|
|
15
|
+
if project_type in ("celery", "full"):
|
|
16
|
+
celery_import = " ext_celery,\n"
|
|
17
|
+
celery_in_list = " ext_celery,\n"
|
|
18
|
+
|
|
19
|
+
return f'''"""
|
|
20
|
+
扩展功能统一初始化
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
import time
|
|
24
|
+
from typing import Any
|
|
25
|
+
|
|
26
|
+
from extensions import (
|
|
27
|
+
ext_logger,
|
|
28
|
+
ext_database,
|
|
29
|
+
ext_redis,
|
|
30
|
+
{celery_import} # 在这里导入更多扩展
|
|
31
|
+
# ext_mail,
|
|
32
|
+
# ext_storage,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
# 扩展初始化顺序列表
|
|
36
|
+
extensions = [
|
|
37
|
+
ext_logger,
|
|
38
|
+
ext_database,
|
|
39
|
+
ext_redis,
|
|
40
|
+
{celery_in_list} # 在这里添加更多扩展,按初始化顺序排列
|
|
41
|
+
# ext_mail,
|
|
42
|
+
# ext_storage,
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def init_all_extensions(app: Any = None):
|
|
47
|
+
"""
|
|
48
|
+
统一初始化所有扩展功能
|
|
49
|
+
|
|
50
|
+
按 extensions 列表顺序初始化每个扩展,支持:
|
|
51
|
+
- is_enabled() 检查扩展是否启用
|
|
52
|
+
- init_app(app) 初始化扩展
|
|
53
|
+
- 记录初始化时间
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
app: 应用实例(FastApp 或 AsyncCelery),可选
|
|
57
|
+
"""
|
|
58
|
+
for ext in extensions:
|
|
59
|
+
short_name = ext.__name__.split(".")[-1]
|
|
60
|
+
|
|
61
|
+
# 检查扩展是否启用
|
|
62
|
+
is_enabled = ext.is_enabled() if hasattr(ext, "is_enabled") else True
|
|
63
|
+
if not is_enabled:
|
|
64
|
+
print(f"⏭️ 跳过 {{short_name}}(未启用)")
|
|
65
|
+
continue
|
|
66
|
+
|
|
67
|
+
# 初始化扩展
|
|
68
|
+
try:
|
|
69
|
+
start_time = time.perf_counter()
|
|
70
|
+
ext.init_app(app)
|
|
71
|
+
end_time = time.perf_counter()
|
|
72
|
+
elapsed_ms = round((end_time - start_time) * 1000, 2)
|
|
73
|
+
print(f"✅ {{short_name}} 初始化成功 ({{elapsed_ms}} ms)")
|
|
74
|
+
except Exception as e:
|
|
75
|
+
print(f"❌ {{short_name}} 初始化失败: {{e}}")
|
|
76
|
+
raise
|
|
77
|
+
'''
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
"extensions_init_py": _get_extensions_init_py,
|
|
81
|
+
|
|
82
|
+
"extensions_logger_py": lambda: '''"""
|
|
83
|
+
日志扩展初始化
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
from tomskit.logger import setup_logging, LoggerConfig
|
|
87
|
+
from typing import Any
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def is_enabled() -> bool:
|
|
91
|
+
"""检查扩展是否启用"""
|
|
92
|
+
return True
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def init_app(app: Any = None):
|
|
96
|
+
"""初始化日志系统"""
|
|
97
|
+
config = LoggerConfig()
|
|
98
|
+
setup_logging(config)
|
|
99
|
+
''',
|
|
100
|
+
|
|
101
|
+
"extensions_database_py": lambda: '''"""
|
|
102
|
+
数据库扩展初始化
|
|
103
|
+
"""
|
|
104
|
+
|
|
105
|
+
from tomskit.sqlalchemy import db, DatabaseConfig
|
|
106
|
+
from typing import Any
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def is_enabled() -> bool:
|
|
110
|
+
"""检查扩展是否启用"""
|
|
111
|
+
return True
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def init_app(app: Any = None):
|
|
115
|
+
"""初始化数据库连接池"""
|
|
116
|
+
config = DatabaseConfig()
|
|
117
|
+
db.initialize_session_pool(
|
|
118
|
+
config.SQLALCHEMY_DATABASE_URI,
|
|
119
|
+
config.SQLALCHEMY_ENGINE_OPTIONS
|
|
120
|
+
)
|
|
121
|
+
''',
|
|
122
|
+
|
|
123
|
+
"extensions_redis_py": lambda: '''"""
|
|
124
|
+
Redis 扩展初始化
|
|
125
|
+
"""
|
|
126
|
+
|
|
127
|
+
from tomskit.redis import RedisClientWrapper, RedisConfig
|
|
128
|
+
from typing import Any
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def is_enabled() -> bool:
|
|
132
|
+
"""检查扩展是否启用"""
|
|
133
|
+
return True
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def init_app(app: Any = None):
|
|
137
|
+
"""初始化 Redis 连接"""
|
|
138
|
+
config = RedisConfig()
|
|
139
|
+
RedisClientWrapper.initialize(config.model_dump())
|
|
140
|
+
''',
|
|
141
|
+
|
|
142
|
+
"extensions_celery_py": lambda: f'''"""
|
|
143
|
+
Celery 扩展初始化
|
|
144
|
+
"""
|
|
145
|
+
|
|
146
|
+
from pathlib import Path
|
|
147
|
+
from typing import Any
|
|
148
|
+
from dotenv import load_dotenv
|
|
149
|
+
|
|
150
|
+
from tomskit.celery import AsyncCelery, CeleryConfig
|
|
151
|
+
|
|
152
|
+
# 全局 Celery 应用实例
|
|
153
|
+
celery_app: AsyncCelery | None = None
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def is_enabled() -> bool:
|
|
157
|
+
"""检查扩展是否启用"""
|
|
158
|
+
return True
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def init_app(app: Any = None) -> AsyncCelery:
|
|
162
|
+
"""
|
|
163
|
+
初始化 Celery 应用
|
|
164
|
+
|
|
165
|
+
Args:
|
|
166
|
+
app: 应用实例(FastApp 或 AsyncCelery),可选
|
|
167
|
+
|
|
168
|
+
Returns:
|
|
169
|
+
AsyncCelery: Celery 应用实例
|
|
170
|
+
"""
|
|
171
|
+
global celery_app
|
|
172
|
+
|
|
173
|
+
# 如果已经初始化,直接返回
|
|
174
|
+
if celery_app is not None:
|
|
175
|
+
return celery_app
|
|
176
|
+
|
|
177
|
+
# 如果传入的是 AsyncCelery 实例,说明已经在 celery_app.py 中创建了
|
|
178
|
+
# 这种情况下只需要保存引用,不需要重新创建
|
|
179
|
+
if isinstance(app, AsyncCelery):
|
|
180
|
+
celery_app = app
|
|
181
|
+
return celery_app
|
|
182
|
+
|
|
183
|
+
# 加载环境变量
|
|
184
|
+
env_path = Path(__file__).parent.parent / ".env"
|
|
185
|
+
if env_path.exists():
|
|
186
|
+
load_dotenv(env_path)
|
|
187
|
+
|
|
188
|
+
# 创建 Celery 配置
|
|
189
|
+
celery_config = CeleryConfig()
|
|
190
|
+
|
|
191
|
+
# 创建 Celery 应用
|
|
192
|
+
celery_app = AsyncCelery(
|
|
193
|
+
'{project_name}',
|
|
194
|
+
broker=celery_config.CELERY_BROKER_URL,
|
|
195
|
+
backend=celery_config.CELERY_RESULT_BACKEND
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
# 应用配置
|
|
199
|
+
celery_app.from_mapping(celery_config.get_celery_config_dict())
|
|
200
|
+
|
|
201
|
+
# 设置应用根路径
|
|
202
|
+
celery_app.set_app_root_path(Path(__file__).parent.parent)
|
|
203
|
+
|
|
204
|
+
return celery_app
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def get_celery_app() -> AsyncCelery:
|
|
208
|
+
"""获取 Celery 应用实例"""
|
|
209
|
+
if celery_app is None:
|
|
210
|
+
raise RuntimeError("Celery app is not initialized. Call init_app() first.")
|
|
211
|
+
return celery_app
|
|
212
|
+
''',
|
|
213
|
+
}
|