fastapi-rtk 1.0.5__tar.gz → 1.0.6__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-1.0.5 → fastapi_rtk-1.0.6}/PKG-INFO +1 -1
- fastapi_rtk-1.0.6/fastapi_rtk/_version.py +1 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/backends/sqla/interface.py +0 -54
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/backends/sqla/model.py +14 -1
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/utils/async_task_runner.py +115 -29
- fastapi_rtk-1.0.5/fastapi_rtk/_version.py +0 -1
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/.gitignore +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/LICENSE +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/README.md +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/__init__.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/api/__init__.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/api/base_api.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/api/model_rest_api.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/apis.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/auth/__init__.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/auth/auth.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/auth/hashers/__init__.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/auth/hashers/pbkdf2.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/auth/hashers/scrypt.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/auth/hashers/utils.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/auth/password_helpers/__init__.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/auth/password_helpers/fab.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/auth/strategies/__init__.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/auth/strategies/config.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/auth/strategies/db.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/auth/strategies/jwt.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/backends/__init__.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/backends/generic/__init__.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/backends/generic/column.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/backends/generic/db.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/backends/generic/exceptions.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/backends/generic/filters.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/backends/generic/interface.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/backends/generic/model.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/backends/generic/session.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/backends/sqla/__init__.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/backends/sqla/column.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/backends/sqla/db.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/backends/sqla/exceptions.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/backends/sqla/extensions/__init__.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/backends/sqla/extensions/audit/__init__.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/backends/sqla/extensions/audit/audit.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/backends/sqla/extensions/audit/types.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/backends/sqla/extensions/geoalchemy2/__init__.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/backends/sqla/extensions/geoalchemy2/filters.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/backends/sqla/extensions/geoalchemy2/geometry_converter.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/backends/sqla/filters.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/backends/sqla/session.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/bases/__init__.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/bases/db.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/bases/file_manager.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/bases/filter.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/bases/interface.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/bases/model.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/bases/session.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/cli/__init__.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/cli/cli.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/cli/commands/__init__.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/cli/commands/db/__init__.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/cli/commands/db/templates/fastapi/README +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/cli/commands/db/templates/fastapi/alembic.ini.mako +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/cli/commands/db/templates/fastapi/env.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/cli/commands/db/templates/fastapi/script.py.mako +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/cli/commands/db/templates/fastapi-multidb/README +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/cli/commands/db/templates/fastapi-multidb/alembic.ini.mako +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/cli/commands/db/templates/fastapi-multidb/env.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/cli/commands/db/templates/fastapi-multidb/script.py.mako +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/cli/commands/export.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/cli/commands/security.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/cli/commands/translate.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/cli/const.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/cli/decorators.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/cli/types.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/cli/utils.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/config.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/const.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/db.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/decorators.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/dependencies.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/exceptions.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/fastapi_react_toolkit.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/file_managers/__init__.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/file_managers/file_manager.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/file_managers/image_manager.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/file_managers/s3_file_manager.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/file_managers/s3_image_manager.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/filters.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/globals.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/lang/__init__.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/lang/babel/__init__.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/lang/babel/cli.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/lang/babel/config.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/lang/babel.cfg +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/lang/lazy_text.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/lang/messages.pot +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/lang/translations/de/LC_MESSAGES/messages.mo +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/lang/translations/de/LC_MESSAGES/messages.po +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/lang/translations/en/LC_MESSAGES/messages.mo +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/lang/translations/en/LC_MESSAGES/messages.po +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/manager.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/middlewares.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/mixins.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/models.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/routers.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/schemas.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/security/__init__.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/security/sqla/__init__.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/security/sqla/apis.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/security/sqla/models.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/security/sqla/security_manager.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/setting.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/types.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/utils/__init__.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/utils/class_factory.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/utils/csv_json_converter.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/utils/deep_merge.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/utils/extender_mixin.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/utils/flask_appbuilder_utils.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/utils/hooks.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/utils/lazy.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/utils/merge_schema.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/utils/multiple_async_contexts.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/utils/prettify_dict.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/utils/pydantic.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/utils/run_utils.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/utils/self_dependencies.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/utils/smartdefaultdict.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/utils/sqla.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/utils/timezone.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/utils/update_signature.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/utils/use_default_when_none.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/utils/werkzeug.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/version.py +0 -0
- {fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/pyproject.toml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fastapi-rtk
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.6
|
|
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__ = "1.0.6"
|
|
@@ -7,9 +7,7 @@ from typing import Annotated, Literal, Type
|
|
|
7
7
|
|
|
8
8
|
import fastapi
|
|
9
9
|
import marshmallow_sqlalchemy
|
|
10
|
-
import pydantic
|
|
11
10
|
import sqlalchemy
|
|
12
|
-
import sqlalchemy.exc
|
|
13
11
|
from pydantic import (
|
|
14
12
|
AfterValidator,
|
|
15
13
|
BeforeValidator,
|
|
@@ -45,7 +43,6 @@ from ...utils import (
|
|
|
45
43
|
lazy_import,
|
|
46
44
|
lazy_self,
|
|
47
45
|
safe_call,
|
|
48
|
-
safe_call_sync,
|
|
49
46
|
smart_run,
|
|
50
47
|
)
|
|
51
48
|
from .db import SQLAQueryBuilder
|
|
@@ -682,57 +679,6 @@ class SQLAInterface(AbstractInterface[ModelType, Session | AsyncSession, Column]
|
|
|
682
679
|
|
|
683
680
|
return result
|
|
684
681
|
|
|
685
|
-
def _generate_schema_from_dict(self, schema_dict):
|
|
686
|
-
# Allow await for deferrable columns
|
|
687
|
-
deferrable_columns = [
|
|
688
|
-
key for key in schema_dict.keys() if key in self.list_properties
|
|
689
|
-
]
|
|
690
|
-
model_name = schema_dict.get("__name__", "UnknownModel")
|
|
691
|
-
if deferrable_columns:
|
|
692
|
-
|
|
693
|
-
async def fill_deferrable(model: Model, col: str):
|
|
694
|
-
try:
|
|
695
|
-
return getattr(model, col)
|
|
696
|
-
except sqlalchemy.exc.MissingGreenlet:
|
|
697
|
-
logger.warning(
|
|
698
|
-
f"'MissingGreenlet' error when accessing {model.__class__.__name__}.{col} to create pydantic model {model_name}, trying to await it instead."
|
|
699
|
-
)
|
|
700
|
-
try:
|
|
701
|
-
await getattr(model.awaitable_attrs, col)
|
|
702
|
-
except Exception as e:
|
|
703
|
-
return_value = (
|
|
704
|
-
[]
|
|
705
|
-
if self.is_relation_one_to_many(col)
|
|
706
|
-
or self.is_relation_many_to_many(col)
|
|
707
|
-
else None
|
|
708
|
-
)
|
|
709
|
-
logger.error(
|
|
710
|
-
f"Error when awaiting {model.__class__.__name__}.{col} to create pydantic model {model_name}, returning {return_value} instead: {e}"
|
|
711
|
-
)
|
|
712
|
-
return return_value
|
|
713
|
-
return getattr(model, col)
|
|
714
|
-
|
|
715
|
-
async def fill_deferables(data: Model):
|
|
716
|
-
async with AsyncTaskRunner():
|
|
717
|
-
for col in deferrable_columns:
|
|
718
|
-
AsyncTaskRunner.add_task(
|
|
719
|
-
lambda col=col: fill_deferrable(data, col)
|
|
720
|
-
)
|
|
721
|
-
|
|
722
|
-
def fill_deferrables_validator(data):
|
|
723
|
-
if isinstance(data, Model):
|
|
724
|
-
safe_call_sync(fill_deferables(data))
|
|
725
|
-
return data
|
|
726
|
-
|
|
727
|
-
decorated_func = pydantic.model_validator(mode="before")(
|
|
728
|
-
fill_deferrables_validator
|
|
729
|
-
)
|
|
730
|
-
schema_dict["__validators__"] = schema_dict.get("__validators__", {})
|
|
731
|
-
schema_dict["__validators__"][fill_deferrables_validator.__name__] = (
|
|
732
|
-
decorated_func
|
|
733
|
-
)
|
|
734
|
-
return super()._generate_schema_from_dict(schema_dict)
|
|
735
|
-
|
|
736
682
|
"""
|
|
737
683
|
--------------------------------------------------------------------------------------------------------
|
|
738
684
|
SQLA RELATED METHODS - ONLY IN SQLAInterface
|
|
@@ -13,7 +13,7 @@ from sqlalchemy.util.typing import Literal
|
|
|
13
13
|
from ...bases.model import BasicModel
|
|
14
14
|
from ...const import DEFAULT_METADATA_KEY
|
|
15
15
|
from ...exceptions import FastAPIReactToolkitException
|
|
16
|
-
from ...utils import smart_run_sync
|
|
16
|
+
from ...utils import AsyncTaskRunner, smart_run_sync
|
|
17
17
|
|
|
18
18
|
__all__ = ["Model", "metadata", "metadatas", "Base"]
|
|
19
19
|
|
|
@@ -125,6 +125,19 @@ class Model(sqlalchemy.ext.asyncio.AsyncAttrs, BasicModel, DeclarativeBase):
|
|
|
125
125
|
def get_pk_attrs(cls):
|
|
126
126
|
return [col.name for col in cls.__mapper__.primary_key]
|
|
127
127
|
|
|
128
|
+
async def load(self, cols: list[str] | str):
|
|
129
|
+
"""
|
|
130
|
+
Asynchronously load the specified columns for the current instance.
|
|
131
|
+
|
|
132
|
+
Args:
|
|
133
|
+
cols (list[str] | str): A list of column names to load or a single column name.
|
|
134
|
+
"""
|
|
135
|
+
async with AsyncTaskRunner() as runner:
|
|
136
|
+
if isinstance(cols, str):
|
|
137
|
+
cols = [cols]
|
|
138
|
+
for col in cols:
|
|
139
|
+
runner.add_task(getattr(self.awaitable_attrs, col))
|
|
140
|
+
|
|
128
141
|
|
|
129
142
|
class Table(SA_Table):
|
|
130
143
|
"""
|
|
@@ -9,6 +9,8 @@ from .prettify_dict import prettify_dict
|
|
|
9
9
|
|
|
10
10
|
__all__ = ["AsyncTaskRunner"]
|
|
11
11
|
|
|
12
|
+
T = typing.TypeVar("T")
|
|
13
|
+
|
|
12
14
|
|
|
13
15
|
class CallerInfo(typing.TypedDict):
|
|
14
16
|
"""
|
|
@@ -36,26 +38,37 @@ class AsyncTaskException(AsyncTaskRunnerException):
|
|
|
36
38
|
self.caller = caller
|
|
37
39
|
|
|
38
40
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
except Exception as e:
|
|
53
|
-
raise AsyncTaskException(str(e), original_exception=e, caller=caller) from e
|
|
41
|
+
class ResultAccessor(typing.Generic[T]):
|
|
42
|
+
"""Helper class that can be awaited OR accessed directly."""
|
|
43
|
+
|
|
44
|
+
def __init__(self, task: "AsyncTask[T]"):
|
|
45
|
+
self._task = task
|
|
46
|
+
|
|
47
|
+
def __await__(self):
|
|
48
|
+
"""Allow awaiting: await task.result"""
|
|
49
|
+
return self._task.__await__()
|
|
50
|
+
|
|
51
|
+
def __repr__(self) -> str:
|
|
52
|
+
"""Direct access without await - returns value or raises error."""
|
|
53
|
+
return repr(self._ensure_result())
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
def __str__(self) -> str:
|
|
56
|
+
"""Direct access without await - returns value or raises error."""
|
|
57
|
+
return str(self._ensure_result())
|
|
56
58
|
|
|
59
|
+
# Make it behave like the actual value when accessed
|
|
60
|
+
def __getattr__(self, name):
|
|
61
|
+
return getattr(self._ensure_result(), name)
|
|
57
62
|
|
|
58
|
-
|
|
63
|
+
def _ensure_result(self):
|
|
64
|
+
if not hasattr(self._task, "_result"):
|
|
65
|
+
raise RuntimeError(
|
|
66
|
+
"Task has not been executed yet. Await the task to get the result."
|
|
67
|
+
)
|
|
68
|
+
return self._task._result
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class AsyncTask(typing.Generic[T]):
|
|
59
72
|
"""
|
|
60
73
|
Represents a task to be run asynchronously.
|
|
61
74
|
|
|
@@ -64,19 +77,51 @@ class AsyncTask:
|
|
|
64
77
|
|
|
65
78
|
def __init__(
|
|
66
79
|
self,
|
|
67
|
-
task: typing.Callable[
|
|
80
|
+
task: typing.Callable[..., typing.Awaitable[T]] | typing.Awaitable[T],
|
|
68
81
|
/,
|
|
69
82
|
caller: CallerInfo | None = None,
|
|
70
83
|
tags: list[str] | None = None,
|
|
71
84
|
):
|
|
72
|
-
self.task =
|
|
85
|
+
self.task = task
|
|
73
86
|
self.caller = caller
|
|
74
87
|
self.tags = tags or []
|
|
75
88
|
|
|
89
|
+
@property
|
|
90
|
+
def result(self):
|
|
91
|
+
"""
|
|
92
|
+
Provides access to the result of the task.
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
ResultAccessor[T]: An accessor that can be awaited or accessed directly.
|
|
96
|
+
"""
|
|
97
|
+
return ResultAccessor(self)
|
|
98
|
+
|
|
76
99
|
def __call__(self):
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
100
|
+
return self._run()
|
|
101
|
+
|
|
102
|
+
def __await__(self):
|
|
103
|
+
return self._run().__await__()
|
|
104
|
+
|
|
105
|
+
async def _run(self):
|
|
106
|
+
"""
|
|
107
|
+
Runs the task and caches the result.
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
T: The result of the task.
|
|
111
|
+
"""
|
|
112
|
+
if hasattr(self, "_result"):
|
|
113
|
+
return self._result
|
|
114
|
+
|
|
115
|
+
try:
|
|
116
|
+
coro = self.task
|
|
117
|
+
if callable(coro):
|
|
118
|
+
coro = coro()
|
|
119
|
+
self._result = await coro
|
|
120
|
+
return self._result
|
|
121
|
+
except Exception as e:
|
|
122
|
+
raise AsyncTaskException(
|
|
123
|
+
str(e), original_exception=e, caller=self.caller
|
|
124
|
+
) from e
|
|
80
125
|
|
|
81
126
|
|
|
82
127
|
class AsyncTaskRunner:
|
|
@@ -144,19 +189,59 @@ class AsyncTaskRunner:
|
|
|
144
189
|
"""
|
|
145
190
|
self.run_tasks_even_if_exception = run_tasks_even_if_exception
|
|
146
191
|
|
|
192
|
+
@typing.overload
|
|
147
193
|
@classmethod
|
|
148
194
|
def add_task(
|
|
149
195
|
cls,
|
|
150
|
-
|
|
196
|
+
task: typing.Callable[..., typing.Awaitable[T]]
|
|
197
|
+
| typing.Awaitable[T]
|
|
198
|
+
| AsyncTask[T],
|
|
199
|
+
*,
|
|
200
|
+
tags: list[str] | None = None,
|
|
201
|
+
instance: "AsyncTaskRunner | None" = None,
|
|
202
|
+
) -> AsyncTask[T]: ...
|
|
203
|
+
|
|
204
|
+
@typing.overload
|
|
205
|
+
@classmethod
|
|
206
|
+
def add_task(
|
|
207
|
+
cls,
|
|
208
|
+
task1: typing.Callable[..., typing.Awaitable[T]]
|
|
209
|
+
| typing.Awaitable[T]
|
|
210
|
+
| AsyncTask[T],
|
|
211
|
+
task2: typing.Callable[..., typing.Awaitable[T]]
|
|
212
|
+
| typing.Awaitable[T]
|
|
213
|
+
| AsyncTask[T],
|
|
214
|
+
*tasks: typing.Callable[..., typing.Awaitable[T]]
|
|
215
|
+
| typing.Awaitable[T]
|
|
216
|
+
| AsyncTask[T],
|
|
217
|
+
tags: list[str] | None = None,
|
|
218
|
+
instance: "AsyncTaskRunner | None" = None,
|
|
219
|
+
) -> list[AsyncTask[T]]: ...
|
|
220
|
+
@classmethod
|
|
221
|
+
def add_task(
|
|
222
|
+
cls,
|
|
223
|
+
*tasks: typing.Callable[..., typing.Awaitable[T]]
|
|
224
|
+
| typing.Awaitable[T]
|
|
225
|
+
| AsyncTask[T],
|
|
151
226
|
tags: list[str] | None = None,
|
|
152
227
|
instance: "AsyncTaskRunner | None" = None,
|
|
153
228
|
):
|
|
229
|
+
"""
|
|
230
|
+
Adds one or more tasks to the current context's task list. The tasks will be executed when exiting the context.
|
|
231
|
+
|
|
232
|
+
Args:
|
|
233
|
+
tags (list[str] | None, optional): Tags to associate with the tasks. Defaults to None.
|
|
234
|
+
instance (AsyncTaskRunner | None, optional): The AsyncTaskRunner instance to add tasks to. Defaults to None.
|
|
235
|
+
|
|
236
|
+
Returns:
|
|
237
|
+
AsyncTask[T] | list[AsyncTask[T]]: The added task(s).
|
|
238
|
+
"""
|
|
154
239
|
task_list = cls._get_current_task_list("add_task", instance=instance)
|
|
155
240
|
# Get caller info
|
|
156
241
|
frame = inspect.currentframe()
|
|
157
242
|
caller = inspect.getouterframes(frame, 2)[1] if frame else None
|
|
158
243
|
|
|
159
|
-
async_tasks = [
|
|
244
|
+
async_tasks: list[AsyncTask[T]] = [
|
|
160
245
|
AsyncTask(
|
|
161
246
|
task,
|
|
162
247
|
caller=CallerInfo(
|
|
@@ -171,6 +256,7 @@ class AsyncTaskRunner:
|
|
|
171
256
|
for task in tasks
|
|
172
257
|
]
|
|
173
258
|
task_list.extend(async_tasks)
|
|
259
|
+
return async_tasks if len(async_tasks) > 1 else async_tasks[0]
|
|
174
260
|
|
|
175
261
|
@classmethod
|
|
176
262
|
def remove_tasks_by_tag(
|
|
@@ -215,16 +301,16 @@ class AsyncTaskRunner:
|
|
|
215
301
|
return
|
|
216
302
|
|
|
217
303
|
if tasks:
|
|
218
|
-
|
|
304
|
+
exceptions_with_index = list[tuple[AsyncTaskException, int]]()
|
|
219
305
|
futures = await asyncio.gather(
|
|
220
306
|
*(task() for task in tasks), return_exceptions=True
|
|
221
307
|
)
|
|
222
|
-
for future in futures:
|
|
308
|
+
for index, future in enumerate(futures):
|
|
223
309
|
if isinstance(future, AsyncTaskException):
|
|
224
310
|
# Handle exceptions from tasks
|
|
225
|
-
|
|
311
|
+
exceptions_with_index.append((future, index))
|
|
226
312
|
|
|
227
|
-
if
|
|
313
|
+
if exceptions_with_index:
|
|
228
314
|
raise AsyncTaskRunnerException(
|
|
229
315
|
f"\n{
|
|
230
316
|
prettify_dict(
|
|
@@ -238,7 +324,7 @@ class AsyncTaskRunner:
|
|
|
238
324
|
tb.format_exception(exc.original_exception)
|
|
239
325
|
),
|
|
240
326
|
}
|
|
241
|
-
for
|
|
327
|
+
for exc, index in exceptions_with_index
|
|
242
328
|
},
|
|
243
329
|
}
|
|
244
330
|
)
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "1.0.5"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/backends/sqla/extensions/audit/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/backends/sqla/extensions/geoalchemy2/__init__.py
RENAMED
|
File without changes
|
{fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/backends/sqla/extensions/geoalchemy2/filters.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/cli/commands/db/templates/fastapi/README
RENAMED
|
File without changes
|
|
File without changes
|
{fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/cli/commands/db/templates/fastapi/env.py
RENAMED
|
File without changes
|
{fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/cli/commands/db/templates/fastapi/script.py.mako
RENAMED
|
File without changes
|
{fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/cli/commands/db/templates/fastapi-multidb/README
RENAMED
|
File without changes
|
|
File without changes
|
{fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/cli/commands/db/templates/fastapi-multidb/env.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/lang/translations/de/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/lang/translations/de/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/lang/translations/en/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{fastapi_rtk-1.0.5 → fastapi_rtk-1.0.6}/fastapi_rtk/lang/translations/en/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|