fastapi-admin-kit 0.1.0__tar.gz → 0.1.2__tar.gz
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_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/.gitignore +1 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/PKG-INFO +11 -8
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/README.md +8 -5
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/__init__.py +4 -1
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/admin/admin_database.py +12 -3
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/admin/core.py +9 -2
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/api/roles.py +1 -1
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/api/search.py +3 -2
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/auth/csrf.py +4 -3
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/auth/views.py +6 -3
- fastapi_admin_kit-0.1.2/fastapi_admin_kit/cli/__init__.py +79 -0
- fastapi_admin_kit-0.1.2/fastapi_admin_kit/cli/__main__.py +5 -0
- fastapi_admin_kit-0.1.2/fastapi_admin_kit/cli/scaffold.py +287 -0
- fastapi_admin_kit-0.1.0/fastapi_admin_kit/cli.py → fastapi_admin_kit-0.1.2/fastapi_admin_kit/cli/user.py +8 -21
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/config/__init__.py +3 -0
- fastapi_admin_kit-0.1.2/fastapi_admin_kit/config/database.py +150 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/form/pipeline.py +20 -3
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/inspection/__init__.py +28 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/modeladmin.py +26 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/router.py +196 -2
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/static/css/admin.css +64 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/static/js/admin.js +13 -1
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/base.html +3 -0
- fastapi_admin_kit-0.1.2/fastapi_admin_kit/templates/partials/_inline_edit_row.html +85 -0
- fastapi_admin_kit-0.1.2/fastapi_admin_kit/templates/partials/inline_edit_form.html +32 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/partials/list_table.html +9 -6
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/views/class_views.py +4 -2
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/views/factory.py +8 -4
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/views/profile.py +8 -2
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/views/renderers.py +2 -1
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/views/roles.py +60 -31
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/views/totp.py +4 -1
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/mkdocs.yml +3 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/pyproject.toml +4 -3
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/LICENSE +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/actions/__init__.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/actions/base.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/actions/registry.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/admin/__init__.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/admin/admin_config.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/admin/admin_router.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/admin/admin_template.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/admin/builtin_models.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/admin/decorators.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/admin/state.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/admin.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/api/__init__.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/api/auth.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/api/crud.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/api/deps.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/api/schema_generator.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/api/schemas.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/audit/__init__.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/audit/context.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/audit/diff.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/audit/event_bus.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/audit/events.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/audit/listener.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/audit/logger.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/audit/middleware.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/audit/models.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/audit/sqlalchemy_logger.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/auth/__init__.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/auth/backend.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/auth/dependencies.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/auth/identity.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/auth/models.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/auth/password.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/auth/permissions.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/auth/protocol.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/auth/ratelimit.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/auth/router.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/auth/session.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/auth/totp.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/config/audit.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/config/auth.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/config/behavior.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/config/nav.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/config/storage.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/config/theme.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/config/ui.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/dashboard/__init__.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/db.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/exceptions.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/field_types.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/filters/__init__.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/filters/base.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/filters/registry.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/flash.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/form/__init__.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/inspection/registry.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/inspection.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/models/__init__.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/models/base.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/nav.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/pagination/__init__.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/pagination/base.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/pagination/cursor.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/pagination/dynamic.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/pagination/offset.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/plugins/__init__.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/py.typed +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/registry/__init__.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/registry/core.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/registry/validation.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/registry.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/static/css/presets.css +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/static/css/tokens.css +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/static/css/variables.css +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/static/icons/heroicons.svg +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/static/js/htmx-config.js +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/storage/__init__.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/storage/base.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/storage/local.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/macros/form_fields.html +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/macros/icons.html +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/macros/table.html +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/macros/widgets.html +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/pages/2fa/setup.html +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/pages/2fa/verify.html +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/pages/audit_detail.html +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/pages/audit_log.html +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/pages/dashboard.html +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/pages/detail.html +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/pages/form.html +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/pages/list.html +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/pages/login.html +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/pages/profile/password.html +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/pages/profile/profile.html +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/pages/role_form.html +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/pages/roles/form.html +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/pages/roles/list.html +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/pages/roles.html +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/pages/settings/theme.html +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/pages/users/form.html +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/pages/users/list.html +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/partials/command_palette.html +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/partials/field_wrapper.html +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/partials/flash_messages.html +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/partials/head.html +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/partials/head_minimal.html +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/partials/mobile_backdrop.html +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/partials/pagination.html +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/partials/permission_widget.html +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/partials/scripts.html +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/partials/sidebar.html +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/templates/partials/topbar.html +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/types.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/validation.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/views/__init__.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/views/audit.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/views/bulk.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/views/context.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/views/dashboard.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/views/delete.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/views/extra.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/views/form.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/views/list.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/views/protocols.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/views/search.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/views/settings.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/views/sidebar.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/views/users.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/views.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/widgets/__init__.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/widgets/base.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/widgets/inputs.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/widgets/registry.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/widgets/relation.py +0 -0
- {fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/widgets/resolver.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fastapi-admin-kit
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: Drop-in admin panel for FastAPI + SQLAlchemy + SQLModel apps
|
|
5
5
|
Project-URL: Homepage, https://github.com/borhanst/fastapi-admin-kit
|
|
6
6
|
Project-URL: Documentation, https://borhanst.github.io/fastapi-admin-kit/
|
|
@@ -25,13 +25,13 @@ Classifier: Typing :: Typed
|
|
|
25
25
|
Requires-Python: >=3.11
|
|
26
26
|
Requires-Dist: aiosqlite>=0.20.0
|
|
27
27
|
Requires-Dist: bcrypt>=4.0.0
|
|
28
|
-
Requires-Dist: fastapi>=0.
|
|
28
|
+
Requires-Dist: fastapi>=0.115.0
|
|
29
29
|
Requires-Dist: itsdangerous>=2.2.0
|
|
30
30
|
Requires-Dist: jinja2>=3.1.0
|
|
31
31
|
Requires-Dist: pyjwt>=2.13.0
|
|
32
32
|
Requires-Dist: python-multipart>=0.0.9
|
|
33
33
|
Requires-Dist: sqlalchemy>=2.0.0
|
|
34
|
-
Requires-Dist: uvicorn>=0.
|
|
34
|
+
Requires-Dist: uvicorn>=0.30.0
|
|
35
35
|
Provides-Extra: dev
|
|
36
36
|
Requires-Dist: hatch>=1.13.0; extra == 'dev'
|
|
37
37
|
Requires-Dist: httpx>=0.27.0; extra == 'dev'
|
|
@@ -58,6 +58,8 @@ Description-Content-Type: text/markdown
|
|
|
58
58
|
|
|
59
59
|
A drop-in admin panel for FastAPI + SQLAlchemy apps, inspired by Django Unfold.
|
|
60
60
|
|
|
61
|
+
> **⚠️ Important Notice:** This project is **not production-ready yet**. It is under active development, and the API and code may massive changes. Use it for development and testing purposes only.
|
|
62
|
+
|
|
61
63
|
📖 **[Documentation](https://borhanst.github.io/fastapi-admin-kit/)** | 🚀 **[Quick Start](#quick-start)** | 📦 **[PyPI](https://pypi.org/project/fastapi-admin-kit/)**
|
|
62
64
|
|
|
63
65
|
## Features
|
|
@@ -66,7 +68,8 @@ A drop-in admin panel for FastAPI + SQLAlchemy apps, inspired by Django Unfold.
|
|
|
66
68
|
- Built-in authentication, RBAC, and audit logging
|
|
67
69
|
- Modern UI with Tailwind CSS, HTMX, and Alpine.js
|
|
68
70
|
- Fully customizable widgets, themes, and templates
|
|
69
|
-
-
|
|
71
|
+
- Inline editing from list view with 3-dot action menu
|
|
72
|
+
- CLI for user management (`fak-admin` / `fak` — create superusers, list users, change passwords)
|
|
70
73
|
- Async-first with support for PostgreSQL, MySQL, and SQLite
|
|
71
74
|
|
|
72
75
|
## Installation
|
|
@@ -138,15 +141,15 @@ Both the full name and the short alias work interchangeably:
|
|
|
138
141
|
|
|
139
142
|
```bash
|
|
140
143
|
# Create a superuser
|
|
141
|
-
|
|
142
|
-
fak
|
|
144
|
+
fak-admin createsuperuser -e admin@example.com -p mypassword
|
|
145
|
+
fak createsuperuser -e admin@example.com -p mypassword # short alias
|
|
143
146
|
|
|
144
147
|
# List all admin users
|
|
145
|
-
|
|
148
|
+
fak-admin users
|
|
146
149
|
fak users
|
|
147
150
|
|
|
148
151
|
# Change a user's password
|
|
149
|
-
|
|
152
|
+
fak-admin changepassword -e admin@example.com -p newpassword
|
|
150
153
|
fak changepassword -e admin@example.com -p newpassword
|
|
151
154
|
```
|
|
152
155
|
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
A drop-in admin panel for FastAPI + SQLAlchemy apps, inspired by Django Unfold.
|
|
8
8
|
|
|
9
|
+
> **⚠️ Important Notice:** This project is **not production-ready yet**. It is under active development, and the API and code may massive changes. Use it for development and testing purposes only.
|
|
10
|
+
|
|
9
11
|
📖 **[Documentation](https://borhanst.github.io/fastapi-admin-kit/)** | 🚀 **[Quick Start](#quick-start)** | 📦 **[PyPI](https://pypi.org/project/fastapi-admin-kit/)**
|
|
10
12
|
|
|
11
13
|
## Features
|
|
@@ -14,7 +16,8 @@ A drop-in admin panel for FastAPI + SQLAlchemy apps, inspired by Django Unfold.
|
|
|
14
16
|
- Built-in authentication, RBAC, and audit logging
|
|
15
17
|
- Modern UI with Tailwind CSS, HTMX, and Alpine.js
|
|
16
18
|
- Fully customizable widgets, themes, and templates
|
|
17
|
-
-
|
|
19
|
+
- Inline editing from list view with 3-dot action menu
|
|
20
|
+
- CLI for user management (`fak-admin` / `fak` — create superusers, list users, change passwords)
|
|
18
21
|
- Async-first with support for PostgreSQL, MySQL, and SQLite
|
|
19
22
|
|
|
20
23
|
## Installation
|
|
@@ -86,15 +89,15 @@ Both the full name and the short alias work interchangeably:
|
|
|
86
89
|
|
|
87
90
|
```bash
|
|
88
91
|
# Create a superuser
|
|
89
|
-
|
|
90
|
-
fak
|
|
92
|
+
fak-admin createsuperuser -e admin@example.com -p mypassword
|
|
93
|
+
fak createsuperuser -e admin@example.com -p mypassword # short alias
|
|
91
94
|
|
|
92
95
|
# List all admin users
|
|
93
|
-
|
|
96
|
+
fak-admin users
|
|
94
97
|
fak users
|
|
95
98
|
|
|
96
99
|
# Change a user's password
|
|
97
|
-
|
|
100
|
+
fak-admin changepassword -e admin@example.com -p newpassword
|
|
98
101
|
fak changepassword -e admin@example.com -p newpassword
|
|
99
102
|
```
|
|
100
103
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from fastapi_admin_kit.admin import Admin
|
|
4
4
|
from fastapi_admin_kit.admin.decorators import column
|
|
5
|
+
from fastapi_admin_kit.config import DatabaseConfig, DatabaseType
|
|
5
6
|
from fastapi_admin_kit.exceptions import ConfigError
|
|
6
7
|
from fastapi_admin_kit.nav import (
|
|
7
8
|
BuiltNavGroup,
|
|
@@ -40,6 +41,8 @@ __all__ = [
|
|
|
40
41
|
"Admin",
|
|
41
42
|
"AdminRegistry",
|
|
42
43
|
"ConfigError",
|
|
44
|
+
"DatabaseConfig",
|
|
45
|
+
"DatabaseType",
|
|
43
46
|
"RegisteredModel",
|
|
44
47
|
"ModelAdmin",
|
|
45
48
|
"column",
|
|
@@ -70,4 +73,4 @@ __all__ = [
|
|
|
70
73
|
# Per-model assets
|
|
71
74
|
"AdminExtra",
|
|
72
75
|
]
|
|
73
|
-
__version__ = "0.1.
|
|
76
|
+
__version__ = "0.1.2"
|
{fastapi_admin_kit-0.1.0 → fastapi_admin_kit-0.1.2}/fastapi_admin_kit/admin/admin_database.py
RENAMED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"""Admin database setup and initialization."""
|
|
2
2
|
|
|
3
|
-
from
|
|
3
|
+
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from fastapi_admin_kit.config.database import DatabaseConfig
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
class AdminDatabase:
|
|
@@ -13,9 +14,17 @@ class AdminDatabase:
|
|
|
13
14
|
self,
|
|
14
15
|
engine: Any | None = None,
|
|
15
16
|
base: Any | None = None,
|
|
17
|
+
database_config: DatabaseConfig | None = None,
|
|
16
18
|
):
|
|
17
19
|
self.engine = engine
|
|
18
20
|
self.base = base
|
|
21
|
+
self.database_config = database_config
|
|
22
|
+
|
|
23
|
+
def _ensure_engine(self) -> Any:
|
|
24
|
+
"""Create the async engine from ``database_config`` if no engine is set."""
|
|
25
|
+
if self.engine is None and self.database_config is not None:
|
|
26
|
+
self.engine = self.database_config.create_engine()
|
|
27
|
+
return self.engine
|
|
19
28
|
|
|
20
29
|
async def _create_tables(self) -> None:
|
|
21
30
|
"""Create all admin database tables (async-safe)."""
|
|
@@ -21,6 +21,7 @@ from fastapi_admin_kit.config import (
|
|
|
21
21
|
AuditConfig,
|
|
22
22
|
AuthConfig,
|
|
23
23
|
BehaviorConfig,
|
|
24
|
+
DatabaseConfig,
|
|
24
25
|
NavConfig,
|
|
25
26
|
StorageConfig,
|
|
26
27
|
ThemeConfig,
|
|
@@ -116,6 +117,7 @@ class Admin:
|
|
|
116
117
|
self,
|
|
117
118
|
app: FastAPI | None = None,
|
|
118
119
|
engine: Engine | None = None,
|
|
120
|
+
database_config: DatabaseConfig | None = None,
|
|
119
121
|
*,
|
|
120
122
|
# Component instances (new API)
|
|
121
123
|
config: AdminConfig | None = None,
|
|
@@ -257,7 +259,9 @@ class Admin:
|
|
|
257
259
|
)
|
|
258
260
|
|
|
259
261
|
if database is None:
|
|
260
|
-
database = AdminDatabase(
|
|
262
|
+
database = AdminDatabase(
|
|
263
|
+
engine=engine, base=base, database_config=database_config
|
|
264
|
+
)
|
|
261
265
|
|
|
262
266
|
if router is None:
|
|
263
267
|
router = AdminRouter(
|
|
@@ -426,9 +430,12 @@ class Admin:
|
|
|
426
430
|
"Admin requires a FastAPI app instance. Pass app= or call setup(app=)."
|
|
427
431
|
)
|
|
428
432
|
|
|
433
|
+
self.database._ensure_engine()
|
|
434
|
+
|
|
429
435
|
if self.database.engine is None:
|
|
430
436
|
raise ConfigError(
|
|
431
|
-
"Admin requires a SQLAlchemy engine.
|
|
437
|
+
"Admin requires a SQLAlchemy engine. "
|
|
438
|
+
"Pass engine= or database_config= to Admin()."
|
|
432
439
|
)
|
|
433
440
|
|
|
434
441
|
app = self._app
|
|
@@ -56,6 +56,7 @@ async def get_search_suggestions(
|
|
|
56
56
|
if registry is None or not q.strip():
|
|
57
57
|
return {"suggestions": [], "query": q}
|
|
58
58
|
|
|
59
|
+
admin_path = request.app.state.admin_config["admin_path"]
|
|
59
60
|
query_lower = q.strip().lower()
|
|
60
61
|
suggestions: list[dict[str, Any]] = []
|
|
61
62
|
|
|
@@ -79,7 +80,7 @@ async def get_search_suggestions(
|
|
|
79
80
|
"model": table_name,
|
|
80
81
|
"label": verbose_name_plural,
|
|
81
82
|
"sublabel": table_name,
|
|
82
|
-
"url": f"/
|
|
83
|
+
"url": f"{admin_path}/{table_name}",
|
|
83
84
|
}
|
|
84
85
|
)
|
|
85
86
|
|
|
@@ -120,7 +121,7 @@ async def get_search_suggestions(
|
|
|
120
121
|
"field": field_name,
|
|
121
122
|
"label": f"{verbose_name_plural} → {field_label}",
|
|
122
123
|
"sublabel": f"{table_name}.{field_name}",
|
|
123
|
-
"url": f"/
|
|
124
|
+
"url": f"{admin_path}/{table_name}?q={q}",
|
|
124
125
|
}
|
|
125
126
|
)
|
|
126
127
|
|
|
@@ -9,7 +9,7 @@ import time
|
|
|
9
9
|
|
|
10
10
|
from fastapi import HTTPException, Request, Response
|
|
11
11
|
from starlette.middleware.base import BaseHTTPMiddleware
|
|
12
|
-
from starlette.responses import
|
|
12
|
+
from starlette.responses import RedirectResponse
|
|
13
13
|
|
|
14
14
|
CSRF_COOKIE_NAME = "admin_csrf_token"
|
|
15
15
|
CSRF_FORM_FIELD = "csrf_token"
|
|
@@ -224,9 +224,10 @@ async def auth_redirect_handler(request: Request, exc: HTTPException) -> Respons
|
|
|
224
224
|
if exc.status_code == 401:
|
|
225
225
|
accept = request.headers.get("accept", "")
|
|
226
226
|
if "text/html" in accept:
|
|
227
|
-
|
|
227
|
+
admin_path = request.app.state.admin_config["admin_path"]
|
|
228
|
+
login_url = f"{admin_path}/login"
|
|
228
229
|
current_path = request.url.path
|
|
229
|
-
if current_path != "/
|
|
230
|
+
if current_path != f"{admin_path}/login":
|
|
230
231
|
if request.url.query:
|
|
231
232
|
login_url += f"?next={current_path}%3F{request.url.query}"
|
|
232
233
|
else:
|
|
@@ -45,7 +45,8 @@ async def login_get(
|
|
|
45
45
|
) -> HTMLResponse:
|
|
46
46
|
"""GET /admin/login — show login page, redirect if already logged in."""
|
|
47
47
|
if session_payload is not None:
|
|
48
|
-
|
|
48
|
+
admin_path = request.app.state.admin_config["admin_path"]
|
|
49
|
+
target = next if _is_safe_url(next) else f"{admin_path}/"
|
|
49
50
|
return RedirectResponse(url=target, status_code=status.HTTP_302_FOUND)
|
|
50
51
|
|
|
51
52
|
jinja_env = request.app.state.admin_jinja_env
|
|
@@ -90,7 +91,8 @@ async def login_post(
|
|
|
90
91
|
if next and _is_safe_url(next):
|
|
91
92
|
redirect_url = next
|
|
92
93
|
else:
|
|
93
|
-
|
|
94
|
+
admin_path = request.app.state.admin_config["admin_path"]
|
|
95
|
+
redirect_url = f"{admin_path}/"
|
|
94
96
|
|
|
95
97
|
samesite = getattr(
|
|
96
98
|
request.app.state.admin_state, "session_samesite", "strict"
|
|
@@ -149,7 +151,8 @@ async def logout_post(
|
|
|
149
151
|
request.app.state.admin_state, "session_samesite", "strict"
|
|
150
152
|
)
|
|
151
153
|
response = RedirectResponse(
|
|
152
|
-
url="/
|
|
154
|
+
url=f"{request.app.state.admin_config['admin_path']}/login",
|
|
155
|
+
status_code=status.HTTP_302_FOUND
|
|
153
156
|
)
|
|
154
157
|
response.delete_cookie(
|
|
155
158
|
key=session_backend.cookie_name,
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"""CLI commands for FastAPI Admin Kit."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import sys
|
|
7
|
+
|
|
8
|
+
from fastapi_admin_kit.cli.scaffold import scaffold_project
|
|
9
|
+
from fastapi_admin_kit.cli.user import (
|
|
10
|
+
handle_user_command,
|
|
11
|
+
register_user_commands,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _init_project(args: argparse.Namespace) -> None:
|
|
16
|
+
"""Create a new FastAPI project with uv."""
|
|
17
|
+
scaffold_project(
|
|
18
|
+
project_name=args.name,
|
|
19
|
+
layout=args.layout,
|
|
20
|
+
directory=args.directory,
|
|
21
|
+
skip_venv=args.no_venv,
|
|
22
|
+
skip_git=args.no_git,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def main() -> None:
|
|
27
|
+
"""Main CLI entry point."""
|
|
28
|
+
parser = argparse.ArgumentParser(
|
|
29
|
+
description="FastAPI Admin Kit CLI — manage admin users and scaffold projects.",
|
|
30
|
+
)
|
|
31
|
+
subparsers = parser.add_subparsers(
|
|
32
|
+
dest="command", help="Available commands"
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
# Register command groups
|
|
36
|
+
register_user_commands(subparsers)
|
|
37
|
+
|
|
38
|
+
# init — scaffold a new FastAPI project
|
|
39
|
+
init_parser = subparsers.add_parser(
|
|
40
|
+
"init", help="Create a new FastAPI project with uv"
|
|
41
|
+
)
|
|
42
|
+
init_parser.add_argument(
|
|
43
|
+
"name", nargs="?", default=None, help="Project name"
|
|
44
|
+
)
|
|
45
|
+
init_parser.add_argument(
|
|
46
|
+
"-l",
|
|
47
|
+
"--layout",
|
|
48
|
+
choices=["flat", "app", "src"],
|
|
49
|
+
default=None,
|
|
50
|
+
help="Project layout (flat, app, src). Interactive if omitted.",
|
|
51
|
+
)
|
|
52
|
+
init_parser.add_argument(
|
|
53
|
+
"-d",
|
|
54
|
+
"--directory",
|
|
55
|
+
default=None,
|
|
56
|
+
help="Target directory (defaults to project name)",
|
|
57
|
+
)
|
|
58
|
+
init_parser.add_argument(
|
|
59
|
+
"--no-venv", action="store_true", help="Skip uv venv creation"
|
|
60
|
+
)
|
|
61
|
+
init_parser.add_argument(
|
|
62
|
+
"--no-git", action="store_true", help="Skip git init"
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
args = parser.parse_args()
|
|
66
|
+
|
|
67
|
+
if args.command is None:
|
|
68
|
+
parser.print_help()
|
|
69
|
+
sys.exit(1)
|
|
70
|
+
|
|
71
|
+
# Dispatch
|
|
72
|
+
if args.command in ("createsuperuser", "users", "changepassword"):
|
|
73
|
+
handle_user_command(args)
|
|
74
|
+
elif args.command == "init":
|
|
75
|
+
_init_project(args)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
if __name__ == "__main__":
|
|
79
|
+
main()
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
"""Interactive project scaffolding for FastAPI projects with uv."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import subprocess
|
|
6
|
+
import sys
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
LAYOUTS = {
|
|
10
|
+
"flat": {
|
|
11
|
+
"name": "Flat (main.py in root)",
|
|
12
|
+
"description": "Simple layout — main.py at project root",
|
|
13
|
+
"files": {
|
|
14
|
+
"main.py": '''\
|
|
15
|
+
from contextlib import asynccontextmanager
|
|
16
|
+
|
|
17
|
+
from fastapi import FastAPI
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@asynccontextmanager
|
|
21
|
+
async def lifespan(app: FastAPI):
|
|
22
|
+
print("Starting up...")
|
|
23
|
+
yield
|
|
24
|
+
print("Shutting down...")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
app = FastAPI(title="{project_name}", lifespan=lifespan)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@app.get("/")
|
|
31
|
+
async def root():
|
|
32
|
+
return {{"message": "Hello from {project_name}!"}}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@app.get("/health")
|
|
36
|
+
async def health():
|
|
37
|
+
return {{"status": "ok"}}
|
|
38
|
+
''',
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
"app": {
|
|
42
|
+
"name": "App directory (app/main.py)",
|
|
43
|
+
"description": "Recommended — app/ package with __init__.py",
|
|
44
|
+
"files": {
|
|
45
|
+
"app/__init__.py": "",
|
|
46
|
+
"app/main.py": '''\
|
|
47
|
+
from contextlib import asynccontextmanager
|
|
48
|
+
|
|
49
|
+
from fastapi import FastAPI
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@asynccontextmanager
|
|
53
|
+
async def lifespan(app: FastAPI):
|
|
54
|
+
print("Starting up...")
|
|
55
|
+
yield
|
|
56
|
+
print("Shutting down...")
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
app = FastAPI(title="{project_name}", lifespan=lifespan)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@app.get("/")
|
|
63
|
+
async def root():
|
|
64
|
+
return {{"message": "Hello from {project_name}!"}}
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@app.get("/health")
|
|
68
|
+
async def health():
|
|
69
|
+
return {{"status": "ok"}}
|
|
70
|
+
''',
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
"src": {
|
|
74
|
+
"name": "Src layout (src/app/main.py)",
|
|
75
|
+
"description": "Src layout — installable package with src/ root",
|
|
76
|
+
"files": {
|
|
77
|
+
"src/__init__.py": "",
|
|
78
|
+
"src/app/__init__.py": "",
|
|
79
|
+
"src/app/main.py": '''\
|
|
80
|
+
from contextlib import asynccontextmanager
|
|
81
|
+
|
|
82
|
+
from fastapi import FastAPI
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
@asynccontextmanager
|
|
86
|
+
async def lifespan(app: FastAPI):
|
|
87
|
+
print("Starting up...")
|
|
88
|
+
yield
|
|
89
|
+
print("Shutting down...")
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
app = FastAPI(title="{project_name}", lifespan=lifespan)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@app.get("/")
|
|
96
|
+
async def root():
|
|
97
|
+
return {{"message": "Hello from {project_name}!"}}
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
@app.get("/health")
|
|
101
|
+
async def health():
|
|
102
|
+
return {{"status": "ok"}}
|
|
103
|
+
''',
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _pyproject_content(project_name: str, layout: str, description: str = "") -> str:
|
|
110
|
+
"""Generate pyproject.toml content."""
|
|
111
|
+
entrypoints = {
|
|
112
|
+
"flat": "main:app",
|
|
113
|
+
"app": "app.main:app",
|
|
114
|
+
"src": "app.main:app",
|
|
115
|
+
}
|
|
116
|
+
packages_val = {
|
|
117
|
+
"flat": "main.py",
|
|
118
|
+
"app": "app",
|
|
119
|
+
"src": "src/app",
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return f'''\
|
|
123
|
+
[project]
|
|
124
|
+
name = "{project_name}"
|
|
125
|
+
version = "0.1.0"
|
|
126
|
+
description = "{description or project_name}"
|
|
127
|
+
readme = "README.md"
|
|
128
|
+
requires-python = ">=3.11"
|
|
129
|
+
dependencies = [
|
|
130
|
+
"fastapi[standard]>=0.115.0",
|
|
131
|
+
"uvicorn[standard]>=0.30.0",
|
|
132
|
+
]
|
|
133
|
+
|
|
134
|
+
[tool.hatch.build.targets.wheel]
|
|
135
|
+
packages = ["{packages_val[layout]}"]
|
|
136
|
+
|
|
137
|
+
[tool.fastapi]
|
|
138
|
+
entrypoint = "{entrypoints[layout]}"
|
|
139
|
+
|
|
140
|
+
[build-system]
|
|
141
|
+
requires = ["hatchling"]
|
|
142
|
+
build-backend = "hatchling.build"
|
|
143
|
+
|
|
144
|
+
[tool.ruff]
|
|
145
|
+
line-length = 100
|
|
146
|
+
target-version = "py311"
|
|
147
|
+
'''
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def _gitignore_content() -> str:
|
|
151
|
+
return '''\
|
|
152
|
+
__pycache__/
|
|
153
|
+
*.py[cod]
|
|
154
|
+
*.egg-info/
|
|
155
|
+
dist/
|
|
156
|
+
build/
|
|
157
|
+
.venv/
|
|
158
|
+
.env
|
|
159
|
+
*.db
|
|
160
|
+
*.sqlite3
|
|
161
|
+
'''
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def _python_version_content() -> str:
|
|
165
|
+
return "3.11\n"
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def _input(prompt: str, default: str = "") -> str:
|
|
169
|
+
"""Read user input with optional default."""
|
|
170
|
+
suffix = f" [{default}]" if default else ""
|
|
171
|
+
value = input(f"{prompt}{suffix}: ").strip()
|
|
172
|
+
return value or default
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def _select(options: list[str], prompt: str) -> int:
|
|
176
|
+
"""Display numbered options and return selected index."""
|
|
177
|
+
print(f"\n{prompt}")
|
|
178
|
+
for i, opt in enumerate(options, 1):
|
|
179
|
+
print(f" {i}) {opt}")
|
|
180
|
+
while True:
|
|
181
|
+
choice = input("\nEnter number: ").strip()
|
|
182
|
+
if choice.isdigit() and 1 <= int(choice) <= len(options):
|
|
183
|
+
return int(choice) - 1
|
|
184
|
+
print(f"Invalid choice. Enter 1-{len(options)}.")
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def _run(cmd: list[str], cwd: Path) -> bool:
|
|
188
|
+
"""Run a subprocess, return True on success."""
|
|
189
|
+
result = subprocess.run(cmd, cwd=cwd, capture_output=True, text=True)
|
|
190
|
+
if result.returncode != 0:
|
|
191
|
+
print(f"Error running {' '.join(cmd)}:")
|
|
192
|
+
print(result.stderr or result.stdout)
|
|
193
|
+
return False
|
|
194
|
+
return True
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def scaffold_project(
|
|
198
|
+
project_name: str | None = None,
|
|
199
|
+
layout: str | None = None,
|
|
200
|
+
directory: str | None = None,
|
|
201
|
+
skip_venv: bool = False,
|
|
202
|
+
skip_git: bool = False,
|
|
203
|
+
) -> Path:
|
|
204
|
+
"""
|
|
205
|
+
Create a new FastAPI project.
|
|
206
|
+
|
|
207
|
+
Interactive when args are missing; non-interactive when all provided.
|
|
208
|
+
Returns the project directory path.
|
|
209
|
+
"""
|
|
210
|
+
# --- Collect inputs interactively ---
|
|
211
|
+
if not project_name:
|
|
212
|
+
project_name = _input("Project name", "my-fastapi-app")
|
|
213
|
+
|
|
214
|
+
if not layout:
|
|
215
|
+
options = [f"{LAYOUTS[k]['name']} — {LAYOUTS[k]['description']}" for k in LAYOUTS]
|
|
216
|
+
idx = _select(options, "Select project structure:")
|
|
217
|
+
layout = list(LAYOUTS.keys())[idx]
|
|
218
|
+
|
|
219
|
+
project_dir = Path(directory or project_name).resolve()
|
|
220
|
+
|
|
221
|
+
if project_dir.exists() and any(project_dir.iterdir()):
|
|
222
|
+
confirm = _input(f"'{project_dir}' already exists. Overwrite?", "n")
|
|
223
|
+
if confirm.lower() not in ("y", "yes"):
|
|
224
|
+
print("Aborted.")
|
|
225
|
+
sys.exit(1)
|
|
226
|
+
|
|
227
|
+
project_dir.mkdir(parents=True, exist_ok=True)
|
|
228
|
+
|
|
229
|
+
# --- Write files ---
|
|
230
|
+
print(f"\nCreating project '{project_name}' in {project_dir} ...")
|
|
231
|
+
|
|
232
|
+
# pyproject.toml
|
|
233
|
+
(project_dir / "pyproject.toml").write_text(_pyproject_content(project_name, layout))
|
|
234
|
+
|
|
235
|
+
# .gitignore
|
|
236
|
+
(project_dir / ".gitignore").write_text(_gitignore_content())
|
|
237
|
+
|
|
238
|
+
# .python-version
|
|
239
|
+
(project_dir / ".python-version").write_text(_python_version_content())
|
|
240
|
+
|
|
241
|
+
# README.md
|
|
242
|
+
(project_dir / "README.md").write_text(f"# {project_name}\n\nA FastAPI project.\n")
|
|
243
|
+
|
|
244
|
+
# Layout files
|
|
245
|
+
layout_data = LAYOUTS[layout]
|
|
246
|
+
for rel_path, content in layout_data["files"].items():
|
|
247
|
+
file_path = project_dir / rel_path
|
|
248
|
+
file_path.parent.mkdir(parents=True, exist_ok=True)
|
|
249
|
+
file_path.write_text(content.format(project_name=project_name))
|
|
250
|
+
|
|
251
|
+
print("Project files created.")
|
|
252
|
+
|
|
253
|
+
# --- uv init ---
|
|
254
|
+
if not skip_venv:
|
|
255
|
+
print("\nSetting up virtual environment with uv...")
|
|
256
|
+
if not _run(["uv", "venv"], project_dir):
|
|
257
|
+
print("Warning: uv venv creation failed. Create manually: uv venv")
|
|
258
|
+
else:
|
|
259
|
+
print(" Virtual environment created.")
|
|
260
|
+
|
|
261
|
+
print("Installing dependencies...")
|
|
262
|
+
if not _run(["uv", "sync"], project_dir):
|
|
263
|
+
# uv sync may fail if uv.lock doesn't exist yet, try uv pip install
|
|
264
|
+
print(" Trying uv pip install...")
|
|
265
|
+
_run(["uv", "pip", "install", "-e", "."], project_dir)
|
|
266
|
+
else:
|
|
267
|
+
print(" Dependencies installed.")
|
|
268
|
+
|
|
269
|
+
# --- git init ---
|
|
270
|
+
if not skip_git:
|
|
271
|
+
print("\nInitializing git repository...")
|
|
272
|
+
_run(["git", "init"], project_dir)
|
|
273
|
+
_run(["git", "add", "."], project_dir)
|
|
274
|
+
_run(["git", "commit", "-m", "Initial commit"], project_dir)
|
|
275
|
+
print(" Git repository initialized.")
|
|
276
|
+
|
|
277
|
+
# --- Summary ---
|
|
278
|
+
entrypoints = {"flat": "main:app", "app": "app.main:app", "src": "app.main:app"}
|
|
279
|
+
print(f"\nDone! Project '{project_name}' is ready.\n")
|
|
280
|
+
print(f" cd {project_dir.name}")
|
|
281
|
+
if not skip_venv:
|
|
282
|
+
print(" source .venv/bin/activate # or: uv run fastapi dev")
|
|
283
|
+
print(" fastapi dev # starts at http://localhost:8000")
|
|
284
|
+
print(f"\n Entrypoint: {entrypoints[layout]}")
|
|
285
|
+
print(f" Layout: {LAYOUTS[layout]['name']}")
|
|
286
|
+
|
|
287
|
+
return project_dir
|