amsdal 0.5.7__cp312-cp312-macosx_10_13_universal2.whl → 0.5.8__cp312-cp312-macosx_10_13_universal2.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 (67) hide show
  1. amsdal/__about__.py +1 -1
  2. amsdal/__migrations__/0003_update_class_file.py +91 -0
  3. amsdal/cloud/__init__.cpython-312-darwin.so +0 -0
  4. amsdal/cloud/client.cpython-312-darwin.so +0 -0
  5. amsdal/cloud/constants.cpython-312-darwin.so +0 -0
  6. amsdal/cloud/enums.cpython-312-darwin.so +0 -0
  7. amsdal/cloud/models/__init__.cpython-312-darwin.so +0 -0
  8. amsdal/cloud/models/base.cpython-312-darwin.so +0 -0
  9. amsdal/cloud/services/__init__.cpython-312-darwin.so +0 -0
  10. amsdal/cloud/services/actions/__init__.cpython-312-darwin.so +0 -0
  11. amsdal/cloud/services/actions/add_allowlist_ip.cpython-312-darwin.so +0 -0
  12. amsdal/cloud/services/actions/add_basic_auth.cpython-312-darwin.so +0 -0
  13. amsdal/cloud/services/actions/add_dependency.cpython-312-darwin.so +0 -0
  14. amsdal/cloud/services/actions/add_secret.cpython-312-darwin.so +0 -0
  15. amsdal/cloud/services/actions/base.cpython-312-darwin.so +0 -0
  16. amsdal/cloud/services/actions/create_deploy.cpython-312-darwin.so +0 -0
  17. amsdal/cloud/services/actions/create_env.cpython-312-darwin.so +0 -0
  18. amsdal/cloud/services/actions/create_session.cpython-312-darwin.so +0 -0
  19. amsdal/cloud/services/actions/delete_allowlist_ip.cpython-312-darwin.so +0 -0
  20. amsdal/cloud/services/actions/delete_basic_auth.cpython-312-darwin.so +0 -0
  21. amsdal/cloud/services/actions/delete_dependency.cpython-312-darwin.so +0 -0
  22. amsdal/cloud/services/actions/delete_env.cpython-312-darwin.so +0 -0
  23. amsdal/cloud/services/actions/delete_secret.cpython-312-darwin.so +0 -0
  24. amsdal/cloud/services/actions/destroy_deploy.cpython-312-darwin.so +0 -0
  25. amsdal/cloud/services/actions/expose_db.cpython-312-darwin.so +0 -0
  26. amsdal/cloud/services/actions/get_basic_auth_credentials.cpython-312-darwin.so +0 -0
  27. amsdal/cloud/services/actions/get_monitoring_info.cpython-312-darwin.so +0 -0
  28. amsdal/cloud/services/actions/list_dependencies.cpython-312-darwin.so +0 -0
  29. amsdal/cloud/services/actions/list_deploys.cpython-312-darwin.so +0 -0
  30. amsdal/cloud/services/actions/list_envs.cpython-312-darwin.so +0 -0
  31. amsdal/cloud/services/actions/list_secrets.cpython-312-darwin.so +0 -0
  32. amsdal/cloud/services/actions/manager.cpython-312-darwin.so +0 -0
  33. amsdal/cloud/services/actions/signup_action.cpython-312-darwin.so +0 -0
  34. amsdal/cloud/services/actions/update_deploy.cpython-312-darwin.so +0 -0
  35. amsdal/cloud/services/auth/__init__.cpython-312-darwin.so +0 -0
  36. amsdal/cloud/services/auth/base.cpython-312-darwin.so +0 -0
  37. amsdal/cloud/services/auth/credentials.cpython-312-darwin.so +0 -0
  38. amsdal/cloud/services/auth/manager.cpython-312-darwin.so +0 -0
  39. amsdal/cloud/services/auth/signup_service.cpython-312-darwin.so +0 -0
  40. amsdal/cloud/services/auth/token.cpython-312-darwin.so +0 -0
  41. amsdal/configs/main.py +5 -0
  42. amsdal/configs/main.pyi +3 -0
  43. amsdal/contrib/__init__.cpython-312-darwin.so +0 -0
  44. amsdal/contrib/auth/lifecycle/consumer.pyi +1 -1
  45. amsdal/fixtures/__init__.cpython-312-darwin.so +0 -0
  46. amsdal/fixtures/manager.cpython-312-darwin.so +0 -0
  47. amsdal/fixtures/manager.pyi +1 -1
  48. amsdal/fixtures/utils.cpython-312-darwin.so +0 -0
  49. amsdal/manager.cpython-312-darwin.so +0 -0
  50. amsdal/mixins/__init__.cpython-312-darwin.so +0 -0
  51. amsdal/mixins/class_versions_mixin.cpython-312-darwin.so +0 -0
  52. amsdal/models/core/class_property.py +1 -0
  53. amsdal/models/core/file.py +180 -81
  54. amsdal/schemas/core/file/properties/validate_data.py +2 -3
  55. amsdal/schemas/manager.cpython-312-darwin.so +0 -0
  56. amsdal/services/__init__.cpython-312-darwin.so +0 -0
  57. amsdal/services/transaction_execution.cpython-312-darwin.so +0 -0
  58. amsdal/storages/__init__.py +20 -0
  59. amsdal/storages/__init__.pyi +8 -0
  60. amsdal/storages/file_system.py +214 -0
  61. amsdal/storages/file_system.pyi +36 -0
  62. amsdal/utils/tests/migrations.py +45 -66
  63. {amsdal-0.5.7.dist-info → amsdal-0.5.8.dist-info}/METADATA +1 -1
  64. {amsdal-0.5.7.dist-info → amsdal-0.5.8.dist-info}/RECORD +67 -62
  65. {amsdal-0.5.7.dist-info → amsdal-0.5.8.dist-info}/WHEEL +0 -0
  66. {amsdal-0.5.7.dist-info → amsdal-0.5.8.dist-info}/licenses/LICENSE.txt +0 -0
  67. {amsdal-0.5.7.dist-info → amsdal-0.5.8.dist-info}/top_level.txt +0 -0
@@ -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.AMSDAL_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: ...
@@ -0,0 +1,214 @@
1
+ import asyncio
2
+ import os
3
+ from contextlib import suppress
4
+ from pathlib import Path
5
+ from typing import IO
6
+ from typing import Any
7
+ from typing import BinaryIO
8
+
9
+ from amsdal_models.storage.base import Storage
10
+ from amsdal_models.storage.errors import StorageError
11
+ from amsdal_models.storage.helpers import build_storage_address
12
+ from amsdal_models.storage.types import FileProtocol
13
+ from amsdal_utils.config.manager import AmsdalConfigManager
14
+
15
+ CHUNK_SIZE = 8 * 1024
16
+
17
+
18
+ class FileSystemStorage(Storage):
19
+ """
20
+ Simple filesystem-based storage backend.
21
+
22
+ - base_dir: root directory for stored files
23
+ - base_url: URL prefix for building public URLs (optional)
24
+ """
25
+
26
+ keeps_local_copy = False
27
+
28
+ def __init__(
29
+ self,
30
+ base_dir: str | os.PathLike[Any] | None = None,
31
+ base_url: str | None = None,
32
+ *,
33
+ serialize_base_dir: bool = True,
34
+ serialize_base_url: bool = True,
35
+ ) -> None:
36
+ from amsdal.configs.main import settings
37
+
38
+ # If AMSDAL is configured to run in async mode, ensure aiofiles is installed.
39
+ if AmsdalConfigManager().get_config().async_mode:
40
+ try:
41
+ import aiofiles # noqa: F401
42
+ except ImportError as e:
43
+ msg = (
44
+ "AMSDAL is configured to run in async mode, but the 'aiofiles' package is not installed.\n"
45
+ "Please install it to enable async file operations.\n\n"
46
+ "Example:\n"
47
+ " pip install aiofiles\n\n"
48
+ f"Original error: {e}"
49
+ )
50
+ raise ImportError(msg) from e
51
+
52
+ _base_dir = base_dir or settings.AMSDAL_MEDIA_ROOT
53
+ _base_url = base_url or settings.AMSDAL_MEDIA_URL
54
+
55
+ self.base_dir = Path(_base_dir).resolve()
56
+ self.base_url = _base_url
57
+ self.base_dir.mkdir(parents=True, exist_ok=True)
58
+ self.serialize_base_dir = serialize_base_dir
59
+ self.serialize_base_url = serialize_base_url
60
+
61
+ def save(self, file: FileProtocol, content: BinaryIO) -> str:
62
+ suggested = file.filename
63
+ final_name = self._get_available_name(suggested)
64
+ full_path = self._full_path(final_name)
65
+ full_path.parent.mkdir(parents=True, exist_ok=True)
66
+
67
+ with full_path.open('wb') as f:
68
+ # Ensure reading from start
69
+ with suppress(Exception):
70
+ if hasattr(content, 'seek'):
71
+ content.seek(0)
72
+
73
+ chunk = content.read(CHUNK_SIZE)
74
+
75
+ while chunk:
76
+ f.write(chunk)
77
+ chunk = content.read(CHUNK_SIZE)
78
+
79
+ file.storage_address = build_storage_address(self, final_name)
80
+ return final_name
81
+
82
+ def open(self, file: FileProtocol, mode: str = 'rb') -> IO[Any]:
83
+ name = self._name_for(file)
84
+ full_path = self._full_path(name)
85
+
86
+ if not full_path.exists():
87
+ msg = f'File not found: {name}'
88
+ raise StorageError(msg)
89
+ return full_path.open(mode)
90
+
91
+ def delete(self, file: FileProtocol) -> None:
92
+ name = self._name_for(file)
93
+ try:
94
+ self._full_path(name).unlink(missing_ok=True)
95
+ except Exception as e:
96
+ msg = f"Failed to delete '{name}': {e}"
97
+ raise StorageError(msg) from e
98
+
99
+ def exists(self, file: FileProtocol) -> bool:
100
+ name = self._name_for(file)
101
+ return self._full_path(name).exists()
102
+
103
+ def url(self, file: FileProtocol) -> str:
104
+ name = self._name_for(file)
105
+ if not self.base_url:
106
+ # Return file path as fallback
107
+ return self._full_path(name).as_uri()
108
+
109
+ prefix = self.base_url.rstrip('/')
110
+ name_posix = Path(name).as_posix().lstrip('/')
111
+
112
+ return f'{prefix}/{name_posix}'
113
+
114
+ # ---- async counterparts ----
115
+ async def asave(self, file: FileProtocol, content: BinaryIO) -> str:
116
+ import aiofiles.os
117
+
118
+ suggested = file.filename
119
+ final_name = self._get_available_name(suggested)
120
+ full_path = self._full_path(final_name)
121
+ # Ensure directory exists
122
+ await aiofiles.os.makedirs(str(full_path.parent), exist_ok=True)
123
+
124
+ # Ensure reading from start
125
+ with suppress(Exception):
126
+ if hasattr(content, 'seek'):
127
+ with suppress(Exception):
128
+ await asyncio.to_thread(content.seek, 0)
129
+
130
+ async with aiofiles.open(str(full_path), 'wb') as f: # type: ignore[call-arg]
131
+ while True:
132
+ chunk = await asyncio.to_thread(content.read, CHUNK_SIZE)
133
+ if not chunk:
134
+ break
135
+ await f.write(chunk)
136
+
137
+ file.storage_address = build_storage_address(self, final_name)
138
+
139
+ return final_name
140
+
141
+ async def aopen(self, file: FileProtocol, mode: str = 'rb') -> Any:
142
+ import aiofiles.ospath
143
+
144
+ name = self._name_for(file)
145
+ full_path = self._full_path(name)
146
+
147
+ if not await aiofiles.ospath.exists(str(full_path)):
148
+ msg = f'File not found: {name}'
149
+ raise StorageError(msg)
150
+
151
+ return aiofiles.open(str(full_path), mode) # type: ignore[call-overload]
152
+
153
+ async def adelete(self, file: FileProtocol) -> None:
154
+ import aiofiles.os
155
+ import aiofiles.ospath
156
+
157
+ name = self._name_for(file)
158
+ full_path = self._full_path(name)
159
+
160
+ if await aiofiles.ospath.exists(str(full_path)):
161
+ try:
162
+ await aiofiles.os.remove(str(full_path))
163
+ except Exception as e: # pragma: no cover - error path
164
+ msg = f"Failed to delete '{name}': {e}"
165
+ raise StorageError(msg) from e
166
+
167
+ async def aexists(self, file: FileProtocol) -> bool:
168
+ import aiofiles.ospath
169
+
170
+ name = self._name_for(file)
171
+ return await aiofiles.ospath.exists(str(self._full_path(name)))
172
+
173
+ async def aurl(self, file: FileProtocol) -> str:
174
+ # Pure computation; no disk I/O.
175
+ return self.url(file)
176
+
177
+ def _full_path(self, name: str) -> Path:
178
+ # Sanitize name to avoid path traversal
179
+ norm = Path(name).as_posix().lstrip('/')
180
+
181
+ return (self.base_dir / norm).resolve()
182
+
183
+ def _get_available_name(self, name: str) -> str:
184
+ # If file exists, add suffixes to avoid collision
185
+ candidate = Path(name)
186
+ base = candidate.stem
187
+ suffix = candidate.suffix
188
+ parent = candidate.parent.as_posix()
189
+ i = 0
190
+ final = candidate.as_posix()
191
+
192
+ # Check filesystem directly to avoid relying on public exists signature
193
+ while self._full_path(final).exists():
194
+ i += 1
195
+ new_name = f'{base}_{i}{suffix}'
196
+ final = str(Path(parent) / new_name) if parent and parent != '.' else new_name
197
+ return final
198
+
199
+ def _name_for(self, file: FileProtocol) -> str:
200
+ if getattr(file, 'storage_address', None) and getattr(file.storage_address, 'ref', None) is not None:
201
+ if getattr(file.storage_address.ref, 'object_id', None) is not None: # type: ignore[union-attr]
202
+ return str(file.storage_address.ref.object_id) # type: ignore[union-attr]
203
+ return file.filename
204
+
205
+ def _export_kwargs(self) -> dict[str, Any]:
206
+ kwargs = {}
207
+
208
+ if self.serialize_base_dir:
209
+ kwargs['base_dir'] = str(self.base_dir)
210
+
211
+ if self.serialize_base_url:
212
+ kwargs['base_url'] = self.base_url
213
+
214
+ return kwargs
@@ -0,0 +1,36 @@
1
+ import os
2
+ from _typeshed import Incomplete
3
+ from amsdal_models.storage.base import Storage
4
+ from amsdal_models.storage.types import FileProtocol
5
+ from pathlib import Path
6
+ from typing import Any, BinaryIO, IO
7
+
8
+ CHUNK_SIZE: Incomplete
9
+
10
+ class FileSystemStorage(Storage):
11
+ """
12
+ Simple filesystem-based storage backend.
13
+
14
+ - base_dir: root directory for stored files
15
+ - base_url: URL prefix for building public URLs (optional)
16
+ """
17
+ keeps_local_copy: bool
18
+ base_dir: Incomplete
19
+ base_url: Incomplete
20
+ serialize_base_dir: Incomplete
21
+ serialize_base_url: Incomplete
22
+ def __init__(self, base_dir: str | os.PathLike[Any] | None = None, base_url: str | None = None, *, serialize_base_dir: bool = True, serialize_base_url: bool = True) -> None: ...
23
+ def save(self, file: FileProtocol, content: BinaryIO) -> str: ...
24
+ def open(self, file: FileProtocol, mode: str = 'rb') -> IO[Any]: ...
25
+ def delete(self, file: FileProtocol) -> None: ...
26
+ def exists(self, file: FileProtocol) -> bool: ...
27
+ def url(self, file: FileProtocol) -> str: ...
28
+ async def asave(self, file: FileProtocol, content: BinaryIO) -> str: ...
29
+ async def aopen(self, file: FileProtocol, mode: str = 'rb') -> Any: ...
30
+ async def adelete(self, file: FileProtocol) -> None: ...
31
+ async def aexists(self, file: FileProtocol) -> bool: ...
32
+ async def aurl(self, file: FileProtocol) -> str: ...
33
+ def _full_path(self, name: str) -> Path: ...
34
+ def _get_available_name(self, name: str) -> str: ...
35
+ def _name_for(self, file: FileProtocol) -> str: ...
36
+ def _export_kwargs(self) -> dict[str, Any]: ...
@@ -1,17 +1,19 @@
1
1
  import contextlib
2
+ from asyncio import iscoroutine
2
3
 
3
4
  from amsdal_data.connections.historical.schema_version_manager import AsyncHistoricalSchemaVersionManager
4
5
  from amsdal_data.connections.historical.schema_version_manager import HistoricalSchemaVersionManager
5
6
  from amsdal_models.migration import migrations
6
7
  from amsdal_models.migration.executors.default_executor import DefaultAsyncMigrationExecutor
7
8
  from amsdal_models.migration.executors.default_executor import DefaultMigrationExecutor
8
- from amsdal_models.migration.file_migration_executor import SimpleFileMigrationExecutorManager
9
+ from amsdal_models.migration.file_migration_executor import AsyncFileMigrationExecutorManager
10
+ from amsdal_models.migration.file_migration_executor import FileMigrationExecutorManager
9
11
  from amsdal_models.migration.file_migration_generator import SimpleFileMigrationGenerator
12
+ from amsdal_models.migration.file_migration_store import AsyncFileMigrationStore
13
+ from amsdal_models.migration.file_migration_store import FileMigrationStore
10
14
  from amsdal_models.migration.file_migration_writer import FileMigrationWriter
11
- from amsdal_models.migration.migrations import MigrateData
12
15
  from amsdal_models.migration.migrations import MigrationSchemas
13
16
  from amsdal_models.migration.migrations_loader import MigrationsLoader
14
- from amsdal_models.migration.utils import contrib_to_module_root_path
15
17
  from amsdal_models.schemas.class_schema_loader import ClassSchemaLoader
16
18
  from amsdal_utils.models.enums import ModuleType
17
19
 
@@ -22,29 +24,28 @@ from amsdal.configs.main import settings
22
24
  def migrate() -> None:
23
25
  schemas = MigrationSchemas()
24
26
  executor = DefaultMigrationExecutor(schemas, use_foreign_keys=True)
27
+ store = FileMigrationStore(settings.migrations_root_path)
28
+ store.init_migration_table()
29
+
30
+ class UserMigrationsLoader(MigrationsLoader):
31
+ def __init__(self):
32
+ super().__init__(settings.migrations_root_path, ModuleType.USER)
33
+ self._migrations_files = []
25
34
 
26
35
  with contextlib.suppress(Exception):
27
36
  HistoricalSchemaVersionManager().object_classes # noqa: B018
28
37
 
29
- _migrate_per_loader(
30
- executor,
31
- MigrationsLoader(
32
- migrations_dir=CORE_MIGRATIONS_PATH,
33
- module_type=ModuleType.CORE,
34
- ),
38
+ # migrate core and contrib due to applied migrations
39
+ executor_manager = FileMigrationExecutorManager(
40
+ core_migrations_path=CORE_MIGRATIONS_PATH,
41
+ app_migrations_loader=UserMigrationsLoader(),
42
+ executor=executor,
43
+ store=store,
44
+ contrib=settings.CONTRIBS,
35
45
  )
46
+ executor_manager.execute()
36
47
 
37
- for contrib in settings.CONTRIBS:
38
- contrib_root_path = contrib_to_module_root_path(contrib)
39
- _migrate_per_loader(
40
- executor,
41
- MigrationsLoader(
42
- migrations_dir=contrib_root_path / settings.MIGRATIONS_DIRECTORY_NAME,
43
- module_type=ModuleType.CONTRIB,
44
- module_name=contrib,
45
- ),
46
- )
47
-
48
+ # always apply migrations for user models
48
49
  user_schema_loader = ClassSchemaLoader(
49
50
  settings.USER_MODELS_MODULE,
50
51
  class_filter=lambda cls: cls.__module_type__ == ModuleType.USER,
@@ -85,46 +86,31 @@ def migrate() -> None:
85
86
  executor.flush_buffer()
86
87
 
87
88
 
88
- def _migrate_per_loader(executor: DefaultMigrationExecutor, loader: MigrationsLoader) -> None:
89
- for _migration in loader:
90
- migration_class = SimpleFileMigrationExecutorManager.get_migration_class(_migration)
91
- migration_class_instance = migration_class()
92
-
93
- for _operation in migration_class_instance.operations:
94
- if isinstance(_operation, MigrateData):
95
- executor.flush_buffer()
96
-
97
- _operation.forward(executor)
98
-
99
- executor.flush_buffer()
100
-
101
-
102
89
  async def async_migrate() -> None:
103
90
  schemas = MigrationSchemas()
104
91
  executor = DefaultAsyncMigrationExecutor(schemas)
92
+ store = AsyncFileMigrationStore(settings.migrations_root_path)
93
+ await store.init_migration_table()
94
+
95
+ class UserMigrationsLoader(MigrationsLoader):
96
+ def __init__(self):
97
+ super().__init__(settings.migrations_root_path, ModuleType.USER)
98
+ self._migrations_files = []
105
99
 
106
100
  with contextlib.suppress(Exception):
107
101
  await AsyncHistoricalSchemaVersionManager().object_classes
108
102
 
109
- await _async_migrate_per_loader(
110
- executor,
111
- MigrationsLoader(
112
- migrations_dir=CORE_MIGRATIONS_PATH,
113
- module_type=ModuleType.CORE,
114
- ),
103
+ # migrate core and contrib due to applied migrations
104
+ executor_manager = AsyncFileMigrationExecutorManager(
105
+ core_migrations_path=CORE_MIGRATIONS_PATH,
106
+ app_migrations_loader=UserMigrationsLoader(),
107
+ executor=executor,
108
+ store=store,
109
+ contrib=settings.CONTRIBS,
115
110
  )
111
+ await executor_manager.execute()
116
112
 
117
- for contrib in settings.CONTRIBS:
118
- contrib_root_path = contrib_to_module_root_path(contrib)
119
- await _async_migrate_per_loader(
120
- executor,
121
- MigrationsLoader(
122
- migrations_dir=contrib_root_path / settings.MIGRATIONS_DIRECTORY_NAME,
123
- module_type=ModuleType.CONTRIB,
124
- module_name=contrib,
125
- ),
126
- )
127
-
113
+ # always apply migrations for user models
128
114
  user_schema_loader = ClassSchemaLoader(
129
115
  settings.USER_MODELS_MODULE,
130
116
  class_filter=lambda cls: cls.__module_type__ == ModuleType.USER,
@@ -146,6 +132,10 @@ async def async_migrate() -> None:
146
132
  )
147
133
 
148
134
  _operation.forward(executor)
135
+ forward_result = _operation.forward(executor)
136
+
137
+ if iscoroutine(forward_result):
138
+ await forward_result
149
139
 
150
140
  for object_schema in _cycle_schemas:
151
141
  for _operation_data in SimpleFileMigrationGenerator.build_operations(
@@ -160,20 +150,9 @@ async def async_migrate() -> None:
160
150
  new_schema=_operation_data.new_schema.model_dump(),
161
151
  )
162
152
 
163
- _operation.forward(executor)
164
-
165
- await executor.flush_buffer()
166
-
153
+ forward_result = _operation.forward(executor)
167
154
 
168
- async def _async_migrate_per_loader(executor: DefaultAsyncMigrationExecutor, loader: MigrationsLoader) -> None:
169
- for _migration in loader:
170
- migration_class = SimpleFileMigrationExecutorManager.get_migration_class(_migration)
171
- migration_class_instance = migration_class()
155
+ if iscoroutine(forward_result):
156
+ await forward_result
172
157
 
173
- for _operation in migration_class_instance.operations:
174
- if isinstance(_operation, MigrateData):
175
- await executor.flush_buffer()
176
-
177
- _operation.forward(executor)
178
-
179
- await executor.flush_buffer()
158
+ await executor.flush_buffer()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: amsdal
3
- Version: 0.5.7
3
+ Version: 0.5.8
4
4
  Summary: AMSDAL
5
5
  License: AMSDAL End User License Agreement
6
6