fastapi-scaff 0.4.1__py3-none-any.whl → 0.4.2__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.

Potentially problematic release.


This version of fastapi-scaff might be problematic. Click here for more details.

fastapi_scaff/__init__.py CHANGED
@@ -7,4 +7,4 @@
7
7
  @history
8
8
  """
9
9
 
10
- __version__ = "0.4.1"
10
+ __version__ = "0.4.2"
fastapi_scaff/__main__.py CHANGED
@@ -520,7 +520,26 @@ redis_max_connections:
520
520
  tplpath.parent.mkdir(parents=True, exist_ok=True)
521
521
  with open(tplpath, "w+", encoding="utf-8") as f:
522
522
  v = v.replace("from app_celery", f"from {name}")
523
+ if k == "app_celery/__init__.py":
524
+ v = v.replace(f"""main=\"app_celery\"""", f"""main=\"{name}\"""")
525
+ elif k == "app_celery/README.md":
526
+ v = v.replace("# app-celery", f"# {name}")
527
+ v = v.replace("app_celery", name)
523
528
  f.write(v)
529
+ for ext in ["runcbeat.py", "runcworker.py", "app/api/default/aping.py"]:
530
+ if ext == "app/api/default/aping.py" and not (work_dir / "app/api/default").is_dir():
531
+ continue
532
+ path = work_dir / ext
533
+ if path.is_file():
534
+ sys.stdout.write(f"[{ext}] Existed\n")
535
+ else:
536
+ sys.stdout.write(f"[{ext}] Writing\n")
537
+ with open(path, "w+", encoding="utf-8") as f:
538
+ v = project_tpl_dict[ext]
539
+ v = v.replace("""celery_module: str = \"app_celery\"""", f"""celery_module: str = \"{names[0]}\"""")
540
+ if ext == "app/api/default/aping.py":
541
+ v = v.replace("from app_celery", f"from {names[0]}")
542
+ f.write(v)
524
543
 
525
544
 
526
545
  if __name__ == "__main__":
@@ -2,10 +2,10 @@
2
2
  ".gitignore": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packaging\n.Python\nbuild/\ndevelop-eggs/\ndist/\ndownloads/\neggs/\n.eggs/\nlib/\nlib64/\nparts/\nsdist/\nvar/\nwheels/\nshare/python-wheels/\n*.egg-info/\n.installed.cfg\n*.egg\nMANIFEST\n\n# PyInstaller\n# Usually these files are written by a python script from a template\n# before PyInstaller builds the exe, so as to inject date/other infos into it.\n*.manifest\n*.spec\n\n# Installer logs\npip-log.txt\npip-delete-this-directory.txt\n\n# Unit test / coverage reports\nhtmlcov/\n.tox/\n.nox/\n.coverage\n.coverage.*\n.cache\nnosetests.xml\ncoverage.xml\n*.cover\n*.py,cover\n.hypothesis/\n.pytest_cache/\ncover/\n\n# Translations\n*.mo\n*.pot\n\n# Django stuff:\n*.log\nlocal_settings.py\ndb.sqlite3\ndb.sqlite3-journal\n\n# Flask stuff:\ninstance/\n.webassets-cache\n\n# Scrapy stuff:\n.scrapy\n\n# Sphinx documentation\ndocs/_build/\n\n# PyBuilder\n.pybuilder/\ntarget/\n\n# Jupyter Notebook\n.ipynb_checkpoints\n\n# IPython\nprofile_default/\nipython_config.py\n\n# pyenv\n# For a library or package, you might want to ignore these files since the code is\n# intended to run in multiple environments; otherwise, check them in:\n# .python-version\n\n# pipenv\n# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.\n# However, in case of collaboration, if having platform-specific dependencies or dependencies\n# having no cross-platform support, pipenv may install dependencies that don't work, or not\n# install all needed dependencies.\n#Pipfile.lock\n\n# PEP 582; used by e.g. github.com/David-OConnor/pyflow\n__pypackages__/\n\n# Celery stuff\ncelerybeat-schedule\ncelerybeat.pid\n\n# SageMath parsed files\n*.sage.py\n\n# Environments\n#.env\n.venv\nenv/\nvenv/\nENV/\nenv.bak/\nvenv.bak/\n\n# Spyder project settings\n.spyderproject\n.spyproject\n\n# Rope project settings\n.ropeproject\n\n# mkdocs documentation\n/site\n\n# mypy\n.mypy_cache/\n.dmypy.json\ndmypy.json\n\n# Pyre type checker\n.pyre/\n\n# pytype static type analyzer\n.pytype/\n\n# Cython debug symbols\ncython_debug/\n\n# Append\n.idea\n.vscode\n*.sqlite\ncelerybeat-schedule.*\n",
3
3
  ".python-version": "3.12\n",
4
4
  "LICENSE": "Copyright (c) 2024 axiner\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n",
5
- "README.md": "# fastapi-scaff\n\n## What is this?\n\n- by: axiner\n- fastapi-scaff\n- This is a fastapi scaff.\n - new project\n - add api\n - about project:\n - auto init project (conf, db, log...)\n - auto register router\n - auto register middleware\n - ...\n - integrated sqlalchemy\n - integrated jwt\\api-key\n - integrated celery\n - ...\n - about structure:\n - standard\n - light\n - micro\n - more documents: [\u8bf7\u70b9\u51fb\u94fe\u63a5](https://blog.csdn.net/atpuxiner/article/details/144291336?fromshare=blogdetail&sharetype=blogdetail&sharerId=144291336&sharerefer=PC&sharesource=atpuxiner&sharefrom=from_link)\n\n## Project structure\n\n- ASM: ASM mode\n - A api\n - S services(&schemas)\n - M models\n- Calling process: main.py(initializer) -> (middleware) - api - services(&schemas) - (models)\n- Structure: (The naming has been finalized after multiple revisions, making it concise and easy to understand)\n ```\n \u2514\u2500\u2500 fastapi-scaff\n \u251c\u2500\u2500 app (\u5e94\u7528)\n \u2502 \u251c\u2500\u2500 api \u251c\u2500\u2500 (api)\n \u2502 \u2502 \u2514\u2500\u2500 v1 \u2502 \u2514\u2500\u2500 (v1)\n \u2502 \u251c\u2500\u2500 initializer \u251c\u2500\u2500 (\u521d\u59cb\u5316)\n \u2502 \u2502 \u251c\u2500\u2500 conf \u2502 \u251c\u2500\u2500 (\u914d\u7f6e)\n \u2502 \u2502 \u251c\u2500\u2500 db \u2502 \u251c\u2500\u2500 (\u6570\u636e\u5e93)\n \u2502 \u2502 \u251c\u2500\u2500 log \u2502 \u251c\u2500\u2500 (\u65e5\u5fd7)\n \u2502 \u2502 \u2514\u2500\u2500 ... \u2502 \u2514\u2500\u2500 (...)\n \u2502 \u251c\u2500\u2500 middleware \u251c\u2500\u2500 (\u4e2d\u95f4\u4ef6)\n \u2502 \u251c\u2500\u2500 models \u251c\u2500\u2500 (\u6570\u636e\u6a21\u578b)\n \u2502 \u251c\u2500\u2500 schemas \u251c\u2500\u2500 (\u6570\u636e\u7ed3\u6784)\n \u2502 \u251c\u2500\u2500 services \u251c\u2500\u2500 (\u4e1a\u52a1\u903b\u8f91)\n \u2502 \u251c\u2500\u2500 utils \u251c\u2500\u2500 (utils)\n \u2502 \u2514\u2500\u2500 main.py \u2514\u2500\u2500 (main.py)\n \u251c\u2500\u2500 app_celery (\u5e94\u7528-celery)\n \u251c\u2500\u2500 config (\u914d\u7f6e\u76ee\u5f55)\n \u251c\u2500\u2500 deploy (\u90e8\u7f72\u76ee\u5f55)\n \u251c\u2500\u2500 docs (\u6587\u6863\u76ee\u5f55)\n \u251c\u2500\u2500 logs (\u65e5\u5fd7\u76ee\u5f55)\n \u251c\u2500\u2500 tests (\u6d4b\u8bd5\u76ee\u5f55)\n \u251c\u2500\u2500 .gitignore\n \u251c\u2500\u2500 LICENSE\n \u251c\u2500\u2500 README.md\n \u251c\u2500\u2500 requirements.txt\n \u2514\u2500\u2500 runcbeat.py\n \u2514\u2500\u2500 runcworker.py\n \u2514\u2500\u2500 runserver.py\n ```\n\n- \u3010Other structure\u3011\n - light\uff1aPlease create and view (with `-e light`)\n - micro\uff1aPlease create and view (with `-e micro`)\n\n## Installation\n\nThis package can be installed using pip (Python>=3.11):\n> pip install fastapi-scaff\n\n## Scaff usage\n\n- 1\uff09help document\n - `fastapi-scaff -h`\n- 2\uff09new project\n - `fastapi-scaff new <myproj>`\n - *light structure*: `fastapi-scaff new <myproj> -e light`\n - *micro structure*: `fastapi-scaff new <myproj> -e micro`\n- 3\uff09add api\n - `cd to project root dir`\n - `fastapi-scaff add <myapi>`\n- 4\uff09integrated celery (default not integrated)\n - M1\u3002`new` with `--celery`: `fastapi-scaff new <myproj> --celery`\n - M2\u3002`add` with `--celery`: `fastapi-scaff add <mycelery> --celery`\n\n## Project run\n\n- 1\uff09cd to project root dir\n- 2\uff09modify the configuration, such as for the database\n- 3\uff09`pip install -r requirements.txt`\n- 4\uff09`python runserver.py`\n - more parameters see:\n - about uvicorn: [click here](https://www.uvicorn.org/)\n - about gunicorn: [click here](https://docs.gunicorn.org/en/stable/)\n\n## License\n\nThis project is released under the MIT License (MIT). See [LICENSE](LICENSE)\n",
5
+ "README.md": "# fastapi-scaff\n\n## What is this?\n\n- by: axiner\n- fastapi-scaff\n- This is a fastapi scaff.\n - new project\n - add api\n - about project:\n - auto init project (conf, db, log...)\n - auto register router\n - auto register middleware\n - ...\n - integrated sqlalchemy\n - integrated jwt\\api-key\n - integrated celery\n - ...\n - about structure:\n - standard\n - light\n - micro\n - more documents: [\u8bf7\u70b9\u51fb\u94fe\u63a5](https://blog.csdn.net/atpuxiner/article/details/144291336?fromshare=blogdetail&sharetype=blogdetail&sharerId=144291336&sharerefer=PC&sharesource=atpuxiner&sharefrom=from_link)\n\n## Project structure\n\n- ASM: ASM mode\n - A api\n - S services(&schemas)\n - M models\n- Calling process: main.py(initializer) -> (middleware) - api - services(&schemas) - (models)\n- Structure: (The naming has been finalized after multiple revisions, making it concise and easy to understand)\n ```\n \u2514\u2500\u2500 fastapi-scaff\n \u251c\u2500\u2500 app (\u5e94\u7528)\n \u2502 \u251c\u2500\u2500 api \u251c\u2500\u2500 (api)\n \u2502 \u2502 \u2514\u2500\u2500 v1 \u2502 \u2514\u2500\u2500 (v1)\n \u2502 \u251c\u2500\u2500 initializer \u251c\u2500\u2500 (\u521d\u59cb\u5316)\n \u2502 \u2502 \u251c\u2500\u2500 conf \u2502 \u251c\u2500\u2500 (\u914d\u7f6e)\n \u2502 \u2502 \u251c\u2500\u2500 db \u2502 \u251c\u2500\u2500 (\u6570\u636e\u5e93)\n \u2502 \u2502 \u251c\u2500\u2500 log \u2502 \u251c\u2500\u2500 (\u65e5\u5fd7)\n \u2502 \u2502 \u2514\u2500\u2500 ... \u2502 \u2514\u2500\u2500 (...)\n \u2502 \u251c\u2500\u2500 middleware \u251c\u2500\u2500 (\u4e2d\u95f4\u4ef6)\n \u2502 \u251c\u2500\u2500 models \u251c\u2500\u2500 (\u6570\u636e\u6a21\u578b)\n \u2502 \u251c\u2500\u2500 schemas \u251c\u2500\u2500 (\u6570\u636e\u7ed3\u6784)\n \u2502 \u251c\u2500\u2500 services \u251c\u2500\u2500 (\u4e1a\u52a1\u903b\u8f91)\n \u2502 \u251c\u2500\u2500 utils \u251c\u2500\u2500 (utils)\n \u2502 \u2514\u2500\u2500 main.py \u2514\u2500\u2500 (main.py)\n \u251c\u2500\u2500 app_celery (\u5e94\u7528-celery)\n \u251c\u2500\u2500 config (\u914d\u7f6e\u76ee\u5f55)\n \u251c\u2500\u2500 deploy (\u90e8\u7f72\u76ee\u5f55)\n \u251c\u2500\u2500 docs (\u6587\u6863\u76ee\u5f55)\n \u251c\u2500\u2500 logs (\u65e5\u5fd7\u76ee\u5f55)\n \u251c\u2500\u2500 tests (\u6d4b\u8bd5\u76ee\u5f55)\n \u251c\u2500\u2500 .gitignore\n \u251c\u2500\u2500 LICENSE\n \u251c\u2500\u2500 README.md\n \u251c\u2500\u2500 requirements.txt\n \u2514\u2500\u2500 runcbeat.py\n \u2514\u2500\u2500 runcworker.py\n \u2514\u2500\u2500 runserver.py\n ```\n\n- \u3010Other structure\u3011\n - light\uff1aPlease create and view (with `-e light`)\n - micro\uff1aPlease create and view (with `-e micro`)\n\n## Installation\n\nThis package can be installed using pip (Python>=3.11):\n> pip install fastapi-scaff\n\n## Scaff usage\n\n- 1\uff09help document\n - `fastapi-scaff -h`\n- 2\uff09new project\n - `fastapi-scaff new <myproj>`\n - *light structure*: `fastapi-scaff new <myproj> -e light`\n - *micro structure*: `fastapi-scaff new <myproj> -e micro`\n- 3\uff09add api\n - `cd to project root dir`\n - `fastapi-scaff add <myapi>`\n- 4\uff09integrated celery\n - M1\u3002`new` with `--celery`: `fastapi-scaff new <myproj> --celery`\n - M2\u3002`add` with `--celery`: `fastapi-scaff add <mycelery> --celery`\n\n## Project run\n\n- 1\uff09cd to project root dir\n- 2\uff09modify the configuration, such as for the database\n- 3\uff09`pip install -r requirements.txt`\n- 4\uff09`python runserver.py`\n - more parameters see:\n - about uvicorn: [click here](https://www.uvicorn.org/)\n - about gunicorn: [click here](https://docs.gunicorn.org/en/stable/)\n\n## License\n\nThis project is released under the MIT License (MIT). See [LICENSE](LICENSE)\n",
6
6
  "requirements.txt": "# -*- coding: utf-8 -*-\n# Python>=3.11\nfastapi==0.120.3\nuvicorn==0.38.0\norjson==3.11.4\ntoollib==1.8.6\npython-dotenv==1.2.1\nPyYAML==6.0.3\nloguru==0.7.3\nPyJWT==2.10.1\nbcrypt==5.0.0\nSQLAlchemy==2.0.44\naiosqlite==0.21.0\nredis==7.0.1\ncelery==5.5.3\n",
7
- "runcbeat.py": "\"\"\"\n@author axiner\n@version v1.0.0\n@created 2025/09/20 10:10\n@abstract runcbeat\uff08\u66f4\u591a\u53c2\u6570\u8bf7\u81ea\u884c\u6307\u5b9a\uff09\n@description\n@history\n\"\"\"\nimport argparse\nimport subprocess\n\n\ndef main(\n loglevel: str = \"info\",\n scheduler: str = None,\n pidfile: str = None,\n max_interval: int = 5,\n):\n parser = argparse.ArgumentParser(description=\"CeleryBeat\u542f\u52a8\u5668\")\n parser.add_argument(\"-l\", \"--loglevel\", type=str, default=\"info\", metavar=\"\", help=\"\u65e5\u5fd7\u7b49\u7ea7\")\n parser.add_argument(\"-S\", \"--scheduler\", type=str, default=None, metavar=\"\", help=\"\u8c03\u5ea6\u5668\u7c7b\u578b\")\n parser.add_argument(\"--pidfile\", type=str, default=None, metavar=\"\", help=\"pid\u6587\u4ef6\")\n parser.add_argument(\"--max-interval\", type=int, default=5, metavar=\"\", help=\"\u68c0\u6d4b\u4efb\u52a1\u95f4\u9694\")\n args = parser.parse_args()\n loglevel = args.loglevel or loglevel\n scheduler = args.scheduler or scheduler\n pidfile = args.pidfile or pidfile\n max_interval = args.max_interval or max_interval\n command = [\n \"celery\",\n \"-A\",\n \"app_celery.consumer\",\n \"beat\",\n f\"--loglevel={loglevel}\",\n f\"--max-interval={max_interval}\",\n ]\n if scheduler:\n command.extend([\"--scheduler\", scheduler])\n if pidfile:\n command.extend([\"--pidfile\", pidfile])\n subprocess.run(command, check=True)\n\n\nif __name__ == '__main__':\n main()\n",
8
- "runcworker.py": "\"\"\"\n@author axiner\n@version v1.0.0\n@created 2025/09/20 10:10\n@abstract runcworker\uff08\u66f4\u591a\u53c2\u6570\u8bf7\u81ea\u884c\u6307\u5b9a\uff09\n@description\n@history\n\"\"\"\nimport argparse\nimport platform\nimport subprocess\nfrom os import cpu_count\n\n\ndef main(\n name: str, # `app_celery/consumer/workers`\u4e0b\u7684\u6a21\u5757\u540d\n loglevel: str = \"info\",\n concurrency: int = None,\n pool: str = None,\n):\n parser = argparse.ArgumentParser(description=\"CeleryWorker\u542f\u52a8\u5668\")\n parser.add_argument(\"-n\", \"--name\", type=str, metavar=\"\", help=\"\u540d\u79f0\")\n parser.add_argument(\"-l\", \"--loglevel\", type=str, default=\"info\", metavar=\"\", help=\"\u65e5\u5fd7\u7b49\u7ea7\")\n parser.add_argument(\"-c\", \"--concurrency\", type=int, default=None, metavar=\"\", help=\"\u5e76\u53d1\u6570\")\n parser.add_argument(\"-P\", \"--pool\", type=str, default=None, metavar=\"\", help=\"\u5e76\u53d1\u6a21\u578b\")\n args = parser.parse_args()\n name = args.name or name\n loglevel = args.loglevel or loglevel\n concurrency = args.concurrency or concurrency\n pool = args.pool or pool\n if pool is None:\n if platform.system().lower().startswith(\"win\"):\n pool = 'gevent'\n if not concurrency:\n concurrency = 100\n else:\n pool = 'prefork'\n if not concurrency:\n concurrency = cpu_count()\n command = [\n \"celery\",\n \"-A\",\n f\"app_celery.consumer.workers.{name}\",\n \"worker\",\n f\"--loglevel={loglevel}\",\n f\"--concurrency={concurrency}\",\n f\"--pool={pool}\",\n ]\n subprocess.run(\n command,\n check=True,\n )\n\n\nif __name__ == '__main__':\n main(\n name=\"ping\",\n )\n",
7
+ "runcbeat.py": "\"\"\"\n@author axiner\n@version v1.0.0\n@created 2025/09/20 10:10\n@abstract runcbeat\uff08\u66f4\u591a\u53c2\u6570\u8bf7\u81ea\u884c\u6307\u5b9a\uff09\n@description\n@history\n\"\"\"\nimport argparse\nimport subprocess\n\n\ndef main(\n loglevel: str = \"info\",\n scheduler: str = None,\n pidfile: str = None,\n max_interval: int = 5,\n celery_module: str = \"app_celery\",\n):\n parser = argparse.ArgumentParser(description=\"CeleryBeat\u542f\u52a8\u5668\")\n parser.add_argument(\"-l\", \"--loglevel\", type=str, default=\"info\", metavar=\"\", help=\"\u65e5\u5fd7\u7b49\u7ea7\")\n parser.add_argument(\"-S\", \"--scheduler\", type=str, default=None, metavar=\"\", help=\"\u8c03\u5ea6\u5668\u7c7b\u578b\")\n parser.add_argument(\"--pidfile\", type=str, default=None, metavar=\"\", help=\"pid\u6587\u4ef6\")\n parser.add_argument(\"--max-interval\", type=int, default=5, metavar=\"\", help=\"\u68c0\u6d4b\u4efb\u52a1\u95f4\u9694\")\n parser.add_argument(\"--celery-module\", type=str, default=\"app_celery\", metavar=\"\", help=\"celery\u6a21\u5757\")\n args = parser.parse_args()\n loglevel = args.loglevel or loglevel\n scheduler = args.scheduler or scheduler\n pidfile = args.pidfile or pidfile\n max_interval = args.max_interval or max_interval\n celery_module = args.celery_module or celery_module\n command = [\n \"celery\",\n \"-A\",\n f\"{celery_module}.consumer\",\n \"beat\",\n f\"--loglevel={loglevel}\",\n f\"--max-interval={max_interval}\",\n ]\n if scheduler:\n command.extend([\"--scheduler\", scheduler])\n if pidfile:\n command.extend([\"--pidfile\", pidfile])\n subprocess.run(command, check=True)\n\n\nif __name__ == '__main__':\n main()\n",
8
+ "runcworker.py": "\"\"\"\n@author axiner\n@version v1.0.0\n@created 2025/09/20 10:10\n@abstract runcworker\uff08\u66f4\u591a\u53c2\u6570\u8bf7\u81ea\u884c\u6307\u5b9a\uff09\n@description\n@history\n\"\"\"\nimport argparse\nimport platform\nimport subprocess\nfrom os import cpu_count\n\n\ndef main(\n name: str, # `<celery_module>/consumer/workers`\u4e0b\u7684\u6a21\u5757\u540d\n loglevel: str = \"info\",\n concurrency: int = None,\n pool: str = None,\n celery_module: str = \"app_celery\",\n):\n parser = argparse.ArgumentParser(description=\"CeleryWorker\u542f\u52a8\u5668\")\n parser.add_argument(\"-n\", \"--name\", type=str, metavar=\"\", help=\"\u540d\u79f0\")\n parser.add_argument(\"-l\", \"--loglevel\", type=str, default=\"info\", metavar=\"\", help=\"\u65e5\u5fd7\u7b49\u7ea7\")\n parser.add_argument(\"-c\", \"--concurrency\", type=int, default=None, metavar=\"\", help=\"\u5e76\u53d1\u6570\")\n parser.add_argument(\"-P\", \"--pool\", type=str, default=None, metavar=\"\", help=\"\u5e76\u53d1\u6a21\u578b\")\n parser.add_argument(\"--celery-module\", type=str, default=\"app_celery\", metavar=\"\", help=\"celery\u6a21\u5757\")\n args = parser.parse_args()\n name = args.name or name\n loglevel = args.loglevel or loglevel\n concurrency = args.concurrency or concurrency\n pool = args.pool or pool\n celery_module = args.celery_module or celery_module\n if pool is None:\n if platform.system().lower().startswith(\"win\"):\n pool = 'gevent'\n if not concurrency:\n concurrency = 100\n else:\n pool = 'prefork'\n if not concurrency:\n concurrency = cpu_count()\n command = [\n \"celery\",\n \"-A\",\n f\"{celery_module}.consumer.workers.{name}\",\n \"worker\",\n f\"--loglevel={loglevel}\",\n f\"--concurrency={concurrency}\",\n f\"--pool={pool}\",\n ]\n subprocess.run(\n command,\n check=True,\n )\n\n\nif __name__ == '__main__':\n main(\n name=\"ping\",\n )\n",
9
9
  "runserver.py": "\"\"\"\n@author axiner\n@version v1.0.0\n@created 2024/07/29 22:22\n@abstract runserver\uff08\u66f4\u591a\u53c2\u6570\u8bf7\u81ea\u884c\u6307\u5b9a\uff09\n@description\n@history\n\"\"\"\nimport argparse\nimport subprocess\nimport sys\n\nimport uvicorn\n\n\ndef run_by_unicorn(\n host: str,\n port: int,\n workers: int,\n log_level: str,\n is_reload: bool,\n):\n log_config = {\n \"version\": 1,\n \"disable_existing_loggers\": False,\n \"formatters\": {\n \"default\": {\n \"()\": \"uvicorn.logging.DefaultFormatter\",\n \"fmt\": \"%(asctime)s %(levelname)s %(filename)s:%(lineno)d %(message)s\",\n \"use_colors\": None\n },\n \"access\": {\n \"()\": \"uvicorn.logging.AccessFormatter\",\n \"fmt\": \"%(asctime)s %(levelname)s %(client_addr)s - \\\"%(request_line)s\\\" %(status_code)s\"\n }\n },\n \"handlers\": {\n \"default\": {\n \"formatter\": \"default\",\n \"class\": \"logging.StreamHandler\",\n \"stream\": \"ext://sys.stderr\"\n },\n \"access\": {\n \"formatter\": \"access\",\n \"class\": \"logging.StreamHandler\",\n \"stream\": \"ext://sys.stdout\"\n }\n },\n \"loggers\": {\n \"uvicorn\": {\n \"handlers\": [\n \"default\"\n ],\n \"level\": \"INFO\",\n \"propagate\": False\n },\n \"uvicorn.error\": {\n \"level\": \"INFO\"\n },\n \"uvicorn.access\": {\n \"handlers\": [\n \"access\"\n ],\n \"level\": \"INFO\",\n \"propagate\": False\n }\n }\n }\n uvicorn.run(\n app=\"app.main:app\",\n host=host,\n port=port,\n workers=workers,\n log_level=log_level,\n log_config=log_config,\n reload=is_reload,\n )\n\n\ndef run_by_gunicorn(\n host: str,\n port: int,\n workers: int,\n log_level: str,\n is_reload: bool,\n):\n cmd = (\n \"gunicorn app.main:app \"\n \"--worker-class=uvicorn.workers.UvicornWorker \"\n \"--bind={host}:{port} \"\n \"--workers={workers} \"\n \"--log-level={log_level} \"\n \"--access-logfile=- \"\n \"--error-logfile=- \"\n .format(\n host=host,\n port=port,\n workers=workers,\n log_level=log_level,\n )\n )\n if is_reload:\n cmd += f\" --reload\"\n subprocess.run(cmd, shell=True)\n\n\ndef main(\n host: str,\n port: int,\n workers: int,\n log_level: str,\n is_reload: bool,\n is_gunicorn: bool,\n):\n parser = argparse.ArgumentParser(description=\"App\u542f\u52a8\u5668\")\n parser.add_argument(\"--host\", type=str, metavar=\"\", help=\"host\")\n parser.add_argument(\"--port\", type=int, metavar=\"\", help=\"port\")\n parser.add_argument(\"--workers\", type=int, metavar=\"\", help=\"\u8fdb\u7a0b\u6570\")\n parser.add_argument(\"--log-level\", type=str, metavar=\"\", help=\"\u65e5\u5fd7\u7b49\u7ea7\")\n parser.add_argument(\"--is-reload\", action=\"store_true\", help=\"\u662f\u5426reload\")\n parser.add_argument(\"--is-gunicorn\", action=\"store_true\", help=\"\u662f\u5426gunicorn\")\n args = parser.parse_args()\n kwargs = {\n \"host\": args.host or host,\n \"port\": args.port or port,\n \"workers\": args.workers or workers,\n \"log_level\": args.log_level or log_level,\n \"is_reload\": args.is_reload or is_reload,\n }\n if (args.is_gunicorn or is_gunicorn) and not sys.platform.lower().startswith(\"win\"):\n try:\n import gunicorn # noqa\n except ImportError:\n sys.stderr.write(\"gunicorn\u672a\u627e\u5230\uff0c\u6b63\u5728\u5c1d\u8bd5\u81ea\u52a8\u5b89\u88c5...\\n\")\n try:\n subprocess.run(\n [\"pip\", \"install\", \"gunicorn\"],\n check=True,\n stdout=subprocess.PIPE,\n stderr=subprocess.PIPE)\n sys.stderr.write(\"gunicorn\u5b89\u88c5\u6210\u529f\\n\")\n except subprocess.CalledProcessError as e:\n sys.stderr.write(f\"gunicorn\u5b89\u88c5\u5931\u8d25: {e.stderr.decode().strip()}\\n\")\n raise\n run_by_gunicorn(**kwargs)\n else:\n run_by_unicorn(**kwargs)\n\n\nif __name__ == '__main__':\n main(\n host=\"0.0.0.0\",\n port=8000,\n workers=3,\n log_level=\"debug\",\n is_reload=False, # For development environment\n is_gunicorn=False, # Not supported on Windows\n )\n",
10
10
  "app/main.py": "\"\"\"\n@author axiner\n@version v1.0.0\n@created 2024/07/29 22:22\n@abstract main\n@description\n@history\n\"\"\"\nfrom contextlib import asynccontextmanager\nfrom fastapi import FastAPI\nfrom fastapi.responses import ORJSONResponse\n\nfrom app import (\n api,\n middleware,\n)\nfrom app.initializer import g\n\ng.setup()\n# #\nopenapi_url = \"/openapi.json\"\ndocs_url = \"/docs\"\nredoc_url = \"/redoc\"\nif g.config.app_disable_docs is True:\n openapi_url, docs_url, redoc_url = None, None, None\n\n\n@asynccontextmanager\nasync def lifespan(app_: FastAPI):\n g.logger.info(f\"Application env '{g.config.app_env}'\")\n g.logger.info(f\"Application yaml '{g.config.app_yaml.name}'\")\n g.logger.info(f\"Application title '{g.config.app_title}'\")\n g.logger.info(f\"Application version '{g.config.app_version}'\")\n # #\n g.logger.info(\"Application server running\")\n yield\n g.logger.info(\"Application server shutdown\")\n\n\napp = FastAPI(\n title=g.config.app_title,\n summary=g.config.app_summary,\n description=g.config.app_description,\n version=g.config.app_version,\n debug=g.config.app_debug,\n openapi_url=openapi_url,\n docs_url=docs_url,\n redoc_url=redoc_url,\n lifespan=lifespan,\n default_response_class=ORJSONResponse,\n)\n# #\napi.register_routers(app)\nmiddleware.register_middlewares(app)\n",
11
11
  "app/__init__.py": "\"\"\"\n@author axiner\n@version v1.0.0\n@created 2024/07/29 22:22\n@abstract app\n@description\n@history\n\"\"\"\nfrom pathlib import Path\n\nAPP_DIR = Path(__file__).absolute().parent\n",
@@ -41,7 +41,7 @@
41
41
  "app/utils/jwt_util.py": "import secrets\nfrom datetime import datetime, timedelta\n\nimport bcrypt\nimport jwt\n\n_JWT_ALGORITHM = \"HS256\"\n\n\ndef gen_jwt(payload: dict, jwt_key: str, exp_minutes: int = 24 * 60 * 30, algorithm: str = _JWT_ALGORITHM):\n payload.update({\"exp\": datetime.utcnow() + timedelta(minutes=exp_minutes)})\n encoded_jwt = jwt.encode(payload=payload, key=jwt_key, algorithm=algorithm)\n return encoded_jwt\n\n\ndef verify_jwt(token: str, jwt_key: str = None, algorithms: tuple = (_JWT_ALGORITHM,)) -> dict:\n if not jwt_key:\n return jwt.decode(jwt=token, options={\"verify_signature\": False})\n return jwt.decode(jwt=token, key=jwt_key, algorithms=algorithms)\n\n\ndef gen_jwt_key():\n return secrets.token_hex(16)\n\n\ndef hash_password(password: str) -> str:\n salt = bcrypt.gensalt()\n hashed_password = bcrypt.hashpw(password.encode('utf-8'), salt)\n return hashed_password.decode('utf-8')\n\n\ndef verify_password(password: str, hashed_password: str) -> bool:\n return bcrypt.checkpw(password.encode('utf-8'), hashed_password.encode('utf-8'))\n",
42
42
  "app/utils/__init__.py": "\"\"\"\nutils\n\"\"\"\n",
43
43
  "app_celery/conf.py": "import os\nfrom pathlib import Path\n\nimport yaml\nfrom dotenv import load_dotenv\nfrom toollib.utils import get_cls_attrs, parse_variable\n\n_APP_DIR = Path(__file__).absolute().parent\n_CONFIG_DIR = _APP_DIR.parent.joinpath(\"config\")\n\nload_dotenv(dotenv_path=os.environ.setdefault(\n key=\"env_path\",\n value=str(_CONFIG_DIR.joinpath(\".env\")))\n)\n# #\napp_yaml = Path(\n os.environ.get(\"app_yaml\") or\n _CONFIG_DIR.joinpath(f\"app_{os.environ.setdefault(key='app_env', value='dev')}.yaml\")\n)\nif not app_yaml.is_file():\n raise RuntimeError(f\"\u914d\u7f6e\u6587\u4ef6\u4e0d\u5b58\u5728\uff1a{app_yaml}\")\n\n\nclass Config:\n \"\"\"\u914d\u7f6e\"\"\"\n _yaml_conf: dict = None\n app_dir: Path = _APP_DIR\n # #\n app_env: str = \"dev\"\n app_yaml: Path = app_yaml\n # #\n celery_broker_url: str\n celery_backend_url: str\n celery_timezone: str = \"Asia/Shanghai\"\n celery_enable_utc: bool = True\n celery_task_serializer: str = \"json\"\n celery_result_serializer: str = \"json\"\n celery_accept_content: list = [\"json\"]\n celery_task_ignore_result: bool = False\n celery_result_expire: int = 86400\n celery_task_track_started: bool = True\n celery_worker_concurrency: int = 8\n celery_worker_prefetch_multiplier: int = 2\n celery_worker_max_tasks_per_child: int = 100\n celery_broker_connection_retry_on_startup: bool = True\n celery_task_reject_on_worker_lost: bool = True\n\n def setup(self):\n self.setattr_from_env_or_yaml()\n return self\n\n def setattr_from_env_or_yaml(self):\n cls_attrs = get_cls_attrs(Config)\n for k, item in cls_attrs.items():\n v_type, v = item\n if callable(v_type):\n if k in os.environ: # \u4f18\u5148\u73af\u5883\u53d8\u91cf\n v = parse_variable(k=k, v_type=v_type, v_from=os.environ, default=v)\n else:\n v = parse_variable(k=k, v_type=v_type, v_from=self.load_yaml(), default=v)\n setattr(self, k, v)\n\n def load_yaml(self, reload: bool = False) -> dict:\n if self._yaml_conf and not reload:\n return self._yaml_conf\n with open(app_yaml, mode=\"r\", encoding=\"utf-8\") as file:\n self._yaml_conf = yaml.load(file, Loader=yaml.FullLoader)\n return self._yaml_conf\n\n\nconfig = Config().setup()\n",
44
- "app_celery/README.md": "# app-celery\n\n## \u7b80\u4ecb\n\n### producer\uff1a\u751f\u4ea7\u8005\uff08\u53d1\u5e03\u4efb\u52a1\uff09\n\n- register\uff1a\u6ce8\u518c\u4e2d\u5fc3\n - \u5c06`consumer`\u7684`tasks`\u6ce8\u518c\u5230`producer`\u7684`register`\u4e2d\n- publisher\uff1a\u53d1\u5e03\u8005\n - \u9879\u76ee\u4e2d\u901a\u8fc7\u53d1\u5e03\u8005\u6765\u53d1\u5e03\u4efb\u52a1\uff1a\u53ef\u53c2\u8003`app/api/default/aping.py`\uff08\u8fd9\u91cc\u53ea\u662f\u7b80\u5355\u793a\u4f8b\uff0c\u5b9e\u9645\u4e0a\u5e94\u8be5\u5728`services`\u5c42\u8c03\u7528\uff09\n\n### consumer\uff1a\u6d88\u8d39\u8005\uff08\u6267\u884c\u4efb\u52a1\uff09\n\n- tasks: \u4efb\u52a1\n - \u5b9a\u65f6\u4efb\u52a1\uff08beat_xxx\uff09\n - 1\u3002\u521b\u5efa\u5b9a\u65f6\u4efb\u52a1\n - 2\u3002\u53d1\u5e03\u5b9a\u65f6\u4efb\u52a1\uff08\u901a\u8fc7celery\u5185\u90e8\u7684`beat`\u8c03\u7528\uff09\n - \u8fdb\u5165`app_celery`\u7236\u7ea7\u76ee\u5f55\uff0c\u5373\u5de5\u4f5c\u76ee\u5f55\n - \u542f\u52a8\u547d\u4ee4\uff1a\uff08\u66f4\u591a\u53c2\u6570\u8bf7\u81ea\u884c\u6307\u5b9a\uff09\n - \u65b9\u5f0f1\u3002\u76f4\u63a5\u6267\u884c\u811a\u672c: `python runcbeat.py`\n - \u65b9\u5f0f2\u3002\u4f7f\u7528\u547d\u4ee4\u884c\uff1a`celery -A app_celery.consumer beat --loglevel=info --max-interval=5`\n - 3\u3002\u542f\u52a8\u6d88\u8d39\u8005worker\n - \u5f02\u6b65\u4efb\u52a1\uff08xxx)\n - 1\u3002\u521b\u5efa\u5f02\u6b65\u4efb\u52a1\uff0c\u5e76\u6ce8\u518c\u5230`producer`\u7684`register`\uff0c\u6839\u636e\u6ce8\u518c\u7684\u89c4\u5219\u8fdb\u884c`\u4efb\u52a1\u8c03\u7528`\u548c`worker\u542f\u52a8`\n - 2\u3002\u53d1\u5e03\u5f02\u6b65\u4efb\u52a1\uff08\u901a\u8fc7\u751f\u4ea7\u8005\u7684`publisher`\u8c03\u7528\uff09\n - \u53ef\u53c2\u8003`app/api/default/aping.py`\uff08\u8fd9\u91cc\u53ea\u662f\u7b80\u5355\u793a\u4f8b\uff0c\u5b9e\u9645\u4e0a\u5e94\u8be5\u5728`services`\u5c42\u8c03\u7528\uff09\n - 3\u3002\u542f\u52a8\u6d88\u8d39\u8005worker\n- workers: \u5de5\u4f5c\u8005\n - 1\u3002\u521b\u5efaworker\u670d\u52a1\uff0c\u5b9a\u4e49\u961f\u5217\u7b49\u5c5e\u6027\uff08\u4e3a\u65b9\u4fbf\u6269\u5c55\u5efa\u8bae\u4e00\u7c7b\u4efb\u52a1\u4e00\u4e2a\u670d\u52a1\uff09\n - 2\u3002\u542f\u52a8worker\u670d\u52a1\uff1a\n - 1\u3002\u8fdb\u5165`app_celery`\u7236\u7ea7\u76ee\u5f55\uff0c\u5373\u5de5\u4f5c\u76ee\u5f55\n - 2\u3002\u542f\u52a8\u547d\u4ee4\uff1a\uff08\u66f4\u591a\u53c2\u6570\u8bf7\u81ea\u884c\u6307\u5b9a\uff09\n - \u65b9\u5f0f1\u3002\u76f4\u63a5\u6267\u884c\u811a\u672c: `python runcworker.py -n ping`\n - \u65b9\u5f0f2\u3002\u4f7f\u7528\u547d\u4ee4\u884c\uff1a`celery -A app_celery.consumer.workers.ping worker --loglevel=info --concurrency=5`\n- yaml\u914d\u7f6e\n\n```yaml\ncelery_broker_url: redis://:<password>@<host>:<port>/<db>\ncelery_backend_url: redis://:<password>@<host>:<port>/<db>\ncelery_timezone: Asia/Shanghai\ncelery_enable_utc: true\ncelery_task_serializer: json\ncelery_result_serializer: json\ncelery_accept_content: [ json ]\ncelery_task_ignore_result: false\ncelery_result_expire: 86400\ncelery_task_track_started: true\ncelery_worker_concurrency: 8\ncelery_worker_prefetch_multiplier: 2\ncelery_worker_max_tasks_per_child: 100\ncelery_broker_connection_retry_on_startup: true\ncelery_task_reject_on_worker_lost: true\n```\n\n- \u6d88\u8d39\u7aef\u4f9d\u8d56\n\n```text\ncelery\nredis\n```\n\n### \u6ce8\u610f\uff1a\n\n- \u6700\u597d\u4e0e`app`\u89e3\u8026\uff0c\u5373\uff1a\n - \u53ea`app`\u5355\u5411\u8c03\u7528`app_celery`\n - \u4f46`app_celery`\u4e0d\u8c03\u7528`app`\n",
44
+ "app_celery/README.md": "# app-celery\n\n## \u7b80\u4ecb\n\n### producer\uff1a\u751f\u4ea7\u8005\uff08\u53d1\u5e03\u4efb\u52a1\uff09\n\n- register\uff1a\u6ce8\u518c\u4e2d\u5fc3\n - \u5c06`consumer`\u7684`tasks`\u6ce8\u518c\u5230`producer`\u7684`register`\u4e2d\n- publisher\uff1a\u53d1\u5e03\u8005\n - \u9879\u76ee\u4e2d\u901a\u8fc7`publisher.publish`\u6765\u53d1\u5e03\u4efb\u52a1\n\n### consumer\uff1a\u6d88\u8d39\u8005\uff08\u6267\u884c\u4efb\u52a1\uff09\n\n- tasks: \u4efb\u52a1\n - \u5b9a\u65f6\u4efb\u52a1\uff08beat_xxx\uff09\n - 1\u3002\u521b\u5efa\u5b9a\u65f6\u4efb\u52a1\n - 2\u3002\u53d1\u5e03\u5b9a\u65f6\u4efb\u52a1\uff08\u901a\u8fc7celery\u5185\u90e8\u7684`beat`\u8c03\u7528\uff09\n - \u8fdb\u5165`app_celery`\u7236\u7ea7\u76ee\u5f55\uff0c\u5373\u5de5\u4f5c\u76ee\u5f55\n - \u542f\u52a8\u547d\u4ee4\uff1a\uff08\u66f4\u591a\u53c2\u6570\u8bf7\u81ea\u884c\u6307\u5b9a\uff09\n - \u65b9\u5f0f1\u3002\u76f4\u63a5\u6267\u884c\u811a\u672c: `python runcbeat.py --celery-module=app_celery`\n - \u65b9\u5f0f2\u3002\u4f7f\u7528\u547d\u4ee4\u884c\uff1a`celery -A app_celery.consumer beat --loglevel=info --max-interval=5`\n - 3\u3002\u542f\u52a8\u6d88\u8d39\u8005worker\n - \u5f02\u6b65\u4efb\u52a1\uff08xxx)\n - 1\u3002\u521b\u5efa\u5f02\u6b65\u4efb\u52a1\uff0c\u5e76\u6ce8\u518c\u5230`producer`\u7684`register`\uff0c\u6839\u636e\u6ce8\u518c\u7684\u89c4\u5219\u8fdb\u884c`\u4efb\u52a1\u8c03\u7528`\u548c`worker\u542f\u52a8`\n - 2\u3002\u53d1\u5e03\u5f02\u6b65\u4efb\u52a1\uff08\u901a\u8fc7\u751f\u4ea7\u8005\u7684`publisher.publish`\u8c03\u7528\uff09\n - 3\u3002\u542f\u52a8\u6d88\u8d39\u8005worker\n- workers: \u5de5\u4f5c\u8005\n - 1\u3002\u521b\u5efaworker\u670d\u52a1\uff0c\u5b9a\u4e49\u961f\u5217\u7b49\u5c5e\u6027\uff08\u4e3a\u65b9\u4fbf\u6269\u5c55\u5efa\u8bae\u4e00\u7c7b\u4efb\u52a1\u4e00\u4e2a\u670d\u52a1\uff09\n - 2\u3002\u542f\u52a8worker\u670d\u52a1\uff1a\n - 1\u3002\u8fdb\u5165`app_celery`\u7236\u7ea7\u76ee\u5f55\uff0c\u5373\u5de5\u4f5c\u76ee\u5f55\n - 2\u3002\u542f\u52a8\u547d\u4ee4\uff1a\uff08\u66f4\u591a\u53c2\u6570\u8bf7\u81ea\u884c\u6307\u5b9a\uff09\n - \u65b9\u5f0f1\u3002\u76f4\u63a5\u6267\u884c\u811a\u672c: `python runcworker.py -n ping --celery-module=app_celery`\n - \u65b9\u5f0f2\u3002\u4f7f\u7528\u547d\u4ee4\u884c\uff1a`celery -A app_celery.consumer.workers.ping worker --loglevel=info --concurrency=5`\n- yaml\u914d\u7f6e\n\n```yaml\ncelery_broker_url: redis://:<password>@<host>:<port>/<db>\ncelery_backend_url: redis://:<password>@<host>:<port>/<db>\ncelery_timezone: Asia/Shanghai\ncelery_enable_utc: true\ncelery_task_serializer: json\ncelery_result_serializer: json\ncelery_accept_content: [ json ]\ncelery_task_ignore_result: false\ncelery_result_expire: 86400\ncelery_task_track_started: true\ncelery_worker_concurrency: 8\ncelery_worker_prefetch_multiplier: 2\ncelery_worker_max_tasks_per_child: 100\ncelery_broker_connection_retry_on_startup: true\ncelery_task_reject_on_worker_lost: true\n```\n\n- \u6d88\u8d39\u7aef\u4f9d\u8d56\n\n```text\ncelery\nredis\n```\n\n### \u6ce8\u610f\uff1a\n\n- \u6700\u597d\u4e0e`app`\u89e3\u8026\uff0c\u5373\uff1a\n - \u53ea`app`\u5355\u5411\u8c03\u7528`app_celery`\n - \u4f46`app_celery`\u4e0d\u8c03\u7528`app`\n",
45
45
  "app_celery/requirements.txt": "# -*- coding: utf-8 -*-\n# Python>=3.11\ntoollib==1.8.6\npython-dotenv==1.2.1\nPyYAML==6.0.3\npydantic==2.12.3\ncelery==5.5.3\nredis==7.0.1\ngevent==25.9.1\n",
46
46
  "app_celery/__init__.py": "\"\"\"\n@author axiner\n@version v0.0.1\n@created 2025/09/20 10:10\n@abstract app-celery\n@description\n@history\n\"\"\"\nfrom celery import Celery\n\nfrom app_celery.conf import config\n\n\ndef make_celery(include: list = None, configs: dict = None):\n app = Celery(\n main=\"app_celery\",\n broker=config.celery_broker_url,\n backend=config.celery_backend_url,\n include=include,\n )\n app.conf.update(\n timezone=config.celery_timezone,\n enable_utc=config.celery_enable_utc,\n task_serializer=config.celery_task_serializer,\n result_serializer=config.celery_result_serializer,\n accept_content=config.celery_accept_content,\n celery_task_ignore_result=config.celery_task_ignore_result,\n celery_result_expire=config.celery_result_expire,\n celery_task_track_started=config.celery_task_track_started,\n worker_concurrency=config.celery_worker_concurrency,\n worker_prefetch_multiplier=config.celery_worker_prefetch_multiplier,\n worker_max_tasks_per_child=config.celery_worker_max_tasks_per_child,\n broker_connection_retry_on_startup=config.celery_broker_connection_retry_on_startup,\n task_reject_on_worker_lost=config.celery_task_reject_on_worker_lost,\n )\n if configs:\n app.conf.update(configs)\n return app\n",
47
47
  "app_celery/consumer/__init__.py": "\"\"\"\n\u6d88\u8d39\u8005\n\"\"\"\nimport re\nfrom pathlib import Path\n\nfrom app_celery import make_celery\n\n\ndef autodiscover_task_modules(\n task_name: str = \"tasks\",\n task_module: str = \"app_celery.consumer.tasks\",\n) -> list:\n \"\"\"\n \u81ea\u52a8\u53d1\u73b0\u4efb\u52a1\u6a21\u5757\n - \u53ef\u5728\u6a21\u5757\u4e2d\u52a0\u5165`_active = False`\u6765\u53d6\u6d88\u6fc0\u6d3b\n \"\"\"\n task_modules = []\n active_pat = re.compile(r\"^_active\\s*=\\s*False\\s*(?:#.*)?$\", re.MULTILINE)\n for p in Path(__file__).parent.joinpath(task_name).rglob(\"*.py\"):\n if p.stem == \"__init__\":\n continue\n if active_pat.search(p.read_text(encoding=\"utf-8\")):\n continue\n task_modules.append(f\"{task_module}.{p.stem}\")\n return task_modules\n\n\ncelery_app = make_celery(\n include=autodiscover_task_modules()\n)\n",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastapi-scaff
3
- Version: 0.4.1
3
+ Version: 0.4.2
4
4
  Summary: This is a fastapi scaff.
5
5
  Author-email: axiner <atpuxiner@163.com>
6
6
  Project-URL: Homepage, https://github.com/atpuxiner/fastapi-scaff
@@ -94,7 +94,7 @@ This package can be installed using pip (Python>=3.11):
94
94
  - 3)add api
95
95
  - `cd to project root dir`
96
96
  - `fastapi-scaff add <myapi>`
97
- - 4)integrated celery (default not integrated)
97
+ - 4)integrated celery
98
98
  - M1。`new` with `--celery`: `fastapi-scaff new <myproj> --celery`
99
99
  - M2。`add` with `--celery`: `fastapi-scaff add <mycelery> --celery`
100
100
 
@@ -0,0 +1,10 @@
1
+ fastapi_scaff/__init__.py,sha256=mvIjTaLzVsyh6d8u-YSK_FMFk7R4-B9i3NN9s-YQ7jY,120
2
+ fastapi_scaff/__main__.py,sha256=q1radtezRoR6aiTiBxpCZbiu7IrEDGiHeEwz58zeJ_E,21773
3
+ fastapi_scaff/_api_tpl.json,sha256=yLmeKkE-0KqWVDLs5_SuiVMw7jV9vndmkavQkXrIF2M,8590
4
+ fastapi_scaff/_project_tpl.json,sha256=Zcc3jzDxvtsSbLbTN_fdkrOl6NfcM1PkKFXUUz36Unw,109424
5
+ fastapi_scaff-0.4.2.dist-info/licenses/LICENSE,sha256=A5H6q7zd1QrL3iVs1KLsBOG0ImV-t9PpPspM4x-4Ea8,1069
6
+ fastapi_scaff-0.4.2.dist-info/METADATA,sha256=xF5NUf4WnlhV_5Ct-STPfaWYm94xGXUvmK_2iX4nmKU,4186
7
+ fastapi_scaff-0.4.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
8
+ fastapi_scaff-0.4.2.dist-info/entry_points.txt,sha256=kzs28nmpRWVCmWmZav3X7u7YOIOEir3sCkLnvQKTJbY,62
9
+ fastapi_scaff-0.4.2.dist-info/top_level.txt,sha256=LeyfUxMRhdbRHcYoH37ftfdspyZ8V3Uut2YBaTCzq2k,14
10
+ fastapi_scaff-0.4.2.dist-info/RECORD,,
@@ -1,10 +0,0 @@
1
- fastapi_scaff/__init__.py,sha256=myi27QqdiwG5o89BwgXbkqqWn9upZYBppskjtzOTFbY,120
2
- fastapi_scaff/__main__.py,sha256=2M5svRc5gRIfn0F9vJ0X-GpwY3FWbJOm5zbfpPhBrhk,20619
3
- fastapi_scaff/_api_tpl.json,sha256=yLmeKkE-0KqWVDLs5_SuiVMw7jV9vndmkavQkXrIF2M,8590
4
- fastapi_scaff/_project_tpl.json,sha256=TPz5ouHjkrOolntk7RURnHVUCzEKHgKQqA0UW6VOu2g,109288
5
- fastapi_scaff-0.4.1.dist-info/licenses/LICENSE,sha256=A5H6q7zd1QrL3iVs1KLsBOG0ImV-t9PpPspM4x-4Ea8,1069
6
- fastapi_scaff-0.4.1.dist-info/METADATA,sha256=TpKUKZ0ll0y1QlsL4POtF8DqyD7Laz38T_DTrERxmvU,4211
7
- fastapi_scaff-0.4.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
8
- fastapi_scaff-0.4.1.dist-info/entry_points.txt,sha256=kzs28nmpRWVCmWmZav3X7u7YOIOEir3sCkLnvQKTJbY,62
9
- fastapi_scaff-0.4.1.dist-info/top_level.txt,sha256=LeyfUxMRhdbRHcYoH37ftfdspyZ8V3Uut2YBaTCzq2k,14
10
- fastapi_scaff-0.4.1.dist-info/RECORD,,