FastAPI-fastkit 1.2.1__py3-none-any.whl → 1.4.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.
- fastapi_fastkit/__init__.py +1 -1
- fastapi_fastkit/backend/inspection/__init__.py +26 -0
- fastapi_fastkit/backend/inspection/checks.py +349 -0
- fastapi_fastkit/backend/inspection/consistency.py +125 -0
- fastapi_fastkit/backend/inspection/context.py +67 -0
- fastapi_fastkit/backend/inspection/core.py +347 -0
- fastapi_fastkit/backend/inspection/docker.py +185 -0
- fastapi_fastkit/backend/inspection/freshness.py +145 -0
- fastapi_fastkit/backend/inspection/fsutils.py +139 -0
- fastapi_fastkit/backend/inspection/lint.py +89 -0
- fastapi_fastkit/backend/inspection/report.py +58 -0
- fastapi_fastkit/backend/inspection/smoke.py +327 -0
- fastapi_fastkit/backend/inspection/strategies.py +336 -0
- fastapi_fastkit/backend/inspector.py +18 -1279
- fastapi_fastkit/backend/interactive/__init__.py +8 -0
- fastapi_fastkit/backend/interactive/config_builder.py +66 -65
- fastapi_fastkit/backend/interactive/prompts.py +205 -5
- fastapi_fastkit/backend/interactive/selectors.py +28 -2
- fastapi_fastkit/backend/main.py +956 -95
- fastapi_fastkit/backend/package_managers/base.py +172 -0
- fastapi_fastkit/backend/package_managers/factory.py +6 -5
- fastapi_fastkit/backend/package_managers/pdm_manager.py +32 -85
- fastapi_fastkit/backend/package_managers/pip_manager.py +31 -85
- fastapi_fastkit/backend/package_managers/poetry_manager.py +73 -113
- fastapi_fastkit/backend/package_managers/uv_manager.py +46 -115
- fastapi_fastkit/backend/project_builder/__init__.py +10 -0
- fastapi_fastkit/backend/project_builder/config_generator.py +813 -450
- fastapi_fastkit/backend/project_builder/config_schema.py +384 -0
- fastapi_fastkit/backend/project_builder/dependency_collector.py +105 -66
- fastapi_fastkit/backend/project_builder/preset_layout.py +429 -0
- fastapi_fastkit/backend/scaffolder.py +578 -0
- fastapi_fastkit/backend/transducer.py +54 -22
- fastapi_fastkit/cli.py +452 -284
- fastapi_fastkit/core/settings.py +248 -43
- fastapi_fastkit/fastapi_project_template/README.md +88 -23
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/README.md-tpl +3 -0
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/pyproject.toml-tpl +25 -23
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/requirements.txt-tpl +39 -36
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/api/api.py-tpl +3 -0
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/api/routes/items.py-tpl +1 -2
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/core/config.py-tpl +5 -6
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/crud/items.py-tpl +1 -2
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/main.py-tpl +9 -1
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/schemas/items.py-tpl +1 -2
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/tests/conftest.py-tpl +0 -1
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/.env-tpl +21 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/.gitignore-tpl +33 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/Dockerfile-tpl +18 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/README.md-tpl +210 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/alembic.ini-tpl +119 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/pyproject.toml-tpl +86 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/requirements.txt-tpl +23 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/scripts/format.sh-tpl +5 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/scripts/lint.sh-tpl +6 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/scripts/run-server.sh-tpl +8 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/scripts/test.sh-tpl +6 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/alembic/README-tpl +1 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/alembic/env.py-tpl +51 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/alembic/script.py.mako-tpl +26 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/alembic/versions/0001_initial_auth_schema.py-tpl +62 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/api/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/api/deps.py-tpl +91 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/api/health.py-tpl +11 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/api/router.py-tpl +17 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/core/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/core/config.py-tpl +64 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/core/security.py-tpl +100 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/db/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/db/session.py-tpl +36 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/domains/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/domains/auth/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/domains/auth/models.py-tpl +25 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/domains/auth/repository.py-tpl +41 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/domains/auth/router.py-tpl +82 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/domains/auth/schemas.py-tpl +14 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/domains/auth/service.py-tpl +65 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/domains/users/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/domains/users/models.py-tpl +35 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/domains/users/repository.py-tpl +33 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/domains/users/router.py-tpl +71 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/domains/users/schemas.py-tpl +29 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/domains/users/service.py-tpl +55 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/main.py-tpl +69 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/template-config.yml-tpl +16 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/tests/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/tests/conftest.py-tpl +73 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/tests/test_auth.py-tpl +201 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/tests/test_health.py-tpl +15 -0
- fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/tests/test_users.py-tpl +77 -0
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/pyproject.toml-tpl +25 -23
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/requirements.txt-tpl +39 -36
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/api/api.py-tpl +3 -0
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/api/routes/items.py-tpl +3 -3
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/core/config.py-tpl +5 -6
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/crud/items.py-tpl +1 -2
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/helper/pagination.py-tpl +8 -8
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/main.py-tpl +9 -0
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/schemas/base.py-tpl +1 -1
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/schemas/items.py-tpl +1 -2
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/tests/conftest.py-tpl +0 -1
- fastapi_fastkit/fastapi_project_template/fastapi-default/pyproject.toml-tpl +22 -20
- fastapi_fastkit/fastapi_project_template/fastapi-default/requirements.txt-tpl +37 -34
- fastapi_fastkit/fastapi_project_template/fastapi-default/src/api/api.py-tpl +3 -0
- fastapi_fastkit/fastapi_project_template/fastapi-default/src/api/routes/items.py-tpl +1 -2
- fastapi_fastkit/fastapi_project_template/fastapi-default/src/core/config.py-tpl +5 -6
- fastapi_fastkit/fastapi_project_template/fastapi-default/src/crud/items.py-tpl +1 -2
- fastapi_fastkit/fastapi_project_template/fastapi-default/src/main.py-tpl +9 -1
- fastapi_fastkit/fastapi_project_template/fastapi-default/src/schemas/items.py-tpl +1 -2
- fastapi_fastkit/fastapi_project_template/fastapi-default/tests/conftest.py-tpl +2 -3
- fastapi_fastkit/fastapi_project_template/fastapi-default/tests/test_items.py-tpl +0 -2
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/Dockerfile-tpl +1 -1
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/README.md-tpl +3 -0
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/pyproject.toml-tpl +25 -23
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/requirements.txt-tpl +41 -36
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/api/api.py-tpl +3 -0
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/api/routes/items.py-tpl +1 -2
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/core/config.py-tpl +5 -6
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/crud/items.py-tpl +1 -2
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/main.py-tpl +9 -1
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/schemas/items.py-tpl +1 -2
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/tests/conftest.py-tpl +2 -3
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/tests/test_items.py-tpl +0 -2
- fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/.env-tpl +2 -0
- fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/.gitignore-tpl +31 -0
- fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/README.md-tpl +128 -0
- fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/pyproject.toml-tpl +69 -0
- fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/requirements.txt-tpl +37 -0
- fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/scripts/format.sh-tpl +5 -0
- fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/scripts/lint.sh-tpl +6 -0
- fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/scripts/run-server.sh-tpl +8 -0
- fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/scripts/test.sh-tpl +6 -0
- fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/src/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/src/app/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/src/app/api/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/src/app/api/health.py-tpl +11 -0
- fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/src/app/api/router.py-tpl +15 -0
- fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/src/app/core/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/src/app/core/config.py-tpl +49 -0
- fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/src/app/db/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/src/app/db/memory.py-tpl +49 -0
- fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/src/app/domains/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/src/app/domains/items/__init__.py-tpl +9 -0
- fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/src/app/domains/items/models.py-tpl +17 -0
- fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/src/app/domains/items/repository.py-tpl +47 -0
- fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/src/app/domains/items/router.py-tpl +58 -0
- fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/src/app/domains/items/schemas.py-tpl +23 -0
- fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/src/app/domains/items/service.py-tpl +51 -0
- fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/src/app/main.py-tpl +28 -0
- fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/tests/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/tests/conftest.py-tpl +23 -0
- fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/tests/test_health.py-tpl +11 -0
- fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/tests/test_items.py-tpl +77 -0
- fastapi_fastkit/fastapi_project_template/fastapi-empty/README.md-tpl +2 -2
- fastapi_fastkit/fastapi_project_template/fastapi-empty/pyproject.toml-tpl +18 -16
- fastapi_fastkit/fastapi_project_template/fastapi-empty/requirements.txt-tpl +36 -10
- fastapi_fastkit/fastapi_project_template/fastapi-empty/src/core/config.py-tpl +5 -6
- fastapi_fastkit/fastapi_project_template/fastapi-empty/src/main.py-tpl +3 -1
- fastapi_fastkit/fastapi_project_template/fastapi-empty/tests/conftest.py-tpl +0 -1
- fastapi_fastkit/fastapi_project_template/fastapi-empty/tests/test_main.py-tpl +0 -1
- fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/.env-tpl +15 -0
- fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/.gitignore-tpl +31 -0
- fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/Dockerfile-tpl +18 -0
- fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/README.md-tpl +193 -0
- fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/pyproject.toml-tpl +76 -0
- fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/requirements.txt-tpl +15 -0
- fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/scripts/chat.sh-tpl +10 -0
- fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/scripts/format.sh-tpl +5 -0
- fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/scripts/lint.sh-tpl +6 -0
- fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/scripts/run-server.sh-tpl +8 -0
- fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/scripts/test.sh-tpl +6 -0
- fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/api/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/api/chat.py-tpl +62 -0
- fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/api/deps.py-tpl +23 -0
- fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/api/health.py-tpl +11 -0
- fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/api/router.py-tpl +13 -0
- fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/core/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/core/config.py-tpl +67 -0
- fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/llm/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/llm/agent.py-tpl +136 -0
- fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/llm/client.py-tpl +30 -0
- fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/llm/tools.py-tpl +131 -0
- fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/main.py-tpl +53 -0
- fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/memory/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/memory/base.py-tpl +27 -0
- fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/memory/in_memory.py-tpl +32 -0
- fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/schemas/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/schemas/chat.py-tpl +46 -0
- fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/template-config.yml-tpl +16 -0
- fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/tests/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/tests/conftest.py-tpl +158 -0
- fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/tests/test_chat.py-tpl +160 -0
- fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/tests/test_health.py-tpl +12 -0
- fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/tests/test_memory.py-tpl +38 -0
- fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/tests/test_tools.py-tpl +37 -0
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/README.md-tpl +1 -1
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/pyproject.toml-tpl +29 -26
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/requirements.txt-tpl +68 -39
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/src/api/api.py-tpl +3 -0
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/src/api/routes/auth.py-tpl +4 -5
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/src/api/routes/items.py-tpl +3 -4
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/src/auth/dependencies.py-tpl +4 -5
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/src/core/config.py-tpl +4 -5
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/src/main.py-tpl +4 -1
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/src/{mcp → mcp_server}/router.py-tpl +3 -5
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/src/schemas/items.py-tpl +6 -7
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/tests/conftest.py-tpl +1 -1
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/tests/test_auth.py-tpl +0 -1
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/tests/test_items.py-tpl +0 -1
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/tests/test_mcp.py-tpl +0 -1
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/Dockerfile-tpl +1 -1
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/pyproject.toml-tpl +26 -24
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/requirements.txt-tpl +44 -41
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/alembic/env.py-tpl +1 -3
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/alembic/versions/bedcdc35b64a_first_alembic.py-tpl +5 -6
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/api/api.py-tpl +2 -0
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/api/routes/items.py-tpl +2 -4
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/core/config.py-tpl +1 -2
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/core/db.py-tpl +1 -1
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/crud/items.py-tpl +4 -6
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/main.py-tpl +9 -0
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/schemas/items.py-tpl +4 -5
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/tests/conftest.py-tpl +1 -5
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/tests/test_items.py-tpl +0 -2
- fastapi_fastkit/fastapi_project_template/fastapi-single-module/.env-tpl +1 -0
- fastapi_fastkit/fastapi_project_template/fastapi-single-module/.gitignore-tpl +30 -0
- fastapi_fastkit/fastapi_project_template/fastapi-single-module/pyproject.toml-tpl +7 -5
- fastapi_fastkit/fastapi_project_template/fastapi-single-module/requirements.txt-tpl +26 -6
- fastapi_fastkit/fastapi_project_template/fastapi-single-module/src/main.py-tpl +3 -0
- fastapi_fastkit/fastapi_project_template/fastapi-single-module/tests/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-single-module/tests/conftest.py-tpl +0 -1
- fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/.env-tpl +7 -0
- fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/.gitignore-tpl +35 -0
- fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/Dockerfile-tpl +18 -0
- fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/README.md-tpl +166 -0
- fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/alembic.ini-tpl +44 -0
- fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/pyproject.toml-tpl +82 -0
- fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/requirements.txt-tpl +21 -0
- fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/scripts/format.sh-tpl +5 -0
- fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/scripts/lint.sh-tpl +6 -0
- fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/scripts/migrate.sh-tpl +7 -0
- fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/scripts/run-server.sh-tpl +8 -0
- fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/scripts/test.sh-tpl +6 -0
- fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/alembic/README-tpl +9 -0
- fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/alembic/env.py-tpl +72 -0
- fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/alembic/script.py.mako-tpl +27 -0
- fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/alembic/versions/0001_create_items_table.py-tpl +38 -0
- fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/api/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/api/health.py-tpl +11 -0
- fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/api/router.py-tpl +15 -0
- fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/core/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/core/config.py-tpl +62 -0
- fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/crud/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/crud/base.py-tpl +62 -0
- fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/crud/pagination.py-tpl +21 -0
- fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/db/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/db/base.py-tpl +12 -0
- fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/db/session.py-tpl +50 -0
- fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/domains/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/domains/items/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/domains/items/crud.py-tpl +26 -0
- fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/domains/items/models.py-tpl +70 -0
- fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/domains/items/router.py-tpl +69 -0
- fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/main.py-tpl +43 -0
- fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/template-config.yml-tpl +16 -0
- fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/tests/__init__.py-tpl +0 -0
- fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/tests/conftest.py-tpl +60 -0
- fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/tests/test_crud_base.py-tpl +43 -0
- fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/tests/test_health.py-tpl +12 -0
- fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/tests/test_items.py-tpl +110 -0
- fastapi_fastkit/fastapi_project_template/modules/api/routes/new_route.py-tpl +2 -2
- fastapi_fastkit/fragments/README.md +90 -0
- fastapi_fastkit/fragments/auth/fastapi_users.py.j2 +8 -0
- fastapi_fastkit/fragments/auth/jwt.py.j2 +44 -0
- fastapi_fastkit/fragments/auth/oauth2.py.j2 +105 -0
- fastapi_fastkit/fragments/auth/session.py.j2 +67 -0
- fastapi_fastkit/fragments/db/mongodb.py.j2 +19 -0
- fastapi_fastkit/fragments/db/redis.py.j2 +26 -0
- fastapi_fastkit/fragments/db/sqlalchemy.py.j2 +45 -0
- fastapi_fastkit/fragments/docker/docker_compose.j2 +84 -0
- fastapi_fastkit/fragments/docker/dockerfile.j2 +19 -0
- fastapi_fastkit/fragments/features/cache.py.j2 +26 -0
- fastapi_fastkit/fragments/features/pagination.py.j2 +31 -0
- fastapi_fastkit/fragments/features/tasks_celery.py.j2 +50 -0
- fastapi_fastkit/fragments/features/tasks_dramatiq.py.j2 +59 -0
- fastapi_fastkit/fragments/features/websocket.py.j2 +66 -0
- fastapi_fastkit/fragments/header.j2 +4 -0
- fastapi_fastkit/fragments/logging/structured.py.j2 +88 -0
- fastapi_fastkit/fragments/main/imports/async_tasks.j2 +1 -0
- fastapi_fastkit/fragments/main/imports/caching.j2 +5 -0
- fastapi_fastkit/fragments/main/imports/fastapi_users.j2 +1 -0
- fastapi_fastkit/fragments/main/imports/jwt.j2 +1 -0
- fastapi_fastkit/fragments/main/imports/loguru.j2 +1 -0
- fastapi_fastkit/fragments/main/imports/mongodb.j2 +1 -0
- fastapi_fastkit/fragments/main/imports/oauth2.j2 +4 -0
- fastapi_fastkit/fragments/main/imports/opentelemetry.j2 +6 -0
- fastapi_fastkit/fragments/main/imports/pagination.j2 +3 -0
- fastapi_fastkit/fragments/main/imports/prometheus.j2 +1 -0
- fastapi_fastkit/fragments/main/imports/rate_limiting.j2 +3 -0
- fastapi_fastkit/fragments/main/imports/session_auth.j2 +4 -0
- fastapi_fastkit/fragments/main/imports/sqlalchemy.j2 +2 -0
- fastapi_fastkit/fragments/main/imports/structured_logging.j2 +1 -0
- fastapi_fastkit/fragments/main/imports/websocket.j2 +1 -0
- fastapi_fastkit/fragments/main/lifespan/caching.j2 +7 -0
- fastapi_fastkit/fragments/main/lifespan/mongodb.j2 +2 -0
- fastapi_fastkit/fragments/main/lifespan/prometheus.j2 +2 -0
- fastapi_fastkit/fragments/main/lifespan/sqlalchemy.j2 +2 -0
- fastapi_fastkit/fragments/main/setup/async_tasks.j2 +1 -0
- fastapi_fastkit/fragments/main/setup/caching.j2 +1 -0
- fastapi_fastkit/fragments/main/setup/cors.j2 +8 -0
- fastapi_fastkit/fragments/main/setup/oauth2.j2 +3 -0
- fastapi_fastkit/fragments/main/setup/opentelemetry.j2 +19 -0
- fastapi_fastkit/fragments/main/setup/pagination.j2 +2 -0
- fastapi_fastkit/fragments/main/setup/rate_limiting.j2 +3 -0
- fastapi_fastkit/fragments/main/setup/session_auth.j2 +6 -0
- fastapi_fastkit/fragments/main/setup/structured_logging.j2 +2 -0
- fastapi_fastkit/fragments/main/setup/websocket.j2 +1 -0
- fastapi_fastkit/fragments/main.py.j2 +57 -0
- fastapi_fastkit/fragments/migrations/alembic_ini.j2 +42 -0
- fastapi_fastkit/fragments/migrations/env.py.j2 +76 -0
- fastapi_fastkit/fragments/migrations/initial_revision.py.j2 +27 -0
- fastapi_fastkit/fragments/migrations/migrate_sh.j2 +34 -0
- fastapi_fastkit/fragments/migrations/script.py.mako.j2 +26 -0
- fastapi_fastkit/fragments/tasks/celery_worker.py.j2 +49 -0
- fastapi_fastkit/fragments/tasks/dramatiq_worker.py.j2 +41 -0
- fastapi_fastkit/fragments/test/factories.py.j2 +68 -0
- fastapi_fastkit/fragments/test/pytest_ini.j2 +16 -0
- fastapi_fastkit/fragments/test/test_factories.py.j2 +27 -0
- fastapi_fastkit/fragments/test/test_main.py.j2 +46 -0
- fastapi_fastkit/fragments/tooling/devcontainer.j2 +26 -0
- fastapi_fastkit/fragments/tooling/github_actions.j2 +37 -0
- fastapi_fastkit/fragments/tooling/makefile.j2 +40 -0
- fastapi_fastkit/fragments/tooling/pre_commit.j2 +36 -0
- fastapi_fastkit/fragments/tooling/ruff_toml.j2 +16 -0
- fastapi_fastkit/utils/config_file.py +263 -0
- fastapi_fastkit/utils/main.py +111 -6
- {fastapi_fastkit-1.2.1.dist-info → fastapi_fastkit-1.4.0.dist-info}/METADATA +33 -6
- fastapi_fastkit-1.4.0.dist-info/RECORD +484 -0
- {fastapi_fastkit-1.2.1.dist-info → fastapi_fastkit-1.4.0.dist-info}/WHEEL +1 -1
- fastapi_fastkit/fastapi_project_template/fastapi-async-crud/setup.py-tpl +0 -25
- fastapi_fastkit/fastapi_project_template/fastapi-custom-response/setup.py-tpl +0 -27
- fastapi_fastkit/fastapi_project_template/fastapi-default/setup.py-tpl +0 -22
- fastapi_fastkit/fastapi_project_template/fastapi-dockerized/setup.py-tpl +0 -22
- fastapi_fastkit/fastapi_project_template/fastapi-empty/setup.py-tpl +0 -22
- fastapi_fastkit/fastapi_project_template/fastapi-mcp/setup.py-tpl +0 -51
- fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/setup.py-tpl +0 -25
- fastapi_fastkit/fastapi_project_template/fastapi-single-module/setup.py-tpl +0 -17
- fastapi_fastkit-1.2.1.dist-info/RECORD +0 -256
- /fastapi_fastkit/fastapi_project_template/fastapi-mcp/src/{mcp → mcp_server}/__init__.py-tpl +0 -0
- {fastapi_fastkit-1.2.1.dist-info → fastapi_fastkit-1.4.0.dist-info}/entry_points.txt +0 -0
- {fastapi_fastkit-1.2.1.dist-info → fastapi_fastkit-1.4.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
# --------------------------------------------------------------------------
|
|
2
|
+
# Project configuration file (de)serialization for non-interactive ``init``.
|
|
3
|
+
#
|
|
4
|
+
# ``fastkit init --interactive`` builds a plain configuration dict; this
|
|
5
|
+
# module lets that same dict travel through a file so a project can be
|
|
6
|
+
# reproduced without answering a single prompt (``--config``), and so an
|
|
7
|
+
# interactive session can be captured for later reuse (``--save-config``).
|
|
8
|
+
#
|
|
9
|
+
# Supported formats are picked from the file extension: JSON and TOML are
|
|
10
|
+
# always available (both ship with the stdlib on Python 3.12), YAML only
|
|
11
|
+
# when PyYAML happens to be installed — fastkit deliberately does not add it
|
|
12
|
+
# as a runtime dependency.
|
|
13
|
+
#
|
|
14
|
+
# @author bnbong bbbong9@gmail.com
|
|
15
|
+
# --------------------------------------------------------------------------
|
|
16
|
+
import importlib
|
|
17
|
+
import json
|
|
18
|
+
import os
|
|
19
|
+
import tomllib
|
|
20
|
+
from typing import Any, Dict, List, Tuple
|
|
21
|
+
|
|
22
|
+
from fastapi_fastkit.backend.interactive.validators import (
|
|
23
|
+
validate_email_format,
|
|
24
|
+
validate_project_name,
|
|
25
|
+
)
|
|
26
|
+
from fastapi_fastkit.backend.project_builder.config_schema import (
|
|
27
|
+
ConfigSchemaError,
|
|
28
|
+
normalize_project_config,
|
|
29
|
+
validate_project_config_schema,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
JSON_EXTENSIONS: Tuple[str, ...] = (".json",)
|
|
33
|
+
TOML_EXTENSIONS: Tuple[str, ...] = (".toml",)
|
|
34
|
+
YAML_EXTENSIONS: Tuple[str, ...] = (".yaml", ".yml")
|
|
35
|
+
|
|
36
|
+
SUPPORTED_EXTENSIONS: Tuple[str, ...] = (
|
|
37
|
+
JSON_EXTENSIONS + TOML_EXTENSIONS + YAML_EXTENSIONS
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
# Keys the scaffolder needs; everything else in the file is passed through
|
|
41
|
+
# untouched so feature blocks stay forward-compatible.
|
|
42
|
+
REQUIRED_KEYS: Tuple[str, ...] = ("project_name", "author", "author_email")
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class ConfigFileError(Exception):
|
|
46
|
+
"""Raised when a project config file cannot be read, parsed or trusted."""
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _yaml_module() -> Any:
|
|
50
|
+
"""Return the optional PyYAML module, or None when it isn't installed."""
|
|
51
|
+
try:
|
|
52
|
+
# Imported dynamically: PyYAML is optional, so a static import would
|
|
53
|
+
# make it look like a hard dependency to type checkers and readers.
|
|
54
|
+
return importlib.import_module("yaml")
|
|
55
|
+
except ImportError:
|
|
56
|
+
return None
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def load_project_config(path: str) -> Dict[str, Any]:
|
|
60
|
+
"""
|
|
61
|
+
Load a project configuration dict from a JSON / TOML / YAML file.
|
|
62
|
+
|
|
63
|
+
:param path: Path to the configuration file
|
|
64
|
+
:return: Configuration dictionary equivalent to the interactive builder's
|
|
65
|
+
:raises ConfigFileError: If the file is missing, of an unsupported format,
|
|
66
|
+
unparsable, or does not describe a mapping.
|
|
67
|
+
"""
|
|
68
|
+
if not os.path.exists(path):
|
|
69
|
+
raise ConfigFileError(f"Config file not found: {path}")
|
|
70
|
+
|
|
71
|
+
extension = os.path.splitext(path)[1].lower()
|
|
72
|
+
|
|
73
|
+
if extension in JSON_EXTENSIONS:
|
|
74
|
+
raw = _load_json(path)
|
|
75
|
+
elif extension in TOML_EXTENSIONS:
|
|
76
|
+
raw = _load_toml(path)
|
|
77
|
+
elif extension in YAML_EXTENSIONS:
|
|
78
|
+
raw = _load_yaml(path)
|
|
79
|
+
else:
|
|
80
|
+
raise ConfigFileError(
|
|
81
|
+
f"Unsupported config file extension '{extension or path}'. "
|
|
82
|
+
f"Supported extensions: {', '.join(SUPPORTED_EXTENSIONS)}"
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
if not isinstance(raw, dict):
|
|
86
|
+
raise ConfigFileError(
|
|
87
|
+
f"Config file '{path}' must contain a mapping at its top level."
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
return raw
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _load_json(path: str) -> Any:
|
|
94
|
+
try:
|
|
95
|
+
with open(path, "r", encoding="utf-8") as f:
|
|
96
|
+
return json.load(f)
|
|
97
|
+
except (OSError, UnicodeDecodeError, json.JSONDecodeError) as e:
|
|
98
|
+
raise ConfigFileError(f"Could not parse JSON config '{path}': {e}")
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _load_toml(path: str) -> Any:
|
|
102
|
+
try:
|
|
103
|
+
with open(path, "rb") as f:
|
|
104
|
+
return tomllib.load(f)
|
|
105
|
+
except (OSError, tomllib.TOMLDecodeError) as e:
|
|
106
|
+
raise ConfigFileError(f"Could not parse TOML config '{path}': {e}")
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _load_yaml(path: str) -> Any:
|
|
110
|
+
yaml = _yaml_module()
|
|
111
|
+
if yaml is None:
|
|
112
|
+
raise ConfigFileError(
|
|
113
|
+
"YAML config files need PyYAML, which is not installed. "
|
|
114
|
+
"Install it (pip install pyyaml) or use a .json / .toml config file instead."
|
|
115
|
+
)
|
|
116
|
+
try:
|
|
117
|
+
with open(path, "r", encoding="utf-8") as f:
|
|
118
|
+
return yaml.safe_load(f)
|
|
119
|
+
except Exception as e:
|
|
120
|
+
# PyYAML raises its own YAMLError hierarchy; catching broadly keeps
|
|
121
|
+
# this import-optional module free of a yaml type import.
|
|
122
|
+
raise ConfigFileError(f"Could not parse YAML config '{path}': {e}")
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def validate_project_config(config: Dict[str, Any]) -> List[str]:
|
|
126
|
+
"""
|
|
127
|
+
Validate a loaded configuration against the interactive-mode rules.
|
|
128
|
+
|
|
129
|
+
Reuses ``interactive.validators`` so a file-driven run is held to exactly
|
|
130
|
+
the same standard as an answered prompt.
|
|
131
|
+
|
|
132
|
+
:param config: Configuration dictionary
|
|
133
|
+
:return: List of human-readable error messages (empty when the config is valid)
|
|
134
|
+
"""
|
|
135
|
+
errors: List[str] = []
|
|
136
|
+
|
|
137
|
+
for key in REQUIRED_KEYS:
|
|
138
|
+
if not config.get(key):
|
|
139
|
+
errors.append(f"Missing required config key: '{key}'")
|
|
140
|
+
|
|
141
|
+
project_name = config.get("project_name")
|
|
142
|
+
if isinstance(project_name, str) and project_name:
|
|
143
|
+
is_valid, message = validate_project_name(project_name)
|
|
144
|
+
if not is_valid and message:
|
|
145
|
+
errors.append(message)
|
|
146
|
+
|
|
147
|
+
author_email = config.get("author_email")
|
|
148
|
+
if isinstance(author_email, str) and author_email:
|
|
149
|
+
if not validate_email_format(author_email):
|
|
150
|
+
errors.append(f"Invalid author email format: '{author_email}'")
|
|
151
|
+
|
|
152
|
+
# Feature selections are held to the catalog: an axis spelled in a shape
|
|
153
|
+
# the pipeline cannot read used to reach generation and produce a project
|
|
154
|
+
# whose ``main.py`` imported modules nobody wrote.
|
|
155
|
+
errors.extend(validate_project_config_schema(config))
|
|
156
|
+
|
|
157
|
+
return errors
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def load_normalized_project_config(path: str) -> Dict[str, Any]:
|
|
161
|
+
"""
|
|
162
|
+
Load a config file and return it in the canonical pipeline shape.
|
|
163
|
+
|
|
164
|
+
``load_project_config`` deliberately hands back exactly what the file
|
|
165
|
+
said (so ``--save-config`` round-trips byte for byte); this wrapper is
|
|
166
|
+
what the generation pipeline consumes, because every consumer of a
|
|
167
|
+
configuration must see the same normalised selections.
|
|
168
|
+
|
|
169
|
+
:param path: Path to the configuration file
|
|
170
|
+
:return: Normalised configuration dictionary
|
|
171
|
+
:raises ConfigFileError: If the file cannot be read, parsed or trusted
|
|
172
|
+
"""
|
|
173
|
+
raw = load_project_config(path)
|
|
174
|
+
try:
|
|
175
|
+
return normalize_project_config(raw)
|
|
176
|
+
except ConfigSchemaError as e:
|
|
177
|
+
raise ConfigFileError(f"Invalid project config '{path}': {e}")
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def save_project_config(config: Dict[str, Any], path: str) -> None:
|
|
181
|
+
"""
|
|
182
|
+
Write a configuration dict to a JSON / TOML / YAML file.
|
|
183
|
+
|
|
184
|
+
:param config: Configuration dictionary produced by the interactive builder
|
|
185
|
+
:param path: Destination path; the extension selects the format
|
|
186
|
+
:raises ConfigFileError: If the format is unsupported or the write fails
|
|
187
|
+
"""
|
|
188
|
+
extension = os.path.splitext(path)[1].lower()
|
|
189
|
+
|
|
190
|
+
if extension in JSON_EXTENSIONS:
|
|
191
|
+
content = (
|
|
192
|
+
json.dumps(config, indent=2, sort_keys=True, ensure_ascii=False) + "\n"
|
|
193
|
+
)
|
|
194
|
+
elif extension in TOML_EXTENSIONS:
|
|
195
|
+
content = _dump_toml(config)
|
|
196
|
+
elif extension in YAML_EXTENSIONS:
|
|
197
|
+
yaml = _yaml_module()
|
|
198
|
+
if yaml is None:
|
|
199
|
+
raise ConfigFileError(
|
|
200
|
+
"Saving YAML config files needs PyYAML, which is not installed. "
|
|
201
|
+
"Use a .json / .toml path instead."
|
|
202
|
+
)
|
|
203
|
+
content = str(yaml.safe_dump(config, sort_keys=True, allow_unicode=True))
|
|
204
|
+
else:
|
|
205
|
+
raise ConfigFileError(
|
|
206
|
+
f"Unsupported config file extension '{extension or path}'. "
|
|
207
|
+
f"Supported extensions: {', '.join(SUPPORTED_EXTENSIONS)}"
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
try:
|
|
211
|
+
parent = os.path.dirname(os.path.abspath(path))
|
|
212
|
+
os.makedirs(parent, exist_ok=True)
|
|
213
|
+
with open(path, "w", encoding="utf-8") as f:
|
|
214
|
+
f.write(content)
|
|
215
|
+
except OSError as e:
|
|
216
|
+
raise ConfigFileError(f"Could not write config file '{path}': {e}")
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def _dump_toml(config: Dict[str, Any]) -> str:
|
|
220
|
+
"""
|
|
221
|
+
Serialize a configuration dict to TOML.
|
|
222
|
+
|
|
223
|
+
Python 3.12 ships a TOML reader but no writer, and fastkit may not add a
|
|
224
|
+
runtime dependency for one. The interactive config only ever holds
|
|
225
|
+
strings, booleans, numbers, string lists and one level of nested tables
|
|
226
|
+
(``database``), which this covers.
|
|
227
|
+
"""
|
|
228
|
+
scalars: List[str] = []
|
|
229
|
+
tables: List[str] = []
|
|
230
|
+
|
|
231
|
+
for key in sorted(config):
|
|
232
|
+
value = config[key]
|
|
233
|
+
if isinstance(value, dict):
|
|
234
|
+
table_lines = [f"[{key}]"]
|
|
235
|
+
for sub_key in sorted(value):
|
|
236
|
+
table_lines.append(f"{sub_key} = {format_toml_value(value[sub_key])}")
|
|
237
|
+
tables.append("\n".join(table_lines))
|
|
238
|
+
else:
|
|
239
|
+
scalars.append(f"{key} = {format_toml_value(value)}")
|
|
240
|
+
|
|
241
|
+
sections = ["\n".join(scalars)] if scalars else []
|
|
242
|
+
sections.extend(tables)
|
|
243
|
+
return "\n\n".join(section for section in sections if section) + "\n"
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def format_toml_value(value: Any) -> str:
|
|
247
|
+
"""
|
|
248
|
+
Render a Python value as a TOML literal.
|
|
249
|
+
|
|
250
|
+
Shared with pyproject metadata injection so both writers escape and
|
|
251
|
+
quote values identically.
|
|
252
|
+
|
|
253
|
+
:param value: Value to render (bool / int / float / list / str)
|
|
254
|
+
:return: TOML literal string
|
|
255
|
+
"""
|
|
256
|
+
if isinstance(value, bool):
|
|
257
|
+
return "true" if value else "false"
|
|
258
|
+
if isinstance(value, (int, float)):
|
|
259
|
+
return str(value)
|
|
260
|
+
if isinstance(value, (list, tuple)):
|
|
261
|
+
return "[" + ", ".join(format_toml_value(item) for item in value) + "]"
|
|
262
|
+
escaped = str(value).replace("\\", "\\\\").replace('"', '\\"')
|
|
263
|
+
return f'"{escaped}"'
|
fastapi_fastkit/utils/main.py
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
# --------------------------------------------------------------------------
|
|
6
6
|
import os
|
|
7
7
|
import re
|
|
8
|
+
import tomllib
|
|
8
9
|
import traceback
|
|
9
10
|
from typing import Any, Dict, Optional
|
|
10
11
|
|
|
@@ -24,6 +25,14 @@ logger = get_logger(__name__)
|
|
|
24
25
|
REGEX = r"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,7}\b"
|
|
25
26
|
|
|
26
27
|
|
|
28
|
+
# Canonical identity markers used to distinguish FastAPI-fastkit-managed
|
|
29
|
+
# projects from unrelated FastAPI projects in the user workspace. Kept as
|
|
30
|
+
# module-level constants so templates, metadata injection, and detection
|
|
31
|
+
# logic all reference the same strings.
|
|
32
|
+
FASTKIT_DESCRIPTION_MARKER = "[FastAPI-fastkit templated]"
|
|
33
|
+
FASTKIT_TOOL_SECTION = "fastapi-fastkit" # the [tool.<this>] table key
|
|
34
|
+
|
|
35
|
+
|
|
27
36
|
def get_optimal_console_size() -> tuple[int, int]:
|
|
28
37
|
"""
|
|
29
38
|
Get optimal console size based on terminal dimensions.
|
|
@@ -273,19 +282,115 @@ def validate_email(ctx: Context, param: Any, value: Any) -> Any:
|
|
|
273
282
|
|
|
274
283
|
def is_fastkit_project(project_dir: str) -> bool:
|
|
275
284
|
"""
|
|
276
|
-
Check if the project was created
|
|
277
|
-
|
|
285
|
+
Check if the project was created/managed by FastAPI-fastkit.
|
|
286
|
+
|
|
287
|
+
Detection precedence (any single match is sufficient):
|
|
288
|
+
|
|
289
|
+
1. ``pyproject.toml`` with ``[tool.fastapi-fastkit].managed = true``
|
|
290
|
+
(machine-readable marker; set by ``fastkit`` during project generation).
|
|
291
|
+
2. ``pyproject.toml`` ``[project].description`` contains the
|
|
292
|
+
``[FastAPI-fastkit templated]`` marker (case-insensitive).
|
|
293
|
+
3. ``setup.py`` contains ``fastapi-fastkit`` (case-insensitive) — preserves
|
|
294
|
+
the legacy detection path for projects generated before the pyproject
|
|
295
|
+
marker existed.
|
|
278
296
|
|
|
279
297
|
:param project_dir: Path to the project directory
|
|
280
298
|
:return: True if the project was created with fastkit, False otherwise
|
|
281
299
|
"""
|
|
300
|
+
if _pyproject_marks_fastkit(os.path.join(project_dir, "pyproject.toml")):
|
|
301
|
+
return True
|
|
302
|
+
|
|
282
303
|
setup_py = os.path.join(project_dir, "setup.py")
|
|
283
|
-
if
|
|
304
|
+
if os.path.exists(setup_py):
|
|
305
|
+
try:
|
|
306
|
+
with open(setup_py, "r", encoding="utf-8") as f:
|
|
307
|
+
content = f.read()
|
|
308
|
+
if FASTKIT_TOOL_SECTION in content.lower():
|
|
309
|
+
return True
|
|
310
|
+
except (OSError, UnicodeDecodeError):
|
|
311
|
+
pass
|
|
312
|
+
|
|
313
|
+
return False
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
def _pyproject_marks_fastkit(pyproject_path: str) -> bool:
|
|
317
|
+
"""Return True if ``pyproject.toml`` carries a FastAPI-fastkit marker.
|
|
318
|
+
|
|
319
|
+
Tries structured TOML parsing first (authoritative), falling back to a
|
|
320
|
+
plain-text scan if the file is malformed so detection still works on
|
|
321
|
+
hand-edited or partially written pyproject files.
|
|
322
|
+
"""
|
|
323
|
+
if not os.path.exists(pyproject_path):
|
|
284
324
|
return False
|
|
285
325
|
|
|
286
326
|
try:
|
|
287
|
-
with open(
|
|
288
|
-
|
|
289
|
-
|
|
327
|
+
with open(pyproject_path, "rb") as f:
|
|
328
|
+
data = tomllib.load(f)
|
|
329
|
+
except (OSError, tomllib.TOMLDecodeError, UnicodeDecodeError):
|
|
330
|
+
return _pyproject_text_marks_fastkit(pyproject_path)
|
|
331
|
+
|
|
332
|
+
tool_section = data.get("tool", {}).get(FASTKIT_TOOL_SECTION, {})
|
|
333
|
+
if isinstance(tool_section, dict) and tool_section.get("managed") is True:
|
|
334
|
+
return True
|
|
335
|
+
|
|
336
|
+
description = data.get("project", {}).get("description", "")
|
|
337
|
+
if (
|
|
338
|
+
isinstance(description, str)
|
|
339
|
+
and FASTKIT_DESCRIPTION_MARKER.lower() in description.lower()
|
|
340
|
+
):
|
|
341
|
+
return True
|
|
342
|
+
|
|
343
|
+
return False
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
def _pyproject_text_marks_fastkit(pyproject_path: str) -> bool:
|
|
347
|
+
"""Fallback plain-text scan for malformed pyproject files."""
|
|
348
|
+
try:
|
|
349
|
+
with open(pyproject_path, "r", encoding="utf-8") as f:
|
|
350
|
+
content = f.read().lower()
|
|
290
351
|
except (OSError, UnicodeDecodeError):
|
|
291
352
|
return False
|
|
353
|
+
|
|
354
|
+
if f"[tool.{FASTKIT_TOOL_SECTION}]" in content:
|
|
355
|
+
return True
|
|
356
|
+
if FASTKIT_DESCRIPTION_MARKER.lower() in content:
|
|
357
|
+
return True
|
|
358
|
+
return False
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
def read_fastkit_metadata(project_dir: str) -> Dict[str, Any]:
|
|
362
|
+
"""Read the ``[tool.fastapi-fastkit]`` block of a generated project.
|
|
363
|
+
|
|
364
|
+
The block is the shared contract between generation (``init`` /
|
|
365
|
+
``startdemo``) and the commands that operate on an existing project
|
|
366
|
+
(``runserver``, ``addroute``): it records the template, preset,
|
|
367
|
+
package manager, selected features and — most importantly — the
|
|
368
|
+
``app_module`` entrypoint, so those commands no longer have to
|
|
369
|
+
re-derive the layout heuristically.
|
|
370
|
+
|
|
371
|
+
:param project_dir: Path to the generated project directory
|
|
372
|
+
:return: The metadata mapping, or an empty dict when the project has no
|
|
373
|
+
readable ``pyproject.toml`` / no fastkit block.
|
|
374
|
+
"""
|
|
375
|
+
pyproject_path = os.path.join(project_dir, "pyproject.toml")
|
|
376
|
+
if not os.path.exists(pyproject_path):
|
|
377
|
+
return {}
|
|
378
|
+
|
|
379
|
+
try:
|
|
380
|
+
with open(pyproject_path, "rb") as f:
|
|
381
|
+
data = tomllib.load(f)
|
|
382
|
+
except (OSError, tomllib.TOMLDecodeError, UnicodeDecodeError) as e:
|
|
383
|
+
debug_log(
|
|
384
|
+
f"Could not read fastkit metadata from {pyproject_path}: {e}", "warning"
|
|
385
|
+
)
|
|
386
|
+
return {}
|
|
387
|
+
|
|
388
|
+
tool_section = data.get("tool", {})
|
|
389
|
+
if not isinstance(tool_section, dict):
|
|
390
|
+
return {}
|
|
391
|
+
|
|
392
|
+
metadata = tool_section.get(FASTKIT_TOOL_SECTION, {})
|
|
393
|
+
if not isinstance(metadata, dict):
|
|
394
|
+
return {}
|
|
395
|
+
|
|
396
|
+
return dict(metadata)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: FastAPI-fastkit
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.4.0
|
|
4
4
|
Summary: Fast, easy-to-use starter kit for new users of Python and FastAPI
|
|
5
5
|
Author-Email: bnbong <bbbong9@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -11,6 +11,7 @@ Project-URL: Changelog, https://bnbong.github.io/FastAPI-fastkit/changelog/
|
|
|
11
11
|
Requires-Python: >=3.12
|
|
12
12
|
Requires-Dist: click>=8.1.7
|
|
13
13
|
Requires-Dist: rich>=13.9.2
|
|
14
|
+
Requires-Dist: jinja2>=3.1
|
|
14
15
|
Provides-Extra: dev
|
|
15
16
|
Requires-Dist: pytest>=9.0.3; extra == "dev"
|
|
16
17
|
Requires-Dist: pytest-cov>=6.2.1; extra == "dev"
|
|
@@ -19,10 +20,11 @@ Requires-Dist: pre-commit>=4.0.1; extra == "dev"
|
|
|
19
20
|
Requires-Dist: mypy>=1.12.0; extra == "dev"
|
|
20
21
|
Requires-Dist: isort>=5.13.2; extra == "dev"
|
|
21
22
|
Requires-Dist: pygments>=2.20.0; extra == "dev"
|
|
23
|
+
Requires-Dist: types-pyyaml>=6.0.12.20260408; extra == "dev"
|
|
22
24
|
Description-Content-Type: text/markdown
|
|
23
25
|
|
|
24
26
|
<p align="center">
|
|
25
|
-
<img align="top" width="70%" src="
|
|
27
|
+
<img align="top" width="70%" src=".github/fastkit_general_logo.png" alt="FastAPI-fastkit"/>
|
|
26
28
|
</p>
|
|
27
29
|
<p align="center">
|
|
28
30
|
<em><b>FastAPI-fastkit</b>: Fast, easy-to-use starter kit for new users of Python and FastAPI</em>
|
|
@@ -57,6 +59,8 @@ This project was inspired by the `SpringBoot initializer` & Python Django's `dja
|
|
|
57
59
|
- **🔍 Automated template quality assurance** : Weekly automated testing ensures all templates remain functional and up-to-date
|
|
58
60
|
- **🚀 Multiple project templates** : Choose from various pre-configured templates for different use cases (async CRUD, Docker, PostgreSQL, etc.)
|
|
59
61
|
- **📦 Multiple package manager support** : Choose your preferred Python package manager (pip, uv, pdm, poetry) for dependency management
|
|
62
|
+
- **🧾 Reproducible project configs** : Save an interactive session to a `.json` / `.toml` / `.yaml` file and replay it with `fastkit init --config`
|
|
63
|
+
- **🏷️ Self-describing projects** : Every generated project records its template, preset, package manager, entrypoint and selected features in a `[tool.fastapi-fastkit]` block that `runserver` and `addroute` read back
|
|
60
64
|
|
|
61
65
|
## Installation
|
|
62
66
|
|
|
@@ -82,6 +86,12 @@ fastkit init [OPTIONS]
|
|
|
82
86
|
- Key options:
|
|
83
87
|
- `--project-name`, `--author`, `--author-email`, `--description`
|
|
84
88
|
- `--package-manager` [pip|uv|pdm|poetry]
|
|
89
|
+
- `--config <path>`: create the project from a saved config file (`.json` / `.toml`, and `.yaml` when PyYAML is installed) with no prompts
|
|
90
|
+
- `--save-config <path>`: with `--interactive`, record the answers for later reuse
|
|
91
|
+
- `--dry-run`: print the files and packages that would be created, write nothing
|
|
92
|
+
- `--no-venv`: skip virtual environment creation (implies `--no-install`)
|
|
93
|
+
- `--no-install`: skip dependency installation
|
|
94
|
+
- `--yes` / `-y`: skip the "Overwrite these files?" confirmation when deploying in place
|
|
85
95
|
- Stack selection: `minimal` | `standard` | `full` (interactive)
|
|
86
96
|
|
|
87
97
|
### Create a project with interactive mode
|
|
@@ -90,6 +100,7 @@ fastkit init --interactive
|
|
|
90
100
|
```
|
|
91
101
|
- What it does: Guided step-by-step project setup with intelligent feature selection
|
|
92
102
|
- Features:
|
|
103
|
+
- **Architecture preset**: `minimal` | `single-module` | `classic-layered` | `domain-starter` (default)
|
|
93
104
|
- **Database selection**: PostgreSQL, MySQL, MongoDB, Redis, SQLite
|
|
94
105
|
- **Authentication**: JWT, OAuth2, FastAPI-Users, Session-based
|
|
95
106
|
- **Background tasks**: Celery, Dramatiq
|
|
@@ -97,14 +108,20 @@ fastkit init --interactive
|
|
|
97
108
|
- **Monitoring**: Loguru, OpenTelemetry, Prometheus
|
|
98
109
|
- **Testing**: Basic (pytest), Coverage, Advanced (with faker, factory-boy)
|
|
99
110
|
- **Utilities**: CORS, Rate-Limiting, Pagination, WebSocket
|
|
111
|
+
- **Logging**: structured JSON logging with a request-id middleware
|
|
112
|
+
- **Migrations**: Alembic (async env, baseline revision)
|
|
113
|
+
- **Tooling**: ruff, pre-commit, GitHub Actions, devcontainer, Makefile (multi-select)
|
|
100
114
|
- **Deployment**: Docker, docker-compose with auto-generated configs
|
|
101
115
|
- **Package manager**: pip, uv, pdm, poetry
|
|
102
116
|
- **Custom packages**: Add your own dependencies
|
|
103
|
-
- Auto-generates:
|
|
104
|
-
- `main.py`
|
|
105
|
-
- Database and authentication configuration files
|
|
106
|
-
- Docker deployment files (Dockerfile
|
|
117
|
+
- Auto-generates (varies by preset — see [the matrix](https://bnbong.github.io/FastAPI-fastkit/reference/preset-feature-matrix/) for details):
|
|
118
|
+
- `main.py` regenerated from selected features for `minimal` / `single-module`; preserved as-shipped for `classic-layered` / `domain-starter`
|
|
119
|
+
- Database and authentication configuration files at preset-specific paths
|
|
120
|
+
- Docker deployment files (`Dockerfile`, `docker-compose.yml`) with the preset's correct uvicorn entrypoint
|
|
107
121
|
- Test configuration (pytest with coverage)
|
|
122
|
+
- `/health` and `/ready` endpoints on every generated project
|
|
123
|
+
- Real working code — not just installed packages — for background tasks, caching, WebSocket, pagination, OpenTelemetry, OAuth2 and session-based auth
|
|
124
|
+
- `--dry-run` previews the exact file tree a run would create, including logging/migrations/tooling artifacts
|
|
108
125
|
|
|
109
126
|
### Create a project from a template
|
|
110
127
|
```console
|
|
@@ -114,8 +131,16 @@ fastkit startdemo [TEMPLATE] [OPTIONS]
|
|
|
114
131
|
- Key options:
|
|
115
132
|
- `--project-name`, `--author`, `--author-email`, `--description`
|
|
116
133
|
- `--package-manager` [pip|uv|pdm|poetry]
|
|
134
|
+
- `--dry-run`, `--no-venv`, `--no-install`, `--yes`/`-y` — same meaning as on `init`
|
|
135
|
+
- Refuses to run if the target project directory already exists (`--dry-run` excepted)
|
|
117
136
|
- Tip: List available templates with `fastkit list-templates`
|
|
118
137
|
|
|
138
|
+
New in v1.4.0: `fastapi-auth-jwt` (JWT auth with refresh rotation),
|
|
139
|
+
`fastapi-sqlmodel` (async SQLModel + Alembic + generic CRUD), and
|
|
140
|
+
`fastapi-llm-agent` (streaming Claude agent with a tool loop).
|
|
141
|
+
`fastapi-dockerized` and `fastapi-async-crud` are deprecated — they still
|
|
142
|
+
work, but are no longer recommended starting points.
|
|
143
|
+
|
|
119
144
|
### Add a new route
|
|
120
145
|
```console
|
|
121
146
|
fastkit addroute <project_name> <route_name>
|
|
@@ -144,9 +169,11 @@ fastkit deleteproject <project_name>
|
|
|
144
169
|
|
|
145
170
|
For comprehensive guides and detailed usage instructions, visit our documentation:
|
|
146
171
|
|
|
172
|
+
- 🧭 **[Which starter should I choose?](https://bnbong.github.io/FastAPI-fastkit/user-guide/choosing-a-starter/)** - Beginner decision guide for `startdemo` templates and interactive presets
|
|
147
173
|
- 📚 **[User Guide](https://bnbong.github.io/FastAPI-fastkit/user-guide/quick-start/)** - Detailed installation and usage guides
|
|
148
174
|
- 🎯 **[Tutorial](https://bnbong.github.io/FastAPI-fastkit/tutorial/getting-started/)** - Step-by-step tutorials for beginners
|
|
149
175
|
- 📖 **[CLI Reference](https://bnbong.github.io/FastAPI-fastkit/user-guide/cli-reference/)** - Complete command reference
|
|
176
|
+
- 🧱 **[Architecture Preset Matrix](https://bnbong.github.io/FastAPI-fastkit/reference/preset-feature-matrix/)** - Per-preset / per-feature contract for interactive generation
|
|
150
177
|
- 🔍 **[Template Quality Assurance](https://bnbong.github.io/FastAPI-fastkit/reference/template-quality-assurance/)** - Automated testing and quality standards
|
|
151
178
|
|
|
152
179
|
## Contributing
|