fastapp-cli 0.1.0__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.
Files changed (67) hide show
  1. fastapp_cli/__init__.py +3 -0
  2. fastapp_cli/create.py +157 -0
  3. fastapp_cli/main.py +33 -0
  4. fastapp_cli/naming.py +39 -0
  5. fastapp_cli/prompts.py +35 -0
  6. fastapp_cli/render.py +130 -0
  7. fastapp_cli/templates/__init__.py +1 -0
  8. fastapp_cli/templates/project/.env.development.example.j2 +21 -0
  9. fastapp_cli/templates/project/.env.example.j2 +29 -0
  10. fastapp_cli/templates/project/.env.j2 +27 -0
  11. fastapp_cli/templates/project/.gitignore +178 -0
  12. fastapp_cli/templates/project/.pre-commit-config.yaml.j2 +80 -0
  13. fastapp_cli/templates/project/.python-version.j2 +1 -0
  14. fastapp_cli/templates/project/Dockerfile.j2 +17 -0
  15. fastapp_cli/templates/project/Makefile.j2 +31 -0
  16. fastapp_cli/templates/project/README.md.j2 +68 -0
  17. fastapp_cli/templates/project/alembic/env.py.j2 +84 -0
  18. fastapp_cli/templates/project/alembic/script.py.mako +28 -0
  19. fastapp_cli/templates/project/alembic/versions/.gitkeep +0 -0
  20. fastapp_cli/templates/project/alembic.ini.j2 +50 -0
  21. fastapp_cli/templates/project/app/__init__.py.j2 +1 -0
  22. fastapp_cli/templates/project/app/api/__init__.py.j2 +1 -0
  23. fastapp_cli/templates/project/app/api/deps.py.j2 +33 -0
  24. fastapp_cli/templates/project/app/api/v1/__init__.py.j2 +1 -0
  25. fastapp_cli/templates/project/app/api/v1/endpoints/__init__.py.j2 +1 -0
  26. fastapp_cli/templates/project/app/api/v1/endpoints/health.py.j2 +33 -0
  27. fastapp_cli/templates/project/app/api/v1/endpoints/items.py.j2 +90 -0
  28. fastapp_cli/templates/project/app/api/v1/router.py.j2 +9 -0
  29. fastapp_cli/templates/project/app/core/__init__.py.j2 +1 -0
  30. fastapp_cli/templates/project/app/core/celery_app.py.j2 +62 -0
  31. fastapp_cli/templates/project/app/core/config.py.j2 +105 -0
  32. fastapp_cli/templates/project/app/core/context_var.py.j2 +13 -0
  33. fastapp_cli/templates/project/app/core/database.py.j2 +50 -0
  34. fastapp_cli/templates/project/app/core/exceptions.py.j2 +175 -0
  35. fastapp_cli/templates/project/app/core/logging.py.j2 +125 -0
  36. fastapp_cli/templates/project/app/core/middleware.py.j2 +39 -0
  37. fastapp_cli/templates/project/app/crud/__init__.py.j2 +1 -0
  38. fastapp_cli/templates/project/app/crud/base.py.j2 +229 -0
  39. fastapp_cli/templates/project/app/crud/item.py.j2 +10 -0
  40. fastapp_cli/templates/project/app/main.py.j2 +118 -0
  41. fastapp_cli/templates/project/app/models/__init__.py.j2 +10 -0
  42. fastapp_cli/templates/project/app/models/base.py.j2 +59 -0
  43. fastapp_cli/templates/project/app/models/item.py.j2 +22 -0
  44. fastapp_cli/templates/project/app/schemas/__init__.py.j2 +1 -0
  45. fastapp_cli/templates/project/app/schemas/common.py.j2 +81 -0
  46. fastapp_cli/templates/project/app/schemas/item.py.j2 +35 -0
  47. fastapp_cli/templates/project/app/services/__init__.py.j2 +1 -0
  48. fastapp_cli/templates/project/app/services/base.py.j2 +79 -0
  49. fastapp_cli/templates/project/app/services/item_service.py.j2 +10 -0
  50. fastapp_cli/templates/project/app/tasks/__init__.py.j2 +1 -0
  51. fastapp_cli/templates/project/app/tasks/sample_tasks.py.j2 +28 -0
  52. fastapp_cli/templates/project/app/utils/__init__.py.j2 +1 -0
  53. fastapp_cli/templates/project/docs/SQLModel/345/256/232/344/271/211/347/244/272/344/276/213.md +400 -0
  54. fastapp_cli/templates/project/pm2.config.json.j2 +47 -0
  55. fastapp_cli/templates/project/pyproject.toml.j2 +195 -0
  56. fastapp_cli/templates/project/scripts/celery_beat.sh.j2 +9 -0
  57. fastapp_cli/templates/project/scripts/celery_flower.sh.j2 +22 -0
  58. fastapp_cli/templates/project/scripts/celery_worker.sh.j2 +15 -0
  59. fastapp_cli/templates/project/scripts/start.sh.j2 +17 -0
  60. fastapp_cli/templates/project/tests/api/test_health.py.j2 +15 -0
  61. fastapp_cli/templates/project/tests/api/test_items.py.j2 +61 -0
  62. fastapp_cli/templates/project/tests/conftest.py.j2 +61 -0
  63. fastapp_cli/templates/project/tests/services/test_item_service.py.j2 +44 -0
  64. fastapp_cli-0.1.0.dist-info/METADATA +102 -0
  65. fastapp_cli-0.1.0.dist-info/RECORD +67 -0
  66. fastapp_cli-0.1.0.dist-info/WHEEL +4 -0
  67. fastapp_cli-0.1.0.dist-info/entry_points.txt +2 -0
@@ -0,0 +1,3 @@
1
+ """fastapp-cli: FastAPI 项目脚手架."""
2
+
3
+ __version__ = "0.1.0"
fastapp_cli/create.py ADDED
@@ -0,0 +1,157 @@
1
+ """``fastapp create`` 命令实现.
2
+
3
+ 流程:校验 → 交互补全 → 渲染 → git init → 输出下一步指引。
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ import subprocess
9
+ from datetime import datetime, timezone
10
+ from pathlib import Path
11
+
12
+ import typer
13
+
14
+ from fastapp_cli import __version__
15
+ from fastapp_cli import prompts
16
+ from fastapp_cli.naming import validate_project_name
17
+ from fastapp_cli.render import render_project
18
+
19
+ FILE_COUNT_EXCLUDE = {".git"}
20
+
21
+
22
+ def _git_user_name() -> str | None:
23
+ """读取 git 全局配置中的 user.name,失败返回 None."""
24
+ try:
25
+ result = subprocess.run(
26
+ ["git", "config", "user.name"],
27
+ capture_output=True,
28
+ text=True,
29
+ check=True,
30
+ )
31
+ name = result.stdout.strip()
32
+ return name or None
33
+ except (subprocess.CalledProcessError, FileNotFoundError, OSError):
34
+ return None
35
+
36
+
37
+ def _count_files(out_dir: Path) -> int:
38
+ return sum(
39
+ 1 for p in out_dir.rglob("*")
40
+ if p.is_file() and not any(part in FILE_COUNT_EXCLUDE for part in p.parts)
41
+ )
42
+
43
+
44
+ def _git_init(project_dir: Path) -> bool:
45
+ """初始化 git 仓库,失败时告警但不阻塞."""
46
+ try:
47
+ subprocess.run(
48
+ ["git", "init", "-q"],
49
+ cwd=project_dir,
50
+ capture_output=True,
51
+ check=True,
52
+ )
53
+ return True
54
+ except (subprocess.CalledProcessError, FileNotFoundError, OSError) as exc:
55
+ typer.secho(f"⚠ git init 失败,已跳过:{exc}", fg=typer.colors.YELLOW)
56
+ return False
57
+
58
+
59
+ def create(
60
+ project_name: str = typer.Argument(
61
+ ..., help="项目名:小写字母/数字/连字符,如 my-server(应用包固定位 app)"
62
+ ),
63
+ description: str = typer.Option(
64
+ None,
65
+ "--description",
66
+ help="项目描述(未提供时交互提问)",
67
+ ),
68
+ pm2: bool = typer.Option(
69
+ None,
70
+ "--pm2/--no-pm2",
71
+ help="是否生成 pm2.config.json(未指定时交互提问)",
72
+ ),
73
+ docker: bool = typer.Option(
74
+ None,
75
+ "--docker/--no-docker",
76
+ help="是否生成 Dockerfile(未指定时交互提问)",
77
+ ),
78
+ python_version: str = typer.Option(
79
+ "3.12",
80
+ "--python",
81
+ help="生成项目的目标 Python 版本",
82
+ ),
83
+ author: str = typer.Option(
84
+ None,
85
+ "--author",
86
+ help="作者署名(默认取 git config user.name)",
87
+ ),
88
+ force: bool = typer.Option(
89
+ False,
90
+ "--force",
91
+ help="目标目录已存在时覆盖重建",
92
+ ),
93
+ no_git: bool = typer.Option(
94
+ False,
95
+ "--no-git",
96
+ help="跳过 git init",
97
+ ),
98
+ ) -> None:
99
+ """生成一个完整、可直接运行的 FastAPI 项目."""
100
+ # 1. 校验
101
+ try:
102
+ name = validate_project_name(project_name)
103
+ except ValueError as exc:
104
+ typer.secho(f"✘ {exc}", fg=typer.colors.RED, err=True)
105
+ raise typer.Exit(code=1) from exc
106
+
107
+ project_dir = Path.cwd() / name
108
+ if project_dir.exists():
109
+ if not force:
110
+ typer.secho(
111
+ f"✘ 目标目录已存在:{project_dir}(使用 --force 覆盖重建)",
112
+ fg=typer.colors.RED,
113
+ err=True,
114
+ )
115
+ raise typer.Exit(code=1)
116
+ typer.secho(f"⚠ 覆盖重建已存在目录:{project_dir}", fg=typer.colors.YELLOW)
117
+ import shutil
118
+
119
+ shutil.rmtree(project_dir)
120
+
121
+ # 2. 交互补全(flag 已提供则跳过)
122
+ desc = prompts.ask_description(description)
123
+ use_pm2 = prompts.ask_use_pm2(pm2)
124
+ use_docker = prompts.ask_use_docker(docker)
125
+ author_name = author or _git_user_name() or "fastapp-cli"
126
+
127
+ # 3. 渲染
128
+ ctx: dict[str, object] = {
129
+ "project_name": name,
130
+ "project_description": desc,
131
+ "python_version": python_version,
132
+ "author_name": author_name,
133
+ "use_pm2": use_pm2,
134
+ "use_docker": use_docker,
135
+ "year": datetime.now(timezone.utc).year,
136
+ "fastapp_cli_version": __version__,
137
+ }
138
+ try:
139
+ render_project(project_dir, ctx)
140
+ except RuntimeError as exc:
141
+ typer.secho(f"✘ 渲染失败:{exc}", fg=typer.colors.RED, err=True)
142
+ raise typer.Exit(code=1) from exc
143
+
144
+ # 4. git init
145
+ if not no_git:
146
+ if _git_init(project_dir):
147
+ typer.secho("✔ 已初始化 git 仓库", fg=typer.colors.GREEN)
148
+
149
+ # 5. 输出指引
150
+ typer.secho(
151
+ f"✔ 生成项目 {name}/({_count_files(project_dir)} 个文件)",
152
+ fg=typer.colors.GREEN,
153
+ )
154
+ typer.echo("下一步:")
155
+ typer.echo(f" cd {name} && uv sync")
156
+ typer.echo(" make dev # 或 uv run uvicorn app.main:app --reload")
157
+ typer.echo(" 访问 /api/v1/docs 查看接口文档")
fastapp_cli/main.py ADDED
@@ -0,0 +1,33 @@
1
+ """fastapp CLI 入口."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import typer
6
+
7
+ from fastapp_cli import __version__
8
+ from fastapp_cli.create import create
9
+
10
+ app = typer.Typer(
11
+ name="fastapp",
12
+ help="FastAPI 项目脚手架:一条命令生成完整可运行的 FastAPI 工程",
13
+ no_args_is_help=True,
14
+ add_completion=False,
15
+ )
16
+
17
+
18
+ @app.callback()
19
+ def _root() -> None:
20
+ """fastapp CLI."""
21
+
22
+
23
+ @app.command()
24
+ def version() -> None:
25
+ """显示版本号."""
26
+ typer.echo(f"fastapp-cli {__version__}")
27
+
28
+
29
+ app.command()(create)
30
+
31
+
32
+ if __name__ == "__main__":
33
+ app()
fastapp_cli/naming.py ADDED
@@ -0,0 +1,39 @@
1
+ """project_name 命名校验.
2
+
3
+ 应用包名固定位 ``app``,``project_name`` 仅用于目录名与 pyproject name:
4
+ 小写字母 / 数字 / 连字符,且不以连字符开头或结尾。
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import re
10
+
11
+ PROJECT_NAME_RE = re.compile(r"^[a-z][a-z0-9]*(-[a-z0-9]+)*$")
12
+
13
+ MAX_LENGTH = 64
14
+
15
+
16
+ def validate_project_name(name: str) -> str:
17
+ """校验 project_name,非法时抛出 ValueError.
18
+
19
+ 规则:
20
+ - 非空,长度 <= 64
21
+ - 仅小写字母 / 数字 / 连字符
22
+ - 以小写字母开头,不以连字符开头或结尾,不含连续连字符
23
+
24
+ :param name: 项目名,如 ``my-server``
25
+ :return: 校验通过的项目名
26
+ :raises ValueError: 名称非法
27
+ """
28
+ name = (name or "").strip()
29
+ if not name:
30
+ raise ValueError("项目名不能为空")
31
+ if len(name) > MAX_LENGTH:
32
+ raise ValueError(f"项目名过长(最多 {MAX_LENGTH} 字符):{name}")
33
+ if not PROJECT_NAME_RE.match(name):
34
+ raise ValueError(
35
+ f"项目名非法:{name!r}。"
36
+ "仅允许小写字母、数字与连字符,须以字母开头,"
37
+ "不能以连字符开头/结尾或包含连续连字符,示例:my-server"
38
+ )
39
+ return name
fastapp_cli/prompts.py ADDED
@@ -0,0 +1,35 @@
1
+ """混合模式交互提问.
2
+
3
+ 关键项(描述 / pm2 / Dockerfile)在未通过 flag 提供时交互提问;
4
+ flag 已提供则跳过提问,实现零交互。
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import typer
10
+
11
+ DEFAULT_DESCRIPTION = "A FastAPI project created by fastapp-cli"
12
+
13
+
14
+ def ask_description(provided: str | None) -> str:
15
+ """获取项目描述:flag 已提供则直接使用,否则交互提问."""
16
+ if provided:
17
+ return provided
18
+ return typer.prompt(
19
+ "项目描述",
20
+ default=DEFAULT_DESCRIPTION,
21
+ )
22
+
23
+
24
+ def ask_use_pm2(provided: bool | None) -> bool:
25
+ """是否生成 pm2 配置:未指定时交互提问."""
26
+ if provided is not None:
27
+ return provided
28
+ return typer.confirm("是否包含 pm2 配置?", default=False)
29
+
30
+
31
+ def ask_use_docker(provided: bool | None) -> bool:
32
+ """是否生成 Dockerfile:未指定时交互提问."""
33
+ if provided is not None:
34
+ return provided
35
+ return typer.confirm("是否包含 Dockerfile?", default=False)
fastapp_cli/render.py ADDED
@@ -0,0 +1,130 @@
1
+ """Jinja2 模板渲染引擎.
2
+
3
+ - 模板随包发布,通过 ``importlib.resources`` 加载,离线可用;
4
+ - ``.j2`` 后缀文件渲染并剥离后缀,其余文件原样拷贝;
5
+ - 渲染完成后自检输出文件中无 ``{{`` / ``{%`` 残留,发现即报错。
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import shutil
11
+ from importlib import resources
12
+ from pathlib import Path
13
+ from typing import Any
14
+
15
+ import jinja2
16
+ from jinja2 import Environment, FileSystemLoader
17
+
18
+ TEMPLATES_PACKAGE = "fastapp_cli.templates"
19
+ PROJECT_TEMPLATE_DIR = "project"
20
+
21
+ RENDER_SUFFIX = ".j2"
22
+
23
+ JINJA_ENV = Environment(
24
+ loader=FileSystemLoader("/"), # 实际以绝对路径渲染单个文件,此处仅占位
25
+ keep_trailing_newline=True,
26
+ undefined=jinja2.StrictUndefined,
27
+ )
28
+
29
+
30
+ def template_root() -> Path:
31
+ """返回包内项目模板根目录(发布后随 wheel 分发)."""
32
+ traversable = resources.files(TEMPLATES_PACKAGE) / PROJECT_TEMPLATE_DIR
33
+ # as_file 支持压缩包场景;常规 wheel/开发目录下为真实路径
34
+ with resources.as_file(traversable) as path:
35
+ return Path(path)
36
+
37
+
38
+ def render_string(template_text: str, ctx: dict[str, Any]) -> str:
39
+ """渲染单段模板文本."""
40
+ return JINJA_ENV.from_string(template_text).render(**ctx)
41
+
42
+
43
+ def _iter_template_files(root: Path) -> list[Path]:
44
+ """递归收集模板文件(跳过目录与 .gitkeep 空占位保留处理)."""
45
+ return sorted(p for p in root.rglob("*") if p.is_file())
46
+
47
+
48
+ def render_project(
49
+ out_dir: Path,
50
+ ctx: dict[str, Any],
51
+ *,
52
+ template_dir: Path | None = None,
53
+ ) -> list[Path]:
54
+ """渲染整个项目模板到目标目录.
55
+
56
+ :param out_dir: 输出目录(须不存在或已清空)
57
+ :param ctx: 模板变量
58
+ :param template_dir: 模板根目录,默认使用包内模板
59
+ :return: 实际写出的文件路径列表(相对 out_dir)
60
+ :raises RuntimeError: 渲染产物中存在 Jinja 残留标记
61
+ """
62
+ root = template_dir if template_dir is not None else template_root()
63
+ out_dir.mkdir(parents=True, exist_ok=True)
64
+
65
+ written: list[Path] = []
66
+ for src in _iter_template_files(root):
67
+ rel = src.relative_to(root)
68
+ dest = out_dir / rel
69
+
70
+ # .j2 后缀剥离:main.py.j2 -> main.py
71
+ if rel.suffix == RENDER_SUFFIX:
72
+ dest = dest.with_suffix("")
73
+
74
+ dest.parent.mkdir(parents=True, exist_ok=True)
75
+
76
+ if rel.suffix == RENDER_SUFFIX:
77
+ text = src.read_text(encoding="utf-8")
78
+ rendered = render_string(text, ctx)
79
+ # 条件文件:模板整体被 {% if %} 包裹,条件不满足时渲染结果为空 -> 跳过生成
80
+ if not rendered.strip():
81
+ continue
82
+ dest.write_text(rendered, encoding="utf-8")
83
+ _assert_no_jinja_residue(dest)
84
+ # shell 脚本一律保持可执行位
85
+ if dest.suffix == ".sh":
86
+ dest.chmod(dest.stat().st_mode | 0o111)
87
+ else:
88
+ shutil.copyfile(src, dest)
89
+ # 保持脚本可执行位
90
+ if src.stat().st_mode & 0o111:
91
+ dest.chmod(dest.stat().st_mode | 0o111)
92
+
93
+ written.append(dest)
94
+
95
+ _verify_tree(out_dir, len(written))
96
+ return written
97
+
98
+
99
+ def _assert_no_jinja_residue(path: Path) -> None:
100
+ """自检渲染产物中不允许残留 Jinja 标记."""
101
+ text = path.read_text(encoding="utf-8")
102
+ for marker in ("{{", "{%"):
103
+ if marker in text:
104
+ line_no = next(
105
+ i + 1
106
+ for i, line in enumerate(text.splitlines())
107
+ if marker in line
108
+ )
109
+ raise RuntimeError(
110
+ f"渲染残留:{path} 第 {line_no} 行发现未渲染的 Jinja 标记 {marker!r}"
111
+ )
112
+
113
+
114
+ def _verify_tree(out_dir: Path, expected_count: int) -> None:
115
+ """整体自检:目标文件数与实际写出数一致,且无 Jinja 残留."""
116
+ out_files = [p for p in out_dir.rglob("*") if p.is_file()]
117
+ if len(out_files) != expected_count:
118
+ raise RuntimeError(
119
+ f"渲染自检失败:预期写出 {expected_count} 个文件,"
120
+ f"实际 {len(out_files)} 个"
121
+ )
122
+ for path in out_files:
123
+ # 跳过 gitkeep 等空文件;仅扫描文本
124
+ try:
125
+ text = path.read_text(encoding="utf-8")
126
+ except UnicodeDecodeError:
127
+ continue
128
+ for marker in ("{{", "{%"):
129
+ if marker in text:
130
+ raise RuntimeError(f"渲染残留:{path} 发现未渲染的 Jinja 标记 {marker!r}")
@@ -0,0 +1 @@
1
+ """模板包资源定位标记."""
@@ -0,0 +1,21 @@
1
+ # 开发环境差异配置(示例)
2
+ # 使用方式:
3
+ # cp .env.development.example .env.development
4
+ # 启动时自动加载:APP_ENV=development bash scripts/start.sh
5
+
6
+ APP_ENV=development
7
+ DEBUG=true
8
+
9
+ # 开发库
10
+ MYSQL_SERVER=localhost
11
+ MYSQL_PORT=3306
12
+ MYSQL_USER=root
13
+ MYSQL_PASSWORD=root
14
+ MYSQL_DB={{ project_name | replace('-', '_') }}_dev
15
+
16
+ # 打印 SQL 方便排查
17
+ SQL_ECHO=true
18
+
19
+ # 本地 Redis
20
+ CELERY_BROKER_URL=redis://localhost:6379/0
21
+ CELERY_RESULT_BACKEND=redis://localhost:6379/1
@@ -0,0 +1,29 @@
1
+ # ========== App ==========
2
+ APP_NAME={{ project_name }}
3
+ APP_ENV=development
4
+ API_V1_PREFIX=/api/v1
5
+ DEBUG=false
6
+
7
+ # ========== Server ==========
8
+ HOST=0.0.0.0
9
+ PORT=8000
10
+
11
+ # ========== MySQL ==========
12
+ MYSQL_SERVER=localhost
13
+ MYSQL_PORT=3306
14
+ MYSQL_USER=root
15
+ MYSQL_PASSWORD=
16
+ MYSQL_DB={{ project_name | replace('-', '_') }}
17
+ # 是否打印 SQL(开发环境使用)
18
+ SQL_ECHO=false
19
+
20
+ # ========== Celery(redis,缺席时应用启动自动降级 memory://) ==========
21
+ CELERY_BROKER_URL=redis://localhost:6379/0
22
+ CELERY_RESULT_BACKEND=redis://localhost:6379/1
23
+ CELERY_TASK_DEFAULT_QUEUE=default
24
+
25
+ # ========== Flower ==========
26
+ FLOWER_HOST=0.0.0.0
27
+ FLOWER_PORT=5555
28
+ # 基本认证(可选),格式:user:password,多个用逗号分隔
29
+ # FLOWER_BASIC_AUTH=admin:admin
@@ -0,0 +1,27 @@
1
+ # 本地默认配置(已 gitignore)。生产配置参考 .env.example / .env.production.example
2
+ # ========== App ==========
3
+ APP_NAME={{ project_name }}
4
+ APP_ENV=development
5
+ API_V1_PREFIX=/api/v1
6
+ DEBUG=true
7
+
8
+ # ========== Server ==========
9
+ HOST=0.0.0.0
10
+ PORT=8000
11
+
12
+ # ========== MySQL(未配置时应用可启动,health 返回 database=down) ==========
13
+ MYSQL_SERVER=localhost
14
+ MYSQL_PORT=3306
15
+ MYSQL_USER=root
16
+ MYSQL_PASSWORD=
17
+ MYSQL_DB={{ project_name | replace('-', '_') }}_dev
18
+ SQL_ECHO=true
19
+
20
+ # ========== Celery(本地无 redis 时启动自动降级 memory://) ==========
21
+ CELERY_BROKER_URL=redis://localhost:6379/0
22
+ CELERY_RESULT_BACKEND=redis://localhost:6379/1
23
+ CELERY_TASK_DEFAULT_QUEUE=default
24
+
25
+ # ========== Flower ==========
26
+ FLOWER_HOST=0.0.0.0
27
+ FLOWER_PORT=5555
@@ -0,0 +1,178 @@
1
+ ### Python template
2
+ # Byte-compiled / optimized / DLL files
3
+ __pycache__/
4
+ *.py[cod]
5
+ *$py.class
6
+
7
+ # C extensions
8
+ *.so
9
+
10
+ # Distribution / packaging
11
+ .Python
12
+ build/
13
+ develop-eggs/
14
+ dist/
15
+ downloads/
16
+ eggs/
17
+ .eggs/
18
+ lib/
19
+ lib64/
20
+ parts/
21
+ sdist/
22
+ var/
23
+ wheels/
24
+ share/python-wheels/
25
+ *.egg-info/
26
+ .installed.cfg
27
+ *.egg
28
+ MANIFEST
29
+
30
+ # PyInstaller
31
+ # Usually these files are written by a python script from a template
32
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
33
+ *.manifest
34
+ *.spec
35
+
36
+ # Installer logs
37
+ pip-log.txt
38
+ pip-delete-this-directory.txt
39
+
40
+ # Unit test / coverage reports
41
+ htmlcov/
42
+ .tox/
43
+ .nox/
44
+ .coverage
45
+ .coverage.*
46
+ .cache
47
+ nosetests.xml
48
+ coverage.xml
49
+ *.cover
50
+ *.py,cover
51
+ .hypothesis/
52
+ .pytest_cache/
53
+ cover/
54
+
55
+ # Translations
56
+ *.mo
57
+ *.pot
58
+
59
+ # Django stuff:
60
+ *.log
61
+ local_settings.py
62
+ db.sqlite3
63
+ db.sqlite3-journal
64
+
65
+ # Flask stuff:
66
+ instance/
67
+ .webassets-cache
68
+
69
+ # Scrapy stuff:
70
+ .scrapy
71
+
72
+ # Sphinx documentation
73
+ docs/_build/
74
+
75
+ # PyBuilder
76
+ .pybuilder/
77
+ target/
78
+
79
+ # Jupyter Notebook
80
+ .ipynb_checkpoints
81
+
82
+ # IPython
83
+ profile_default/
84
+ ipython_config.py
85
+
86
+ # pyenv
87
+ # For a library or package, you might want to ignore these files since the code is
88
+ # intended to run in multiple environments; otherwise, check them in:
89
+ # .python-version
90
+
91
+ # pipenv
92
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
93
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
94
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
95
+ # install all needed dependencies.
96
+ #Pipfile.lock
97
+
98
+ # poetry
99
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
100
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
101
+ # commonly ignored for libraries.
102
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
103
+ #poetry.lock
104
+
105
+ # pdm
106
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
107
+ #pdm.lock
108
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
109
+ # in version control.
110
+ # https://pdm.fming.dev/latest/usage/project/#working-with-version-control
111
+ .pdm.toml
112
+ .pdm-python
113
+ .pdm-build/
114
+
115
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
116
+ __pypackages__/
117
+
118
+ # Celery stuff
119
+ celerybeat-schedule
120
+ celerybeat.pid
121
+
122
+ # SageMath parsed files
123
+ *.sage.py
124
+
125
+ # Environments
126
+ .env
127
+ .env.development
128
+ .env.production
129
+ .env.test
130
+ .env.local
131
+ !.env.example
132
+ !.env.development.example
133
+ !.env.production.example
134
+ !.env.test.example
135
+ .venv
136
+ env/
137
+ venv/
138
+ ENV/
139
+ env.bak/
140
+ venv.bak/
141
+
142
+ # Spyder project settings
143
+ .spyderproject
144
+ .spyproject
145
+
146
+ # Rope project settings
147
+ .ropeproject
148
+
149
+ # mkdocs documentation
150
+ /site
151
+
152
+ # mypy
153
+ .mypy_cache/
154
+ .dmypy.json
155
+ dmypy.json
156
+
157
+ # Pyre type checker
158
+ .pyre/
159
+
160
+ # pytype static type analyzer
161
+ .pytype/
162
+
163
+ # Cython debug symbols
164
+ cython_debug/
165
+
166
+ # PyCharm
167
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
168
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
169
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
170
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
171
+ .idea/
172
+ .env.dev
173
+ .env.prod
174
+
175
+ # Project specific
176
+ logs/
177
+ .DS_Store
178
+ .ruff_cache/