fastapi-rtk 2.1.2__tar.gz → 2.1.4__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_rtk-2.1.2 → fastapi_rtk-2.1.4}/PKG-INFO +1 -1
- fastapi_rtk-2.1.4/fastapi_rtk/_version.py +1 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/api/base_api.py +20 -12
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/api/model_rest_api/__init__.py +18 -12
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/api/model_rest_api/_columns.py +3 -1
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/api/model_rest_api/_info_mixin.py +2 -6
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/auth/strategies/db.py +1 -3
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/backends/sqla/db.py +6 -3
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/backends/sqla/extensions/audit/_decorators_mixin.py +2 -6
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/backends/sqla/extensions/audit/_processing_mixin.py +2 -6
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/bases/interface.py +8 -10
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/cli/commands/security.py +14 -11
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/db.py +9 -19
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/decorators.py +3 -1
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/manager.py +3 -1
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/schemas.py +6 -2
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/security/sqla/apis.py +1 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/security/sqla/security_manager/_user_mixin.py +3 -1
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/conftest.py +0 -1
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/integration/api/test_model_rest_api.py +27 -6
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/integration/apis/test_info_contract.py +1 -3
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/integration/auth/test_oauth.py +17 -25
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/integration/conftest.py +0 -1
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/integration/file_managers/test_file_routes.py +4 -12
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/api/conftest.py +0 -1
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/api/model_rest_api/test_columns.py +3 -9
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/api/model_rest_api/test_file_mixin.py +0 -2
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/api/model_rest_api/test_init.py +24 -10
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/api/test_base_api.py +24 -3
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/auth/password_helpers/test_fab.py +1 -2
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/auth/strategies/test_config.py +2 -3
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/auth/strategies/test_db.py +1 -2
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/auth/strategies/test_jwt.py +2 -5
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/auth/test_auth.py +9 -9
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/backends/generic/test_column.py +0 -1
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/backends/generic/test_db.py +2 -7
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/backends/generic/test_filters.py +0 -1
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/backends/generic/test_interface.py +1 -2
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/backends/generic/test_model.py +3 -2
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/backends/generic/test_session.py +2 -7
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/backends/sqla/conftest.py +1 -2
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/backends/sqla/test_audit.py +2 -7
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/backends/sqla/test_column.py +5 -6
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/backends/sqla/test_db.py +11 -26
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/backends/sqla/test_filters.py +1 -3
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/backends/sqla/test_geoalchemy2.py +49 -39
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/backends/sqla/test_interface.py +1 -2
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/backends/sqla/test_model.py +2 -5
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/backends/sqla/test_session.py +4 -5
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/bases/test_db.py +0 -1
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/bases/test_file_manager.py +0 -1
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/bases/test_filter.py +0 -1
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/bases/test_interface.py +0 -2
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/bases/test_model.py +0 -1
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/cli/commands/conftest.py +0 -1
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/cli/commands/test_export.py +1 -6
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/cli/commands/test_security.py +21 -39
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/cli/commands/test_security_crypto.py +0 -1
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/cli/conftest.py +0 -1
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/cli/test_cli.py +1 -2
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/cli/test_decorators.py +0 -1
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/cli/test_utils.py +0 -1
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/file_managers/conftest.py +0 -1
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/file_managers/test_file_manager.py +0 -1
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/file_managers/test_image_manager.py +0 -1
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/file_managers/test_s3_file_manager.py +0 -1
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/lang/test_babel_cli.py +0 -1
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/lang/test_babel_config.py +0 -1
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/lang/test_lazy_text.py +0 -1
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/security/sqla/conftest.py +1 -2
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/security/sqla/test_apis.py +10 -4
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/security/sqla/test_models.py +1 -4
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/security/sqla/test_security_manager.py +1 -5
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/test_config.py +0 -1
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/test_const.py +0 -1
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/test_db.py +9 -21
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/test_decorators.py +11 -12
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/test_dependencies.py +2 -5
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/test_exceptions.py +0 -1
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/test_globals.py +0 -1
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/test_manager.py +3 -4
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/test_middlewares.py +1 -4
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/test_registry.py +0 -1
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/test_routers.py +29 -34
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/test_schemas.py +2 -4
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/test_setting.py +0 -1
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/test_types.py +3 -2
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/utils/test_extender_mixin.py +0 -1
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/utils/test_flask_appbuilder_utils.py +0 -1
- fastapi_rtk-2.1.2/fastapi_rtk/_version.py +0 -1
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/.gitignore +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/LICENSE +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/README.md +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/api/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/api/model_rest_api/_add_mixin.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/api/model_rest_api/_bulk_mixin.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/api/model_rest_api/_delete_mixin.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/api/model_rest_api/_download_mixin.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/api/model_rest_api/_edit_mixin.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/api/model_rest_api/_file_mixin.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/api/model_rest_api/_list_mixin.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/api/model_rest_api/_params.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/api/model_rest_api/_show_mixin.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/api/model_rest_api/_upload_mixin.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/apis/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/apis/info.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/apis/license.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/auth/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/auth/auth.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/auth/hashers/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/auth/hashers/pbkdf2.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/auth/hashers/scrypt.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/auth/ldap.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/auth/password_helpers/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/auth/password_helpers/fab.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/auth/strategies/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/auth/strategies/config.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/auth/strategies/jwt.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/backends/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/backends/generic/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/backends/generic/column.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/backends/generic/db.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/backends/generic/exceptions.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/backends/generic/filters.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/backends/generic/interface.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/backends/generic/model.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/backends/generic/session.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/backends/sqla/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/backends/sqla/column.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/backends/sqla/exceptions.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/backends/sqla/extensions/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/backends/sqla/extensions/audit/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/backends/sqla/extensions/audit/_lifecycle_mixin.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/backends/sqla/extensions/audit/_logger.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/backends/sqla/extensions/audit/audit.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/backends/sqla/extensions/audit/types.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/backends/sqla/extensions/geoalchemy2/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/backends/sqla/extensions/geoalchemy2/filters.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/backends/sqla/extensions/geoalchemy2/geometry_converter.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/backends/sqla/filters.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/backends/sqla/interface.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/backends/sqla/model.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/backends/sqla/session.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/bases/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/bases/db.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/bases/file_manager.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/bases/filter.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/bases/model.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/bases/session.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/cli/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/cli/cli.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/cli/commands/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/cli/commands/_security_crypto.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/cli/commands/db/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/cli/commands/db/templates/fastapi/README +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/cli/commands/db/templates/fastapi/alembic.ini.mako +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/cli/commands/db/templates/fastapi/env.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/cli/commands/db/templates/fastapi/script.py.mako +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/cli/commands/db/templates/fastapi-multidb/README +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/cli/commands/db/templates/fastapi-multidb/alembic.ini.mako +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/cli/commands/db/templates/fastapi-multidb/env.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/cli/commands/db/templates/fastapi-multidb/script.py.mako +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/cli/commands/export.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/cli/commands/translate.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/cli/const.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/cli/decorators.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/cli/types.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/cli/utils.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/config.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/const.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/dependencies.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/exceptions.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/fastapi_react_toolkit.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/file_managers/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/file_managers/file_manager.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/file_managers/image_manager.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/file_managers/s3_file_manager.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/file_managers/s3_image_manager.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/filters.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/globals.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/lang/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/lang/babel/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/lang/babel/cli.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/lang/babel/config.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/lang/babel.cfg +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/lang/lazy_text.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/lang/messages.pot +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/lang/translations/de/LC_MESSAGES/messages.mo +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/lang/translations/de/LC_MESSAGES/messages.po +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/lang/translations/en/LC_MESSAGES/messages.mo +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/lang/translations/en/LC_MESSAGES/messages.po +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/middlewares.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/mixins.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/models.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/py.typed +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/registry.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/routers.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/security/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/security/sqla/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/security/sqla/models.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/security/sqla/security_manager/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/security/sqla/security_manager/_association_mixin.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/security/sqla/security_manager/_builtin_role_mixin.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/security/sqla/security_manager/_cleanup_mixin.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/security/sqla/security_manager/_exception_filters.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/security/sqla/security_manager/_export.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/security/sqla/security_manager/_import.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/security/sqla/security_manager/_role_mixin.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/setting.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/types.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/utils/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/utils/async_task_runner.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/utils/class_factory.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/utils/csv_json_converter.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/utils/deep_merge.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/utils/extender_mixin.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/utils/flask_appbuilder_utils.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/utils/formatter.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/utils/hooks.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/utils/lazy.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/utils/merge_schema.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/utils/multiple_async_contexts.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/utils/pydantic.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/utils/run_utils.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/utils/self_dependencies.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/utils/smartdefaultdict.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/utils/sqla.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/utils/timezone.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/utils/update_signature.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/utils/use_default_when_none.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/version.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/pyproject.toml +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/docker-compose.gis.yml +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/integration/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/integration/api/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/integration/apis/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/integration/auth/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/integration/auth/test_auth_flow.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/integration/file_managers/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/integration/security/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/integration/security/sqla/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/integration/security/sqla/test_security_manager.py +1 -1
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/integration/test_app_smoke.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/api/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/api/model_rest_api/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/apis/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/apis/test_info.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/apis/test_license.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/auth/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/auth/hashers/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/auth/hashers/test_pbkdf2.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/auth/hashers/test_scrypt.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/auth/password_helpers/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/auth/strategies/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/backends/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/backends/generic/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/backends/generic/test_exceptions.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/backends/sqla/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/backends/sqla/test_audit_types.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/bases/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/bases/test_session.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/cli/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/cli/commands/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/cli/commands/test_db.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/cli/commands/test_translate.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/cli/test_types.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/file_managers/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/file_managers/test_s3_image_manager.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/lang/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/security/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/security/sqla/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/test_fastapi_react_toolkit.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/test_filters.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/test_mixins.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/test_models.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/test_version.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/utils/__init__.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/utils/test_async_task_runner.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/utils/test_class_factory.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/utils/test_csv_json_converter.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/utils/test_deep_merge.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/utils/test_formatter.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/utils/test_hooks.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/utils/test_lazy.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/utils/test_merge_schema.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/utils/test_multiple_async_contexts.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/utils/test_pydantic.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/utils/test_run_utils.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/utils/test_self_dependencies.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/utils/test_smartdefaultdict.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/utils/test_sqla.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/utils/test_timezone.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/utils/test_update_signature.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/tests/unit/utils/test_use_default_when_none.py +0 -0
- {fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fastapi-rtk
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.4
|
|
4
4
|
Summary: A package that provides a set of tools to build a FastAPI application with a Class-Based CRUD API.
|
|
5
5
|
Project-URL: Homepage, https://codeberg.org/datatactics/fastapi-rtk
|
|
6
6
|
Project-URL: Issues, https://codeberg.org/datatactics/fastapi-rtk/issues
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "2.1.4"
|
|
@@ -201,24 +201,27 @@ class BaseApi:
|
|
|
201
201
|
self, metadata["response_model_str"]
|
|
202
202
|
)
|
|
203
203
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
extra_dependencies = metadata["dependencies"]
|
|
207
|
-
if extra_dependencies and not data.get("dependencies"):
|
|
208
|
-
data["dependencies"] = []
|
|
209
|
-
for dep in extra_dependencies:
|
|
204
|
+
resolved_dependencies = []
|
|
205
|
+
for dep in metadata.get("dependencies") or []:
|
|
210
206
|
func, kwargs = dep
|
|
211
207
|
if kwargs:
|
|
208
|
+
# Resolve into a fresh dict; the source kwargs live in
|
|
209
|
+
# the shared registry and must stay un-mutated so other
|
|
210
|
+
# instances of the same Api class can resolve them too.
|
|
211
|
+
resolved_kwargs = {}
|
|
212
212
|
for key, val in kwargs.items():
|
|
213
213
|
if val == ":self":
|
|
214
|
-
|
|
215
|
-
elif val.startswith(":f"):
|
|
214
|
+
resolved_kwargs[key] = self
|
|
215
|
+
elif isinstance(val, str) and val.startswith(":f"):
|
|
216
216
|
prop = val.split(".")[1]
|
|
217
|
-
|
|
218
|
-
|
|
217
|
+
resolved_kwargs[key] = metadata[prop]
|
|
218
|
+
else:
|
|
219
|
+
resolved_kwargs[key] = val
|
|
220
|
+
resolved_dependencies.append(
|
|
221
|
+
Depends(func(**resolved_kwargs))
|
|
222
|
+
)
|
|
219
223
|
else:
|
|
220
|
-
|
|
221
|
-
data["dependencies"].append(func)
|
|
224
|
+
resolved_dependencies.append(Depends(func))
|
|
222
225
|
|
|
223
226
|
path, methods, rest_data = (
|
|
224
227
|
data["path"],
|
|
@@ -226,6 +229,11 @@ class BaseApi:
|
|
|
226
229
|
{k: v for k, v in data.items() if k != "methods"},
|
|
227
230
|
)
|
|
228
231
|
|
|
232
|
+
if resolved_dependencies:
|
|
233
|
+
rest_data["dependencies"] = (
|
|
234
|
+
list(data.get("dependencies") or []) + resolved_dependencies
|
|
235
|
+
)
|
|
236
|
+
|
|
229
237
|
self.messages.append(
|
|
230
238
|
f"Registering route {self.router.prefix}{path} {methods}"
|
|
231
239
|
)
|
|
@@ -32,11 +32,11 @@ from pydantic import BaseModel, Field
|
|
|
32
32
|
|
|
33
33
|
from ...backends.sqla.filters import BaseFilter, BaseOprFilter
|
|
34
34
|
from ...backends.sqla.interface import SQLAInterface
|
|
35
|
+
from ...bases import DBQueryParams
|
|
35
36
|
from ...const import AVAILABLE_ROUTES
|
|
36
37
|
from ...dependencies import current_permissions
|
|
37
38
|
from ...exceptions import HTTPWithValidationException, raise_exception
|
|
38
39
|
from ...lang.lazy_text import translate
|
|
39
|
-
from ...bases import DBQueryParams
|
|
40
40
|
from ...schemas import (
|
|
41
41
|
BaseResponseMany,
|
|
42
42
|
BaseResponseSingle,
|
|
@@ -59,13 +59,7 @@ from ._edit_mixin import EditMixin
|
|
|
59
59
|
from ._file_mixin import FileMixin
|
|
60
60
|
from ._info_mixin import InfoMixin
|
|
61
61
|
from ._list_mixin import ListMixin
|
|
62
|
-
from ._upload_mixin import UploadMixin
|
|
63
62
|
from ._params import (
|
|
64
|
-
PARAM_BODY_SESSION,
|
|
65
|
-
PARAM_ID_SESSION,
|
|
66
|
-
PARAM_ID_SESSION_ITEM,
|
|
67
|
-
PARAM_IDS_Q_SESSION_ITEMS,
|
|
68
|
-
PARAM_Q,
|
|
69
63
|
P_BODY,
|
|
70
64
|
P_ID,
|
|
71
65
|
P_IDS,
|
|
@@ -73,9 +67,15 @@ from ._params import (
|
|
|
73
67
|
P_ITEMS,
|
|
74
68
|
P_Q,
|
|
75
69
|
P_SESSION,
|
|
70
|
+
PARAM_BODY_SESSION,
|
|
71
|
+
PARAM_ID_SESSION,
|
|
72
|
+
PARAM_ID_SESSION_ITEM,
|
|
73
|
+
PARAM_IDS_Q_SESSION_ITEMS,
|
|
74
|
+
PARAM_Q,
|
|
76
75
|
Params,
|
|
77
76
|
)
|
|
78
77
|
from ._show_mixin import ShowMixin
|
|
78
|
+
from ._upload_mixin import UploadMixin
|
|
79
79
|
|
|
80
80
|
__all__ = ["ModelRestApi"]
|
|
81
81
|
|
|
@@ -208,7 +208,9 @@ class ModelRestApi(
|
|
|
208
208
|
base_order = ("name", "asc")
|
|
209
209
|
```
|
|
210
210
|
"""
|
|
211
|
-
base_filters:
|
|
211
|
+
base_filters: (
|
|
212
|
+
typing.List[typing.Tuple[str, typing.Type[BaseFilter], typing.Any]] | None
|
|
213
|
+
) = None
|
|
212
214
|
"""
|
|
213
215
|
The default filters to apply for the following endpoints: `download`, `list`, `show`, `add`, and `edit`. Defaults to None.
|
|
214
216
|
|
|
@@ -219,7 +221,9 @@ class ModelRestApi(
|
|
|
219
221
|
]
|
|
220
222
|
```
|
|
221
223
|
"""
|
|
222
|
-
base_opr_filters:
|
|
224
|
+
base_opr_filters: (
|
|
225
|
+
typing.List[typing.Tuple[typing.Type[BaseOprFilter], typing.Any]] | None
|
|
226
|
+
) = None
|
|
223
227
|
"""
|
|
224
228
|
The default opr filters to apply for the following endpoints: `download`, `list`, `show`, `add`, and `edit`. Defaults to None.
|
|
225
229
|
|
|
@@ -659,7 +663,8 @@ class ModelRestApi(
|
|
|
659
663
|
| typing.Callable[[ColumnInfo | ColumnEnumInfo | ColumnRelationInfo], bool]
|
|
660
664
|
| dict[
|
|
661
665
|
str,
|
|
662
|
-
bool
|
|
666
|
+
bool
|
|
667
|
+
| typing.Callable[[ColumnInfo | ColumnEnumInfo | ColumnRelationInfo], bool],
|
|
663
668
|
]
|
|
664
669
|
) = lazy(lambda: lambda info: len(info.values) > 100)
|
|
665
670
|
"""
|
|
@@ -700,7 +705,8 @@ class ModelRestApi(
|
|
|
700
705
|
| typing.Callable[[ColumnInfo | ColumnEnumInfo | ColumnRelationInfo], bool]
|
|
701
706
|
| dict[
|
|
702
707
|
str,
|
|
703
|
-
bool
|
|
708
|
+
bool
|
|
709
|
+
| typing.Callable[[ColumnInfo | ColumnEnumInfo | ColumnRelationInfo], bool],
|
|
704
710
|
]
|
|
705
711
|
) = lazy(lambda: lambda info: len(info.values) > 100)
|
|
706
712
|
"""
|
|
@@ -1172,7 +1178,7 @@ class ModelRestApi(
|
|
|
1172
1178
|
filter_classes=self.base_filters,
|
|
1173
1179
|
opr_filters=q.opr_filters,
|
|
1174
1180
|
opr_filter_classes=self.base_opr_filters,
|
|
1175
|
-
global_filter=(self.list_columns, q.global_filter)
|
|
1181
|
+
global_filter=(q.columns or self.list_columns, q.global_filter)
|
|
1176
1182
|
if q.global_filter
|
|
1177
1183
|
else None,
|
|
1178
1184
|
)
|
|
@@ -94,7 +94,9 @@ class ColumnsMixin:
|
|
|
94
94
|
return re.sub("[._]", " ", name).title()
|
|
95
95
|
|
|
96
96
|
def _init_filters(
|
|
97
|
-
self,
|
|
97
|
+
self,
|
|
98
|
+
datamodel: SQLAInterface,
|
|
99
|
+
filters: typing.List[typing.Tuple[str, typing.Type[BaseFilter], typing.Any]],
|
|
98
100
|
):
|
|
99
101
|
"""
|
|
100
102
|
Initialize the filter for the API.
|
|
@@ -48,9 +48,7 @@ class InfoMixin:
|
|
|
48
48
|
add_obj_schema: typing.Type[BaseModel]
|
|
49
49
|
add_jsonforms_use_enum: (
|
|
50
50
|
bool
|
|
51
|
-
| typing.Callable[
|
|
52
|
-
[ColumnInfo | ColumnEnumInfo | ColumnRelationInfo], bool
|
|
53
|
-
]
|
|
51
|
+
| typing.Callable[[ColumnInfo | ColumnEnumInfo | ColumnRelationInfo], bool]
|
|
54
52
|
| dict[
|
|
55
53
|
str,
|
|
56
54
|
bool
|
|
@@ -64,9 +62,7 @@ class InfoMixin:
|
|
|
64
62
|
edit_obj_schema: typing.Type[BaseModel]
|
|
65
63
|
edit_jsonforms_use_enum: (
|
|
66
64
|
bool
|
|
67
|
-
| typing.Callable[
|
|
68
|
-
[ColumnInfo | ColumnEnumInfo | ColumnRelationInfo], bool
|
|
69
|
-
]
|
|
65
|
+
| typing.Callable[[ColumnInfo | ColumnEnumInfo | ColumnRelationInfo], bool]
|
|
70
66
|
| dict[
|
|
71
67
|
str,
|
|
72
68
|
bool
|
|
@@ -89,9 +89,7 @@ class AccessToken(SQLAlchemyBaseAccessTokenTable[int], Model):
|
|
|
89
89
|
|
|
90
90
|
|
|
91
91
|
async def get_access_token_db(
|
|
92
|
-
session: SQLASession = Depends(
|
|
93
|
-
get_session_factory(AccessToken.__bind_key__)
|
|
94
|
-
),
|
|
92
|
+
session: SQLASession = Depends(get_session_factory(AccessToken.__bind_key__)),
|
|
95
93
|
):
|
|
96
94
|
yield SQLAlchemyAccessTokenDatabase(session, AccessToken)
|
|
97
95
|
|
|
@@ -117,7 +117,9 @@ class SQLAQueryBuilder(AbstractQueryBuilder[Select[tuple[T]]]):
|
|
|
117
117
|
col = order_column
|
|
118
118
|
|
|
119
119
|
#! If the order column comes from a request, it will be in the format ClassName.column_name
|
|
120
|
-
if col.startswith(
|
|
120
|
+
if col.startswith(
|
|
121
|
+
self.datamodel.obj.__class__.__name__
|
|
122
|
+
): # pragma: no cover - obj.__class__.__name__ is metaclass name (DeclarativeMeta), almost never matches
|
|
121
123
|
col = col.split(".", 1)[1]
|
|
122
124
|
|
|
123
125
|
statement, col = self._retrieve_column(statement, col)
|
|
@@ -430,8 +432,9 @@ class SQLAQueryBuilder(AbstractQueryBuilder[Select[tuple[T]]]):
|
|
|
430
432
|
[sub_col],
|
|
431
433
|
),
|
|
432
434
|
rules={
|
|
433
|
-
"type": lambda x1, x2:
|
|
434
|
-
|
|
435
|
+
"type": lambda x1, x2: (
|
|
436
|
+
LOAD_TYPE_MAPPING[x2] > LOAD_TYPE_MAPPING[x1]
|
|
437
|
+
)
|
|
435
438
|
},
|
|
436
439
|
)
|
|
437
440
|
|
|
@@ -22,12 +22,8 @@ class DecoratorsMixin:
|
|
|
22
22
|
# Attributes supplied by the composed ``Audit`` class via MRO.
|
|
23
23
|
models: list[typing.Type[SQLAModel]]
|
|
24
24
|
excluded_models: list[typing.Type[SQLAModel]]
|
|
25
|
-
included_properties: collections.defaultdict[
|
|
26
|
-
|
|
27
|
-
]
|
|
28
|
-
excluded_properties: collections.defaultdict[
|
|
29
|
-
typing.Type[SQLAModel], list[str]
|
|
30
|
-
]
|
|
25
|
+
included_properties: collections.defaultdict[typing.Type[SQLAModel], list[str]]
|
|
26
|
+
excluded_properties: collections.defaultdict[typing.Type[SQLAModel], list[str]]
|
|
31
27
|
mapping_insert_updates_when_no_changes: collections.defaultdict[
|
|
32
28
|
typing.Type[SQLAModel], bool | None
|
|
33
29
|
]
|
|
@@ -33,12 +33,8 @@ class ProcessingMixin:
|
|
|
33
33
|
schemas: dict[str, typing.Type[pydantic.BaseModel]]
|
|
34
34
|
models: list[typing.Type[SQLAModel]]
|
|
35
35
|
excluded_models: list[typing.Type[SQLAModel]]
|
|
36
|
-
included_properties: collections.defaultdict[
|
|
37
|
-
|
|
38
|
-
]
|
|
39
|
-
excluded_properties: collections.defaultdict[
|
|
40
|
-
typing.Type[SQLAModel], list[str]
|
|
41
|
-
]
|
|
36
|
+
included_properties: collections.defaultdict[typing.Type[SQLAModel], list[str]]
|
|
37
|
+
excluded_properties: collections.defaultdict[typing.Type[SQLAModel], list[str]]
|
|
42
38
|
mapping_insert_updates_when_no_changes: collections.defaultdict[
|
|
43
39
|
typing.Type[SQLAModel], bool | None
|
|
44
40
|
]
|
|
@@ -89,7 +89,7 @@ class MissingGreenletError(FastAPIReactToolkitException):
|
|
|
89
89
|
f"raised MissingGreenlet while pydantic accessed an attribute. "
|
|
90
90
|
f"Fix by eager-loading the missing relationship "
|
|
91
91
|
f"(`selectinload` / `joinedload`), by calling "
|
|
92
|
-
f
|
|
92
|
+
f'`await instance.load("<col>")` before the instance leaves '
|
|
93
93
|
f"the async context, or by adding the column to "
|
|
94
94
|
f"`list_columns` / `show_columns` (or the narrower "
|
|
95
95
|
f"`list_select_columns` / `show_select_columns`, or "
|
|
@@ -106,8 +106,8 @@ class MissingGreenletError(FastAPIReactToolkitException):
|
|
|
106
106
|
f"underlying relationship "
|
|
107
107
|
f"(e.g. add `selectinload({model_label}.{col})` or "
|
|
108
108
|
f"`joinedload({model_label}.{col})` to the query), by "
|
|
109
|
-
f
|
|
110
|
-
f
|
|
109
|
+
f'calling `await instance.load("{col}")` before the instance '
|
|
110
|
+
f'leaves the async context, or by adding `"{col}"` to '
|
|
111
111
|
f"`list_columns` / `show_columns` (or the narrower "
|
|
112
112
|
f"`list_select_columns` / `show_select_columns`, or "
|
|
113
113
|
f"`extra_list_fetch_columns` / `extra_show_fetch_columns` "
|
|
@@ -1098,20 +1098,18 @@ class AbstractInterface(abc.ABC, typing.Generic[T, C, CT]):
|
|
|
1098
1098
|
pass
|
|
1099
1099
|
return value
|
|
1100
1100
|
|
|
1101
|
-
schema_dict["__validators__"]["raise_on_greenlet"] = (
|
|
1102
|
-
|
|
1103
|
-
)
|
|
1101
|
+
schema_dict["__validators__"]["raise_on_greenlet"] = pydantic.model_validator(
|
|
1102
|
+
mode="before"
|
|
1103
|
+
)(classmethod(raise_on_greenlet))
|
|
1104
1104
|
|
|
1105
1105
|
if async_columns:
|
|
1106
|
-
|
|
1107
1106
|
interface_self = self
|
|
1108
1107
|
|
|
1109
1108
|
def populate_async_columns(self):
|
|
1110
1109
|
for col in async_columns:
|
|
1111
1110
|
AsyncTaskRunner.add_task(
|
|
1112
|
-
lambda col=col,
|
|
1113
|
-
|
|
1114
|
-
self, col
|
|
1111
|
+
lambda col=col, interface_self=interface_self: (
|
|
1112
|
+
interface_self._populate_async_column(self, col)
|
|
1115
1113
|
)
|
|
1116
1114
|
)
|
|
1117
1115
|
return self
|
|
@@ -548,7 +548,9 @@ async def promote(
|
|
|
548
548
|
|
|
549
549
|
sm = g.current_app.sm
|
|
550
550
|
async with db.session() as session:
|
|
551
|
-
user = await sm.get_user(
|
|
551
|
+
user = await sm.get_user(
|
|
552
|
+
email_or_username, session=session, raise_exception=True
|
|
553
|
+
)
|
|
552
554
|
current = [r.name for r in user.roles]
|
|
553
555
|
if g.admin_role in current:
|
|
554
556
|
typer.echo(f"User {user.username} already has role {g.admin_role}.")
|
|
@@ -577,7 +579,9 @@ async def demote(
|
|
|
577
579
|
|
|
578
580
|
sm = g.current_app.sm
|
|
579
581
|
async with db.session() as session:
|
|
580
|
-
user = await sm.get_user(
|
|
582
|
+
user = await sm.get_user(
|
|
583
|
+
email_or_username, session=session, raise_exception=True
|
|
584
|
+
)
|
|
581
585
|
current = [r.name for r in user.roles]
|
|
582
586
|
if g.admin_role not in current:
|
|
583
587
|
typer.echo(f"User {user.username} does not have role {g.admin_role}.")
|
|
@@ -801,9 +805,7 @@ async def rename_role(
|
|
|
801
805
|
old_name: Annotated[
|
|
802
806
|
str, typer.Option(..., help="The current name of the role.")
|
|
803
807
|
] = "",
|
|
804
|
-
new_name: Annotated[
|
|
805
|
-
str, typer.Option(..., help="The new name for the role.")
|
|
806
|
-
] = "",
|
|
808
|
+
new_name: Annotated[str, typer.Option(..., help="The new name for the role.")] = "",
|
|
807
809
|
):
|
|
808
810
|
"""
|
|
809
811
|
Rename a role. The members of the role are preserved.
|
|
@@ -818,9 +820,12 @@ async def rename_role(
|
|
|
818
820
|
|
|
819
821
|
sm = g.current_app.sm
|
|
820
822
|
async with db.session() as session:
|
|
821
|
-
existing =
|
|
822
|
-
|
|
823
|
-
|
|
823
|
+
existing = (
|
|
824
|
+
await sm.get_roles(
|
|
825
|
+
[old_name, new_name], session=session, raise_exception=False
|
|
826
|
+
)
|
|
827
|
+
or []
|
|
828
|
+
)
|
|
824
829
|
by_name = {r.name: r for r in existing}
|
|
825
830
|
if old_name not in by_name:
|
|
826
831
|
raise typer.BadParameter(f"Role {old_name!r} does not exist.")
|
|
@@ -951,9 +956,7 @@ async def list_permissions(
|
|
|
951
956
|
roles = await sm.get_roles([role], session=session, raise_exception=False)
|
|
952
957
|
if not roles:
|
|
953
958
|
raise typer.BadParameter(f"Role {role!r} does not exist.")
|
|
954
|
-
filters.append(
|
|
955
|
-
{"col": "roles", "opr": "rel_m_m", "value": [roles[0].id]}
|
|
956
|
-
)
|
|
959
|
+
filters.append({"col": "roles", "opr": "rel_m_m", "value": [roles[0].id]})
|
|
957
960
|
if api:
|
|
958
961
|
filters.append({"col": "api.name", "opr": "eq", "value": api})
|
|
959
962
|
if filters:
|
|
@@ -196,28 +196,18 @@ class DatabaseSessionManager:
|
|
|
196
196
|
"""
|
|
197
197
|
|
|
198
198
|
_engine: SQLAEngine | None = None
|
|
199
|
-
_sessionmaker: SQLASessionMaker | None =
|
|
200
|
-
None
|
|
201
|
-
)
|
|
199
|
+
_sessionmaker: SQLASessionMaker | None = None
|
|
202
200
|
_engine_binds: dict[str, SQLAEngine] = None
|
|
203
|
-
_sessionmaker_binds: dict[
|
|
204
|
-
|
|
205
|
-
] = None
|
|
206
|
-
_scoped_session_maker: (
|
|
207
|
-
SQLAScopedSession | None
|
|
208
|
-
) = None
|
|
209
|
-
_scoped_session_maker_binds: dict[
|
|
210
|
-
str, SQLAScopedSession
|
|
211
|
-
] = None
|
|
201
|
+
_sessionmaker_binds: dict[str, SQLASessionMaker] = None
|
|
202
|
+
_scoped_session_maker: SQLAScopedSession | None = None
|
|
203
|
+
_scoped_session_maker_binds: dict[str, SQLAScopedSession] = None
|
|
212
204
|
_scoped_session: SQLASession | None = None
|
|
213
205
|
_scoped_session_binds: dict[str, SQLASession] = None
|
|
214
206
|
|
|
215
207
|
_session_context = contextvars.ContextVar[SQLASession](
|
|
216
208
|
"DatabaseSessionManager:current_session"
|
|
217
209
|
)
|
|
218
|
-
_sessions_context = smartdefaultdict[
|
|
219
|
-
str, contextvars.ContextVar[SQLASession]
|
|
220
|
-
](
|
|
210
|
+
_sessions_context = smartdefaultdict[str, contextvars.ContextVar[SQLASession]](
|
|
221
211
|
lambda key: contextvars.ContextVar[SQLASession](
|
|
222
212
|
f"DatabaseSessionManager:current_session:{key}"
|
|
223
213
|
)
|
|
@@ -295,7 +285,9 @@ class DatabaseSessionManager:
|
|
|
295
285
|
copy_metadata = MetaData()
|
|
296
286
|
for table_name in FASTAPI_RTK_TABLES:
|
|
297
287
|
table = metadata.tables.get(table_name)
|
|
298
|
-
if
|
|
288
|
+
if (
|
|
289
|
+
table is None
|
|
290
|
+
): # pragma: no cover - defensive; FASTAPI_RTK_TABLES are always registered
|
|
299
291
|
continue
|
|
300
292
|
table.to_metadata(copy_metadata)
|
|
301
293
|
await self._create_all(conn, copy_metadata)
|
|
@@ -571,9 +563,7 @@ class DatabaseSessionManager:
|
|
|
571
563
|
expire_on_commit=False,
|
|
572
564
|
)
|
|
573
565
|
|
|
574
|
-
def _init_scoped_session(
|
|
575
|
-
self, sessionmaker: SQLASessionMaker
|
|
576
|
-
):
|
|
566
|
+
def _init_scoped_session(self, sessionmaker: SQLASessionMaker):
|
|
577
567
|
"""
|
|
578
568
|
Initializes the scoped session.
|
|
579
569
|
|
|
@@ -338,7 +338,9 @@ def relationship_filter(attr: str | _RelationshipDeclared):
|
|
|
338
338
|
if isinstance(attr, _RelationshipDeclared):
|
|
339
339
|
caller_locals = inspect.currentframe().f_back.f_locals
|
|
340
340
|
caller_locals = {k: v for k, v in caller_locals.items() if v is attr}
|
|
341
|
-
if
|
|
341
|
+
if (
|
|
342
|
+
not caller_locals
|
|
343
|
+
): # pragma: no cover - requires impossible caller stack inspection
|
|
342
344
|
raise Exception(
|
|
343
345
|
"relationship_filter decorator could not find the attribute for the relationship."
|
|
344
346
|
)
|
|
@@ -26,7 +26,9 @@ from .setting import Setting
|
|
|
26
26
|
from .utils import T, call_with_valid_kwargs, lazy_self, safe_call
|
|
27
27
|
|
|
28
28
|
if typing.TYPE_CHECKING:
|
|
29
|
-
from .security.sqla.security_manager import
|
|
29
|
+
from .security.sqla.security_manager import (
|
|
30
|
+
SecurityManager, # noqa: F401 # forward-ref target for `lazy`
|
|
31
|
+
)
|
|
30
32
|
|
|
31
33
|
__all__ = ["UserManager"]
|
|
32
34
|
|
|
@@ -434,7 +434,9 @@ class QuerySchema(BaseModel):
|
|
|
434
434
|
translate("Invalid columns: Not a valid JSON string"),
|
|
435
435
|
input=v,
|
|
436
436
|
)
|
|
437
|
-
except
|
|
437
|
+
except (
|
|
438
|
+
ValidationError
|
|
439
|
+
) as e: # pragma: no cover - defensive; str() cast can't raise ValidationError
|
|
438
440
|
raise HTTPWithValidationException(
|
|
439
441
|
fastapi.status.HTTP_400_BAD_REQUEST,
|
|
440
442
|
"literal_error",
|
|
@@ -527,7 +529,9 @@ class QuerySchema(BaseModel):
|
|
|
527
529
|
)
|
|
528
530
|
new_filters = []
|
|
529
531
|
for index, filter in enumerate(filters):
|
|
530
|
-
if isinstance(
|
|
532
|
+
if isinstance(
|
|
533
|
+
filter, OprFilterSchema
|
|
534
|
+
): # pragma: no cover - QuerySchema.opr_filters is str-typed; pre-built schema instances unreachable
|
|
531
535
|
new_filters.append(filter)
|
|
532
536
|
elif isinstance(filter, dict):
|
|
533
537
|
new_filters.append(OprFilterSchema(**filter))
|
|
@@ -3,6 +3,7 @@ from typing import List
|
|
|
3
3
|
import sqlalchemy
|
|
4
4
|
from fastapi import Depends, HTTPException, Request, status
|
|
5
5
|
from pydantic import BaseModel, EmailStr, Field
|
|
6
|
+
|
|
6
7
|
from ...api import BaseApi, ModelRestApi
|
|
7
8
|
from ...backends.sqla.interface import SQLAInterface
|
|
8
9
|
from ...backends.sqla.session import SQLASession
|
{fastapi_rtk-2.1.2 → fastapi_rtk-2.1.4}/fastapi_rtk/security/sqla/security_manager/_user_mixin.py
RENAMED
|
@@ -8,11 +8,13 @@ from pydantic import BaseModel
|
|
|
8
8
|
from ....backends.sqla.session import SQLASession
|
|
9
9
|
from ....db import UserDatabase, db
|
|
10
10
|
from ....globals import g
|
|
11
|
+
from ..models import Role, User
|
|
11
12
|
from ._exception_filters import (
|
|
12
13
|
SecurityExceptionFilter,
|
|
14
|
+
)
|
|
15
|
+
from ._exception_filters import (
|
|
13
16
|
should_reraise as _should_reraise,
|
|
14
17
|
)
|
|
15
|
-
from ..models import Role, User
|
|
16
18
|
|
|
17
19
|
__all__ = ["UserMixin"]
|
|
18
20
|
|
|
@@ -13,7 +13,6 @@ import json
|
|
|
13
13
|
import types
|
|
14
14
|
|
|
15
15
|
import pytest
|
|
16
|
-
|
|
17
16
|
from fastapi_rtk.schemas import GeneralResponse
|
|
18
17
|
|
|
19
18
|
pytestmark = pytest.mark.asyncio
|
|
@@ -585,6 +584,31 @@ class TestListWithFilters:
|
|
|
585
584
|
names = [r["name"] for r in body["result"]]
|
|
586
585
|
assert "Beta" in names
|
|
587
586
|
|
|
587
|
+
async def test_list_global_filter_spans_only_shown_columns(
|
|
588
|
+
self, client, admin_token, seeded_widgets
|
|
589
|
+
):
|
|
590
|
+
# "second" is the description of the Beta widget. With only `name`
|
|
591
|
+
# shown, global search must not match it; once `description` is shown
|
|
592
|
+
# it must. Proves the search span follows the columns query param.
|
|
593
|
+
hidden = await client.get(
|
|
594
|
+
"/api/v1/widgets/",
|
|
595
|
+
params={"columns": json.dumps(["name"]), "global_filter": "second"},
|
|
596
|
+
headers={"Authorization": f"Bearer {admin_token}"},
|
|
597
|
+
)
|
|
598
|
+
assert hidden.status_code == 200
|
|
599
|
+
assert [r["name"] for r in hidden.json()["result"]] == []
|
|
600
|
+
|
|
601
|
+
shown = await client.get(
|
|
602
|
+
"/api/v1/widgets/",
|
|
603
|
+
params={
|
|
604
|
+
"columns": json.dumps(["name", "description"]),
|
|
605
|
+
"global_filter": "second",
|
|
606
|
+
},
|
|
607
|
+
headers={"Authorization": f"Bearer {admin_token}"},
|
|
608
|
+
)
|
|
609
|
+
assert shown.status_code == 200
|
|
610
|
+
assert "Beta" in [r["name"] for r in shown.json()["result"]]
|
|
611
|
+
|
|
588
612
|
async def test_list_invalid_column_raises_400(
|
|
589
613
|
self, client, admin_token, seeded_widgets
|
|
590
614
|
):
|
|
@@ -650,9 +674,8 @@ class TestBulk:
|
|
|
650
674
|
self, client, admin_token, widgets_api, seeded_widgets
|
|
651
675
|
):
|
|
652
676
|
async def bulk_count(self, body, query, session):
|
|
653
|
-
from sqlalchemy import func, select
|
|
654
|
-
|
|
655
677
|
from fastapi_rtk.utils import smart_run
|
|
678
|
+
from sqlalchemy import func, select
|
|
656
679
|
|
|
657
680
|
stmt = select(func.count()).select_from(query.obj)
|
|
658
681
|
result = await smart_run(session.scalar, stmt)
|
|
@@ -845,9 +868,7 @@ class TestPreDeleteModelSwap:
|
|
|
845
868
|
class TestPostDeleteModelSwap:
|
|
846
869
|
"""post_delete returning a Model swaps the response item."""
|
|
847
870
|
|
|
848
|
-
async def test_post_delete_returns_model(
|
|
849
|
-
self, client, admin_token, widgets_api
|
|
850
|
-
):
|
|
871
|
+
async def test_post_delete_returns_model(self, client, admin_token, widgets_api):
|
|
851
872
|
post = await client.post(
|
|
852
873
|
"/api/v1/widgets/",
|
|
853
874
|
headers={"Authorization": f"Bearer {admin_token}"},
|
|
@@ -84,9 +84,7 @@ class TestRelationsInInfo:
|
|
|
84
84
|
add_cols = [c["name"] for c in body["add_columns"]]
|
|
85
85
|
assert "country" in add_cols or "country_id" in add_cols
|
|
86
86
|
|
|
87
|
-
async def test_post_widget_with_country_relation(
|
|
88
|
-
self, client, admin_token
|
|
89
|
-
):
|
|
87
|
+
async def test_post_widget_with_country_relation(self, client, admin_token):
|
|
90
88
|
# Create a country first.
|
|
91
89
|
country_resp = await client.post(
|
|
92
90
|
"/api/v1/countries/",
|