amsdal 0.4.13__cp311-cp311-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.
Files changed (269) hide show
  1. amsdal/Third-Party Materials - AMSDAL Dependencies - License Notices.md +1334 -0
  2. amsdal/__about__.py +4 -0
  3. amsdal/__about__.pyi +1 -0
  4. amsdal/__init__.py +23 -0
  5. amsdal/__init__.pyi +9 -0
  6. amsdal/__migrations__/0000_initial.py +217 -0
  7. amsdal/__migrations__/0001_datetime_type.py +18 -0
  8. amsdal/__migrations__/0002_fixture_order.py +44 -0
  9. amsdal/__migrations__/0003_schema_type_in_class_meta.py +44 -0
  10. amsdal/cloud/__init__.cpython-311-x86_64-linux-gnu.so +0 -0
  11. amsdal/cloud/__init__.pyi +0 -0
  12. amsdal/cloud/client.cpython-311-x86_64-linux-gnu.so +0 -0
  13. amsdal/cloud/client.pyi +57 -0
  14. amsdal/cloud/constants.cpython-311-x86_64-linux-gnu.so +0 -0
  15. amsdal/cloud/constants.pyi +13 -0
  16. amsdal/cloud/enums.cpython-311-x86_64-linux-gnu.so +0 -0
  17. amsdal/cloud/enums.pyi +68 -0
  18. amsdal/cloud/models/__init__.cpython-311-x86_64-linux-gnu.so +0 -0
  19. amsdal/cloud/models/__init__.pyi +0 -0
  20. amsdal/cloud/models/base.cpython-311-x86_64-linux-gnu.so +0 -0
  21. amsdal/cloud/models/base.pyi +247 -0
  22. amsdal/cloud/services/__init__.cpython-311-x86_64-linux-gnu.so +0 -0
  23. amsdal/cloud/services/__init__.pyi +0 -0
  24. amsdal/cloud/services/actions/__init__.cpython-311-x86_64-linux-gnu.so +0 -0
  25. amsdal/cloud/services/actions/__init__.pyi +0 -0
  26. amsdal/cloud/services/actions/add_allowlist_ip.cpython-311-x86_64-linux-gnu.so +0 -0
  27. amsdal/cloud/services/actions/add_allowlist_ip.pyi +19 -0
  28. amsdal/cloud/services/actions/add_basic_auth.cpython-311-x86_64-linux-gnu.so +0 -0
  29. amsdal/cloud/services/actions/add_basic_auth.pyi +21 -0
  30. amsdal/cloud/services/actions/add_dependency.cpython-311-x86_64-linux-gnu.so +0 -0
  31. amsdal/cloud/services/actions/add_dependency.pyi +19 -0
  32. amsdal/cloud/services/actions/add_secret.cpython-311-x86_64-linux-gnu.so +0 -0
  33. amsdal/cloud/services/actions/add_secret.pyi +20 -0
  34. amsdal/cloud/services/actions/base.cpython-311-x86_64-linux-gnu.so +0 -0
  35. amsdal/cloud/services/actions/base.pyi +122 -0
  36. amsdal/cloud/services/actions/create_deploy.cpython-311-x86_64-linux-gnu.so +0 -0
  37. amsdal/cloud/services/actions/create_deploy.pyi +41 -0
  38. amsdal/cloud/services/actions/create_env.cpython-311-x86_64-linux-gnu.so +0 -0
  39. amsdal/cloud/services/actions/create_env.pyi +19 -0
  40. amsdal/cloud/services/actions/create_session.cpython-311-x86_64-linux-gnu.so +0 -0
  41. amsdal/cloud/services/actions/create_session.pyi +17 -0
  42. amsdal/cloud/services/actions/delete_allowlist_ip.cpython-311-x86_64-linux-gnu.so +0 -0
  43. amsdal/cloud/services/actions/delete_allowlist_ip.pyi +19 -0
  44. amsdal/cloud/services/actions/delete_basic_auth.cpython-311-x86_64-linux-gnu.so +0 -0
  45. amsdal/cloud/services/actions/delete_basic_auth.pyi +20 -0
  46. amsdal/cloud/services/actions/delete_dependency.cpython-311-x86_64-linux-gnu.so +0 -0
  47. amsdal/cloud/services/actions/delete_dependency.pyi +21 -0
  48. amsdal/cloud/services/actions/delete_env.cpython-311-x86_64-linux-gnu.so +0 -0
  49. amsdal/cloud/services/actions/delete_env.pyi +21 -0
  50. amsdal/cloud/services/actions/delete_secret.cpython-311-x86_64-linux-gnu.so +0 -0
  51. amsdal/cloud/services/actions/delete_secret.pyi +21 -0
  52. amsdal/cloud/services/actions/destroy_deploy.cpython-311-x86_64-linux-gnu.so +0 -0
  53. amsdal/cloud/services/actions/destroy_deploy.pyi +18 -0
  54. amsdal/cloud/services/actions/expose_db.cpython-311-x86_64-linux-gnu.so +0 -0
  55. amsdal/cloud/services/actions/expose_db.pyi +22 -0
  56. amsdal/cloud/services/actions/get_basic_auth_credentials.cpython-311-x86_64-linux-gnu.so +0 -0
  57. amsdal/cloud/services/actions/get_basic_auth_credentials.pyi +21 -0
  58. amsdal/cloud/services/actions/get_monitoring_info.cpython-311-x86_64-linux-gnu.so +0 -0
  59. amsdal/cloud/services/actions/get_monitoring_info.pyi +21 -0
  60. amsdal/cloud/services/actions/list_dependencies.cpython-311-x86_64-linux-gnu.so +0 -0
  61. amsdal/cloud/services/actions/list_dependencies.pyi +21 -0
  62. amsdal/cloud/services/actions/list_deploys.cpython-311-x86_64-linux-gnu.so +0 -0
  63. amsdal/cloud/services/actions/list_deploys.pyi +19 -0
  64. amsdal/cloud/services/actions/list_envs.cpython-311-x86_64-linux-gnu.so +0 -0
  65. amsdal/cloud/services/actions/list_envs.pyi +20 -0
  66. amsdal/cloud/services/actions/list_secrets.cpython-311-x86_64-linux-gnu.so +0 -0
  67. amsdal/cloud/services/actions/list_secrets.pyi +22 -0
  68. amsdal/cloud/services/actions/manager.cpython-311-x86_64-linux-gnu.so +0 -0
  69. amsdal/cloud/services/actions/manager.pyi +278 -0
  70. amsdal/cloud/services/actions/signup_action.cpython-311-x86_64-linux-gnu.so +0 -0
  71. amsdal/cloud/services/actions/signup_action.pyi +20 -0
  72. amsdal/cloud/services/actions/update_deploy.cpython-311-x86_64-linux-gnu.so +0 -0
  73. amsdal/cloud/services/actions/update_deploy.pyi +19 -0
  74. amsdal/cloud/services/auth/__init__.cpython-311-x86_64-linux-gnu.so +0 -0
  75. amsdal/cloud/services/auth/__init__.pyi +0 -0
  76. amsdal/cloud/services/auth/base.cpython-311-x86_64-linux-gnu.so +0 -0
  77. amsdal/cloud/services/auth/base.pyi +6 -0
  78. amsdal/cloud/services/auth/credentials.cpython-311-x86_64-linux-gnu.so +0 -0
  79. amsdal/cloud/services/auth/credentials.pyi +30 -0
  80. amsdal/cloud/services/auth/manager.cpython-311-x86_64-linux-gnu.so +0 -0
  81. amsdal/cloud/services/auth/manager.pyi +26 -0
  82. amsdal/cloud/services/auth/signup_service.cpython-311-x86_64-linux-gnu.so +0 -0
  83. amsdal/cloud/services/auth/signup_service.pyi +32 -0
  84. amsdal/cloud/services/auth/token.cpython-311-x86_64-linux-gnu.so +0 -0
  85. amsdal/cloud/services/auth/token.pyi +27 -0
  86. amsdal/configs/__init__.py +0 -0
  87. amsdal/configs/__init__.pyi +0 -0
  88. amsdal/configs/constants.py +33 -0
  89. amsdal/configs/constants.pyi +22 -0
  90. amsdal/configs/main.py +258 -0
  91. amsdal/configs/main.pyi +173 -0
  92. amsdal/context/__init__.py +0 -0
  93. amsdal/context/__init__.pyi +0 -0
  94. amsdal/context/manager.py +69 -0
  95. amsdal/context/manager.pyi +50 -0
  96. amsdal/contrib/__init__.cpython-311-x86_64-linux-gnu.so +0 -0
  97. amsdal/contrib/__init__.pyi +0 -0
  98. amsdal/contrib/app_config.py +7 -0
  99. amsdal/contrib/app_config.pyi +6 -0
  100. amsdal/contrib/auth/__init__.py +0 -0
  101. amsdal/contrib/auth/__init__.pyi +0 -0
  102. amsdal/contrib/auth/app.py +27 -0
  103. amsdal/contrib/auth/app.pyi +15 -0
  104. amsdal/contrib/auth/decorators/__init__.py +35 -0
  105. amsdal/contrib/auth/decorators/__init__.pyi +6 -0
  106. amsdal/contrib/auth/errors.py +7 -0
  107. amsdal/contrib/auth/errors.pyi +4 -0
  108. amsdal/contrib/auth/fixtures/basic_permissions.json +64 -0
  109. amsdal/contrib/auth/lifecycle/__init__.py +0 -0
  110. amsdal/contrib/auth/lifecycle/__init__.pyi +0 -0
  111. amsdal/contrib/auth/lifecycle/consumer.py +394 -0
  112. amsdal/contrib/auth/lifecycle/consumer.pyi +108 -0
  113. amsdal/contrib/auth/migrations/0000_initial.py +84 -0
  114. amsdal/contrib/auth/models/__init__.py +0 -0
  115. amsdal/contrib/auth/models/__init__.pyi +0 -0
  116. amsdal/contrib/auth/models/login_session.py +118 -0
  117. amsdal/contrib/auth/models/login_session.pyi +37 -0
  118. amsdal/contrib/auth/models/permission.py +23 -0
  119. amsdal/contrib/auth/models/permission.pyi +18 -0
  120. amsdal/contrib/auth/models/user.py +106 -0
  121. amsdal/contrib/auth/models/user.pyi +46 -0
  122. amsdal/contrib/auth/settings.py +36 -0
  123. amsdal/contrib/auth/settings.pyi +26 -0
  124. amsdal/contrib/frontend_configs/__init__.py +0 -0
  125. amsdal/contrib/frontend_configs/__init__.pyi +0 -0
  126. amsdal/contrib/frontend_configs/app.py +24 -0
  127. amsdal/contrib/frontend_configs/app.pyi +19 -0
  128. amsdal/contrib/frontend_configs/constants.py +1 -0
  129. amsdal/contrib/frontend_configs/constants.pyi +1 -0
  130. amsdal/contrib/frontend_configs/conversion/__init__.py +5 -0
  131. amsdal/contrib/frontend_configs/conversion/__init__.pyi +3 -0
  132. amsdal/contrib/frontend_configs/conversion/convert.py +286 -0
  133. amsdal/contrib/frontend_configs/conversion/convert.pyi +22 -0
  134. amsdal/contrib/frontend_configs/lifecycle/__init__.py +0 -0
  135. amsdal/contrib/frontend_configs/lifecycle/__init__.pyi +0 -0
  136. amsdal/contrib/frontend_configs/lifecycle/consumer.py +306 -0
  137. amsdal/contrib/frontend_configs/lifecycle/consumer.pyi +98 -0
  138. amsdal/contrib/frontend_configs/migrations/0000_initial.py +256 -0
  139. amsdal/contrib/frontend_configs/models/__init__.py +0 -0
  140. amsdal/contrib/frontend_configs/models/__init__.pyi +0 -0
  141. amsdal/contrib/frontend_configs/models/frontend_activator_config.py +22 -0
  142. amsdal/contrib/frontend_configs/models/frontend_activator_config.pyi +12 -0
  143. amsdal/contrib/frontend_configs/models/frontend_config_async_validator.py +11 -0
  144. amsdal/contrib/frontend_configs/models/frontend_config_async_validator.pyi +7 -0
  145. amsdal/contrib/frontend_configs/models/frontend_config_control_action.py +54 -0
  146. amsdal/contrib/frontend_configs/models/frontend_config_control_action.pyi +32 -0
  147. amsdal/contrib/frontend_configs/models/frontend_config_group_validator.py +21 -0
  148. amsdal/contrib/frontend_configs/models/frontend_config_group_validator.pyi +11 -0
  149. amsdal/contrib/frontend_configs/models/frontend_config_option.py +12 -0
  150. amsdal/contrib/frontend_configs/models/frontend_config_option.pyi +8 -0
  151. amsdal/contrib/frontend_configs/models/frontend_config_skip_none_base.py +17 -0
  152. amsdal/contrib/frontend_configs/models/frontend_config_skip_none_base.pyi +8 -0
  153. amsdal/contrib/frontend_configs/models/frontend_config_slider_option.py +13 -0
  154. amsdal/contrib/frontend_configs/models/frontend_config_slider_option.pyi +9 -0
  155. amsdal/contrib/frontend_configs/models/frontend_config_text_mask.py +14 -0
  156. amsdal/contrib/frontend_configs/models/frontend_config_text_mask.pyi +10 -0
  157. amsdal/contrib/frontend_configs/models/frontend_config_validator.py +28 -0
  158. amsdal/contrib/frontend_configs/models/frontend_config_validator.pyi +15 -0
  159. amsdal/contrib/frontend_configs/models/frontend_control_config.py +87 -0
  160. amsdal/contrib/frontend_configs/models/frontend_control_config.pyi +35 -0
  161. amsdal/contrib/frontend_configs/models/frontend_model_config.py +14 -0
  162. amsdal/contrib/frontend_configs/models/frontend_model_config.pyi +9 -0
  163. amsdal/contrib/frontend_configs/utils.py +29 -0
  164. amsdal/contrib/frontend_configs/utils.pyi +17 -0
  165. amsdal/errors.py +31 -0
  166. amsdal/errors.pyi +12 -0
  167. amsdal/fixtures/__init__.cpython-311-x86_64-linux-gnu.so +0 -0
  168. amsdal/fixtures/__init__.pyi +0 -0
  169. amsdal/fixtures/manager.cpython-311-x86_64-linux-gnu.so +0 -0
  170. amsdal/fixtures/manager.pyi +170 -0
  171. amsdal/fixtures/utils.cpython-311-x86_64-linux-gnu.so +0 -0
  172. amsdal/fixtures/utils.pyi +9 -0
  173. amsdal/manager.cpython-311-x86_64-linux-gnu.so +0 -0
  174. amsdal/manager.pyi +265 -0
  175. amsdal/mixins/__init__.cpython-311-x86_64-linux-gnu.so +0 -0
  176. amsdal/mixins/__init__.pyi +0 -0
  177. amsdal/mixins/class_versions_mixin.cpython-311-x86_64-linux-gnu.so +0 -0
  178. amsdal/mixins/class_versions_mixin.pyi +12 -0
  179. amsdal/models/__init__.py +19 -0
  180. amsdal/models/__init__.pyi +9 -0
  181. amsdal/models/core/__init__.py +0 -0
  182. amsdal/models/core/__init__.pyi +0 -0
  183. amsdal/models/core/class_object.py +37 -0
  184. amsdal/models/core/class_object.pyi +24 -0
  185. amsdal/models/core/class_object_meta.py +26 -0
  186. amsdal/models/core/class_object_meta.pyi +15 -0
  187. amsdal/models/core/class_property.py +20 -0
  188. amsdal/models/core/class_property.pyi +11 -0
  189. amsdal/models/core/class_property_meta.py +15 -0
  190. amsdal/models/core/class_property_meta.pyi +10 -0
  191. amsdal/models/core/file.py +156 -0
  192. amsdal/models/core/file.pyi +104 -0
  193. amsdal/models/core/fixture.py +25 -0
  194. amsdal/models/core/fixture.pyi +14 -0
  195. amsdal/models/core/option.py +11 -0
  196. amsdal/models/core/option.pyi +8 -0
  197. amsdal/models/core/validator.py +12 -0
  198. amsdal/models/core/validator.pyi +8 -0
  199. amsdal/models/types/__init__.py +0 -0
  200. amsdal/models/types/__init__.pyi +0 -0
  201. amsdal/models/types/object.py +26 -0
  202. amsdal/models/types/object.pyi +16 -0
  203. amsdal/py.typed +0 -0
  204. amsdal/queryset/__init__.py +21 -0
  205. amsdal/queryset/__init__.pyi +6 -0
  206. amsdal/schemas/__init__.py +0 -0
  207. amsdal/schemas/__init__.pyi +0 -0
  208. amsdal/schemas/core/class_object/model.json +31 -0
  209. amsdal/schemas/core/class_object/properties/display_name.py +9 -0
  210. amsdal/schemas/core/class_object_meta/model.json +59 -0
  211. amsdal/schemas/core/class_property/model.json +22 -0
  212. amsdal/schemas/core/class_property_meta/model.json +23 -0
  213. amsdal/schemas/core/file/hooks/pre_create.py +24 -0
  214. amsdal/schemas/core/file/hooks/pre_update.py +24 -0
  215. amsdal/schemas/core/file/model.json +23 -0
  216. amsdal/schemas/core/file/properties/from_file.py +34 -0
  217. amsdal/schemas/core/file/properties/mimetype.py +13 -0
  218. amsdal/schemas/core/file/properties/str.py +6 -0
  219. amsdal/schemas/core/file/properties/to_file.py +24 -0
  220. amsdal/schemas/core/file/properties/validate_data.py +32 -0
  221. amsdal/schemas/core/fixture/model.json +35 -0
  222. amsdal/schemas/core/option/model.json +19 -0
  223. amsdal/schemas/core/validator/model.json +19 -0
  224. amsdal/schemas/interfaces.py +25 -0
  225. amsdal/schemas/interfaces.pyi +20 -0
  226. amsdal/schemas/manager.cpython-311-x86_64-linux-gnu.so +0 -0
  227. amsdal/schemas/manager.py +0 -0
  228. amsdal/schemas/manager.pyi +0 -0
  229. amsdal/schemas/mixins/__init__.py +0 -0
  230. amsdal/schemas/mixins/__init__.pyi +0 -0
  231. amsdal/schemas/mixins/check_dependencies_mixin.py +125 -0
  232. amsdal/schemas/mixins/check_dependencies_mixin.pyi +45 -0
  233. amsdal/schemas/mixins/verify_schemas_mixin.py +96 -0
  234. amsdal/schemas/mixins/verify_schemas_mixin.pyi +33 -0
  235. amsdal/schemas/repository.py +84 -0
  236. amsdal/schemas/repository.pyi +22 -0
  237. amsdal/schemas/types/anything/model.json +7 -0
  238. amsdal/schemas/types/array/model.json +7 -0
  239. amsdal/schemas/types/binary/model.json +7 -0
  240. amsdal/schemas/types/boolean/model.json +17 -0
  241. amsdal/schemas/types/date/model.json +7 -0
  242. amsdal/schemas/types/datetime/model.json +7 -0
  243. amsdal/schemas/types/dictionary/model.json +8 -0
  244. amsdal/schemas/types/number/model.json +8 -0
  245. amsdal/schemas/types/object/model.json +53 -0
  246. amsdal/schemas/types/string/model.json +8 -0
  247. amsdal/schemas/utils.py +16 -0
  248. amsdal/schemas/utils.pyi +10 -0
  249. amsdal/services/__init__.cpython-311-x86_64-linux-gnu.so +0 -0
  250. amsdal/services/__init__.pyi +0 -0
  251. amsdal/services/transaction_execution.cpython-311-x86_64-linux-gnu.so +0 -0
  252. amsdal/services/transaction_execution.pyi +93 -0
  253. amsdal/transactions/__init__.py +13 -0
  254. amsdal/transactions/__init__.pyi +4 -0
  255. amsdal/utils/__init__.py +0 -0
  256. amsdal/utils/__init__.pyi +0 -0
  257. amsdal/utils/contrib_paths.py +23 -0
  258. amsdal/utils/contrib_paths.pyi +14 -0
  259. amsdal/utils/rollback/__init__.py +440 -0
  260. amsdal/utils/rollback/__init__.pyi +38 -0
  261. amsdal/utils/tests/__init__.py +0 -0
  262. amsdal/utils/tests/enums.py +18 -0
  263. amsdal/utils/tests/factories.py +49 -0
  264. amsdal/utils/tests/helpers.py +499 -0
  265. amsdal-0.4.13.dist-info/METADATA +369 -0
  266. amsdal-0.4.13.dist-info/RECORD +269 -0
  267. amsdal-0.4.13.dist-info/WHEEL +6 -0
  268. amsdal-0.4.13.dist-info/licenses/LICENSE.txt +107 -0
  269. amsdal-0.4.13.dist-info/top_level.txt +1 -0
@@ -0,0 +1,49 @@
1
+ import contextlib
2
+ from typing import Any
3
+ from typing import Generic
4
+ from typing import TypeVar
5
+ from typing import Union
6
+ from typing import get_origin
7
+
8
+ from amsdal_models.classes.model import LegacyModel
9
+ from amsdal_models.classes.model import Model
10
+ from amsdal_utils.models.data_models.reference import Reference
11
+ from polyfactory.factories.base import BuildContext
12
+ from polyfactory.field_meta import FieldMeta
13
+ from polyfactory.field_meta import Null
14
+
15
+ try:
16
+ import polyfactory.factories.pydantic_factory as factories
17
+ except ImportError:
18
+ _msg = '"polyfactory" package is required for using this module. Use "pip install amsdal[factory]" to install it.'
19
+ raise ImportError(_msg) from None
20
+
21
+
22
+ T = TypeVar('T', bound=Model)
23
+
24
+
25
+ class AmsdalFactory(Generic[T], factories.ModelFactory[T]):
26
+ __is_base_factory__ = True
27
+
28
+ @classmethod
29
+ def get_field_value(
30
+ cls,
31
+ field_meta: FieldMeta,
32
+ field_build_parameters: Any | None = None,
33
+ build_context: BuildContext | None = None,
34
+ ) -> Any:
35
+ if get_origin(field_meta.annotation) is Union and field_meta.default is Null:
36
+ with contextlib.suppress(TypeError):
37
+ is_class_definition = any(
38
+ issubclass(arg, LegacyModel) for arg in field_meta.annotation.__args__
39
+ ) and any(issubclass(arg, Reference) for arg in field_meta.annotation.__args__)
40
+ is_optional = any(issubclass(arg, type(None)) for arg in field_meta.annotation.__args__)
41
+
42
+ if is_optional:
43
+ field_meta.annotation = type(None)
44
+ elif is_class_definition:
45
+ for _type in field_meta.annotation.__args__:
46
+ if not issubclass(_type, LegacyModel | type(None) | Reference):
47
+ field_meta.annotation = _type
48
+
49
+ return super().get_field_value(field_meta, field_build_parameters, build_context)
@@ -0,0 +1,499 @@
1
+ import contextlib
2
+ import os
3
+ import random
4
+ import string
5
+ import tempfile
6
+ from collections.abc import AsyncGenerator
7
+ from collections.abc import AsyncIterator
8
+ from collections.abc import Generator
9
+ from collections.abc import Iterator
10
+ from contextlib import asynccontextmanager
11
+ from contextlib import contextmanager
12
+ from contextlib import suppress
13
+ from pathlib import Path
14
+ from typing import Any
15
+
16
+ import yaml
17
+ from amsdal_data.application import AsyncDataApplication
18
+ from amsdal_data.connections.historical.schema_version_manager import AsyncHistoricalSchemaVersionManager
19
+ from amsdal_data.connections.historical.schema_version_manager import HistoricalSchemaVersionManager
20
+ from amsdal_models.migration import migrations
21
+ from amsdal_models.migration.executors.default_executor import DefaultAsyncMigrationExecutor
22
+ from amsdal_models.migration.executors.default_executor import DefaultMigrationExecutor
23
+ from amsdal_models.migration.file_migration_executor import FileMigrationExecutorManager
24
+ from amsdal_models.migration.file_migration_generator import FileMigrationGenerator
25
+ from amsdal_models.migration.file_migration_writer import FileMigrationWriter
26
+ from amsdal_models.migration.migrations import MigrateData
27
+ from amsdal_models.migration.migrations import MigrationSchemas
28
+ from amsdal_models.migration.migrations_loader import MigrationsLoader
29
+ from amsdal_models.migration.utils import contrib_to_module_root_path
30
+ from amsdal_models.schemas.class_schema_loader import ClassSchemaLoader
31
+ from amsdal_utils.config.manager import AmsdalConfigManager
32
+ from amsdal_utils.models.enums import ModuleType
33
+
34
+ from amsdal.configs.constants import CORE_MIGRATIONS_PATH
35
+ from amsdal.configs.main import settings
36
+ from amsdal.manager import AmsdalManager
37
+ from amsdal.manager import AsyncAmsdalManager
38
+ from amsdal.utils.tests.enums import DbExecutionType
39
+ from amsdal.utils.tests.enums import LakehouseOption
40
+ from amsdal.utils.tests.enums import StateOption
41
+
42
+ TESTS_DIR = Path(os.getcwd())
43
+
44
+
45
+ def create_postgres_database(database: str) -> tuple[str, str, str, str]:
46
+ import psycopg
47
+
48
+ db_host = os.getenv('POSTGRES_HOST', 'localhost')
49
+ db_port = os.getenv('POSTGRES_PORT', '5432')
50
+ db_user = os.getenv('POSTGRES_USER', 'postgres')
51
+ db_password = os.getenv('POSTGRES_PASSWORD', 'example')
52
+
53
+ conn = psycopg.connect(
54
+ host=db_host,
55
+ port=db_port,
56
+ user=db_user,
57
+ password=db_password,
58
+ autocommit=True,
59
+ )
60
+ cur = conn.cursor()
61
+
62
+ with suppress(psycopg.errors.DuplicateDatabase):
63
+ cur.execute(f'CREATE DATABASE "{database}"')
64
+
65
+ cur.close()
66
+ conn.close()
67
+
68
+ return (
69
+ db_host,
70
+ db_port,
71
+ db_user,
72
+ db_password,
73
+ )
74
+
75
+
76
+ @contextmanager
77
+ def override_settings(**kwargs: Any) -> Iterator[None]:
78
+ """
79
+ A context manager that temporarily overrides settings.
80
+
81
+ This is a copy of django.test.utils.override_settings, but with the
82
+ ability to override settings with None.
83
+ """
84
+ from amsdal.configs.main import settings
85
+
86
+ original_settings = settings.model_dump()
87
+
88
+ settings.override(**kwargs)
89
+
90
+ try:
91
+ yield
92
+ finally:
93
+ settings.override(**original_settings)
94
+
95
+
96
+ def _get_config_template(
97
+ db_execution_type: DbExecutionType,
98
+ lakehouse_option: LakehouseOption,
99
+ state_option: StateOption,
100
+ *,
101
+ is_async: bool = False,
102
+ ) -> str:
103
+ config_object: dict[str, Any] = {
104
+ 'application_name': 'test_client_app',
105
+ 'async_mode': is_async,
106
+ 'connections': [
107
+ {
108
+ 'name': 'lock',
109
+ 'backend': 'amsdal_data.lock.implementations.thread_lock.ThreadLock',
110
+ },
111
+ ],
112
+ 'resources_config': {
113
+ 'lakehouse': 'lakehouse',
114
+ 'lock': 'lock',
115
+ 'repository': {'default': 'state'},
116
+ },
117
+ }
118
+ if lakehouse_option in [
119
+ LakehouseOption.postgres,
120
+ LakehouseOption.postgres_immutable,
121
+ ]:
122
+ config_object['connections'].append(
123
+ {
124
+ 'name': 'lakehouse',
125
+ 'backend': 'postgres-historical-async' if is_async else 'postgres-historical',
126
+ 'credentials': [
127
+ {
128
+ 'db_host': '{{ db_host }}',
129
+ 'db_port': '{{ db_port }}',
130
+ 'db_user': '{{ db_user }}',
131
+ 'db_password': '{{ db_password }}',
132
+ 'db_name': '{{ lakehouse_postgres_db }}',
133
+ }
134
+ ],
135
+ }
136
+ )
137
+ elif lakehouse_option in [LakehouseOption.sqlite, LakehouseOption.sqlite_immutable]:
138
+ config_object['connections'].append(
139
+ {
140
+ 'name': 'lakehouse',
141
+ 'backend': 'sqlite-historical-async' if is_async else 'sqlite-historical',
142
+ 'credentials': [{'db_path': '{{ db_dir }}/sqlite_lakehouse.sqlite3'}],
143
+ }
144
+ )
145
+
146
+ if db_execution_type == DbExecutionType.lakehouse_only:
147
+ config_object['resources_config']['repository']['default'] = 'lakehouse'
148
+
149
+ return yaml.dump(config_object)
150
+
151
+ if state_option == StateOption.postgres:
152
+ config_object['connections'].append(
153
+ {
154
+ 'name': 'state',
155
+ 'backend': 'postgres-async' if is_async else 'postgres',
156
+ 'credentials': [
157
+ {
158
+ 'db_host': '{{ db_host }}',
159
+ 'db_port': '{{ db_port }}',
160
+ 'db_user': '{{ db_user }}',
161
+ 'db_password': '{{ db_password }}',
162
+ 'db_name': '{{ state_postgres_db }}',
163
+ }
164
+ ],
165
+ }
166
+ )
167
+
168
+ elif state_option == StateOption.sqlite:
169
+ config_object['connections'].append(
170
+ {
171
+ 'name': 'state',
172
+ 'backend': 'sqlite-async' if is_async else 'sqlite',
173
+ 'credentials': [{'db_path': '{{ db_dir }}/sqlite_state.sqlite3'}],
174
+ }
175
+ )
176
+
177
+ return yaml.dump(config_object)
178
+
179
+
180
+ @contextmanager
181
+ def _init_manager(
182
+ db_execution_type: DbExecutionType,
183
+ lakehouse_option: LakehouseOption,
184
+ state_option: StateOption,
185
+ *,
186
+ is_async: bool = False,
187
+ ) -> Generator[tuple[Path, Path], Any, None]:
188
+ Path('.tmp').mkdir(exist_ok=True)
189
+ with tempfile.TemporaryDirectory(dir='.tmp') as temp_dir:
190
+ db_dir = Path(temp_dir) / 'db_dir'
191
+ (db_dir / 'warehouse').mkdir(exist_ok=True, parents=True)
192
+
193
+ lakehouse_database = ''.join(random.sample(string.ascii_letters, 16))
194
+ state_database = ''.join(random.sample(string.ascii_letters, 16))
195
+ config_text = _get_config_template(db_execution_type, lakehouse_option, state_option, is_async=is_async)
196
+
197
+ if lakehouse_option in [
198
+ LakehouseOption.postgres,
199
+ LakehouseOption.postgres_immutable,
200
+ ]:
201
+ (
202
+ db_host,
203
+ db_port,
204
+ db_user,
205
+ db_password,
206
+ ) = create_postgres_database(lakehouse_database)
207
+
208
+ config_text = (
209
+ config_text.replace('{{ db_host }}', db_host)
210
+ .replace('{{ db_port }}', db_port)
211
+ .replace('{{ db_user }}', db_user)
212
+ .replace('{{ db_password }}', db_password)
213
+ .replace('{{ lakehouse_postgres_db }}', lakehouse_database)
214
+ )
215
+ elif lakehouse_option in [
216
+ LakehouseOption.sqlite,
217
+ LakehouseOption.sqlite_immutable,
218
+ ]:
219
+ config_text = config_text.replace('{{ db_dir }}', db_dir.absolute().as_posix())
220
+
221
+ if state_option == StateOption.postgres:
222
+ create_postgres_database(state_database)
223
+ config_text = (
224
+ config_text.replace('{{ db_host }}', db_host)
225
+ .replace('{{ db_port }}', db_port)
226
+ .replace('{{ db_user }}', db_user)
227
+ .replace('{{ db_password }}', db_password)
228
+ .replace('{{ state_postgres_db }}', state_database)
229
+ )
230
+ elif state_option == StateOption.sqlite:
231
+ config_text = config_text.replace('{{ db_dir }}', db_dir.absolute().as_posix())
232
+
233
+ config_path = Path(temp_dir) / 'config.yml'
234
+ config_path.write_text(config_text)
235
+
236
+ yield db_dir, config_path
237
+
238
+
239
+ @contextmanager
240
+ def init_manager(
241
+ src_dir_path: Path,
242
+ db_execution_type: DbExecutionType,
243
+ lakehouse_option: LakehouseOption,
244
+ state_option: StateOption,
245
+ ) -> Generator[AmsdalManager, Any, None]:
246
+ with _init_manager(db_execution_type, lakehouse_option, state_option) as (
247
+ db_dir,
248
+ config_path,
249
+ ):
250
+ with override_settings(
251
+ APP_PATH=db_dir,
252
+ CONFIG_PATH=config_path,
253
+ USER_MODELS_MODULE_PATH=src_dir_path / 'models',
254
+ TRANSACTIONS_MODULE_PATH=src_dir_path / 'transactions',
255
+ FIXTURES_MODULE_PATH=src_dir_path / 'fixtures',
256
+ ):
257
+ config_manager = AmsdalConfigManager()
258
+ config_manager.load_config(config_path)
259
+ manager = AmsdalManager()
260
+ manager.setup()
261
+ manager.post_setup() # type: ignore[call-arg]
262
+
263
+ try:
264
+ yield manager
265
+ finally:
266
+ manager.teardown()
267
+ AmsdalManager.invalidate()
268
+ AmsdalConfigManager.invalidate()
269
+
270
+
271
+ @asynccontextmanager
272
+ async def async_init_manager(
273
+ src_dir_path: Path,
274
+ db_execution_type: DbExecutionType,
275
+ lakehouse_option: LakehouseOption,
276
+ state_option: StateOption,
277
+ ) -> AsyncIterator[AsyncAmsdalManager]:
278
+ with _init_manager(db_execution_type, lakehouse_option, state_option, is_async=True) as (db_dir, config_path):
279
+ with override_settings(
280
+ APP_PATH=db_dir,
281
+ CONFIG_PATH=config_path,
282
+ USER_MODELS_MODULE_PATH=src_dir_path / 'models',
283
+ TRANSACTIONS_MODULE_PATH=src_dir_path / 'transactions',
284
+ FIXTURES_MODULE_PATH=src_dir_path / 'fixtures',
285
+ ):
286
+ config_manager = AmsdalConfigManager()
287
+ config_manager.load_config(config_path)
288
+ manager = AsyncAmsdalManager()
289
+ await manager.setup()
290
+ await manager.post_setup() # type: ignore[call-arg,misc]
291
+
292
+ try:
293
+ yield manager
294
+ finally:
295
+ await manager.teardown()
296
+ await AsyncDataApplication().teardown()
297
+ AsyncAmsdalManager.invalidate()
298
+ AmsdalConfigManager.invalidate()
299
+ AsyncDataApplication.invalidate()
300
+
301
+
302
+ def migrate() -> None:
303
+ schemas = MigrationSchemas()
304
+ executor = DefaultMigrationExecutor(schemas, use_foreign_keys=True)
305
+
306
+ with contextlib.suppress(Exception):
307
+ HistoricalSchemaVersionManager().object_classes # noqa: B018
308
+
309
+ _migrate_per_loader(
310
+ executor,
311
+ MigrationsLoader(
312
+ migrations_dir=CORE_MIGRATIONS_PATH,
313
+ module_type=ModuleType.CORE,
314
+ ),
315
+ )
316
+
317
+ for contrib in settings.CONTRIBS:
318
+ contrib_root_path = contrib_to_module_root_path(contrib)
319
+ _migrate_per_loader(
320
+ executor,
321
+ MigrationsLoader(
322
+ migrations_dir=contrib_root_path / settings.MIGRATIONS_DIRECTORY_NAME,
323
+ module_type=ModuleType.CONTRIB,
324
+ module_name=contrib,
325
+ ),
326
+ )
327
+
328
+ user_schema_loader = ClassSchemaLoader(
329
+ settings.USER_MODELS_MODULE,
330
+ class_filter=lambda cls: cls.__module_type__ == ModuleType.USER,
331
+ )
332
+ _schemas, _cycle_schemas = user_schema_loader.load_sorted()
333
+ _schemas_map = {_schema.title: _schema for _schema in _schemas}
334
+
335
+ for object_schema in _schemas:
336
+ for _operation_data in FileMigrationGenerator.build_operations(
337
+ ModuleType.USER,
338
+ object_schema,
339
+ None,
340
+ ):
341
+ _operation_name = FileMigrationWriter.operation_name_map[_operation_data.type]
342
+ _operation = getattr(migrations, _operation_name)(
343
+ module_type=ModuleType.USER,
344
+ class_name=_operation_data.class_name,
345
+ new_schema=_operation_data.new_schema.model_dump(),
346
+ )
347
+
348
+ _operation.forward(executor)
349
+
350
+ for object_schema in _cycle_schemas:
351
+ for _operation_data in FileMigrationGenerator.build_operations(
352
+ ModuleType.USER,
353
+ object_schema,
354
+ _schemas_map[object_schema.title],
355
+ ):
356
+ _operation_name = FileMigrationWriter.operation_name_map[_operation_data.type]
357
+ _operation = getattr(migrations, _operation_name)(
358
+ module_type=ModuleType.USER,
359
+ class_name=_operation_data.class_name,
360
+ new_schema=_operation_data.new_schema.model_dump(),
361
+ )
362
+
363
+ _operation.forward(executor)
364
+
365
+ executor.flush_buffer()
366
+
367
+
368
+ def _migrate_per_loader(executor: DefaultMigrationExecutor, loader: MigrationsLoader) -> None:
369
+ for _migration in loader:
370
+ migration_class = FileMigrationExecutorManager.get_migration_class(_migration)
371
+ migration_class_instance = migration_class()
372
+
373
+ for _operation in migration_class_instance.operations:
374
+ if isinstance(_operation, MigrateData):
375
+ executor.flush_buffer()
376
+
377
+ _operation.forward(executor)
378
+
379
+ executor.flush_buffer()
380
+
381
+
382
+ async def async_migrate() -> None:
383
+ schemas = MigrationSchemas()
384
+ executor = DefaultAsyncMigrationExecutor(schemas)
385
+
386
+ with contextlib.suppress(Exception):
387
+ await AsyncHistoricalSchemaVersionManager().object_classes
388
+
389
+ await _async_migrate_per_loader(
390
+ executor,
391
+ MigrationsLoader(
392
+ migrations_dir=CORE_MIGRATIONS_PATH,
393
+ module_type=ModuleType.CORE,
394
+ ),
395
+ )
396
+
397
+ for contrib in settings.CONTRIBS:
398
+ contrib_root_path = contrib_to_module_root_path(contrib)
399
+ await _async_migrate_per_loader(
400
+ executor,
401
+ MigrationsLoader(
402
+ migrations_dir=contrib_root_path / settings.MIGRATIONS_DIRECTORY_NAME,
403
+ module_type=ModuleType.CONTRIB,
404
+ module_name=contrib,
405
+ ),
406
+ )
407
+
408
+ user_schema_loader = ClassSchemaLoader(
409
+ settings.USER_MODELS_MODULE,
410
+ class_filter=lambda cls: cls.__module_type__ == ModuleType.USER,
411
+ )
412
+ _schemas, _cycle_schemas = user_schema_loader.load_sorted()
413
+ _schemas_map = {_schema.title: _schema for _schema in _schemas}
414
+
415
+ for object_schema in _schemas:
416
+ for _operation_data in FileMigrationGenerator.build_operations(
417
+ ModuleType.USER,
418
+ object_schema,
419
+ None,
420
+ ):
421
+ _operation_name = FileMigrationWriter.operation_name_map[_operation_data.type]
422
+ _operation = getattr(migrations, _operation_name)(
423
+ module_type=ModuleType.USER,
424
+ class_name=_operation_data.class_name,
425
+ new_schema=_operation_data.new_schema.model_dump(),
426
+ )
427
+
428
+ _operation.forward(executor)
429
+
430
+ for object_schema in _cycle_schemas:
431
+ for _operation_data in FileMigrationGenerator.build_operations(
432
+ ModuleType.USER,
433
+ object_schema,
434
+ _schemas_map[object_schema.title],
435
+ ):
436
+ _operation_name = FileMigrationWriter.operation_name_map[_operation_data.type]
437
+ _operation = getattr(migrations, _operation_name)(
438
+ module_type=ModuleType.USER,
439
+ class_name=_operation_data.class_name,
440
+ new_schema=_operation_data.new_schema.model_dump(),
441
+ )
442
+
443
+ _operation.forward(executor)
444
+
445
+ await executor.flush_buffer()
446
+
447
+
448
+ async def _async_migrate_per_loader(executor: DefaultAsyncMigrationExecutor, loader: MigrationsLoader) -> None:
449
+ for _migration in loader:
450
+ migration_class = FileMigrationExecutorManager.get_migration_class(_migration)
451
+ migration_class_instance = migration_class()
452
+
453
+ for _operation in migration_class_instance.operations:
454
+ if isinstance(_operation, MigrateData):
455
+ await executor.flush_buffer()
456
+
457
+ _operation.forward(executor)
458
+
459
+ await executor.flush_buffer()
460
+
461
+
462
+ @contextmanager
463
+ def init_manager_and_migrate(
464
+ src_dir_path: Path,
465
+ db_execution_type: DbExecutionType,
466
+ lakehouse_option: LakehouseOption,
467
+ state_option: StateOption,
468
+ ) -> Generator[AmsdalManager, Any, None]:
469
+ with init_manager(
470
+ src_dir_path=src_dir_path,
471
+ db_execution_type=db_execution_type,
472
+ lakehouse_option=lakehouse_option,
473
+ state_option=state_option,
474
+ ) as manager:
475
+ migrate()
476
+ manager.authenticate()
477
+ manager.init_classes()
478
+
479
+ yield manager
480
+
481
+
482
+ @asynccontextmanager
483
+ async def async_init_manager_and_migrate(
484
+ src_dir_path: Path,
485
+ db_execution_type: DbExecutionType,
486
+ lakehouse_option: LakehouseOption,
487
+ state_option: StateOption,
488
+ ) -> AsyncGenerator[AsyncAmsdalManager, Any]:
489
+ async with async_init_manager(
490
+ src_dir_path=src_dir_path,
491
+ db_execution_type=db_execution_type,
492
+ lakehouse_option=lakehouse_option,
493
+ state_option=state_option,
494
+ ) as manager:
495
+ await async_migrate()
496
+ manager.authenticate()
497
+ manager.init_classes()
498
+
499
+ yield manager