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
tomskit/cli/__init__.py
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
"""
|
|
2
|
+
toms-fast CLI 工具
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import sys
|
|
7
|
+
import tomllib
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Optional
|
|
10
|
+
|
|
11
|
+
from .scaffold import create_project
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def init_migrations(project_path: Optional[Path] = None):
|
|
15
|
+
"""为已存在的项目初始化数据库迁移"""
|
|
16
|
+
if project_path is None:
|
|
17
|
+
project_path = Path.cwd()
|
|
18
|
+
|
|
19
|
+
project_path = Path(project_path).resolve()
|
|
20
|
+
|
|
21
|
+
# 检查是否在 backend 目录或项目根目录
|
|
22
|
+
backend_path = project_path
|
|
23
|
+
project_root = project_path
|
|
24
|
+
if (project_path / "backend").exists():
|
|
25
|
+
# 在项目根目录,使用 backend 目录
|
|
26
|
+
backend_path = project_path / "backend"
|
|
27
|
+
project_root = project_path
|
|
28
|
+
elif not (project_path / "main.py").exists() and not (project_path / "app").exists():
|
|
29
|
+
print("❌ 错误: 未找到项目文件,请确保在项目根目录或 backend 目录运行此命令")
|
|
30
|
+
sys.exit(1)
|
|
31
|
+
else:
|
|
32
|
+
# 在 backend 目录,项目根目录是父目录
|
|
33
|
+
project_root = project_path.parent
|
|
34
|
+
|
|
35
|
+
# 获取项目名称
|
|
36
|
+
project_name = project_root.name
|
|
37
|
+
|
|
38
|
+
# 尝试从 pyproject.toml 读取项目名称
|
|
39
|
+
pyproject_path = backend_path / "pyproject.toml"
|
|
40
|
+
if pyproject_path.exists():
|
|
41
|
+
try:
|
|
42
|
+
with open(pyproject_path, "rb") as f:
|
|
43
|
+
pyproject_data = tomllib.load(f)
|
|
44
|
+
if "project" in pyproject_data and "name" in pyproject_data["project"]:
|
|
45
|
+
project_name = pyproject_data["project"]["name"]
|
|
46
|
+
except Exception:
|
|
47
|
+
# 如果读取失败,使用目录名称
|
|
48
|
+
pass
|
|
49
|
+
|
|
50
|
+
migrations_dir = backend_path / "migrations"
|
|
51
|
+
alembic_ini = migrations_dir / "alembic.ini"
|
|
52
|
+
|
|
53
|
+
# 检查是否已经初始化
|
|
54
|
+
if migrations_dir.exists() and alembic_ini.exists():
|
|
55
|
+
print("⚠️ 警告: migrations 目录和 alembic.ini 已存在")
|
|
56
|
+
response = input("是否重新初始化?这将覆盖现有配置 (y/N): ")
|
|
57
|
+
if response.lower() != 'y':
|
|
58
|
+
print("❌ 已取消")
|
|
59
|
+
return
|
|
60
|
+
|
|
61
|
+
print(f"🚀 正在为{project_name}项目初始化数据库迁移...")
|
|
62
|
+
print(f"📁 后端路径: {backend_path}")
|
|
63
|
+
print(f"📦 项目名称: {project_name}")
|
|
64
|
+
|
|
65
|
+
# 创建 migrations 目录结构
|
|
66
|
+
migrations_dir.mkdir(exist_ok=True)
|
|
67
|
+
versions_dir = migrations_dir / "versions"
|
|
68
|
+
versions_dir.mkdir(exist_ok=True)
|
|
69
|
+
|
|
70
|
+
# 创建 __init__.py 文件
|
|
71
|
+
(migrations_dir / "__init__.py").write_text('"""\n数据库迁移目录\n"""\n', encoding="utf-8")
|
|
72
|
+
(versions_dir / "__init__.py").write_text('"""\n数据库迁移版本目录\n"""\n', encoding="utf-8")
|
|
73
|
+
|
|
74
|
+
# 从模板创建配置文件
|
|
75
|
+
from .templates.migrations import get_migrations_templates
|
|
76
|
+
|
|
77
|
+
templates = get_migrations_templates(project_name)
|
|
78
|
+
|
|
79
|
+
# 创建 migrations/alembic.ini
|
|
80
|
+
if "alembic_ini" in templates:
|
|
81
|
+
alembic_content = templates["alembic_ini"]()
|
|
82
|
+
alembic_ini.write_text(alembic_content, encoding="utf-8")
|
|
83
|
+
print(" ✓ 创建文件: migrations/alembic.ini")
|
|
84
|
+
|
|
85
|
+
# 创建 migrations/env.py
|
|
86
|
+
if "migrations_env_py" in templates:
|
|
87
|
+
env_content = templates["migrations_env_py"]()
|
|
88
|
+
(migrations_dir / "env.py").write_text(env_content, encoding="utf-8")
|
|
89
|
+
print(f" ✓ 创建文件: migrations/env.py")
|
|
90
|
+
|
|
91
|
+
# 创建 migrations/script.py.mako
|
|
92
|
+
if "migrations_script_py_mako" in templates:
|
|
93
|
+
script_content = templates["migrations_script_py_mako"]()
|
|
94
|
+
(migrations_dir / "script.py.mako").write_text(script_content, encoding="utf-8")
|
|
95
|
+
print(f" ✓ 创建文件: migrations/script.py.mako")
|
|
96
|
+
|
|
97
|
+
print("\n✅ 数据库迁移初始化成功!")
|
|
98
|
+
print("\n📝 下一步:")
|
|
99
|
+
print(" # 创建初始迁移:")
|
|
100
|
+
print(" uv run alembic -c migrations/alembic.ini revision --autogenerate -m 'Initial migration'")
|
|
101
|
+
print(" # 应用迁移到数据库:")
|
|
102
|
+
print(" uv run alembic -c migrations/alembic.ini upgrade head")
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def main():
|
|
106
|
+
"""CLI 入口函数"""
|
|
107
|
+
parser = argparse.ArgumentParser(
|
|
108
|
+
description="toms-fast 项目脚手架生成器",
|
|
109
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
subparsers = parser.add_subparsers(dest="command", help="可用命令")
|
|
113
|
+
|
|
114
|
+
# init 命令:创建新项目
|
|
115
|
+
init_parser = subparsers.add_parser("init", help="创建新项目")
|
|
116
|
+
init_parser.add_argument(
|
|
117
|
+
"project_name",
|
|
118
|
+
help="项目名称(将作为包名和目录名)"
|
|
119
|
+
)
|
|
120
|
+
init_parser.add_argument(
|
|
121
|
+
"-d", "--dir",
|
|
122
|
+
dest="target_dir",
|
|
123
|
+
help="目标目录(默认为当前目录)",
|
|
124
|
+
default=None
|
|
125
|
+
)
|
|
126
|
+
init_parser.add_argument(
|
|
127
|
+
"-t", "--type",
|
|
128
|
+
dest="project_type",
|
|
129
|
+
choices=["fastapi", "celery", "full"],
|
|
130
|
+
default="full",
|
|
131
|
+
help="项目类型:fastapi(仅 FastAPI)、celery(仅 Celery)、full(FastAPI + Celery,默认)"
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
# migrations 命令:初始化数据库迁移
|
|
135
|
+
migrations_parser = subparsers.add_parser("migrations", help="为已存在的项目初始化数据库迁移")
|
|
136
|
+
migrations_parser.add_argument(
|
|
137
|
+
"-d", "--dir",
|
|
138
|
+
dest="project_dir",
|
|
139
|
+
help="项目目录(默认为当前目录)",
|
|
140
|
+
default=None
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
args = parser.parse_args()
|
|
144
|
+
|
|
145
|
+
# 如果没有指定命令,默认使用 init(向后兼容)
|
|
146
|
+
if args.command is None:
|
|
147
|
+
# 尝试解析为 init 命令的参数
|
|
148
|
+
if len(sys.argv) > 1 and not sys.argv[1].startswith('-'):
|
|
149
|
+
project_name = sys.argv[1]
|
|
150
|
+
# 解析其他参数
|
|
151
|
+
target_dir = None
|
|
152
|
+
project_type = "full"
|
|
153
|
+
|
|
154
|
+
i = 2
|
|
155
|
+
while i < len(sys.argv):
|
|
156
|
+
if sys.argv[i] in ("-d", "--dir") and i + 1 < len(sys.argv):
|
|
157
|
+
target_dir = sys.argv[i + 1]
|
|
158
|
+
i += 2
|
|
159
|
+
elif sys.argv[i] in ("-t", "--type") and i + 1 < len(sys.argv):
|
|
160
|
+
project_type = sys.argv[i + 1]
|
|
161
|
+
i += 2
|
|
162
|
+
else:
|
|
163
|
+
i += 1
|
|
164
|
+
|
|
165
|
+
# 验证项目名称
|
|
166
|
+
if not project_name.replace("_", "").replace("-", "").isalnum():
|
|
167
|
+
print("❌ 错误: 项目名称只能包含字母、数字、下划线和连字符")
|
|
168
|
+
sys.exit(1)
|
|
169
|
+
|
|
170
|
+
# 创建脚手架
|
|
171
|
+
try:
|
|
172
|
+
create_project(project_name, target_dir, project_type)
|
|
173
|
+
except Exception as e:
|
|
174
|
+
print(f"❌ 创建项目失败: {e}")
|
|
175
|
+
import traceback
|
|
176
|
+
traceback.print_exc()
|
|
177
|
+
sys.exit(1)
|
|
178
|
+
else:
|
|
179
|
+
parser.print_help()
|
|
180
|
+
sys.exit(1)
|
|
181
|
+
elif args.command == "init":
|
|
182
|
+
# 验证项目名称
|
|
183
|
+
if not args.project_name.replace("_", "").replace("-", "").isalnum():
|
|
184
|
+
print("❌ 错误: 项目名称只能包含字母、数字、下划线和连字符")
|
|
185
|
+
sys.exit(1)
|
|
186
|
+
|
|
187
|
+
# 创建脚手架
|
|
188
|
+
try:
|
|
189
|
+
create_project(args.project_name, args.target_dir, args.project_type)
|
|
190
|
+
except Exception as e:
|
|
191
|
+
print(f"❌ 创建项目失败: {e}")
|
|
192
|
+
import traceback
|
|
193
|
+
traceback.print_exc()
|
|
194
|
+
sys.exit(1)
|
|
195
|
+
elif args.command == "migrations":
|
|
196
|
+
# 初始化 migrations
|
|
197
|
+
try:
|
|
198
|
+
init_migrations(args.project_dir)
|
|
199
|
+
except Exception as e:
|
|
200
|
+
print(f"❌ 初始化 migrations 失败: {e}")
|
|
201
|
+
import traceback
|
|
202
|
+
traceback.print_exc()
|
|
203
|
+
sys.exit(1)
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
if __name__ == "__main__":
|
|
207
|
+
main()
|
tomskit/cli/__main__.py
ADDED
tomskit/cli/scaffold.py
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"""
|
|
2
|
+
项目脚手架生成器
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Optional
|
|
7
|
+
|
|
8
|
+
from .templates_config import (
|
|
9
|
+
get_directory_structure,
|
|
10
|
+
get_file_templates,
|
|
11
|
+
get_template_functions,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class ProjectScaffold:
|
|
16
|
+
"""项目脚手架生成器"""
|
|
17
|
+
|
|
18
|
+
def __init__(self, project_name: str, target_dir: Optional[str] = None, project_type: str = "full"):
|
|
19
|
+
self.project_name = project_name
|
|
20
|
+
self.target_dir = Path(target_dir) if target_dir else Path.cwd() / project_name
|
|
21
|
+
self.project_path = self.target_dir / "backend" # 代码放到 backend 目录
|
|
22
|
+
self.project_type = project_type
|
|
23
|
+
self.templates = get_template_functions(project_name, project_type)
|
|
24
|
+
|
|
25
|
+
def create(self):
|
|
26
|
+
"""创建项目结构"""
|
|
27
|
+
project_type_names = {
|
|
28
|
+
"fastapi": "FastAPI",
|
|
29
|
+
"celery": "Celery",
|
|
30
|
+
"full": "FastAPI + Celery"
|
|
31
|
+
}
|
|
32
|
+
print(f"🚀 正在创建项目: {self.project_name}")
|
|
33
|
+
print(f"📦 项目类型: {project_type_names.get(self.project_type, self.project_type)}")
|
|
34
|
+
print(f"📁 目标目录: {self.target_dir}")
|
|
35
|
+
|
|
36
|
+
# 检查目录是否已存在
|
|
37
|
+
if self.target_dir.exists() and any(self.target_dir.iterdir()):
|
|
38
|
+
response = input(f"⚠️ 目录 {self.target_dir} 已存在且不为空,是否继续?(y/N): ")
|
|
39
|
+
if response.lower() != 'y':
|
|
40
|
+
print("❌ 已取消")
|
|
41
|
+
return
|
|
42
|
+
|
|
43
|
+
# 创建 web 目录(前端代码)
|
|
44
|
+
web_dir = self.target_dir / "web"
|
|
45
|
+
web_dir.mkdir(exist_ok=True)
|
|
46
|
+
print(f" ✓ 创建目录: web/")
|
|
47
|
+
|
|
48
|
+
# 创建目录结构
|
|
49
|
+
self._create_directories()
|
|
50
|
+
|
|
51
|
+
# 创建文件(README 单独处理,放到项目根目录)
|
|
52
|
+
self._create_files()
|
|
53
|
+
|
|
54
|
+
print("\n✅ 项目创建成功!")
|
|
55
|
+
print("\n📝 下一步:")
|
|
56
|
+
print(f" cd {self.target_dir}/backend")
|
|
57
|
+
print(" uv sync # 安装依赖(使用 uv 管理)")
|
|
58
|
+
print(" cp .env.example .env")
|
|
59
|
+
print(" # 编辑 .env 文件配置数据库和 Redis")
|
|
60
|
+
|
|
61
|
+
if self.project_type in ("fastapi", "full"):
|
|
62
|
+
print("\n # 数据库迁移:")
|
|
63
|
+
print(" # 1. 创建初始迁移:")
|
|
64
|
+
print(" uv run alembic -c migrations/alembic.ini revision --autogenerate -m 'Initial migration'")
|
|
65
|
+
print(" # 2. 应用迁移到数据库:")
|
|
66
|
+
print(" uv run alembic -c migrations/alembic.ini upgrade head")
|
|
67
|
+
print("\n # 运行 FastAPI 应用:")
|
|
68
|
+
print(" uv run uvicorn main:app --reload")
|
|
69
|
+
if self.project_type in ("celery", "full"):
|
|
70
|
+
print(" # 运行 Celery Worker:")
|
|
71
|
+
print(" uv run celery -A celery_app worker --loglevel=info")
|
|
72
|
+
|
|
73
|
+
def _create_directories(self):
|
|
74
|
+
"""创建目录结构(从配置文件读取)"""
|
|
75
|
+
directory_structure = get_directory_structure(self.project_type)
|
|
76
|
+
for dir_path_str, need_init in directory_structure.items():
|
|
77
|
+
dir_path = self.project_path / dir_path_str
|
|
78
|
+
dir_path.mkdir(parents=True, exist_ok=True)
|
|
79
|
+
|
|
80
|
+
# 如果需要,创建 __init__.py
|
|
81
|
+
if need_init:
|
|
82
|
+
(dir_path / "__init__.py").touch()
|
|
83
|
+
print(f" ✓ 创建目录: {dir_path_str}/ (含 __init__.py)")
|
|
84
|
+
else:
|
|
85
|
+
print(f" ✓ 创建目录: {dir_path_str}/")
|
|
86
|
+
|
|
87
|
+
def _create_files(self):
|
|
88
|
+
"""创建所有文件(从配置文件读取)"""
|
|
89
|
+
file_templates = get_file_templates(self.project_type)
|
|
90
|
+
for file_path_str, template_key in file_templates.items():
|
|
91
|
+
# README.md 放到项目根目录,其他文件放到 backend 目录
|
|
92
|
+
if file_path_str == "README.md":
|
|
93
|
+
template_func = self.templates.get(template_key)
|
|
94
|
+
if template_func is None:
|
|
95
|
+
print(f" ⚠️ 警告: 模板 '{template_key}' 未找到,跳过文件: {file_path_str}")
|
|
96
|
+
continue
|
|
97
|
+
content = template_func()
|
|
98
|
+
readme_path = self.target_dir / "README.md"
|
|
99
|
+
readme_path.write_text(content, encoding="utf-8")
|
|
100
|
+
print(f" ✓ 创建文件: README.md")
|
|
101
|
+
continue
|
|
102
|
+
|
|
103
|
+
# 获取模板内容
|
|
104
|
+
template_func = self.templates.get(template_key)
|
|
105
|
+
if template_func is None:
|
|
106
|
+
print(f" ⚠️ 警告: 模板 '{template_key}' 未找到,跳过文件: {file_path_str}")
|
|
107
|
+
continue
|
|
108
|
+
|
|
109
|
+
content = template_func()
|
|
110
|
+
self._write_file(file_path_str, content)
|
|
111
|
+
|
|
112
|
+
def _write_file(self, relative_path: str, content: str):
|
|
113
|
+
"""写入文件"""
|
|
114
|
+
file_path = self.project_path / relative_path
|
|
115
|
+
file_path.parent.mkdir(parents=True, exist_ok=True)
|
|
116
|
+
file_path.write_text(content, encoding="utf-8")
|
|
117
|
+
print(f" ✓ 创建文件: {relative_path}")
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def create_project(project_name: str, target_dir: Optional[str] = None, project_type: str = "full"):
|
|
121
|
+
"""创建项目的便捷函数"""
|
|
122
|
+
scaffold = ProjectScaffold(project_name, target_dir, project_type)
|
|
123
|
+
scaffold.create()
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""
|
|
2
|
+
模板模块聚合
|
|
3
|
+
从各个子模块导入所有模板函数
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from typing import Callable
|
|
7
|
+
|
|
8
|
+
from . import base, extensions, fastapi, celery, migrations
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def get_all_templates(project_name: str, project_type: str = "full") -> dict[str, Callable[[], str]]:
|
|
12
|
+
"""
|
|
13
|
+
获取所有模板函数
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
project_name: 项目名称
|
|
17
|
+
project_type: 项目类型 (fastapi, celery, full)
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
模板函数字典
|
|
21
|
+
"""
|
|
22
|
+
templates = {}
|
|
23
|
+
|
|
24
|
+
# 基础模板(所有类型都需要)
|
|
25
|
+
templates.update(base.get_base_templates(project_name, project_type))
|
|
26
|
+
|
|
27
|
+
# 扩展模板(所有类型都需要)
|
|
28
|
+
templates.update(extensions.get_extension_templates(project_name, project_type))
|
|
29
|
+
|
|
30
|
+
# FastAPI 模板
|
|
31
|
+
if project_type in ("fastapi", "full"):
|
|
32
|
+
templates.update(fastapi.get_fastapi_templates(project_name))
|
|
33
|
+
|
|
34
|
+
# Celery 模板
|
|
35
|
+
if project_type in ("celery", "full"):
|
|
36
|
+
templates.update(celery.get_celery_templates(project_name))
|
|
37
|
+
|
|
38
|
+
# 数据库迁移模板(FastAPI 和 full 类型需要)
|
|
39
|
+
if project_type in ("fastapi", "full"):
|
|
40
|
+
templates.update(migrations.get_migrations_templates(project_name))
|
|
41
|
+
|
|
42
|
+
return templates
|