synapse-sdk 1.0.0b24__py3-none-any.whl → 2025.9.3__py3-none-any.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.
Potentially problematic release.
This version of synapse-sdk might be problematic. Click here for more details.
- synapse_sdk/clients/agent/ray.py +50 -0
- synapse_sdk/devtools/docs/docs/api/clients/annotation-mixin.md +378 -0
- synapse_sdk/devtools/docs/docs/api/clients/backend.md +368 -1
- synapse_sdk/devtools/docs/docs/api/clients/core-mixin.md +477 -0
- synapse_sdk/devtools/docs/docs/api/clients/data-collection-mixin.md +422 -0
- synapse_sdk/devtools/docs/docs/api/clients/hitl-mixin.md +554 -0
- synapse_sdk/devtools/docs/docs/api/clients/index.md +391 -0
- synapse_sdk/devtools/docs/docs/api/clients/integration-mixin.md +571 -0
- synapse_sdk/devtools/docs/docs/api/clients/ml-mixin.md +578 -0
- synapse_sdk/devtools/docs/docs/api/clients/ray.md +23 -2
- synapse_sdk/devtools/docs/docs/plugins/developing-upload-template.md +1463 -0
- synapse_sdk/devtools/docs/docs/plugins/export-plugins.md +161 -34
- synapse_sdk/devtools/docs/docs/plugins/upload-plugins.md +1497 -213
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/annotation-mixin.md +289 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/backend.md +378 -11
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/core-mixin.md +417 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/data-collection-mixin.md +356 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/hitl-mixin.md +192 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/index.md +391 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/integration-mixin.md +479 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/ml-mixin.md +284 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/ray.md +23 -2
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/developing-upload-template.md +1463 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/export-plugins.md +161 -34
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/upload-plugins.md +1752 -572
- synapse_sdk/devtools/docs/sidebars.ts +7 -0
- synapse_sdk/plugins/README.md +1 -2
- synapse_sdk/plugins/categories/base.py +23 -0
- synapse_sdk/plugins/categories/export/actions/__init__.py +3 -0
- synapse_sdk/plugins/categories/export/actions/export/__init__.py +28 -0
- synapse_sdk/plugins/categories/export/actions/export/action.py +160 -0
- synapse_sdk/plugins/categories/export/actions/export/enums.py +113 -0
- synapse_sdk/plugins/categories/export/actions/export/exceptions.py +53 -0
- synapse_sdk/plugins/categories/export/actions/export/models.py +74 -0
- synapse_sdk/plugins/categories/export/actions/export/run.py +195 -0
- synapse_sdk/plugins/categories/export/actions/export/utils.py +187 -0
- synapse_sdk/plugins/categories/export/templates/plugin/__init__.py +1 -1
- synapse_sdk/plugins/categories/upload/actions/upload/__init__.py +1 -2
- synapse_sdk/plugins/categories/upload/actions/upload/action.py +154 -531
- synapse_sdk/plugins/categories/upload/actions/upload/context.py +185 -0
- synapse_sdk/plugins/categories/upload/actions/upload/factory.py +143 -0
- synapse_sdk/plugins/categories/upload/actions/upload/models.py +66 -29
- synapse_sdk/plugins/categories/upload/actions/upload/orchestrator.py +182 -0
- synapse_sdk/plugins/categories/upload/actions/upload/registry.py +113 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/__init__.py +1 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/base.py +106 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/cleanup.py +62 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/collection.py +62 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/generate.py +80 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/initialize.py +66 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/metadata.py +101 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/organize.py +89 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/upload.py +96 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/validate.py +61 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/__init__.py +1 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/base.py +86 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/data_unit/__init__.py +1 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/data_unit/batch.py +39 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/data_unit/single.py +34 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/file_discovery/__init__.py +1 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/file_discovery/flat.py +233 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/file_discovery/recursive.py +238 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/metadata/__init__.py +1 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/metadata/excel.py +174 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/metadata/none.py +16 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/upload/__init__.py +1 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/upload/async_upload.py +109 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/upload/sync.py +43 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/validation/__init__.py +1 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/validation/default.py +45 -0
- synapse_sdk/plugins/categories/upload/actions/upload/utils.py +194 -83
- synapse_sdk/plugins/categories/upload/templates/config.yaml +4 -0
- synapse_sdk/plugins/categories/upload/templates/plugin/__init__.py +269 -0
- synapse_sdk/plugins/categories/upload/templates/plugin/upload.py +71 -27
- synapse_sdk/plugins/models.py +5 -0
- {synapse_sdk-1.0.0b24.dist-info → synapse_sdk-2025.9.3.dist-info}/METADATA +3 -2
- {synapse_sdk-1.0.0b24.dist-info → synapse_sdk-2025.9.3.dist-info}/RECORD +81 -30
- synapse_sdk/plugins/categories/export/actions/export.py +0 -385
- synapse_sdk/plugins/categories/export/enums.py +0 -7
- {synapse_sdk-1.0.0b24.dist-info → synapse_sdk-2025.9.3.dist-info}/WHEEL +0 -0
- {synapse_sdk-1.0.0b24.dist-info → synapse_sdk-2025.9.3.dist-info}/entry_points.txt +0 -0
- {synapse_sdk-1.0.0b24.dist-info → synapse_sdk-2025.9.3.dist-info}/licenses/LICENSE +0 -0
- {synapse_sdk-1.0.0b24.dist-info → synapse_sdk-2025.9.3.dist-info}/top_level.txt +0 -0
|
@@ -53,7 +53,14 @@ const sidebars: SidebarsConfig = {
|
|
|
53
53
|
type: 'category',
|
|
54
54
|
label: 'Clients',
|
|
55
55
|
items: [
|
|
56
|
+
'api/clients/index',
|
|
56
57
|
'api/clients/backend',
|
|
58
|
+
'api/clients/annotation-mixin',
|
|
59
|
+
'api/clients/core-mixin',
|
|
60
|
+
'api/clients/data-collection-mixin',
|
|
61
|
+
'api/clients/hitl-mixin',
|
|
62
|
+
'api/clients/integration-mixin',
|
|
63
|
+
'api/clients/ml-mixin',
|
|
57
64
|
'api/clients/agent',
|
|
58
65
|
'api/clients/ray',
|
|
59
66
|
'api/clients/base',
|
synapse_sdk/plugins/README.md
CHANGED
|
@@ -329,7 +329,7 @@ from .enums import LogCode, LOG_MESSAGES, UploadStatus
|
|
|
329
329
|
from .exceptions import ExcelParsingError, ExcelSecurityError
|
|
330
330
|
from .models import UploadParams
|
|
331
331
|
from .run import UploadRun
|
|
332
|
-
from .utils import
|
|
332
|
+
from .utils import ExcelSecurityConfig, PathAwareJSONEncoder
|
|
333
333
|
|
|
334
334
|
__all__ = [
|
|
335
335
|
'UploadAction',
|
|
@@ -342,7 +342,6 @@ __all__ = [
|
|
|
342
342
|
'ExcelParsingError',
|
|
343
343
|
'PathAwareJSONEncoder',
|
|
344
344
|
'ExcelSecurityConfig',
|
|
345
|
-
'ExcelMetadataUtils',
|
|
346
345
|
]
|
|
347
346
|
```
|
|
348
347
|
|
|
@@ -181,6 +181,10 @@ class Action:
|
|
|
181
181
|
for key, value in self.package_manager_options.items():
|
|
182
182
|
runtime_env[self.plugin_package_manager][key] = value
|
|
183
183
|
|
|
184
|
+
# Sentry init if SENTRY_DSN is set
|
|
185
|
+
if self.envs.get('SENTRY_INIT_FUNCTION') is not None:
|
|
186
|
+
runtime_env['worker_process_setup_hook'] = self.envs.pop('SENTRY_INIT_FUNCTION')
|
|
187
|
+
|
|
184
188
|
# 맨 마지막에 진행되어야 함
|
|
185
189
|
runtime_env['env_vars'] = self.envs
|
|
186
190
|
|
|
@@ -308,8 +312,27 @@ class Action:
|
|
|
308
312
|
|
|
309
313
|
return JobSubmissionClient(address=self.envs.get('RAY_DASHBOARD_URL'))
|
|
310
314
|
|
|
315
|
+
def _sentry_init(self, sentry_dsn):
|
|
316
|
+
import sentry_sdk
|
|
317
|
+
from sentry_sdk.integrations.ray import RayIntegration
|
|
318
|
+
|
|
319
|
+
sentry_sdk.init(
|
|
320
|
+
dsn=sentry_dsn,
|
|
321
|
+
environment=os.getenv('DEPLOYMENT_TARGET', 'development'),
|
|
322
|
+
integrations=[RayIntegration()],
|
|
323
|
+
send_default_pii=True,
|
|
324
|
+
)
|
|
325
|
+
|
|
326
|
+
def sentry_init(self):
|
|
327
|
+
sentry_dsn = os.getenv('SENTRY_DSN', self.envs.get('SENTRY_DSN') if self.envs else None)
|
|
328
|
+
if sentry_dsn:
|
|
329
|
+
self._sentry_init(sentry_dsn)
|
|
330
|
+
self.envs['SENTRY_INIT_FUNCTION'] = self._sentry_init
|
|
331
|
+
|
|
311
332
|
def ray_init(self):
|
|
312
333
|
import ray
|
|
313
334
|
|
|
335
|
+
self.sentry_init()
|
|
336
|
+
|
|
314
337
|
if not ray.is_initialized():
|
|
315
338
|
ray.init(address=self.envs['RAY_ADDRESS'], ignore_reinit_error=True)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from .action import ExportAction
|
|
2
|
+
from .enums import ExportStatus, LogCode
|
|
3
|
+
from .exceptions import ExportError, ExportTargetError, ExportValidationError
|
|
4
|
+
from .models import ExportParams
|
|
5
|
+
from .run import ExportRun
|
|
6
|
+
from .utils import (
|
|
7
|
+
AssignmentExportTargetHandler,
|
|
8
|
+
ExportTargetHandler,
|
|
9
|
+
GroundTruthExportTargetHandler,
|
|
10
|
+
TargetHandlerFactory,
|
|
11
|
+
TaskExportTargetHandler,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
'ExportAction',
|
|
16
|
+
'ExportStatus',
|
|
17
|
+
'LogCode',
|
|
18
|
+
'ExportError',
|
|
19
|
+
'ExportTargetError',
|
|
20
|
+
'ExportValidationError',
|
|
21
|
+
'ExportParams',
|
|
22
|
+
'ExportRun',
|
|
23
|
+
'ExportTargetHandler',
|
|
24
|
+
'AssignmentExportTargetHandler',
|
|
25
|
+
'GroundTruthExportTargetHandler',
|
|
26
|
+
'TaskExportTargetHandler',
|
|
27
|
+
'TargetHandlerFactory',
|
|
28
|
+
]
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
from itertools import tee
|
|
2
|
+
from typing import Any, Dict
|
|
3
|
+
|
|
4
|
+
from pydantic_core import PydanticCustomError
|
|
5
|
+
|
|
6
|
+
from synapse_sdk.clients.exceptions import ClientError
|
|
7
|
+
from synapse_sdk.i18n import gettext as _
|
|
8
|
+
from synapse_sdk.plugins.categories.base import Action
|
|
9
|
+
from synapse_sdk.plugins.categories.decorators import register_action
|
|
10
|
+
from synapse_sdk.plugins.enums import PluginCategory, RunMethod
|
|
11
|
+
from synapse_sdk.utils.storage import get_pathlib
|
|
12
|
+
|
|
13
|
+
from .enums import LogCode
|
|
14
|
+
from .models import ExportParams
|
|
15
|
+
from .run import ExportRun
|
|
16
|
+
from .utils import TargetHandlerFactory
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@register_action
|
|
20
|
+
class ExportAction(Action):
|
|
21
|
+
"""Main export action for processing and exporting data from various targets.
|
|
22
|
+
|
|
23
|
+
Handles export operations including target validation, data retrieval,
|
|
24
|
+
and file generation. Supports export from assignment, ground_truth, and task
|
|
25
|
+
targets with comprehensive progress tracking and error handling.
|
|
26
|
+
|
|
27
|
+
Features:
|
|
28
|
+
- Multiple target source support (assignment, ground_truth, task)
|
|
29
|
+
- Filter validation and data retrieval
|
|
30
|
+
- Original file and data file export options
|
|
31
|
+
- Progress tracking with detailed metrics
|
|
32
|
+
- Comprehensive error logging
|
|
33
|
+
- Project configuration handling
|
|
34
|
+
|
|
35
|
+
Class Attributes:
|
|
36
|
+
name (str): Action identifier ('export')
|
|
37
|
+
category (PluginCategory): EXPORT category
|
|
38
|
+
method (RunMethod): JOB execution method
|
|
39
|
+
run_class (type): ExportRun for specialized logging
|
|
40
|
+
params_model (type): ExportParams for parameter validation
|
|
41
|
+
progress_categories (dict): Progress tracking configuration
|
|
42
|
+
metrics_categories (dict): Metrics collection configuration
|
|
43
|
+
|
|
44
|
+
Example:
|
|
45
|
+
>>> action = ExportAction(
|
|
46
|
+
... params={
|
|
47
|
+
... 'name': 'Assignment Export',
|
|
48
|
+
... 'storage': 1,
|
|
49
|
+
... 'path': '/exports/assignments',
|
|
50
|
+
... 'target': 'assignment',
|
|
51
|
+
... 'filter': {'project': 123}
|
|
52
|
+
... },
|
|
53
|
+
... plugin_config=config
|
|
54
|
+
... )
|
|
55
|
+
>>> result = action.start()
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
name = 'export'
|
|
59
|
+
category = PluginCategory.EXPORT
|
|
60
|
+
method = RunMethod.JOB
|
|
61
|
+
params_model = ExportParams
|
|
62
|
+
run_class = ExportRun
|
|
63
|
+
progress_categories = {
|
|
64
|
+
'dataset_conversion': {
|
|
65
|
+
'proportion': 100,
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
metrics_categories = {
|
|
69
|
+
'data_file': {
|
|
70
|
+
'stand_by': 0,
|
|
71
|
+
'failed': 0,
|
|
72
|
+
'success': 0,
|
|
73
|
+
},
|
|
74
|
+
'original_file': {
|
|
75
|
+
'stand_by': 0,
|
|
76
|
+
'failed': 0,
|
|
77
|
+
'success': 0,
|
|
78
|
+
},
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
def get_filtered_results(self, filters, handler):
|
|
82
|
+
"""Get filtered target results.
|
|
83
|
+
|
|
84
|
+
Retrieves data from the specified target using the provided filters
|
|
85
|
+
through the appropriate target handler.
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
filters (dict): Filter criteria to apply
|
|
89
|
+
handler (ExportTargetHandler): Target-specific handler
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
tuple: (results, count) where results is the data and count is total
|
|
93
|
+
|
|
94
|
+
Raises:
|
|
95
|
+
PydanticCustomError: If data retrieval fails
|
|
96
|
+
"""
|
|
97
|
+
try:
|
|
98
|
+
result_list = handler.get_results(self.client, filters)
|
|
99
|
+
results = result_list[0]
|
|
100
|
+
count = result_list[1]
|
|
101
|
+
except ClientError:
|
|
102
|
+
raise PydanticCustomError('client_error', _('Unable to get Ground Truth dataset.'))
|
|
103
|
+
return results, count
|
|
104
|
+
|
|
105
|
+
def start(self) -> Dict[str, Any]:
|
|
106
|
+
"""Start the export process.
|
|
107
|
+
|
|
108
|
+
Main entry point for export operations. Handles parameter preparation,
|
|
109
|
+
target handler selection, data retrieval, and export execution.
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
Dict[str, Any]: Export results from the entrypoint
|
|
113
|
+
|
|
114
|
+
Raises:
|
|
115
|
+
Various exceptions based on validation and processing failures
|
|
116
|
+
"""
|
|
117
|
+
self.run.log_message_with_code(LogCode.EXPORT_STARTED)
|
|
118
|
+
|
|
119
|
+
filters = {'expand': 'data', **self.params['filter']}
|
|
120
|
+
target = self.params['target']
|
|
121
|
+
handler = TargetHandlerFactory.get_handler(target)
|
|
122
|
+
|
|
123
|
+
self.params['results'], self.params['count'] = self.get_filtered_results(filters, handler)
|
|
124
|
+
|
|
125
|
+
if self.params['count'] == 0:
|
|
126
|
+
self.run.log_message_with_code(LogCode.NO_RESULTS_FOUND)
|
|
127
|
+
else:
|
|
128
|
+
self.run.log_message_with_code(LogCode.RESULTS_RETRIEVED, self.params['count'])
|
|
129
|
+
|
|
130
|
+
# For the 'ground_truth' target, retrieve project information from the first result and add configuration
|
|
131
|
+
if target == 'ground_truth':
|
|
132
|
+
try:
|
|
133
|
+
# Split generator into two using tee()
|
|
134
|
+
peek_iter, main_iter = tee(self.params['results'])
|
|
135
|
+
first_result = next(peek_iter) # Peek first value only
|
|
136
|
+
project_pk = first_result['project']
|
|
137
|
+
project_info = self.client.get_project(project_pk)
|
|
138
|
+
self.params['project_id'] = project_pk
|
|
139
|
+
self.params['configuration'] = project_info.get('configuration', {})
|
|
140
|
+
self.params['results'] = main_iter # Keep original generator intact
|
|
141
|
+
except (StopIteration, KeyError):
|
|
142
|
+
self.params['configuration'] = {}
|
|
143
|
+
# For the 'assignment' and 'task' targets, retrieve the project from the filter as before
|
|
144
|
+
elif target in ['assignment', 'task'] and 'project' in self.params['filter']:
|
|
145
|
+
project_pk = self.params['filter']['project']
|
|
146
|
+
project_info = self.client.get_project(project_pk)
|
|
147
|
+
self.params['configuration'] = project_info.get('configuration', {})
|
|
148
|
+
|
|
149
|
+
export_items = handler.get_export_item(self.params['results'])
|
|
150
|
+
storage = self.client.get_storage(self.params['storage'])
|
|
151
|
+
pathlib_cwd = get_pathlib(storage, self.params['path'])
|
|
152
|
+
exporter = self.entrypoint(self.run, export_items, pathlib_cwd, **self.params)
|
|
153
|
+
|
|
154
|
+
try:
|
|
155
|
+
result = exporter.export()
|
|
156
|
+
self.run.log_message_with_code(LogCode.EXPORT_COMPLETED)
|
|
157
|
+
return result
|
|
158
|
+
except Exception as e:
|
|
159
|
+
self.run.log_message_with_code(LogCode.EXPORT_FAILED, str(e))
|
|
160
|
+
raise
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
|
|
3
|
+
from synapse_sdk.shared.enums import Context
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ExportStatus(str, Enum):
|
|
7
|
+
"""Export processing status enumeration.
|
|
8
|
+
|
|
9
|
+
Defines the possible states for export operations, data files, and export items
|
|
10
|
+
throughout the export process.
|
|
11
|
+
|
|
12
|
+
Attributes:
|
|
13
|
+
SUCCESS: Export completed successfully
|
|
14
|
+
FAILED: Export failed with errors
|
|
15
|
+
STAND_BY: Export waiting to be processed
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
SUCCESS = 'success'
|
|
19
|
+
FAILED = 'failed'
|
|
20
|
+
STAND_BY = 'stand_by'
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class LogCode(str, Enum):
|
|
24
|
+
"""Type-safe logging codes for export operations.
|
|
25
|
+
|
|
26
|
+
Enumeration of all possible log events during export processing. Each code
|
|
27
|
+
corresponds to a specific event or error state with predefined message
|
|
28
|
+
templates and log levels.
|
|
29
|
+
|
|
30
|
+
The codes are organized by category:
|
|
31
|
+
- Validation codes (VALIDATION_FAILED, STORAGE_VALIDATION_FAILED, etc.)
|
|
32
|
+
- Export processing codes (EXPORT_STARTED, EXPORT_COMPLETED, etc.)
|
|
33
|
+
- File processing codes (ORIGINAL_FILE_EXPORTED, DATA_FILE_EXPORTED, etc.)
|
|
34
|
+
- Error handling codes (TARGET_HANDLER_ERROR, EXPORT_FAILED, etc.)
|
|
35
|
+
|
|
36
|
+
Each code maps to a configuration in LOG_MESSAGES with message template
|
|
37
|
+
and appropriate log level.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
STORAGE_VALIDATION_FAILED = 'STORAGE_VALIDATION_FAILED'
|
|
41
|
+
FILTER_VALIDATION_FAILED = 'FILTER_VALIDATION_FAILED'
|
|
42
|
+
TARGET_VALIDATION_FAILED = 'TARGET_VALIDATION_FAILED'
|
|
43
|
+
VALIDATION_FAILED = 'VALIDATION_FAILED'
|
|
44
|
+
EXPORT_STARTED = 'EXPORT_STARTED'
|
|
45
|
+
EXPORT_COMPLETED = 'EXPORT_COMPLETED'
|
|
46
|
+
EXPORT_FAILED = 'EXPORT_FAILED'
|
|
47
|
+
NO_RESULTS_FOUND = 'NO_RESULTS_FOUND'
|
|
48
|
+
RESULTS_RETRIEVED = 'RESULTS_RETRIEVED'
|
|
49
|
+
ORIGINAL_FILE_EXPORTED = 'ORIGINAL_FILE_EXPORTED'
|
|
50
|
+
DATA_FILE_EXPORTED = 'DATA_FILE_EXPORTED'
|
|
51
|
+
FILE_EXPORT_FAILED = 'FILE_EXPORT_FAILED'
|
|
52
|
+
TARGET_HANDLER_ERROR = 'TARGET_HANDLER_ERROR'
|
|
53
|
+
NULL_DATA_DETECTED = 'NULL_DATA_DETECTED'
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
LOG_MESSAGES = {
|
|
57
|
+
LogCode.STORAGE_VALIDATION_FAILED: {
|
|
58
|
+
'message': 'Storage validation failed.',
|
|
59
|
+
'level': Context.DANGER,
|
|
60
|
+
},
|
|
61
|
+
LogCode.FILTER_VALIDATION_FAILED: {
|
|
62
|
+
'message': 'Filter validation failed.',
|
|
63
|
+
'level': Context.DANGER,
|
|
64
|
+
},
|
|
65
|
+
LogCode.TARGET_VALIDATION_FAILED: {
|
|
66
|
+
'message': 'Target validation failed.',
|
|
67
|
+
'level': Context.DANGER,
|
|
68
|
+
},
|
|
69
|
+
LogCode.VALIDATION_FAILED: {
|
|
70
|
+
'message': 'Validation failed.',
|
|
71
|
+
'level': Context.DANGER,
|
|
72
|
+
},
|
|
73
|
+
LogCode.EXPORT_STARTED: {
|
|
74
|
+
'message': 'Export process started.',
|
|
75
|
+
'level': None,
|
|
76
|
+
},
|
|
77
|
+
LogCode.EXPORT_COMPLETED: {
|
|
78
|
+
'message': 'Export process completed.',
|
|
79
|
+
'level': None,
|
|
80
|
+
},
|
|
81
|
+
LogCode.EXPORT_FAILED: {
|
|
82
|
+
'message': 'Export process failed: {}',
|
|
83
|
+
'level': Context.DANGER,
|
|
84
|
+
},
|
|
85
|
+
LogCode.NO_RESULTS_FOUND: {
|
|
86
|
+
'message': 'No results found for export.',
|
|
87
|
+
'level': Context.WARNING,
|
|
88
|
+
},
|
|
89
|
+
LogCode.RESULTS_RETRIEVED: {
|
|
90
|
+
'message': 'Retrieved {} results for export',
|
|
91
|
+
'level': None,
|
|
92
|
+
},
|
|
93
|
+
LogCode.ORIGINAL_FILE_EXPORTED: {
|
|
94
|
+
'message': 'Original file exported successfully.',
|
|
95
|
+
'level': None,
|
|
96
|
+
},
|
|
97
|
+
LogCode.DATA_FILE_EXPORTED: {
|
|
98
|
+
'message': 'Data file exported successfully.',
|
|
99
|
+
'level': None,
|
|
100
|
+
},
|
|
101
|
+
LogCode.FILE_EXPORT_FAILED: {
|
|
102
|
+
'message': 'Failed to export file: {}',
|
|
103
|
+
'level': Context.DANGER,
|
|
104
|
+
},
|
|
105
|
+
LogCode.TARGET_HANDLER_ERROR: {
|
|
106
|
+
'message': 'Target handler error: {}',
|
|
107
|
+
'level': Context.DANGER,
|
|
108
|
+
},
|
|
109
|
+
LogCode.NULL_DATA_DETECTED: {
|
|
110
|
+
'message': 'Data is null for export item',
|
|
111
|
+
'level': Context.WARNING,
|
|
112
|
+
},
|
|
113
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
class ExportError(Exception):
|
|
2
|
+
"""Base exception for export-related errors.
|
|
3
|
+
|
|
4
|
+
This exception is raised when an export operation encounters errors
|
|
5
|
+
that prevent successful completion. It serves as the base class for
|
|
6
|
+
more specific export-related exceptions.
|
|
7
|
+
|
|
8
|
+
Used during export processing to handle various error conditions
|
|
9
|
+
such as validation failures, data access errors, or processing issues.
|
|
10
|
+
|
|
11
|
+
Example:
|
|
12
|
+
>>> if not validate_export_data(data):
|
|
13
|
+
... raise ExportError("Export data validation failed")
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
pass
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class ExportValidationError(ExportError):
|
|
20
|
+
"""Exception raised when export parameter validation fails.
|
|
21
|
+
|
|
22
|
+
This exception is raised when export parameters or configuration
|
|
23
|
+
fail validation checks, preventing the export operation from starting.
|
|
24
|
+
|
|
25
|
+
Used during parameter validation to distinguish validation errors
|
|
26
|
+
from other types of export failures.
|
|
27
|
+
|
|
28
|
+
Example:
|
|
29
|
+
>>> if not storage_exists(storage_id):
|
|
30
|
+
... raise ExportValidationError(f"Storage {storage_id} does not exist")
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
pass
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class ExportTargetError(ExportError):
|
|
37
|
+
"""Exception raised when export target handling encounters errors.
|
|
38
|
+
|
|
39
|
+
This exception is raised when target-specific operations (assignment,
|
|
40
|
+
ground_truth, task) fail due to data access issues, filter problems,
|
|
41
|
+
or target-specific validation failures.
|
|
42
|
+
|
|
43
|
+
Used during target data retrieval and processing to handle target-specific
|
|
44
|
+
errors separately from general export errors.
|
|
45
|
+
|
|
46
|
+
Example:
|
|
47
|
+
>>> try:
|
|
48
|
+
... results = client.list_assignments(params=filters)
|
|
49
|
+
... except ClientError as e:
|
|
50
|
+
... raise ExportTargetError(f"Failed to retrieve assignments: {e}")
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
pass
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
from typing import Annotated, Literal
|
|
2
|
+
|
|
3
|
+
from pydantic import AfterValidator, BaseModel, field_validator
|
|
4
|
+
from pydantic_core import PydanticCustomError
|
|
5
|
+
|
|
6
|
+
from synapse_sdk.clients.exceptions import ClientError
|
|
7
|
+
from synapse_sdk.i18n import gettext as _
|
|
8
|
+
from synapse_sdk.utils.pydantic.validators import non_blank
|
|
9
|
+
|
|
10
|
+
from .utils import TargetHandlerFactory
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ExportParams(BaseModel):
|
|
14
|
+
"""Export action parameter validation model.
|
|
15
|
+
|
|
16
|
+
Defines and validates all parameters required for export operations.
|
|
17
|
+
Uses Pydantic for type validation and custom validators to ensure
|
|
18
|
+
storage and filter resources exist before processing.
|
|
19
|
+
|
|
20
|
+
Attributes:
|
|
21
|
+
name (str): Human-readable name for the export operation
|
|
22
|
+
description (str | None): Optional description of the export
|
|
23
|
+
storage (int): Storage ID where exported data will be saved
|
|
24
|
+
save_original_file (bool): Whether to save the original file
|
|
25
|
+
path (str): File system path where exported data will be saved
|
|
26
|
+
target (str): The target source to export data from (assignment, ground_truth, task)
|
|
27
|
+
filter (dict): Filter criteria to apply when retrieving data
|
|
28
|
+
extra_params (dict | None): Additional parameters for export customization.
|
|
29
|
+
Example: {"include_metadata": True, "compression": "gzip"}
|
|
30
|
+
|
|
31
|
+
Validation:
|
|
32
|
+
- name: Must be non-blank after validation
|
|
33
|
+
- storage: Must exist and be accessible via client API
|
|
34
|
+
- target: Must be one of the supported target types
|
|
35
|
+
- filter: Must be valid for the specified target type
|
|
36
|
+
|
|
37
|
+
Example:
|
|
38
|
+
>>> params = ExportParams(
|
|
39
|
+
... name="Assignment Export",
|
|
40
|
+
... storage=1,
|
|
41
|
+
... path="/exports/assignments",
|
|
42
|
+
... target="assignment",
|
|
43
|
+
... filter={"project": 123}
|
|
44
|
+
... )
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
name: Annotated[str, AfterValidator(non_blank)]
|
|
48
|
+
description: str | None = None
|
|
49
|
+
storage: int
|
|
50
|
+
save_original_file: bool = True
|
|
51
|
+
path: str
|
|
52
|
+
target: Literal['assignment', 'ground_truth', 'task']
|
|
53
|
+
filter: dict
|
|
54
|
+
extra_params: dict | None = None
|
|
55
|
+
|
|
56
|
+
@field_validator('storage')
|
|
57
|
+
@staticmethod
|
|
58
|
+
def check_storage_exists(value, info):
|
|
59
|
+
action = info.context['action']
|
|
60
|
+
client = action.client
|
|
61
|
+
try:
|
|
62
|
+
client.get_storage(value)
|
|
63
|
+
except ClientError:
|
|
64
|
+
raise PydanticCustomError('client_error', _('Unable to get storage from Synapse backend.'))
|
|
65
|
+
return value
|
|
66
|
+
|
|
67
|
+
@field_validator('filter')
|
|
68
|
+
@staticmethod
|
|
69
|
+
def check_filter_by_target(value, info):
|
|
70
|
+
action = info.context['action']
|
|
71
|
+
client = action.client
|
|
72
|
+
target = action.params['target']
|
|
73
|
+
handler = TargetHandlerFactory.get_handler(target)
|
|
74
|
+
return handler.validate_filter(value, client)
|