amsdal 0.5.34__cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- amsdal/Third-Party Materials - AMSDAL Dependencies - License Notices.md +1362 -0
- amsdal/__about__.py +4 -0
- amsdal/__about__.pyi +1 -0
- amsdal/__init__.py +23 -0
- amsdal/__init__.pyi +9 -0
- amsdal/__migrations__/0000_initial.py +36 -0
- amsdal/__migrations__/0001_create_class_file.py +61 -0
- amsdal/__migrations__/0002_create_class_file.py +109 -0
- amsdal/__migrations__/0003_update_class_file.py +91 -0
- amsdal/__migrations__/0004_update_class_file.py +45 -0
- amsdal/cloud/__init__.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/__init__.pyi +0 -0
- amsdal/cloud/client.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/client.pyi +57 -0
- amsdal/cloud/constants.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/constants.pyi +13 -0
- amsdal/cloud/enums.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/enums.pyi +68 -0
- amsdal/cloud/models/__init__.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/models/__init__.pyi +0 -0
- amsdal/cloud/models/base.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/models/base.pyi +247 -0
- amsdal/cloud/services/__init__.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/__init__.pyi +0 -0
- amsdal/cloud/services/actions/__init__.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/__init__.pyi +0 -0
- amsdal/cloud/services/actions/add_allowlist_ip.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/add_allowlist_ip.pyi +19 -0
- amsdal/cloud/services/actions/add_basic_auth.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/add_basic_auth.pyi +21 -0
- amsdal/cloud/services/actions/add_dependency.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/add_dependency.pyi +19 -0
- amsdal/cloud/services/actions/add_secret.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/add_secret.pyi +20 -0
- amsdal/cloud/services/actions/base.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/base.pyi +122 -0
- amsdal/cloud/services/actions/create_deploy.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/create_deploy.pyi +41 -0
- amsdal/cloud/services/actions/create_env.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/create_env.pyi +19 -0
- amsdal/cloud/services/actions/create_session.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/create_session.pyi +17 -0
- amsdal/cloud/services/actions/delete_allowlist_ip.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/delete_allowlist_ip.pyi +19 -0
- amsdal/cloud/services/actions/delete_basic_auth.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/delete_basic_auth.pyi +20 -0
- amsdal/cloud/services/actions/delete_dependency.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/delete_dependency.pyi +21 -0
- amsdal/cloud/services/actions/delete_env.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/delete_env.pyi +21 -0
- amsdal/cloud/services/actions/delete_secret.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/delete_secret.pyi +21 -0
- amsdal/cloud/services/actions/destroy_deploy.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/destroy_deploy.pyi +18 -0
- amsdal/cloud/services/actions/expose_db.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/expose_db.pyi +22 -0
- amsdal/cloud/services/actions/get_basic_auth_credentials.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/get_basic_auth_credentials.pyi +21 -0
- amsdal/cloud/services/actions/get_monitoring_info.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/get_monitoring_info.pyi +21 -0
- amsdal/cloud/services/actions/list_dependencies.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/list_dependencies.pyi +21 -0
- amsdal/cloud/services/actions/list_deploys.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/list_deploys.pyi +19 -0
- amsdal/cloud/services/actions/list_envs.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/list_envs.pyi +20 -0
- amsdal/cloud/services/actions/list_secrets.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/list_secrets.pyi +22 -0
- amsdal/cloud/services/actions/manager.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/manager.pyi +278 -0
- amsdal/cloud/services/actions/signup_action.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/signup_action.pyi +20 -0
- amsdal/cloud/services/actions/update_deploy.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/actions/update_deploy.pyi +19 -0
- amsdal/cloud/services/auth/__init__.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/auth/__init__.pyi +0 -0
- amsdal/cloud/services/auth/base.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/auth/base.pyi +6 -0
- amsdal/cloud/services/auth/credentials.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/auth/credentials.pyi +30 -0
- amsdal/cloud/services/auth/manager.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/auth/manager.pyi +26 -0
- amsdal/cloud/services/auth/signup_service.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/auth/signup_service.pyi +32 -0
- amsdal/cloud/services/auth/token.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/cloud/services/auth/token.pyi +27 -0
- amsdal/configs/__init__.py +0 -0
- amsdal/configs/__init__.pyi +0 -0
- amsdal/configs/constants.py +33 -0
- amsdal/configs/constants.pyi +22 -0
- amsdal/configs/main.py +274 -0
- amsdal/configs/main.pyi +178 -0
- amsdal/context/__init__.py +0 -0
- amsdal/context/__init__.pyi +0 -0
- amsdal/context/manager.py +69 -0
- amsdal/context/manager.pyi +50 -0
- amsdal/contrib/__init__.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/contrib/__init__.pyi +0 -0
- amsdal/contrib/app_config.py +7 -0
- amsdal/contrib/app_config.pyi +6 -0
- amsdal/contrib/auth/__init__.py +0 -0
- amsdal/contrib/auth/__init__.pyi +0 -0
- amsdal/contrib/auth/app.py +27 -0
- amsdal/contrib/auth/app.pyi +15 -0
- amsdal/contrib/auth/decorators/__init__.py +35 -0
- amsdal/contrib/auth/decorators/__init__.pyi +6 -0
- amsdal/contrib/auth/errors.py +43 -0
- amsdal/contrib/auth/errors.pyi +16 -0
- amsdal/contrib/auth/fixtures/basic_permissions.json +64 -0
- amsdal/contrib/auth/lifecycle/__init__.py +0 -0
- amsdal/contrib/auth/lifecycle/__init__.pyi +0 -0
- amsdal/contrib/auth/lifecycle/consumer.py +394 -0
- amsdal/contrib/auth/lifecycle/consumer.pyi +108 -0
- amsdal/contrib/auth/migrations/0000_initial.py +87 -0
- amsdal/contrib/auth/migrations/0001_add_mfa_support.py +188 -0
- amsdal/contrib/auth/models/__init__.py +1 -0
- amsdal/contrib/auth/models/backup_code.py +85 -0
- amsdal/contrib/auth/models/email_mfa_device.py +108 -0
- amsdal/contrib/auth/models/login_session.py +235 -0
- amsdal/contrib/auth/models/mfa_device.py +86 -0
- amsdal/contrib/auth/models/permission.py +23 -0
- amsdal/contrib/auth/models/sms_device.py +113 -0
- amsdal/contrib/auth/models/totp_device.py +58 -0
- amsdal/contrib/auth/models/user.py +156 -0
- amsdal/contrib/auth/services/__init__.py +1 -0
- amsdal/contrib/auth/services/__init__.pyi +0 -0
- amsdal/contrib/auth/services/mfa_device_service.py +544 -0
- amsdal/contrib/auth/services/mfa_device_service.pyi +216 -0
- amsdal/contrib/auth/services/totp_service.py +358 -0
- amsdal/contrib/auth/services/totp_service.pyi +158 -0
- amsdal/contrib/auth/settings.py +44 -0
- amsdal/contrib/auth/settings.pyi +34 -0
- amsdal/contrib/auth/transactions/__init__.py +1 -0
- amsdal/contrib/auth/transactions/__init__.pyi +0 -0
- amsdal/contrib/auth/transactions/mfa_device_transactions.py +458 -0
- amsdal/contrib/auth/transactions/mfa_device_transactions.pyi +226 -0
- amsdal/contrib/auth/transactions/totp_transactions.py +203 -0
- amsdal/contrib/auth/transactions/totp_transactions.pyi +113 -0
- amsdal/contrib/auth/utils/__init__.py +0 -0
- amsdal/contrib/auth/utils/__init__.pyi +0 -0
- amsdal/contrib/auth/utils/mfa.py +257 -0
- amsdal/contrib/auth/utils/mfa.pyi +119 -0
- amsdal/contrib/frontend_configs/__init__.py +0 -0
- amsdal/contrib/frontend_configs/__init__.pyi +0 -0
- amsdal/contrib/frontend_configs/app.py +24 -0
- amsdal/contrib/frontend_configs/app.pyi +19 -0
- amsdal/contrib/frontend_configs/constants.py +1 -0
- amsdal/contrib/frontend_configs/constants.pyi +1 -0
- amsdal/contrib/frontend_configs/conversion/__init__.py +5 -0
- amsdal/contrib/frontend_configs/conversion/__init__.pyi +3 -0
- amsdal/contrib/frontend_configs/conversion/convert.py +310 -0
- amsdal/contrib/frontend_configs/conversion/convert.pyi +22 -0
- amsdal/contrib/frontend_configs/lifecycle/__init__.py +0 -0
- amsdal/contrib/frontend_configs/lifecycle/__init__.pyi +0 -0
- amsdal/contrib/frontend_configs/lifecycle/consumer.py +306 -0
- amsdal/contrib/frontend_configs/lifecycle/consumer.pyi +98 -0
- amsdal/contrib/frontend_configs/migrations/0000_initial.py +227 -0
- amsdal/contrib/frontend_configs/migrations/0001_update_frontend_control_config.py +245 -0
- amsdal/contrib/frontend_configs/migrations/0002_add_button_and_invoke_actions.py +352 -0
- amsdal/contrib/frontend_configs/migrations/0003_create_class_frontendconfigdashboardelement.py +145 -0
- amsdal/contrib/frontend_configs/models/__init__.py +0 -0
- amsdal/contrib/frontend_configs/models/frontend_activator_config.py +22 -0
- amsdal/contrib/frontend_configs/models/frontend_config_async_validator.py +11 -0
- amsdal/contrib/frontend_configs/models/frontend_config_control_action.py +110 -0
- amsdal/contrib/frontend_configs/models/frontend_config_dashboard.py +51 -0
- amsdal/contrib/frontend_configs/models/frontend_config_group_validator.py +21 -0
- amsdal/contrib/frontend_configs/models/frontend_config_option.py +12 -0
- amsdal/contrib/frontend_configs/models/frontend_config_skip_none_base.py +17 -0
- amsdal/contrib/frontend_configs/models/frontend_config_slider_option.py +13 -0
- amsdal/contrib/frontend_configs/models/frontend_config_text_mask.py +14 -0
- amsdal/contrib/frontend_configs/models/frontend_config_validator.py +28 -0
- amsdal/contrib/frontend_configs/models/frontend_control_config.py +110 -0
- amsdal/contrib/frontend_configs/models/frontend_model_config.py +14 -0
- amsdal/contrib/frontend_configs/utils.py +29 -0
- amsdal/contrib/frontend_configs/utils.pyi +17 -0
- amsdal/errors.py +31 -0
- amsdal/errors.pyi +12 -0
- amsdal/fixtures/__init__.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/fixtures/__init__.pyi +0 -0
- amsdal/fixtures/manager.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/fixtures/manager.pyi +170 -0
- amsdal/fixtures/utils.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/fixtures/utils.pyi +9 -0
- amsdal/manager.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/manager.pyi +265 -0
- amsdal/mixins/__init__.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/mixins/__init__.pyi +0 -0
- amsdal/mixins/class_versions_mixin.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/mixins/class_versions_mixin.pyi +12 -0
- amsdal/models/__init__.py +19 -0
- amsdal/models/core/__init__.py +0 -0
- amsdal/models/core/class_object.py +38 -0
- amsdal/models/core/class_property.py +26 -0
- amsdal/models/core/file.py +243 -0
- amsdal/models/core/fixture.py +25 -0
- amsdal/models/core/option.py +11 -0
- amsdal/models/core/storage_metadata.py +15 -0
- amsdal/models/core/validator.py +12 -0
- amsdal/models/mixins.py +31 -0
- amsdal/models/types/__init__.py +0 -0
- amsdal/models/types/object.py +26 -0
- amsdal/py.typed +0 -0
- amsdal/queryset/__init__.py +21 -0
- amsdal/queryset/__init__.pyi +6 -0
- amsdal/schemas/__init__.py +0 -0
- amsdal/schemas/__init__.pyi +0 -0
- amsdal/schemas/core/class_object/model.json +51 -0
- amsdal/schemas/core/class_object/properties/display_name.py +9 -0
- amsdal/schemas/core/class_property/model.json +41 -0
- amsdal/schemas/core/file/hooks/pre_create.py +24 -0
- amsdal/schemas/core/file/hooks/pre_update.py +24 -0
- amsdal/schemas/core/file/model.json +23 -0
- amsdal/schemas/core/file/properties/from_file.py +34 -0
- amsdal/schemas/core/file/properties/mimetype.py +13 -0
- amsdal/schemas/core/file/properties/str.py +6 -0
- amsdal/schemas/core/file/properties/to_file.py +24 -0
- amsdal/schemas/core/file/properties/validate_data.py +31 -0
- amsdal/schemas/core/fixture/model.json +35 -0
- amsdal/schemas/core/option/model.json +19 -0
- amsdal/schemas/core/storage_metadata/model.json +52 -0
- amsdal/schemas/core/validator/model.json +19 -0
- amsdal/schemas/interfaces.py +25 -0
- amsdal/schemas/interfaces.pyi +20 -0
- amsdal/schemas/manager.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/schemas/manager.py +0 -0
- amsdal/schemas/manager.pyi +0 -0
- amsdal/schemas/mixins/__init__.py +0 -0
- amsdal/schemas/mixins/__init__.pyi +0 -0
- amsdal/schemas/mixins/check_dependencies_mixin.py +130 -0
- amsdal/schemas/mixins/check_dependencies_mixin.pyi +45 -0
- amsdal/schemas/mixins/verify_schemas_mixin.py +96 -0
- amsdal/schemas/mixins/verify_schemas_mixin.pyi +33 -0
- amsdal/schemas/repository.py +84 -0
- amsdal/schemas/repository.pyi +22 -0
- amsdal/schemas/types/anything/model.json +7 -0
- amsdal/schemas/types/array/model.json +7 -0
- amsdal/schemas/types/binary/model.json +7 -0
- amsdal/schemas/types/boolean/model.json +17 -0
- amsdal/schemas/types/date/model.json +7 -0
- amsdal/schemas/types/datetime/model.json +7 -0
- amsdal/schemas/types/dictionary/model.json +8 -0
- amsdal/schemas/types/number/model.json +8 -0
- amsdal/schemas/types/object/model.json +53 -0
- amsdal/schemas/types/string/model.json +8 -0
- amsdal/schemas/utils.py +16 -0
- amsdal/schemas/utils.pyi +10 -0
- amsdal/services/__init__.py +11 -0
- amsdal/services/__init__.pyi +4 -0
- amsdal/services/external_connections.py +262 -0
- amsdal/services/external_connections.pyi +190 -0
- amsdal/services/external_model_generator.py +350 -0
- amsdal/services/external_model_generator.pyi +134 -0
- amsdal/services/transaction_execution.cpython-313-x86_64-linux-gnu.so +0 -0
- amsdal/services/transaction_execution.pyi +93 -0
- amsdal/storages/__init__.py +20 -0
- amsdal/storages/__init__.pyi +8 -0
- amsdal/storages/file_system.py +214 -0
- amsdal/storages/file_system.pyi +36 -0
- amsdal/transactions/__init__.py +13 -0
- amsdal/transactions/__init__.pyi +4 -0
- amsdal/utils/__init__.py +0 -0
- amsdal/utils/__init__.pyi +0 -0
- amsdal/utils/contrib_paths.py +23 -0
- amsdal/utils/contrib_paths.pyi +14 -0
- amsdal/utils/rollback/__init__.py +440 -0
- amsdal/utils/rollback/__init__.pyi +38 -0
- amsdal/utils/tests/__init__.py +0 -0
- amsdal/utils/tests/enums.py +16 -0
- amsdal/utils/tests/factories.py +49 -0
- amsdal/utils/tests/helpers.py +331 -0
- amsdal/utils/tests/migrations.py +157 -0
- amsdal-0.5.34.dist-info/METADATA +375 -0
- amsdal-0.5.34.dist-info/RECORD +276 -0
- amsdal-0.5.34.dist-info/WHEEL +6 -0
- amsdal-0.5.34.dist-info/licenses/LICENSE.txt +107 -0
- amsdal-0.5.34.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
"""
|
|
2
|
+
External Model Generator Service.
|
|
3
|
+
|
|
4
|
+
Generates ExternalModel classes from external connection schemas.
|
|
5
|
+
This allows runtime model generation from external databases without
|
|
6
|
+
manual model definition.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from typing import Any
|
|
10
|
+
from typing import cast
|
|
11
|
+
|
|
12
|
+
from amsdal_data.connections.external.base import SchemaIntrospectionProtocol
|
|
13
|
+
from amsdal_models.classes.external_model import ExternalModel
|
|
14
|
+
from amsdal_models.utils.schema_converter import ExternalSchemaConverter
|
|
15
|
+
from amsdal_utils.schemas.schema import ObjectSchema
|
|
16
|
+
|
|
17
|
+
from amsdal.services.external_connections import ExternalConnectionManager
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ExternalModelGenerator:
|
|
21
|
+
"""
|
|
22
|
+
Service for generating ExternalModel classes from external connections.
|
|
23
|
+
|
|
24
|
+
This service introspects external database schemas and generates
|
|
25
|
+
corresponding ExternalModel classes that can be used immediately
|
|
26
|
+
for querying the external data.
|
|
27
|
+
|
|
28
|
+
Features:
|
|
29
|
+
- Automatic schema introspection
|
|
30
|
+
- Type mapping (SQL types -> Python types)
|
|
31
|
+
- Primary key detection
|
|
32
|
+
- In-memory model class generation
|
|
33
|
+
- No lakehouse schema creation
|
|
34
|
+
|
|
35
|
+
Example usage:
|
|
36
|
+
# Generate models for a single table
|
|
37
|
+
generator = ExternalModelGenerator()
|
|
38
|
+
User = generator.generate_model('external_db', 'users')
|
|
39
|
+
|
|
40
|
+
# Now use the generated model
|
|
41
|
+
users = User.objects.filter(active=True).execute()
|
|
42
|
+
|
|
43
|
+
# Generate models for all tables
|
|
44
|
+
models = generator.generate_models_for_connection('external_db')
|
|
45
|
+
User = models['User']
|
|
46
|
+
Post = models['Post']
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
def __init__(self) -> None:
|
|
50
|
+
self._connection_manager = ExternalConnectionManager()
|
|
51
|
+
self._schema_converter = ExternalSchemaConverter()
|
|
52
|
+
|
|
53
|
+
def generate_model(
|
|
54
|
+
self,
|
|
55
|
+
connection_name: str,
|
|
56
|
+
table_name: str,
|
|
57
|
+
model_name: str | None = None,
|
|
58
|
+
) -> type[ExternalModel]:
|
|
59
|
+
"""
|
|
60
|
+
Generate an ExternalModel class for a specific table.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
connection_name: Name of the external connection
|
|
64
|
+
table_name: Name of the table to generate model for
|
|
65
|
+
model_name: Optional custom model name (defaults to classified table name)
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
type[ExternalModel]: Generated model class ready to use
|
|
69
|
+
|
|
70
|
+
Raises:
|
|
71
|
+
ValueError: If connection doesn't support schema introspection
|
|
72
|
+
ConnectionError: If connection is not available
|
|
73
|
+
RuntimeError: If model generation fails
|
|
74
|
+
|
|
75
|
+
Example:
|
|
76
|
+
generator = ExternalModelGenerator()
|
|
77
|
+
User = generator.generate_model('external_db', 'users')
|
|
78
|
+
|
|
79
|
+
# Query using the generated model
|
|
80
|
+
active_users = User.objects.filter(active=True).execute()
|
|
81
|
+
"""
|
|
82
|
+
# Get the connection
|
|
83
|
+
connection = self._connection_manager.get_connection(connection_name)
|
|
84
|
+
|
|
85
|
+
# Check if connection supports schema introspection
|
|
86
|
+
if not isinstance(connection, SchemaIntrospectionProtocol): # type: ignore[misc]
|
|
87
|
+
msg = (
|
|
88
|
+
f"Connection '{connection_name}' does not support schema introspection. "
|
|
89
|
+
f'Connection type: {type(connection).__name__}'
|
|
90
|
+
)
|
|
91
|
+
raise ValueError(msg)
|
|
92
|
+
|
|
93
|
+
# Get table schema
|
|
94
|
+
table_schema = connection.get_table_schema(table_name)
|
|
95
|
+
|
|
96
|
+
# Convert to ObjectSchema
|
|
97
|
+
# Detect connection type and use appropriate converter
|
|
98
|
+
object_schema = self._convert_schema(
|
|
99
|
+
connection=connection,
|
|
100
|
+
table_name=table_name,
|
|
101
|
+
table_schema=table_schema,
|
|
102
|
+
connection_name=connection_name,
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
# Generate model class from ObjectSchema
|
|
106
|
+
model_class = self._create_model_class(object_schema, model_name)
|
|
107
|
+
|
|
108
|
+
return model_class
|
|
109
|
+
|
|
110
|
+
def generate_models_for_connection(
|
|
111
|
+
self,
|
|
112
|
+
connection_name: str,
|
|
113
|
+
table_names: list[str] | None = None,
|
|
114
|
+
) -> dict[str, type[ExternalModel]]:
|
|
115
|
+
"""
|
|
116
|
+
Generate ExternalModel classes for all tables in a connection.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
connection_name: Name of the external connection
|
|
120
|
+
table_names: Optional list of specific tables to generate models for.
|
|
121
|
+
If None, generates models for all tables.
|
|
122
|
+
|
|
123
|
+
Returns:
|
|
124
|
+
dict[str, type[ExternalModel]]: Dictionary mapping model names to model classes
|
|
125
|
+
|
|
126
|
+
Raises:
|
|
127
|
+
ValueError: If connection doesn't support schema introspection
|
|
128
|
+
ConnectionError: If connection is not available
|
|
129
|
+
|
|
130
|
+
Example:
|
|
131
|
+
generator = ExternalModelGenerator()
|
|
132
|
+
models = generator.generate_models_for_connection('external_db')
|
|
133
|
+
|
|
134
|
+
# Access generated models
|
|
135
|
+
User = models['User']
|
|
136
|
+
Post = models['Post']
|
|
137
|
+
Comment = models['Comment']
|
|
138
|
+
|
|
139
|
+
# Or generate only specific tables
|
|
140
|
+
models = generator.generate_models_for_connection(
|
|
141
|
+
'external_db',
|
|
142
|
+
table_names=['users', 'posts']
|
|
143
|
+
)
|
|
144
|
+
"""
|
|
145
|
+
# Get the connection
|
|
146
|
+
connection = self._connection_manager.get_connection(connection_name)
|
|
147
|
+
|
|
148
|
+
# Check if connection supports schema introspection
|
|
149
|
+
if not isinstance(connection, SchemaIntrospectionProtocol): # type: ignore[misc]
|
|
150
|
+
msg = (
|
|
151
|
+
f"Connection '{connection_name}' does not support schema introspection. "
|
|
152
|
+
f'Connection type: {type(connection).__name__}'
|
|
153
|
+
)
|
|
154
|
+
raise ValueError(msg)
|
|
155
|
+
|
|
156
|
+
# Get list of tables
|
|
157
|
+
if table_names is None:
|
|
158
|
+
table_names = connection.get_table_names()
|
|
159
|
+
|
|
160
|
+
# Generate models for each table
|
|
161
|
+
models: dict[str, type[ExternalModel]] = {}
|
|
162
|
+
for table_name in table_names:
|
|
163
|
+
try:
|
|
164
|
+
model = self.generate_model(connection_name, table_name)
|
|
165
|
+
models[model.__name__] = model
|
|
166
|
+
except Exception as e:
|
|
167
|
+
# Log error but continue with other tables
|
|
168
|
+
print(f"Warning: Failed to generate model for table '{table_name}': {e}")
|
|
169
|
+
continue
|
|
170
|
+
|
|
171
|
+
return models
|
|
172
|
+
|
|
173
|
+
def _convert_schema(
|
|
174
|
+
self,
|
|
175
|
+
connection: Any,
|
|
176
|
+
table_name: str,
|
|
177
|
+
table_schema: list[dict[str, Any]],
|
|
178
|
+
connection_name: str,
|
|
179
|
+
) -> ObjectSchema:
|
|
180
|
+
"""
|
|
181
|
+
Convert raw table schema to ObjectSchema based on connection type.
|
|
182
|
+
|
|
183
|
+
Args:
|
|
184
|
+
connection: The connection object
|
|
185
|
+
table_name: Name of the table
|
|
186
|
+
table_schema: Raw schema data from connection
|
|
187
|
+
connection_name: Name of the connection
|
|
188
|
+
|
|
189
|
+
Returns:
|
|
190
|
+
ObjectSchema: Converted schema
|
|
191
|
+
"""
|
|
192
|
+
# Detect connection type and use appropriate converter
|
|
193
|
+
connection_type = type(connection).__name__
|
|
194
|
+
|
|
195
|
+
if 'sqlite' in connection_type.lower():
|
|
196
|
+
return self._schema_converter.sqlite_schema_to_object_schema(
|
|
197
|
+
table_name=table_name,
|
|
198
|
+
columns=table_schema,
|
|
199
|
+
connection_name=connection_name,
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
# For other connection types, try to use generic converter
|
|
203
|
+
# First, try to detect the schema format
|
|
204
|
+
if table_schema and isinstance(table_schema[0], dict):
|
|
205
|
+
# Check if it's SQLite format (has 'cid', 'name', 'type', 'pk', etc.)
|
|
206
|
+
if all(key in table_schema[0] for key in ('cid', 'name', 'type')):
|
|
207
|
+
return self._schema_converter.sqlite_schema_to_object_schema(
|
|
208
|
+
table_name=table_name,
|
|
209
|
+
columns=table_schema,
|
|
210
|
+
connection_name=connection_name,
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
# Check if it's PostgreSQL format (has 'column_name', 'data_type', etc.)
|
|
214
|
+
if 'column_name' in table_schema[0] and 'data_type' in table_schema[0]:
|
|
215
|
+
return self._schema_converter.postgres_schema_to_object_schema(
|
|
216
|
+
table_name=table_name,
|
|
217
|
+
columns=table_schema,
|
|
218
|
+
connection_name=connection_name,
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
# Try generic converter with format normalization
|
|
222
|
+
normalized_columns = self._normalize_schema_format(table_schema)
|
|
223
|
+
return self._schema_converter.generic_schema_to_object_schema(
|
|
224
|
+
table_name=table_name,
|
|
225
|
+
columns=normalized_columns,
|
|
226
|
+
connection_name=connection_name,
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
msg = f'Unknown schema format for connection type: {connection_type}'
|
|
230
|
+
raise ValueError(msg)
|
|
231
|
+
|
|
232
|
+
def _normalize_schema_format(self, table_schema: list[dict[str, Any]]) -> list[dict[str, Any]]:
|
|
233
|
+
"""
|
|
234
|
+
Normalize various schema formats to generic format.
|
|
235
|
+
|
|
236
|
+
Converts various schema formats to the format expected by generic_schema_to_object_schema:
|
|
237
|
+
{'name': str, 'type': str, 'nullable': bool, 'primary_key': bool, 'default': Any}
|
|
238
|
+
"""
|
|
239
|
+
normalized = []
|
|
240
|
+
|
|
241
|
+
for column in table_schema:
|
|
242
|
+
# Try to extract name
|
|
243
|
+
name = column.get('name') or column.get('column_name') or column.get('field')
|
|
244
|
+
|
|
245
|
+
# Try to extract type
|
|
246
|
+
col_type = column.get('type') or column.get('data_type') or column.get('field_type') or 'TEXT'
|
|
247
|
+
|
|
248
|
+
# Try to extract nullable
|
|
249
|
+
nullable = True
|
|
250
|
+
if 'nullable' in column:
|
|
251
|
+
nullable = column['nullable']
|
|
252
|
+
elif 'is_nullable' in column:
|
|
253
|
+
nullable = column['is_nullable'] in (True, 'YES', 'yes', 1)
|
|
254
|
+
elif 'notnull' in column:
|
|
255
|
+
nullable = column['notnull'] in (False, 0)
|
|
256
|
+
|
|
257
|
+
# Try to extract primary key
|
|
258
|
+
pk = column.get('primary_key') or column.get('pk') or False
|
|
259
|
+
if isinstance(pk, int):
|
|
260
|
+
pk = pk > 0
|
|
261
|
+
|
|
262
|
+
# Try to extract default
|
|
263
|
+
default = column.get('default') or column.get('dflt_value') or column.get('column_default')
|
|
264
|
+
|
|
265
|
+
normalized.append(
|
|
266
|
+
{
|
|
267
|
+
'name': name,
|
|
268
|
+
'type': col_type,
|
|
269
|
+
'nullable': nullable,
|
|
270
|
+
'primary_key': pk,
|
|
271
|
+
'default': default,
|
|
272
|
+
}
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
return normalized
|
|
276
|
+
|
|
277
|
+
def _create_model_class(
|
|
278
|
+
self,
|
|
279
|
+
object_schema: ObjectSchema,
|
|
280
|
+
custom_name: str | None = None,
|
|
281
|
+
) -> type[ExternalModel]:
|
|
282
|
+
"""
|
|
283
|
+
Create an ExternalModel class from ObjectSchema.
|
|
284
|
+
|
|
285
|
+
Args:
|
|
286
|
+
object_schema: The schema to create model from
|
|
287
|
+
custom_name: Optional custom model name
|
|
288
|
+
|
|
289
|
+
Returns:
|
|
290
|
+
type[ExternalModel]: Generated model class
|
|
291
|
+
"""
|
|
292
|
+
# Extract model metadata from schema
|
|
293
|
+
model_name = custom_name or object_schema.title
|
|
294
|
+
table_name = cast(str, object_schema.__table_name__) # type: ignore[attr-defined]
|
|
295
|
+
connection_name = cast(str, object_schema.__connection__) # type: ignore[attr-defined]
|
|
296
|
+
pk_fields = getattr(object_schema, '__primary_key__', None)
|
|
297
|
+
|
|
298
|
+
# Build class attributes
|
|
299
|
+
class_attrs: dict[str, Any] = {
|
|
300
|
+
'__table_name__': table_name,
|
|
301
|
+
'__connection__': connection_name,
|
|
302
|
+
'__module__': __name__,
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
# Add primary key if present
|
|
306
|
+
if pk_fields:
|
|
307
|
+
# For composite keys, use list; for single key, use string
|
|
308
|
+
if len(pk_fields) == 1:
|
|
309
|
+
class_attrs['__primary_key__'] = pk_fields[0]
|
|
310
|
+
else:
|
|
311
|
+
class_attrs['__primary_key__'] = pk_fields
|
|
312
|
+
|
|
313
|
+
# Add field annotations from schema properties
|
|
314
|
+
annotations: dict[str, type] = {}
|
|
315
|
+
if object_schema.properties:
|
|
316
|
+
for field_name, field_def in object_schema.properties.items():
|
|
317
|
+
# Map CoreTypes to Python types for annotations
|
|
318
|
+
field_type = self._core_type_to_python_type(getattr(field_def, 'type', 'string'))
|
|
319
|
+
annotations[field_name] = field_type
|
|
320
|
+
|
|
321
|
+
class_attrs['__annotations__'] = annotations
|
|
322
|
+
|
|
323
|
+
# Create the model class dynamically
|
|
324
|
+
model_class = type(model_name, (ExternalModel,), class_attrs)
|
|
325
|
+
|
|
326
|
+
return cast(type[ExternalModel], model_class)
|
|
327
|
+
|
|
328
|
+
@staticmethod
|
|
329
|
+
def _core_type_to_python_type(core_type: str) -> type:
|
|
330
|
+
"""
|
|
331
|
+
Convert CoreType string to Python type for annotations.
|
|
332
|
+
|
|
333
|
+
Args:
|
|
334
|
+
core_type: CoreType value (e.g., 'string', 'integer')
|
|
335
|
+
|
|
336
|
+
Returns:
|
|
337
|
+
type: Corresponding Python type
|
|
338
|
+
"""
|
|
339
|
+
type_mapping = {
|
|
340
|
+
'string': str,
|
|
341
|
+
'integer': int,
|
|
342
|
+
'number': float,
|
|
343
|
+
'boolean': bool,
|
|
344
|
+
'date': str, # Will be string representation
|
|
345
|
+
'datetime': str, # Will be string representation
|
|
346
|
+
'binary': bytes,
|
|
347
|
+
'array': list,
|
|
348
|
+
'dictionary': dict,
|
|
349
|
+
}
|
|
350
|
+
return type_mapping.get(core_type, str)
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
from _typeshed import Incomplete
|
|
2
|
+
from amsdal.services.external_connections import ExternalConnectionManager as ExternalConnectionManager
|
|
3
|
+
from amsdal_models.classes.external_model import ExternalModel
|
|
4
|
+
from amsdal_utils.schemas.schema import ObjectSchema as ObjectSchema
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
class ExternalModelGenerator:
|
|
8
|
+
"""
|
|
9
|
+
Service for generating ExternalModel classes from external connections.
|
|
10
|
+
|
|
11
|
+
This service introspects external database schemas and generates
|
|
12
|
+
corresponding ExternalModel classes that can be used immediately
|
|
13
|
+
for querying the external data.
|
|
14
|
+
|
|
15
|
+
Features:
|
|
16
|
+
- Automatic schema introspection
|
|
17
|
+
- Type mapping (SQL types -> Python types)
|
|
18
|
+
- Primary key detection
|
|
19
|
+
- In-memory model class generation
|
|
20
|
+
- No lakehouse schema creation
|
|
21
|
+
|
|
22
|
+
Example usage:
|
|
23
|
+
# Generate models for a single table
|
|
24
|
+
generator = ExternalModelGenerator()
|
|
25
|
+
User = generator.generate_model('external_db', 'users')
|
|
26
|
+
|
|
27
|
+
# Now use the generated model
|
|
28
|
+
users = User.objects.filter(active=True).execute()
|
|
29
|
+
|
|
30
|
+
# Generate models for all tables
|
|
31
|
+
models = generator.generate_models_for_connection('external_db')
|
|
32
|
+
User = models['User']
|
|
33
|
+
Post = models['Post']
|
|
34
|
+
"""
|
|
35
|
+
_connection_manager: Incomplete
|
|
36
|
+
_schema_converter: Incomplete
|
|
37
|
+
def __init__(self) -> None: ...
|
|
38
|
+
def generate_model(self, connection_name: str, table_name: str, model_name: str | None = None) -> type[ExternalModel]:
|
|
39
|
+
"""
|
|
40
|
+
Generate an ExternalModel class for a specific table.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
connection_name: Name of the external connection
|
|
44
|
+
table_name: Name of the table to generate model for
|
|
45
|
+
model_name: Optional custom model name (defaults to classified table name)
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
type[ExternalModel]: Generated model class ready to use
|
|
49
|
+
|
|
50
|
+
Raises:
|
|
51
|
+
ValueError: If connection doesn't support schema introspection
|
|
52
|
+
ConnectionError: If connection is not available
|
|
53
|
+
RuntimeError: If model generation fails
|
|
54
|
+
|
|
55
|
+
Example:
|
|
56
|
+
generator = ExternalModelGenerator()
|
|
57
|
+
User = generator.generate_model('external_db', 'users')
|
|
58
|
+
|
|
59
|
+
# Query using the generated model
|
|
60
|
+
active_users = User.objects.filter(active=True).execute()
|
|
61
|
+
"""
|
|
62
|
+
def generate_models_for_connection(self, connection_name: str, table_names: list[str] | None = None) -> dict[str, type[ExternalModel]]:
|
|
63
|
+
"""
|
|
64
|
+
Generate ExternalModel classes for all tables in a connection.
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
connection_name: Name of the external connection
|
|
68
|
+
table_names: Optional list of specific tables to generate models for.
|
|
69
|
+
If None, generates models for all tables.
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
dict[str, type[ExternalModel]]: Dictionary mapping model names to model classes
|
|
73
|
+
|
|
74
|
+
Raises:
|
|
75
|
+
ValueError: If connection doesn't support schema introspection
|
|
76
|
+
ConnectionError: If connection is not available
|
|
77
|
+
|
|
78
|
+
Example:
|
|
79
|
+
generator = ExternalModelGenerator()
|
|
80
|
+
models = generator.generate_models_for_connection('external_db')
|
|
81
|
+
|
|
82
|
+
# Access generated models
|
|
83
|
+
User = models['User']
|
|
84
|
+
Post = models['Post']
|
|
85
|
+
Comment = models['Comment']
|
|
86
|
+
|
|
87
|
+
# Or generate only specific tables
|
|
88
|
+
models = generator.generate_models_for_connection(
|
|
89
|
+
'external_db',
|
|
90
|
+
table_names=['users', 'posts']
|
|
91
|
+
)
|
|
92
|
+
"""
|
|
93
|
+
def _convert_schema(self, connection: Any, table_name: str, table_schema: list[dict[str, Any]], connection_name: str) -> ObjectSchema:
|
|
94
|
+
"""
|
|
95
|
+
Convert raw table schema to ObjectSchema based on connection type.
|
|
96
|
+
|
|
97
|
+
Args:
|
|
98
|
+
connection: The connection object
|
|
99
|
+
table_name: Name of the table
|
|
100
|
+
table_schema: Raw schema data from connection
|
|
101
|
+
connection_name: Name of the connection
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
ObjectSchema: Converted schema
|
|
105
|
+
"""
|
|
106
|
+
def _normalize_schema_format(self, table_schema: list[dict[str, Any]]) -> list[dict[str, Any]]:
|
|
107
|
+
"""
|
|
108
|
+
Normalize various schema formats to generic format.
|
|
109
|
+
|
|
110
|
+
Converts various schema formats to the format expected by generic_schema_to_object_schema:
|
|
111
|
+
{'name': str, 'type': str, 'nullable': bool, 'primary_key': bool, 'default': Any}
|
|
112
|
+
"""
|
|
113
|
+
def _create_model_class(self, object_schema: ObjectSchema, custom_name: str | None = None) -> type[ExternalModel]:
|
|
114
|
+
"""
|
|
115
|
+
Create an ExternalModel class from ObjectSchema.
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
object_schema: The schema to create model from
|
|
119
|
+
custom_name: Optional custom model name
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
type[ExternalModel]: Generated model class
|
|
123
|
+
"""
|
|
124
|
+
@staticmethod
|
|
125
|
+
def _core_type_to_python_type(core_type: str) -> type:
|
|
126
|
+
"""
|
|
127
|
+
Convert CoreType string to Python type for annotations.
|
|
128
|
+
|
|
129
|
+
Args:
|
|
130
|
+
core_type: CoreType value (e.g., 'string', 'integer')
|
|
131
|
+
|
|
132
|
+
Returns:
|
|
133
|
+
type: Corresponding Python type
|
|
134
|
+
"""
|
|
Binary file
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import ast
|
|
2
|
+
from _typeshed import Incomplete
|
|
3
|
+
from amsdal.configs.main import settings as settings
|
|
4
|
+
from amsdal.errors import TransactionNotFoundError as TransactionNotFoundError
|
|
5
|
+
from amsdal_utils.utils.singleton import Singleton
|
|
6
|
+
from collections.abc import Callable as Callable, Generator
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
logger: Incomplete
|
|
11
|
+
|
|
12
|
+
def is_transaction(statement: ast.AST) -> bool:
|
|
13
|
+
"""
|
|
14
|
+
Determines if a given AST statement is a transaction function.
|
|
15
|
+
|
|
16
|
+
This function checks if the provided AST statement is an asynchronous or synchronous function
|
|
17
|
+
definition that is decorated with the `transaction` decorator.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
statement (ast.AST): The AST statement to check.
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
bool: True if the statement is a transaction function, False otherwise.
|
|
24
|
+
"""
|
|
25
|
+
def annotation_is_model(annotation: Any) -> bool: ...
|
|
26
|
+
|
|
27
|
+
class TransactionExecutionService(metaclass=Singleton):
|
|
28
|
+
"""
|
|
29
|
+
Service for executing transactions.
|
|
30
|
+
|
|
31
|
+
This class provides methods to execute transactions, load transaction functions,
|
|
32
|
+
and handle asynchronous transactions. It ensures that transactions are executed
|
|
33
|
+
with the correct arguments and handles any necessary preprocessing of arguments.
|
|
34
|
+
"""
|
|
35
|
+
_transactions: dict[str, Callable[..., Any]]
|
|
36
|
+
def __init__(self) -> None: ...
|
|
37
|
+
def execute_transaction(self, transaction_name: str, args: dict[str, Any], *, load_references: bool = True) -> Any:
|
|
38
|
+
"""
|
|
39
|
+
Executes a transaction with the given name and arguments.
|
|
40
|
+
|
|
41
|
+
This method retrieves the transaction function by its name, processes the arguments,
|
|
42
|
+
and executes the transaction. It handles both synchronous and asynchronous transactions
|
|
43
|
+
and performs necessary preprocessing of arguments, such as loading references.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
transaction_name (str): The name of the transaction to execute.
|
|
47
|
+
args (dict[str, Any]): The arguments to pass to the transaction function.
|
|
48
|
+
load_references (bool, optional): Whether to load references in the arguments. Defaults to True.
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
Any: The result of the transaction execution.
|
|
52
|
+
"""
|
|
53
|
+
async def async_execute_transaction(self, transaction_name: str, args: dict[str, Any], *, load_references: bool = True) -> Any:
|
|
54
|
+
"""
|
|
55
|
+
Executes a transaction with the given name and arguments.
|
|
56
|
+
|
|
57
|
+
This method retrieves the transaction function by its name, processes the arguments,
|
|
58
|
+
and executes the transaction. It handles both synchronous and asynchronous transactions
|
|
59
|
+
and performs necessary preprocessing of arguments, such as loading references.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
transaction_name (str): The name of the transaction to execute.
|
|
63
|
+
args (dict[str, Any]): The arguments to pass to the transaction function.
|
|
64
|
+
load_references (bool, optional): Whether to load references in the arguments. Defaults to True.
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
Any: The result of the transaction execution.
|
|
68
|
+
"""
|
|
69
|
+
def get_transaction_func(self, transaction_name: str) -> Callable[..., Any]:
|
|
70
|
+
"""
|
|
71
|
+
Retrieves the transaction function by its name.
|
|
72
|
+
|
|
73
|
+
This method checks if the transaction function is already loaded in the `_transactions` dictionary.
|
|
74
|
+
If not, it attempts to load the transaction function from the available transaction definitions.
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
transaction_name (str): The name of the transaction function to retrieve.
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
Callable[..., Any]: The transaction function corresponding to the given name.
|
|
81
|
+
|
|
82
|
+
Raises:
|
|
83
|
+
TransactionNotFoundError: If the transaction function with the specified name is not found.
|
|
84
|
+
"""
|
|
85
|
+
@staticmethod
|
|
86
|
+
def _run_async_transaction(transaction_func: Callable[..., Any], args: dict[str, Any]) -> Any: ...
|
|
87
|
+
def _load_transaction(self, transaction_name: str) -> Callable[..., Any]: ...
|
|
88
|
+
@classmethod
|
|
89
|
+
def _get_transaction_definitions(cls) -> Generator[tuple[ast.FunctionDef | ast.AsyncFunctionDef, Path], None, None]: ...
|
|
90
|
+
@classmethod
|
|
91
|
+
def _iterate_module(cls, module_path: Path) -> Generator[tuple[ast.FunctionDef | ast.AsyncFunctionDef, Path], None, None]: ...
|
|
92
|
+
@classmethod
|
|
93
|
+
def _iterate_file(cls, file_path: Path) -> Generator[tuple[ast.FunctionDef | ast.AsyncFunctionDef, Path], None, None]: ...
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from amsdal_models.storage.base import Storage
|
|
2
|
+
|
|
3
|
+
from amsdal.configs.main import settings
|
|
4
|
+
|
|
5
|
+
_DEFAULT_STORAGE = None
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def set_default_storage(storage: Storage) -> None:
|
|
9
|
+
global _DEFAULT_STORAGE # noqa: PLW0603
|
|
10
|
+
_DEFAULT_STORAGE = storage
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def default_storage() -> Storage:
|
|
14
|
+
global _DEFAULT_STORAGE # noqa: PLW0603
|
|
15
|
+
|
|
16
|
+
if _DEFAULT_STORAGE is None:
|
|
17
|
+
# Determine backend from settings
|
|
18
|
+
class_path = settings.DEFAULT_FILE_STORAGE
|
|
19
|
+
_DEFAULT_STORAGE = Storage.from_storage_spec({'storage_class': class_path})
|
|
20
|
+
return _DEFAULT_STORAGE
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
from _typeshed import Incomplete
|
|
2
|
+
from amsdal.configs.main import settings as settings
|
|
3
|
+
from amsdal_models.storage.base import Storage
|
|
4
|
+
|
|
5
|
+
_DEFAULT_STORAGE: Incomplete
|
|
6
|
+
|
|
7
|
+
def set_default_storage(storage: Storage) -> None: ...
|
|
8
|
+
def default_storage() -> Storage: ...
|