synapse-sdk 1.0.0a23__py3-none-any.whl → 2025.12.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.
Files changed (228) hide show
  1. synapse_sdk/__init__.py +24 -0
  2. synapse_sdk/cli/__init__.py +310 -5
  3. synapse_sdk/cli/alias/__init__.py +22 -0
  4. synapse_sdk/cli/alias/create.py +36 -0
  5. synapse_sdk/cli/alias/dataclass.py +31 -0
  6. synapse_sdk/cli/alias/default.py +16 -0
  7. synapse_sdk/cli/alias/delete.py +15 -0
  8. synapse_sdk/cli/alias/list.py +19 -0
  9. synapse_sdk/cli/alias/read.py +15 -0
  10. synapse_sdk/cli/alias/update.py +17 -0
  11. synapse_sdk/cli/alias/utils.py +61 -0
  12. synapse_sdk/cli/code_server.py +687 -0
  13. synapse_sdk/cli/config.py +440 -0
  14. synapse_sdk/cli/devtools.py +90 -0
  15. synapse_sdk/cli/plugin/__init__.py +33 -0
  16. synapse_sdk/cli/{create_plugin.py → plugin/create.py} +2 -2
  17. synapse_sdk/{plugins/cli → cli/plugin}/publish.py +23 -15
  18. synapse_sdk/clients/agent/__init__.py +9 -3
  19. synapse_sdk/clients/agent/container.py +143 -0
  20. synapse_sdk/clients/agent/core.py +19 -0
  21. synapse_sdk/clients/agent/ray.py +298 -9
  22. synapse_sdk/clients/backend/__init__.py +30 -12
  23. synapse_sdk/clients/backend/annotation.py +13 -5
  24. synapse_sdk/clients/backend/core.py +31 -4
  25. synapse_sdk/clients/backend/data_collection.py +186 -0
  26. synapse_sdk/clients/backend/hitl.py +17 -0
  27. synapse_sdk/clients/backend/integration.py +16 -1
  28. synapse_sdk/clients/backend/ml.py +5 -1
  29. synapse_sdk/clients/backend/models.py +78 -0
  30. synapse_sdk/clients/base.py +384 -41
  31. synapse_sdk/clients/ray/serve.py +2 -0
  32. synapse_sdk/clients/validators/collections.py +31 -0
  33. synapse_sdk/devtools/config.py +94 -0
  34. synapse_sdk/devtools/server.py +41 -0
  35. synapse_sdk/devtools/streamlit_app/__init__.py +5 -0
  36. synapse_sdk/devtools/streamlit_app/app.py +128 -0
  37. synapse_sdk/devtools/streamlit_app/services/__init__.py +11 -0
  38. synapse_sdk/devtools/streamlit_app/services/job_service.py +233 -0
  39. synapse_sdk/devtools/streamlit_app/services/plugin_service.py +236 -0
  40. synapse_sdk/devtools/streamlit_app/services/serve_service.py +95 -0
  41. synapse_sdk/devtools/streamlit_app/ui/__init__.py +15 -0
  42. synapse_sdk/devtools/streamlit_app/ui/config_tab.py +76 -0
  43. synapse_sdk/devtools/streamlit_app/ui/deployment_tab.py +66 -0
  44. synapse_sdk/devtools/streamlit_app/ui/http_tab.py +125 -0
  45. synapse_sdk/devtools/streamlit_app/ui/jobs_tab.py +573 -0
  46. synapse_sdk/devtools/streamlit_app/ui/serve_tab.py +346 -0
  47. synapse_sdk/devtools/streamlit_app/ui/status_bar.py +118 -0
  48. synapse_sdk/devtools/streamlit_app/utils/__init__.py +40 -0
  49. synapse_sdk/devtools/streamlit_app/utils/json_viewer.py +197 -0
  50. synapse_sdk/devtools/streamlit_app/utils/log_formatter.py +38 -0
  51. synapse_sdk/devtools/streamlit_app/utils/styles.py +241 -0
  52. synapse_sdk/devtools/streamlit_app/utils/ui_components.py +289 -0
  53. synapse_sdk/devtools/streamlit_app.py +10 -0
  54. synapse_sdk/loggers.py +120 -9
  55. synapse_sdk/plugins/README.md +1340 -0
  56. synapse_sdk/plugins/__init__.py +0 -13
  57. synapse_sdk/plugins/categories/base.py +117 -11
  58. synapse_sdk/plugins/categories/data_validation/actions/validation.py +72 -0
  59. synapse_sdk/plugins/categories/data_validation/templates/plugin/validation.py +33 -5
  60. synapse_sdk/plugins/categories/export/actions/__init__.py +3 -0
  61. synapse_sdk/plugins/categories/export/actions/export/__init__.py +28 -0
  62. synapse_sdk/plugins/categories/export/actions/export/action.py +165 -0
  63. synapse_sdk/plugins/categories/export/actions/export/enums.py +113 -0
  64. synapse_sdk/plugins/categories/export/actions/export/exceptions.py +53 -0
  65. synapse_sdk/plugins/categories/export/actions/export/models.py +74 -0
  66. synapse_sdk/plugins/categories/export/actions/export/run.py +195 -0
  67. synapse_sdk/plugins/categories/export/actions/export/utils.py +187 -0
  68. synapse_sdk/plugins/categories/export/templates/config.yaml +21 -0
  69. synapse_sdk/plugins/categories/export/templates/plugin/__init__.py +390 -0
  70. synapse_sdk/plugins/categories/export/templates/plugin/export.py +160 -0
  71. synapse_sdk/plugins/categories/neural_net/actions/deployment.py +13 -12
  72. synapse_sdk/plugins/categories/neural_net/actions/train.py +1134 -31
  73. synapse_sdk/plugins/categories/neural_net/actions/tune.py +534 -0
  74. synapse_sdk/plugins/categories/neural_net/base/inference.py +1 -1
  75. synapse_sdk/plugins/categories/neural_net/templates/config.yaml +32 -4
  76. synapse_sdk/plugins/categories/neural_net/templates/plugin/inference.py +26 -10
  77. synapse_sdk/plugins/categories/pre_annotation/actions/__init__.py +4 -0
  78. synapse_sdk/plugins/categories/pre_annotation/actions/pre_annotation/__init__.py +3 -0
  79. synapse_sdk/plugins/categories/{export/actions/export.py → pre_annotation/actions/pre_annotation/action.py} +4 -4
  80. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/__init__.py +28 -0
  81. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/action.py +148 -0
  82. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/enums.py +269 -0
  83. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/exceptions.py +14 -0
  84. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/factory.py +76 -0
  85. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/models.py +100 -0
  86. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/orchestrator.py +248 -0
  87. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/run.py +64 -0
  88. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/__init__.py +17 -0
  89. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/annotation.py +265 -0
  90. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/base.py +170 -0
  91. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/extraction.py +83 -0
  92. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/metrics.py +92 -0
  93. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/preprocessor.py +243 -0
  94. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/validation.py +143 -0
  95. synapse_sdk/plugins/categories/pre_annotation/templates/config.yaml +19 -0
  96. synapse_sdk/plugins/categories/pre_annotation/templates/plugin/to_task.py +40 -0
  97. synapse_sdk/plugins/categories/smart_tool/templates/config.yaml +2 -0
  98. synapse_sdk/plugins/categories/upload/__init__.py +0 -0
  99. synapse_sdk/plugins/categories/upload/actions/__init__.py +0 -0
  100. synapse_sdk/plugins/categories/upload/actions/upload/__init__.py +19 -0
  101. synapse_sdk/plugins/categories/upload/actions/upload/action.py +236 -0
  102. synapse_sdk/plugins/categories/upload/actions/upload/context.py +185 -0
  103. synapse_sdk/plugins/categories/upload/actions/upload/enums.py +493 -0
  104. synapse_sdk/plugins/categories/upload/actions/upload/exceptions.py +36 -0
  105. synapse_sdk/plugins/categories/upload/actions/upload/factory.py +138 -0
  106. synapse_sdk/plugins/categories/upload/actions/upload/models.py +214 -0
  107. synapse_sdk/plugins/categories/upload/actions/upload/orchestrator.py +183 -0
  108. synapse_sdk/plugins/categories/upload/actions/upload/registry.py +113 -0
  109. synapse_sdk/plugins/categories/upload/actions/upload/run.py +179 -0
  110. synapse_sdk/plugins/categories/upload/actions/upload/steps/__init__.py +1 -0
  111. synapse_sdk/plugins/categories/upload/actions/upload/steps/base.py +107 -0
  112. synapse_sdk/plugins/categories/upload/actions/upload/steps/cleanup.py +62 -0
  113. synapse_sdk/plugins/categories/upload/actions/upload/steps/collection.py +63 -0
  114. synapse_sdk/plugins/categories/upload/actions/upload/steps/generate.py +91 -0
  115. synapse_sdk/plugins/categories/upload/actions/upload/steps/initialize.py +82 -0
  116. synapse_sdk/plugins/categories/upload/actions/upload/steps/metadata.py +235 -0
  117. synapse_sdk/plugins/categories/upload/actions/upload/steps/organize.py +201 -0
  118. synapse_sdk/plugins/categories/upload/actions/upload/steps/upload.py +104 -0
  119. synapse_sdk/plugins/categories/upload/actions/upload/steps/validate.py +71 -0
  120. synapse_sdk/plugins/categories/upload/actions/upload/strategies/__init__.py +1 -0
  121. synapse_sdk/plugins/categories/upload/actions/upload/strategies/base.py +82 -0
  122. synapse_sdk/plugins/categories/upload/actions/upload/strategies/data_unit/__init__.py +1 -0
  123. synapse_sdk/plugins/categories/upload/actions/upload/strategies/data_unit/batch.py +39 -0
  124. synapse_sdk/plugins/categories/upload/actions/upload/strategies/data_unit/single.py +29 -0
  125. synapse_sdk/plugins/categories/upload/actions/upload/strategies/file_discovery/__init__.py +1 -0
  126. synapse_sdk/plugins/categories/upload/actions/upload/strategies/file_discovery/flat.py +300 -0
  127. synapse_sdk/plugins/categories/upload/actions/upload/strategies/file_discovery/recursive.py +287 -0
  128. synapse_sdk/plugins/categories/upload/actions/upload/strategies/metadata/__init__.py +1 -0
  129. synapse_sdk/plugins/categories/upload/actions/upload/strategies/metadata/excel.py +174 -0
  130. synapse_sdk/plugins/categories/upload/actions/upload/strategies/metadata/none.py +16 -0
  131. synapse_sdk/plugins/categories/upload/actions/upload/strategies/upload/__init__.py +1 -0
  132. synapse_sdk/plugins/categories/upload/actions/upload/strategies/upload/sync.py +84 -0
  133. synapse_sdk/plugins/categories/upload/actions/upload/strategies/validation/__init__.py +1 -0
  134. synapse_sdk/plugins/categories/upload/actions/upload/strategies/validation/default.py +60 -0
  135. synapse_sdk/plugins/categories/upload/actions/upload/utils.py +250 -0
  136. synapse_sdk/plugins/categories/upload/templates/README.md +470 -0
  137. synapse_sdk/plugins/categories/upload/templates/config.yaml +33 -0
  138. synapse_sdk/plugins/categories/upload/templates/plugin/__init__.py +310 -0
  139. synapse_sdk/plugins/categories/upload/templates/plugin/upload.py +102 -0
  140. synapse_sdk/plugins/enums.py +3 -1
  141. synapse_sdk/plugins/models.py +148 -11
  142. synapse_sdk/plugins/templates/plugin-config-schema.json +406 -0
  143. synapse_sdk/plugins/templates/schema.json +491 -0
  144. synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/config.yaml +1 -0
  145. synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/requirements.txt +1 -1
  146. synapse_sdk/plugins/utils/__init__.py +46 -0
  147. synapse_sdk/plugins/utils/actions.py +119 -0
  148. synapse_sdk/plugins/utils/config.py +203 -0
  149. synapse_sdk/plugins/{utils.py → utils/legacy.py} +26 -46
  150. synapse_sdk/plugins/utils/ray_gcs.py +66 -0
  151. synapse_sdk/plugins/utils/registry.py +58 -0
  152. synapse_sdk/shared/__init__.py +25 -0
  153. synapse_sdk/shared/enums.py +93 -0
  154. synapse_sdk/types.py +19 -0
  155. synapse_sdk/utils/converters/__init__.py +240 -0
  156. synapse_sdk/utils/converters/coco/__init__.py +0 -0
  157. synapse_sdk/utils/converters/coco/from_dm.py +322 -0
  158. synapse_sdk/utils/converters/coco/to_dm.py +215 -0
  159. synapse_sdk/utils/converters/dm/__init__.py +57 -0
  160. synapse_sdk/utils/converters/dm/base.py +137 -0
  161. synapse_sdk/utils/converters/dm/from_v1.py +273 -0
  162. synapse_sdk/utils/converters/dm/to_v1.py +321 -0
  163. synapse_sdk/utils/converters/dm/tools/__init__.py +214 -0
  164. synapse_sdk/utils/converters/dm/tools/answer.py +95 -0
  165. synapse_sdk/utils/converters/dm/tools/bounding_box.py +132 -0
  166. synapse_sdk/utils/converters/dm/tools/bounding_box_3d.py +121 -0
  167. synapse_sdk/utils/converters/dm/tools/classification.py +75 -0
  168. synapse_sdk/utils/converters/dm/tools/keypoint.py +117 -0
  169. synapse_sdk/utils/converters/dm/tools/named_entity.py +111 -0
  170. synapse_sdk/utils/converters/dm/tools/polygon.py +122 -0
  171. synapse_sdk/utils/converters/dm/tools/polyline.py +124 -0
  172. synapse_sdk/utils/converters/dm/tools/prompt.py +94 -0
  173. synapse_sdk/utils/converters/dm/tools/relation.py +86 -0
  174. synapse_sdk/utils/converters/dm/tools/segmentation.py +141 -0
  175. synapse_sdk/utils/converters/dm/tools/segmentation_3d.py +83 -0
  176. synapse_sdk/utils/converters/dm/types.py +168 -0
  177. synapse_sdk/utils/converters/dm/utils.py +162 -0
  178. synapse_sdk/utils/converters/dm_legacy/__init__.py +56 -0
  179. synapse_sdk/utils/converters/dm_legacy/from_v1.py +627 -0
  180. synapse_sdk/utils/converters/dm_legacy/to_v1.py +367 -0
  181. synapse_sdk/utils/converters/pascal/__init__.py +0 -0
  182. synapse_sdk/utils/converters/pascal/from_dm.py +244 -0
  183. synapse_sdk/utils/converters/pascal/to_dm.py +214 -0
  184. synapse_sdk/utils/converters/yolo/__init__.py +0 -0
  185. synapse_sdk/utils/converters/yolo/from_dm.py +384 -0
  186. synapse_sdk/utils/converters/yolo/to_dm.py +267 -0
  187. synapse_sdk/utils/dataset.py +46 -0
  188. synapse_sdk/utils/encryption.py +158 -0
  189. synapse_sdk/utils/file/__init__.py +58 -0
  190. synapse_sdk/utils/file/archive.py +32 -0
  191. synapse_sdk/utils/file/checksum.py +56 -0
  192. synapse_sdk/utils/file/chunking.py +31 -0
  193. synapse_sdk/utils/file/download.py +385 -0
  194. synapse_sdk/utils/file/encoding.py +40 -0
  195. synapse_sdk/utils/file/io.py +22 -0
  196. synapse_sdk/utils/file/upload.py +165 -0
  197. synapse_sdk/utils/file/video/__init__.py +29 -0
  198. synapse_sdk/utils/file/video/transcode.py +307 -0
  199. synapse_sdk/utils/file.py.backup +301 -0
  200. synapse_sdk/utils/http.py +138 -0
  201. synapse_sdk/utils/network.py +309 -0
  202. synapse_sdk/utils/storage/__init__.py +72 -0
  203. synapse_sdk/utils/storage/providers/__init__.py +183 -0
  204. synapse_sdk/utils/storage/providers/file_system.py +134 -0
  205. synapse_sdk/utils/storage/providers/gcp.py +13 -0
  206. synapse_sdk/utils/storage/providers/http.py +190 -0
  207. synapse_sdk/utils/storage/providers/s3.py +91 -0
  208. synapse_sdk/utils/storage/providers/sftp.py +47 -0
  209. synapse_sdk/utils/storage/registry.py +17 -0
  210. synapse_sdk-2025.12.3.dist-info/METADATA +123 -0
  211. synapse_sdk-2025.12.3.dist-info/RECORD +279 -0
  212. {synapse_sdk-1.0.0a23.dist-info → synapse_sdk-2025.12.3.dist-info}/WHEEL +1 -1
  213. synapse_sdk/clients/backend/dataset.py +0 -51
  214. synapse_sdk/plugins/categories/import/actions/import.py +0 -10
  215. synapse_sdk/plugins/cli/__init__.py +0 -21
  216. synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/.env +0 -24
  217. synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/.env.dist +0 -24
  218. synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/main.py +0 -4
  219. synapse_sdk/utils/file.py +0 -168
  220. synapse_sdk/utils/storage.py +0 -91
  221. synapse_sdk-1.0.0a23.dist-info/METADATA +0 -44
  222. synapse_sdk-1.0.0a23.dist-info/RECORD +0 -114
  223. /synapse_sdk/{plugins/cli → cli/plugin}/run.py +0 -0
  224. /synapse_sdk/{plugins/categories/import → clients/validators}/__init__.py +0 -0
  225. /synapse_sdk/{plugins/categories/import/actions → devtools}/__init__.py +0 -0
  226. {synapse_sdk-1.0.0a23.dist-info → synapse_sdk-2025.12.3.dist-info}/entry_points.txt +0 -0
  227. {synapse_sdk-1.0.0a23.dist-info → synapse_sdk-2025.12.3.dist-info/licenses}/LICENSE +0 -0
  228. {synapse_sdk-1.0.0a23.dist-info → synapse_sdk-2025.12.3.dist-info}/top_level.txt +0 -0
@@ -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)
@@ -0,0 +1,195 @@
1
+ import json
2
+ from datetime import datetime
3
+ from typing import Optional
4
+
5
+ from pydantic import BaseModel
6
+
7
+ from synapse_sdk.plugins.models import Run
8
+ from synapse_sdk.shared.enums import Context
9
+
10
+ from .enums import LOG_MESSAGES, ExportStatus, LogCode
11
+
12
+
13
+ class ExportRun(Run):
14
+ """Export-specific run management class.
15
+
16
+ Extends the base Run class with export-specific logging capabilities
17
+ and event tracking. Provides type-safe logging using LogCode enums
18
+ and specialized methods for tracking export progress.
19
+
20
+ Manages logging for export events, data files, and export targets
21
+ throughout the export lifecycle. Each log entry includes status,
22
+ timestamps, and relevant metadata.
23
+
24
+ Attributes:
25
+ Inherits all attributes from base Run class plus export-specific
26
+ logging methods and nested model classes for structured logging.
27
+
28
+ Example:
29
+ >>> run = ExportRun(job_id, context)
30
+ >>> run.log_message_with_code(LogCode.EXPORT_STARTED)
31
+ >>> run.log_export_event(LogCode.RESULTS_RETRIEVED, target_id, count)
32
+ """
33
+
34
+ class ExportEventLog(BaseModel):
35
+ """Model for export event log entries.
36
+
37
+ Records significant events during export processing with
38
+ target identification and status information.
39
+
40
+ Attributes:
41
+ target_id (int): The ID of the export target
42
+ info (str | None): Optional additional information
43
+ status (Context): Event status/severity level
44
+ created (str): Timestamp when event occurred
45
+ """
46
+
47
+ target_id: int
48
+ info: str | None = None
49
+ status: Context
50
+ created: str
51
+
52
+ class DataFileLog(BaseModel):
53
+ """Model for data file export log entries.
54
+
55
+ Tracks the export status of individual data files during
56
+ export operations.
57
+
58
+ Attributes:
59
+ target_id (int): The ID of the target being exported
60
+ data_file_info (str | None): JSON information about the data file
61
+ status (ExportStatus): Export status (SUCCESS/FAILED/STAND_BY)
62
+ error (str | None): Error message if export failed
63
+ created (str): Timestamp when log entry was created
64
+ """
65
+
66
+ target_id: int
67
+ data_file_info: str | None
68
+ status: ExportStatus
69
+ error: str | None = None
70
+ created: str
71
+
72
+ class MetricsRecord(BaseModel):
73
+ """Model for export metrics tracking.
74
+
75
+ Records count-based metrics for monitoring export
76
+ progress and success rates.
77
+
78
+ Attributes:
79
+ stand_by (int): Number of items waiting to be processed
80
+ failed (int): Number of items that failed processing
81
+ success (int): Number of items successfully processed
82
+ """
83
+
84
+ stand_by: int
85
+ failed: int
86
+ success: int
87
+
88
+ def log_message_with_code(self, code: LogCode, *args, level: Optional[Context] = None):
89
+ """Log message using predefined code with type safety.
90
+
91
+ Args:
92
+ code (LogCode): The log message code
93
+ *args: Arguments to format the message
94
+ level (Context | None): Optional context level override
95
+ """
96
+ if code not in LOG_MESSAGES:
97
+ self.log_message(f'Unknown log code: {code}')
98
+ return
99
+
100
+ log_config = LOG_MESSAGES[code]
101
+ message = log_config['message'].format(*args) if args else log_config['message']
102
+ log_level = level or log_config['level'] or Context.INFO
103
+
104
+ # Always call log_message for basic logging
105
+ if log_level:
106
+ self.log_message(message, context=log_level.value)
107
+ else:
108
+ self.log_message(message)
109
+
110
+ def log_file(
111
+ self, log_type: str, target_id: int, data_file_info: dict, status: ExportStatus, error: str | None = None
112
+ ):
113
+ """Log export file information.
114
+
115
+ Args:
116
+ log_type (str): The type of log ('export_data_file' or 'export_original_file').
117
+ target_id (int): The ID of the data file.
118
+ data_file_info (dict): The JSON info of the data file.
119
+ status (ExportStatus): The status of the data file.
120
+ error (str | None): The error message, if any.
121
+ """
122
+ now = datetime.now().isoformat()
123
+ self.log(
124
+ log_type,
125
+ self.DataFileLog(
126
+ target_id=target_id,
127
+ data_file_info=json.dumps(data_file_info),
128
+ status=status.value,
129
+ error=error,
130
+ created=now,
131
+ ).model_dump(),
132
+ )
133
+
134
+ def log_export_event(self, code: LogCode, target_id: int, *args, level: Context | None = None):
135
+ """Log export event using predefined code.
136
+
137
+ Args:
138
+ code (str): The log message code.
139
+ target_id (int): The ID of the export target.
140
+ *args: Arguments to format the message.
141
+ level (Context | None): Optional context level override.
142
+ """
143
+ # Call log_message_with_code to handle the basic logging
144
+ self.log_message_with_code(code, *args, level=level)
145
+
146
+ # Also log the event for export-specific tracking
147
+ if code not in LOG_MESSAGES:
148
+ now = datetime.now().isoformat()
149
+ self.log(
150
+ 'export_event',
151
+ self.ExportEventLog(
152
+ target_id=target_id, info=f'Unknown log code: {code}', status=Context.DANGER, created=now
153
+ ).model_dump(),
154
+ )
155
+ return
156
+
157
+ log_config = LOG_MESSAGES[code]
158
+ message = log_config['message'].format(*args) if args else log_config['message']
159
+ log_level = level or log_config['level'] or Context.INFO
160
+
161
+ now = datetime.now().isoformat()
162
+ self.log(
163
+ 'export_event',
164
+ self.ExportEventLog(info=message, status=log_level, target_id=target_id, created=now).model_dump(),
165
+ )
166
+
167
+ def log_metrics(self, record: MetricsRecord, category: str):
168
+ """Log export metrics.
169
+
170
+ Args:
171
+ record (MetricsRecord): The metrics record to log.
172
+ category (str): The category of the metrics.
173
+ """
174
+ record = self.MetricsRecord.model_validate(record)
175
+ self.set_metrics(value=record.model_dump(), category=category)
176
+
177
+ def export_log_json_file(
178
+ self,
179
+ target_id: int,
180
+ data_file_info: dict,
181
+ status: ExportStatus = ExportStatus.STAND_BY,
182
+ error: str | None = None,
183
+ ):
184
+ """Log export json data file."""
185
+ self.log_file('export_data_file', target_id, data_file_info, status, error)
186
+
187
+ def export_log_original_file(
188
+ self,
189
+ target_id: int,
190
+ data_file_info: dict,
191
+ status: ExportStatus = ExportStatus.STAND_BY,
192
+ error: str | None = None,
193
+ ):
194
+ """Log export origin data file."""
195
+ self.log_file('export_original_file', target_id, data_file_info, status, error)
@@ -0,0 +1,187 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import Any
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
+
9
+
10
+ class ExportTargetHandler(ABC):
11
+ """
12
+ Abstract base class for handling export targets.
13
+
14
+ This class defines the blueprint for export target handlers, requiring the implementation
15
+ of methods to validate filters, retrieve results, and process collections of results.
16
+ """
17
+
18
+ @abstractmethod
19
+ def validate_filter(self, value: dict, client: Any):
20
+ """
21
+ Validate filter query params to request original data from api.
22
+
23
+ Args:
24
+ value (dict): The filter criteria to validate.
25
+ client (Any): The client used to validate the filter.
26
+
27
+ Raises:
28
+ PydanticCustomError: If the filter criteria are invalid.
29
+
30
+ Returns:
31
+ dict: The validated filter criteria.
32
+ """
33
+ pass
34
+
35
+ @abstractmethod
36
+ def get_results(self, client: Any, filters: dict):
37
+ """
38
+ Retrieve original data from target sources.
39
+
40
+ Args:
41
+ client (Any): The client used to retrieve the results.
42
+ filters (dict): The filter criteria to apply.
43
+
44
+ Returns:
45
+ tuple: A tuple containing the results and the total count of results.
46
+ """
47
+ pass
48
+
49
+ @abstractmethod
50
+ def get_export_item(self, results):
51
+ """
52
+ Providing elements to build export data.
53
+
54
+ Args:
55
+ results (list): The results to process.
56
+
57
+ Yields:
58
+ generator: A generator that yields processed data items.
59
+ """
60
+ pass
61
+
62
+
63
+ class AssignmentExportTargetHandler(ExportTargetHandler):
64
+ """Handler for assignment target exports.
65
+
66
+ Implements ExportTargetHandler interface for assignment-specific
67
+ export operations including validation, data retrieval, and processing.
68
+ """
69
+
70
+ def validate_filter(self, value: dict, client: Any):
71
+ if 'project' not in value:
72
+ raise PydanticCustomError('missing_field', _('Project is required for Assignment.'))
73
+ try:
74
+ client.list_assignments(params=value)
75
+ except ClientError:
76
+ raise PydanticCustomError('client_error', _('Unable to get Assignment.'))
77
+ return value
78
+
79
+ def get_results(self, client: Any, filters: dict):
80
+ return client.list_assignments(params=filters, list_all=True)
81
+
82
+ def get_export_item(self, results):
83
+ for result in results:
84
+ yield {
85
+ 'data': result['data'],
86
+ 'files': result['file'],
87
+ 'id': result['id'],
88
+ }
89
+
90
+
91
+ class GroundTruthExportTargetHandler(ExportTargetHandler):
92
+ """Handler for ground truth target exports.
93
+
94
+ Implements ExportTargetHandler interface for ground truth dataset
95
+ export operations including validation, data retrieval, and processing.
96
+ """
97
+
98
+ def validate_filter(self, value: dict, client: Any):
99
+ if 'ground_truth_dataset_version' not in value:
100
+ raise PydanticCustomError('missing_field', _('Ground Truth dataset version is required.'))
101
+ try:
102
+ client.get_ground_truth_version(value['ground_truth_dataset_version'])
103
+ except ClientError:
104
+ raise PydanticCustomError('client_error', _('Unable to get Ground Truth dataset version.'))
105
+ return value
106
+
107
+ def get_results(self, client: Any, filters: dict):
108
+ filters['ground_truth_dataset_versions'] = filters.pop('ground_truth_dataset_version')
109
+ return client.list_ground_truth_events(params=filters, list_all=True)
110
+
111
+ def get_export_item(self, results):
112
+ for result in results:
113
+ files_key = next(iter(result['data_unit']['files']))
114
+ yield {
115
+ 'data': result['data'],
116
+ 'files': result['data_unit']['files'][files_key],
117
+ 'id': result['id'],
118
+ }
119
+
120
+
121
+ class TaskExportTargetHandler(ExportTargetHandler):
122
+ """Handler for task target exports.
123
+
124
+ Implements ExportTargetHandler interface for task-specific
125
+ export operations including validation, data retrieval, and processing.
126
+ """
127
+
128
+ def validate_filter(self, value: dict, client: Any):
129
+ if 'project' not in value:
130
+ raise PydanticCustomError('missing_field', _('Project is required for Task.'))
131
+ try:
132
+ client.list_tasks(params=value)
133
+ except ClientError:
134
+ raise PydanticCustomError('client_error', _('Unable to get Task.'))
135
+ return value
136
+
137
+ def get_results(self, client: Any, filters: dict):
138
+ filters['expand'] = ['data_unit', 'assignment', 'workshop']
139
+ return client.list_tasks(params=filters, list_all=True)
140
+
141
+ def get_export_item(self, results):
142
+ for result in results:
143
+ files_key = next(iter(result['data_unit']['files']))
144
+ yield {
145
+ 'data': result['data'],
146
+ 'files': result['data_unit']['files'][files_key],
147
+ 'id': result['id'],
148
+ }
149
+
150
+
151
+ class TargetHandlerFactory:
152
+ """Factory class for creating export target handlers.
153
+
154
+ Provides a centralized way to create appropriate target handlers
155
+ based on the target type. Supports assignment, ground_truth, and task targets.
156
+
157
+ Example:
158
+ >>> handler = TargetHandlerFactory.get_handler('assignment')
159
+ >>> isinstance(handler, AssignmentExportTargetHandler)
160
+ True
161
+ """
162
+
163
+ @staticmethod
164
+ def get_handler(target: str) -> ExportTargetHandler:
165
+ """Get the appropriate target handler for the given target type.
166
+
167
+ Args:
168
+ target (str): The target type ('assignment', 'ground_truth', 'task')
169
+
170
+ Returns:
171
+ ExportTargetHandler: The appropriate handler instance
172
+
173
+ Raises:
174
+ ValueError: If the target type is not supported
175
+
176
+ Example:
177
+ >>> handler = TargetHandlerFactory.get_handler('assignment')
178
+ >>> handler.validate_filter({'project': 123}, client)
179
+ """
180
+ if target == 'assignment':
181
+ return AssignmentExportTargetHandler()
182
+ elif target == 'ground_truth':
183
+ return GroundTruthExportTargetHandler()
184
+ elif target == 'task':
185
+ return TaskExportTargetHandler()
186
+ else:
187
+ raise ValueError(f'Unknown target: {target}')
@@ -0,0 +1,21 @@
1
+ actions:
2
+ export:
3
+ entrypoint: plugin.export.Exporter
4
+ # Filter to only export action specific annotation types (e.g., only export image annotations project)
5
+ # Supported types: image, video, audio, text, pcd, prompt
6
+ annotation_types:
7
+ - image
8
+ - video
9
+ - audio
10
+ - text
11
+ - pcd
12
+ - prompt
13
+
14
+ # Filter to only export specific data types (e.g., only export image data)
15
+ # Supported types: image, video, audio, text, pcd
16
+ data_types:
17
+ - image
18
+ - video
19
+ - audio
20
+ - text
21
+ - pcd