synapse-sdk 1.0.0b4__py3-none-any.whl → 1.0.0b6__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/plugins/categories/export/actions/export.py +7 -3
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task.py +67 -13
- synapse_sdk/plugins/categories/upload/actions/upload.py +5 -8
- {synapse_sdk-1.0.0b4.dist-info → synapse_sdk-1.0.0b6.dist-info}/METADATA +1 -1
- {synapse_sdk-1.0.0b4.dist-info → synapse_sdk-1.0.0b6.dist-info}/RECORD +9 -9
- {synapse_sdk-1.0.0b4.dist-info → synapse_sdk-1.0.0b6.dist-info}/WHEEL +0 -0
- {synapse_sdk-1.0.0b4.dist-info → synapse_sdk-1.0.0b6.dist-info}/entry_points.txt +0 -0
- {synapse_sdk-1.0.0b4.dist-info → synapse_sdk-1.0.0b6.dist-info}/licenses/LICENSE +0 -0
- {synapse_sdk-1.0.0b4.dist-info → synapse_sdk-1.0.0b6.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import json
|
|
2
2
|
from abc import ABC, abstractmethod
|
|
3
3
|
from datetime import datetime
|
|
4
|
+
from itertools import tee
|
|
4
5
|
from typing import Annotated, Any, Literal
|
|
5
6
|
|
|
6
7
|
from pydantic import AfterValidator, BaseModel, field_validator
|
|
@@ -324,16 +325,18 @@ class ExportAction(Action):
|
|
|
324
325
|
handler = TargetHandlerFactory.get_handler(target)
|
|
325
326
|
|
|
326
327
|
self.params['results'], self.params['count'] = self.get_filtered_results(filters, handler)
|
|
327
|
-
export_items = handler.get_export_item(self.params['results'])
|
|
328
328
|
|
|
329
329
|
# For the 'ground_truth' target, retrieve project information from the first result and add configuration
|
|
330
330
|
if target == 'ground_truth':
|
|
331
331
|
try:
|
|
332
|
-
|
|
332
|
+
# Split generator into two using tee()
|
|
333
|
+
peek_iter, main_iter = tee(self.params['results'])
|
|
334
|
+
first_result = next(peek_iter) # Peek first value only
|
|
333
335
|
project_pk = first_result['project']
|
|
334
336
|
project_info = self.client.get_project(project_pk)
|
|
335
337
|
self.params['configuration'] = project_info.get('configuration', {})
|
|
336
|
-
|
|
338
|
+
self.params['results'] = main_iter # Keep original generator intact
|
|
339
|
+
except (StopIteration, KeyError):
|
|
337
340
|
self.params['configuration'] = {}
|
|
338
341
|
# For the 'assignment' and 'task' targets, retrieve the project from the filter as before
|
|
339
342
|
elif target in ['assignment', 'task'] and 'project' in self.params['filter']:
|
|
@@ -341,6 +344,7 @@ class ExportAction(Action):
|
|
|
341
344
|
project_info = self.client.get_project(project_pk)
|
|
342
345
|
self.params['configuration'] = project_info.get('configuration', {})
|
|
343
346
|
|
|
347
|
+
export_items = handler.get_export_item(self.params['results'])
|
|
344
348
|
storage = self.client.get_storage(self.params['storage'])
|
|
345
349
|
pathlib_cwd = get_pathlib(storage, self.params['path'])
|
|
346
350
|
return self.entrypoint(self.run, export_items, pathlib_cwd, **self.params)
|
|
@@ -8,6 +8,7 @@ from pydantic import AfterValidator, BaseModel, field_validator
|
|
|
8
8
|
from pydantic_core import PydanticCustomError
|
|
9
9
|
|
|
10
10
|
from synapse_sdk.clients.backend import BackendClient
|
|
11
|
+
from synapse_sdk.clients.backend.models import JobStatus
|
|
11
12
|
from synapse_sdk.clients.exceptions import ClientError
|
|
12
13
|
from synapse_sdk.plugins.categories.base import Action
|
|
13
14
|
from synapse_sdk.plugins.categories.decorators import register_action
|
|
@@ -35,6 +36,14 @@ class CriticalError(Exception):
|
|
|
35
36
|
super().__init__(self.message)
|
|
36
37
|
|
|
37
38
|
|
|
39
|
+
class PreAnnotationToTaskFailed(Exception):
|
|
40
|
+
"""Pre-annotation to task failed."""
|
|
41
|
+
|
|
42
|
+
def __init__(self, message: str = 'Pre-annotation to task failed'):
|
|
43
|
+
self.message = message
|
|
44
|
+
super().__init__(self.message)
|
|
45
|
+
|
|
46
|
+
|
|
38
47
|
class ToTaskRun(Run):
|
|
39
48
|
class AnnotateTaskEventLog(BaseModel):
|
|
40
49
|
"""Annotate task event log model."""
|
|
@@ -255,6 +264,25 @@ class ToTaskParams(BaseModel):
|
|
|
255
264
|
return value
|
|
256
265
|
|
|
257
266
|
|
|
267
|
+
class ToTaskResult(BaseModel):
|
|
268
|
+
"""Result model for ToTaskAction.start method.
|
|
269
|
+
|
|
270
|
+
Args:
|
|
271
|
+
status (JobStatus): The job status from the action execution.
|
|
272
|
+
message (str): A descriptive message about the action result.
|
|
273
|
+
"""
|
|
274
|
+
|
|
275
|
+
status: JobStatus
|
|
276
|
+
message: str
|
|
277
|
+
|
|
278
|
+
def model_dump(self, **kwargs):
|
|
279
|
+
"""Override model_dump to return status as enum value."""
|
|
280
|
+
data = super().model_dump(**kwargs)
|
|
281
|
+
if 'status' in data and isinstance(data['status'], JobStatus):
|
|
282
|
+
data['status'] = data['status'].value
|
|
283
|
+
return data
|
|
284
|
+
|
|
285
|
+
|
|
258
286
|
@register_action
|
|
259
287
|
class ToTaskAction(Action):
|
|
260
288
|
"""ToTask action for pre-annotation data processing.
|
|
@@ -306,14 +334,20 @@ class ToTaskAction(Action):
|
|
|
306
334
|
}
|
|
307
335
|
}
|
|
308
336
|
|
|
309
|
-
def start(self):
|
|
337
|
+
def start(self) -> dict:
|
|
310
338
|
"""Start to_task action.
|
|
311
339
|
|
|
312
340
|
* Generate tasks.
|
|
313
341
|
* Annotate data to tasks.
|
|
342
|
+
|
|
343
|
+
Returns:
|
|
344
|
+
dict: Validated result with status and message.
|
|
314
345
|
"""
|
|
315
346
|
if not self.run or not self.params:
|
|
316
|
-
|
|
347
|
+
result = ToTaskResult(
|
|
348
|
+
status=JobStatus.FAILED, message='Run instance or parameters not properly initialized'
|
|
349
|
+
)
|
|
350
|
+
raise PreAnnotationToTaskFailed(result.message)
|
|
317
351
|
|
|
318
352
|
# Type assertion to help the linter
|
|
319
353
|
assert isinstance(self.run, ToTaskRun)
|
|
@@ -325,20 +359,23 @@ class ToTaskAction(Action):
|
|
|
325
359
|
if isinstance(project_response, str):
|
|
326
360
|
self.run.log_message_with_code('INVALID_PROJECT_RESPONSE')
|
|
327
361
|
self.run.end_log()
|
|
328
|
-
|
|
362
|
+
result = ToTaskResult(status=JobStatus.FAILED, message='Invalid project response received')
|
|
363
|
+
raise PreAnnotationToTaskFailed(result.message)
|
|
329
364
|
project: Dict[str, Any] = project_response
|
|
330
365
|
|
|
331
366
|
data_collection_id = project.get('data_collection')
|
|
332
367
|
if not data_collection_id:
|
|
333
368
|
self.run.log_message_with_code('NO_DATA_COLLECTION')
|
|
334
369
|
self.run.end_log()
|
|
335
|
-
|
|
370
|
+
result = ToTaskResult(status=JobStatus.FAILED, message='Project does not have a data collection')
|
|
371
|
+
raise PreAnnotationToTaskFailed(result.message)
|
|
336
372
|
|
|
337
373
|
data_collection_response = client.get_data_collection(data_collection_id)
|
|
338
374
|
if isinstance(data_collection_response, str):
|
|
339
375
|
self.run.log_message_with_code('INVALID_DATA_COLLECTION_RESPONSE')
|
|
340
376
|
self.run.end_log()
|
|
341
|
-
|
|
377
|
+
result = ToTaskResult(status=JobStatus.FAILED, message='Invalid data collection response received')
|
|
378
|
+
raise PreAnnotationToTaskFailed(result.message)
|
|
342
379
|
data_collection: Dict[str, Any] = data_collection_response
|
|
343
380
|
|
|
344
381
|
# Generate tasks if provided project is empty.
|
|
@@ -355,7 +392,8 @@ class ToTaskAction(Action):
|
|
|
355
392
|
if not task_ids_count:
|
|
356
393
|
self.run.log_message_with_code('NO_TASKS_FOUND')
|
|
357
394
|
self.run.end_log()
|
|
358
|
-
|
|
395
|
+
result = ToTaskResult(status=JobStatus.FAILED, message='No tasks found to annotate')
|
|
396
|
+
raise PreAnnotationToTaskFailed(result.message)
|
|
359
397
|
|
|
360
398
|
# Annotate data to tasks.
|
|
361
399
|
method = self.params.get('method')
|
|
@@ -365,23 +403,39 @@ class ToTaskAction(Action):
|
|
|
365
403
|
if not target_specification_name:
|
|
366
404
|
self.run.log_message_with_code('TARGET_SPEC_REQUIRED')
|
|
367
405
|
self.run.end_log()
|
|
368
|
-
|
|
406
|
+
result = ToTaskResult(
|
|
407
|
+
status=JobStatus.FAILED, message='Target specification name is required for file annotation method'
|
|
408
|
+
)
|
|
409
|
+
raise PreAnnotationToTaskFailed(result.message)
|
|
369
410
|
|
|
370
411
|
file_specifications = data_collection.get('file_specifications', [])
|
|
371
412
|
target_spec_exists = any(spec.get('name') == target_specification_name for spec in file_specifications)
|
|
372
413
|
if not target_spec_exists:
|
|
373
414
|
self.run.log_message_with_code('TARGET_SPEC_NOT_FOUND', target_specification_name)
|
|
374
415
|
self.run.end_log()
|
|
375
|
-
|
|
416
|
+
result = ToTaskResult(
|
|
417
|
+
status=JobStatus.FAILED,
|
|
418
|
+
message=f"Target specification name '{target_specification_name}' not found in file specifications",
|
|
419
|
+
)
|
|
420
|
+
raise PreAnnotationToTaskFailed(result.message)
|
|
376
421
|
self._handle_annotate_data_from_files(task_ids, target_specification_name)
|
|
377
422
|
elif method == AnnotationMethod.INFERENCE:
|
|
378
423
|
self._handle_annotate_data_with_inference(task_ids)
|
|
379
424
|
else:
|
|
380
425
|
self.run.log_message_with_code('UNSUPPORTED_METHOD', method)
|
|
381
426
|
self.run.end_log()
|
|
382
|
-
|
|
427
|
+
result = ToTaskResult(status=JobStatus.FAILED, message=f'Unsupported annotation method: {method}')
|
|
428
|
+
raise PreAnnotationToTaskFailed(result.message)
|
|
429
|
+
|
|
430
|
+
current_progress = self.run.logger.get_current_progress()
|
|
431
|
+
if current_progress['overall'] != 100:
|
|
432
|
+
result = ToTaskResult(
|
|
433
|
+
status=JobStatus.FAILED, message='Pre-annotation to task failed. Current progress is not 100%'
|
|
434
|
+
)
|
|
435
|
+
raise PreAnnotationToTaskFailed(result.message)
|
|
383
436
|
|
|
384
|
-
|
|
437
|
+
result = ToTaskResult(status=JobStatus.SUCCEEDED, message='Pre-annotation to task completed successfully')
|
|
438
|
+
return result.model_dump()
|
|
385
439
|
|
|
386
440
|
def _handle_annotate_data_from_files(self, task_ids: List[int], target_specification_name: str):
|
|
387
441
|
"""Handle annotate data from files to tasks.
|
|
@@ -757,21 +811,21 @@ class ToTaskAction(Action):
|
|
|
757
811
|
except Exception as e:
|
|
758
812
|
return {'success': False, 'error': f'Failed to restart pre-processor: {str(e)}'}
|
|
759
813
|
|
|
760
|
-
def _extract_primary_file_url(self, task: Dict[str, Any]) -> Tuple[str, str]:
|
|
814
|
+
def _extract_primary_file_url(self, task: Dict[str, Any]) -> Tuple[Optional[str], Optional[str]]:
|
|
761
815
|
"""Extract the primary file URL from task data.
|
|
762
816
|
|
|
763
817
|
Args:
|
|
764
818
|
task (Dict[str, Any]): The task data.
|
|
765
819
|
|
|
766
820
|
Returns:
|
|
767
|
-
Tuple[str, str]: The primary file URL and original name.
|
|
821
|
+
Tuple[Optional[str], Optional[str]]: The primary file URL and original name.
|
|
768
822
|
"""
|
|
769
823
|
data_unit = task.get('data_unit', {})
|
|
770
824
|
files = data_unit.get('files', {})
|
|
771
825
|
|
|
772
826
|
for file_info in files.values():
|
|
773
827
|
if isinstance(file_info, dict) and file_info.get('is_primary') and file_info.get('url'):
|
|
774
|
-
return file_info['url'], file_info
|
|
828
|
+
return file_info['url'], file_info.get('file_name_original')
|
|
775
829
|
|
|
776
830
|
return None, None
|
|
777
831
|
|
|
@@ -18,6 +18,7 @@ from synapse_sdk.i18n import gettext as _
|
|
|
18
18
|
from synapse_sdk.plugins.categories.base import Action
|
|
19
19
|
from synapse_sdk.plugins.categories.decorators import register_action
|
|
20
20
|
from synapse_sdk.plugins.enums import PluginCategory, RunMethod
|
|
21
|
+
from synapse_sdk.plugins.exceptions import ActionError
|
|
21
22
|
from synapse_sdk.plugins.models import Run
|
|
22
23
|
from synapse_sdk.shared.enums import Context
|
|
23
24
|
from synapse_sdk.utils.pydantic.validators import non_blank
|
|
@@ -684,30 +685,26 @@ class UploadAction(Action):
|
|
|
684
685
|
# Validate the organized files
|
|
685
686
|
if not self._validate_organized_files(organized_files, file_specification_template):
|
|
686
687
|
self.run.log_message('Validation failed.', context=Context.ERROR.value)
|
|
687
|
-
|
|
688
|
-
return result
|
|
688
|
+
raise ActionError('Upload is aborted due to validation errors.')
|
|
689
689
|
|
|
690
690
|
# Upload files to synapse-backend.
|
|
691
691
|
if not organized_files:
|
|
692
692
|
self.run.log_message('Files not found on the path.', context=Context.WARNING.value)
|
|
693
|
-
|
|
694
|
-
return result
|
|
693
|
+
raise ActionError('Upload is aborted due to missing files.')
|
|
695
694
|
uploaded_files = self._upload_files(organized_files)
|
|
696
695
|
result['uploaded_files_count'] = len(uploaded_files)
|
|
697
696
|
|
|
698
697
|
# Generate data units for the uploaded data.
|
|
699
698
|
if not uploaded_files:
|
|
700
699
|
self.run.log_message('No files were uploaded.', context=Context.WARNING.value)
|
|
701
|
-
|
|
702
|
-
return result
|
|
700
|
+
raise ActionError('Upload is aborted due to no uploaded files.')
|
|
703
701
|
generated_data_units = self._generate_data_units(uploaded_files)
|
|
704
702
|
result['generated_data_units_count'] = len(generated_data_units)
|
|
705
703
|
|
|
706
704
|
# Setup task with uploaded synapse-backend data units.
|
|
707
705
|
if not generated_data_units:
|
|
708
706
|
self.run.log_message('No data units were generated.', context=Context.WARNING.value)
|
|
709
|
-
|
|
710
|
-
return result
|
|
707
|
+
raise ActionError('Upload is aborted due to no generated data units.')
|
|
711
708
|
|
|
712
709
|
self.run.log_message('Import completed.')
|
|
713
710
|
return result
|
|
@@ -113,7 +113,7 @@ synapse_sdk/plugins/categories/data_validation/templates/plugin/validation.py,sh
|
|
|
113
113
|
synapse_sdk/plugins/categories/export/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
114
114
|
synapse_sdk/plugins/categories/export/enums.py,sha256=gtyngvQ1DKkos9iKGcbecwTVQQ6sDwbrBPSGPNb5Am0,127
|
|
115
115
|
synapse_sdk/plugins/categories/export/actions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
116
|
-
synapse_sdk/plugins/categories/export/actions/export.py,sha256=
|
|
116
|
+
synapse_sdk/plugins/categories/export/actions/export.py,sha256=XxhFIebt9tGTNcj0N6guVhAPP4d2YZ5Lvsx22-va72Y,12263
|
|
117
117
|
synapse_sdk/plugins/categories/export/templates/config.yaml,sha256=N7YmnFROb3s3M35SA9nmabyzoSb5O2t2TRPicwFNN2o,56
|
|
118
118
|
synapse_sdk/plugins/categories/export/templates/plugin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
119
119
|
synapse_sdk/plugins/categories/export/templates/plugin/export.py,sha256=GDb6Ucodsr5aBPMU4alr68-DyFoLR5TyhC_MCaJrkF0,6411
|
|
@@ -141,7 +141,7 @@ synapse_sdk/plugins/categories/post_annotation/templates/plugin/post_annotation.
|
|
|
141
141
|
synapse_sdk/plugins/categories/pre_annotation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
142
142
|
synapse_sdk/plugins/categories/pre_annotation/actions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
143
143
|
synapse_sdk/plugins/categories/pre_annotation/actions/pre_annotation.py,sha256=6ib3RmnGrjpsQ0e_G-mRH1lfFunQ3gh2M831vuDn7HU,344
|
|
144
|
-
synapse_sdk/plugins/categories/pre_annotation/actions/to_task.py,sha256=
|
|
144
|
+
synapse_sdk/plugins/categories/pre_annotation/actions/to_task.py,sha256=x6KPK89OWS7wsmYZ-wFFPhUl_fXEO74NIVB4bUChm6Q,40323
|
|
145
145
|
synapse_sdk/plugins/categories/pre_annotation/templates/config.yaml,sha256=VREoCp9wsvZ8T2E1d_MEKlR8TC_herDJGVQtu3ezAYU,589
|
|
146
146
|
synapse_sdk/plugins/categories/pre_annotation/templates/plugin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
147
147
|
synapse_sdk/plugins/categories/pre_annotation/templates/plugin/pre_annotation.py,sha256=HBHxHuv2gMBzDB2alFfrzI_SZ1Ztk6mo7eFbR5GqHKw,106
|
|
@@ -154,7 +154,7 @@ synapse_sdk/plugins/categories/smart_tool/templates/plugin/__init__.py,sha256=47
|
|
|
154
154
|
synapse_sdk/plugins/categories/smart_tool/templates/plugin/auto_label.py,sha256=eevNg0nOcYFR4z_L_R-sCvVOYoLWSAH1jwDkAf3YCjY,320
|
|
155
155
|
synapse_sdk/plugins/categories/upload/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
156
156
|
synapse_sdk/plugins/categories/upload/actions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
157
|
-
synapse_sdk/plugins/categories/upload/actions/upload.py,sha256=
|
|
157
|
+
synapse_sdk/plugins/categories/upload/actions/upload.py,sha256=Lhc_ezB_FvkDI7LTe50tadOQ2W9vp2ppTWYNJSWYKfY,38114
|
|
158
158
|
synapse_sdk/plugins/categories/upload/templates/config.yaml,sha256=6_dRa0_J2aS8NSUfO4MKbPxZcdPS2FpJzzp51edYAZc,281
|
|
159
159
|
synapse_sdk/plugins/categories/upload/templates/plugin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
160
160
|
synapse_sdk/plugins/categories/upload/templates/plugin/upload.py,sha256=IZU4sdSMSLKPCtlNqF7DP2howTdYR6hr74HCUZsGdPk,1559
|
|
@@ -211,9 +211,9 @@ synapse_sdk/utils/storage/providers/gcp.py,sha256=i2BQCu1Kej1If9SuNr2_lEyTcr5M_n
|
|
|
211
211
|
synapse_sdk/utils/storage/providers/http.py,sha256=2DhIulND47JOnS5ZY7MZUex7Su3peAPksGo1Wwg07L4,5828
|
|
212
212
|
synapse_sdk/utils/storage/providers/s3.py,sha256=ZmqekAvIgcQBdRU-QVJYv1Rlp6VHfXwtbtjTSphua94,2573
|
|
213
213
|
synapse_sdk/utils/storage/providers/sftp.py,sha256=_8s9hf0JXIO21gvm-JVS00FbLsbtvly4c-ETLRax68A,1426
|
|
214
|
-
synapse_sdk-1.0.
|
|
215
|
-
synapse_sdk-1.0.
|
|
216
|
-
synapse_sdk-1.0.
|
|
217
|
-
synapse_sdk-1.0.
|
|
218
|
-
synapse_sdk-1.0.
|
|
219
|
-
synapse_sdk-1.0.
|
|
214
|
+
synapse_sdk-1.0.0b6.dist-info/licenses/LICENSE,sha256=bKzmC5YAg4V1Fhl8OO_tqY8j62hgdncAkN7VrdjmrGk,1101
|
|
215
|
+
synapse_sdk-1.0.0b6.dist-info/METADATA,sha256=mU8-WwXY45NYGlXdk_mS1P9P8Ip21Q_9RqLZ9joe9hc,3718
|
|
216
|
+
synapse_sdk-1.0.0b6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
217
|
+
synapse_sdk-1.0.0b6.dist-info/entry_points.txt,sha256=VNptJoGoNJI8yLXfBmhgUefMsmGI0m3-0YoMvrOgbxo,48
|
|
218
|
+
synapse_sdk-1.0.0b6.dist-info/top_level.txt,sha256=ytgJMRK1slVOKUpgcw3LEyHHP7S34J6n_gJzdkcSsw8,12
|
|
219
|
+
synapse_sdk-1.0.0b6.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|