synapse-sdk 1.0.0a11__py3-none-any.whl → 2026.1.1b2__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.

Files changed (261) hide show
  1. synapse_sdk/__init__.py +24 -0
  2. synapse_sdk/cli/__init__.py +9 -8
  3. synapse_sdk/cli/agent/__init__.py +25 -0
  4. synapse_sdk/cli/agent/config.py +104 -0
  5. synapse_sdk/cli/agent/select.py +197 -0
  6. synapse_sdk/cli/auth.py +104 -0
  7. synapse_sdk/cli/main.py +1025 -0
  8. synapse_sdk/cli/plugin/__init__.py +58 -0
  9. synapse_sdk/cli/plugin/create.py +566 -0
  10. synapse_sdk/cli/plugin/job.py +196 -0
  11. synapse_sdk/cli/plugin/publish.py +322 -0
  12. synapse_sdk/cli/plugin/run.py +131 -0
  13. synapse_sdk/cli/plugin/test.py +200 -0
  14. synapse_sdk/clients/README.md +239 -0
  15. synapse_sdk/clients/__init__.py +5 -0
  16. synapse_sdk/clients/_template.py +266 -0
  17. synapse_sdk/clients/agent/__init__.py +84 -29
  18. synapse_sdk/clients/agent/async_ray.py +289 -0
  19. synapse_sdk/clients/agent/container.py +83 -0
  20. synapse_sdk/clients/agent/plugin.py +101 -0
  21. synapse_sdk/clients/agent/ray.py +296 -39
  22. synapse_sdk/clients/backend/__init__.py +152 -12
  23. synapse_sdk/clients/backend/annotation.py +164 -22
  24. synapse_sdk/clients/backend/core.py +101 -0
  25. synapse_sdk/clients/backend/data_collection.py +292 -0
  26. synapse_sdk/clients/backend/hitl.py +87 -0
  27. synapse_sdk/clients/backend/integration.py +374 -46
  28. synapse_sdk/clients/backend/ml.py +134 -22
  29. synapse_sdk/clients/backend/models.py +247 -0
  30. synapse_sdk/clients/base.py +538 -59
  31. synapse_sdk/clients/exceptions.py +35 -7
  32. synapse_sdk/clients/pipeline/__init__.py +5 -0
  33. synapse_sdk/clients/pipeline/client.py +636 -0
  34. synapse_sdk/clients/protocols.py +178 -0
  35. synapse_sdk/clients/utils.py +86 -8
  36. synapse_sdk/clients/validation.py +58 -0
  37. synapse_sdk/enums.py +76 -0
  38. synapse_sdk/exceptions.py +168 -0
  39. synapse_sdk/integrations/__init__.py +74 -0
  40. synapse_sdk/integrations/_base.py +119 -0
  41. synapse_sdk/integrations/_context.py +53 -0
  42. synapse_sdk/integrations/ultralytics/__init__.py +78 -0
  43. synapse_sdk/integrations/ultralytics/_callbacks.py +126 -0
  44. synapse_sdk/integrations/ultralytics/_patches.py +124 -0
  45. synapse_sdk/loggers.py +476 -95
  46. synapse_sdk/mcp/MCP.md +69 -0
  47. synapse_sdk/mcp/__init__.py +48 -0
  48. synapse_sdk/mcp/__main__.py +6 -0
  49. synapse_sdk/mcp/config.py +349 -0
  50. synapse_sdk/mcp/prompts/__init__.py +4 -0
  51. synapse_sdk/mcp/resources/__init__.py +4 -0
  52. synapse_sdk/mcp/server.py +1352 -0
  53. synapse_sdk/mcp/tools/__init__.py +6 -0
  54. synapse_sdk/plugins/__init__.py +133 -9
  55. synapse_sdk/plugins/action.py +229 -0
  56. synapse_sdk/plugins/actions/__init__.py +82 -0
  57. synapse_sdk/plugins/actions/dataset/__init__.py +37 -0
  58. synapse_sdk/plugins/actions/dataset/action.py +471 -0
  59. synapse_sdk/plugins/actions/export/__init__.py +55 -0
  60. synapse_sdk/plugins/actions/export/action.py +183 -0
  61. synapse_sdk/plugins/actions/export/context.py +59 -0
  62. synapse_sdk/plugins/actions/inference/__init__.py +84 -0
  63. synapse_sdk/plugins/actions/inference/action.py +285 -0
  64. synapse_sdk/plugins/actions/inference/context.py +81 -0
  65. synapse_sdk/plugins/actions/inference/deployment.py +322 -0
  66. synapse_sdk/plugins/actions/inference/serve.py +252 -0
  67. synapse_sdk/plugins/actions/train/__init__.py +54 -0
  68. synapse_sdk/plugins/actions/train/action.py +326 -0
  69. synapse_sdk/plugins/actions/train/context.py +57 -0
  70. synapse_sdk/plugins/actions/upload/__init__.py +49 -0
  71. synapse_sdk/plugins/actions/upload/action.py +165 -0
  72. synapse_sdk/plugins/actions/upload/context.py +61 -0
  73. synapse_sdk/plugins/config.py +98 -0
  74. synapse_sdk/plugins/context/__init__.py +109 -0
  75. synapse_sdk/plugins/context/env.py +113 -0
  76. synapse_sdk/plugins/datasets/__init__.py +113 -0
  77. synapse_sdk/plugins/datasets/converters/__init__.py +76 -0
  78. synapse_sdk/plugins/datasets/converters/base.py +347 -0
  79. synapse_sdk/plugins/datasets/converters/yolo/__init__.py +9 -0
  80. synapse_sdk/plugins/datasets/converters/yolo/from_dm.py +468 -0
  81. synapse_sdk/plugins/datasets/converters/yolo/to_dm.py +381 -0
  82. synapse_sdk/plugins/datasets/formats/__init__.py +82 -0
  83. synapse_sdk/plugins/datasets/formats/dm.py +351 -0
  84. synapse_sdk/plugins/datasets/formats/yolo.py +240 -0
  85. synapse_sdk/plugins/decorators.py +83 -0
  86. synapse_sdk/plugins/discovery.py +790 -0
  87. synapse_sdk/plugins/docs/ACTION_DEV_GUIDE.md +933 -0
  88. synapse_sdk/plugins/docs/ARCHITECTURE.md +1225 -0
  89. synapse_sdk/plugins/docs/LOGGING_SYSTEM.md +683 -0
  90. synapse_sdk/plugins/docs/OVERVIEW.md +531 -0
  91. synapse_sdk/plugins/docs/PIPELINE_GUIDE.md +145 -0
  92. synapse_sdk/plugins/docs/README.md +513 -0
  93. synapse_sdk/plugins/docs/STEP.md +656 -0
  94. synapse_sdk/plugins/enums.py +70 -10
  95. synapse_sdk/plugins/errors.py +92 -0
  96. synapse_sdk/plugins/executors/__init__.py +43 -0
  97. synapse_sdk/plugins/executors/local.py +99 -0
  98. synapse_sdk/plugins/executors/ray/__init__.py +18 -0
  99. synapse_sdk/plugins/executors/ray/base.py +282 -0
  100. synapse_sdk/plugins/executors/ray/job.py +298 -0
  101. synapse_sdk/plugins/executors/ray/jobs_api.py +511 -0
  102. synapse_sdk/plugins/executors/ray/packaging.py +137 -0
  103. synapse_sdk/plugins/executors/ray/pipeline.py +792 -0
  104. synapse_sdk/plugins/executors/ray/task.py +257 -0
  105. synapse_sdk/plugins/models/__init__.py +26 -0
  106. synapse_sdk/plugins/models/logger.py +173 -0
  107. synapse_sdk/plugins/models/pipeline.py +25 -0
  108. synapse_sdk/plugins/pipelines/__init__.py +81 -0
  109. synapse_sdk/plugins/pipelines/action_pipeline.py +417 -0
  110. synapse_sdk/plugins/pipelines/context.py +107 -0
  111. synapse_sdk/plugins/pipelines/display.py +311 -0
  112. synapse_sdk/plugins/runner.py +114 -0
  113. synapse_sdk/plugins/schemas/__init__.py +19 -0
  114. synapse_sdk/plugins/schemas/results.py +152 -0
  115. synapse_sdk/plugins/steps/__init__.py +63 -0
  116. synapse_sdk/plugins/steps/base.py +128 -0
  117. synapse_sdk/plugins/steps/context.py +90 -0
  118. synapse_sdk/plugins/steps/orchestrator.py +128 -0
  119. synapse_sdk/plugins/steps/registry.py +103 -0
  120. synapse_sdk/plugins/steps/utils/__init__.py +20 -0
  121. synapse_sdk/plugins/steps/utils/logging.py +85 -0
  122. synapse_sdk/plugins/steps/utils/timing.py +71 -0
  123. synapse_sdk/plugins/steps/utils/validation.py +68 -0
  124. synapse_sdk/plugins/templates/__init__.py +50 -0
  125. synapse_sdk/plugins/templates/base/.gitignore.j2 +26 -0
  126. synapse_sdk/plugins/templates/base/.synapseignore.j2 +11 -0
  127. synapse_sdk/plugins/templates/base/README.md.j2 +26 -0
  128. synapse_sdk/plugins/templates/base/plugin/__init__.py.j2 +1 -0
  129. synapse_sdk/plugins/templates/base/pyproject.toml.j2 +14 -0
  130. synapse_sdk/plugins/templates/base/requirements.txt.j2 +1 -0
  131. synapse_sdk/plugins/templates/custom/plugin/main.py.j2 +18 -0
  132. synapse_sdk/plugins/templates/data_validation/plugin/validate.py.j2 +32 -0
  133. synapse_sdk/plugins/templates/export/plugin/export.py.j2 +36 -0
  134. synapse_sdk/plugins/templates/neural_net/plugin/inference.py.j2 +36 -0
  135. synapse_sdk/plugins/templates/neural_net/plugin/train.py.j2 +33 -0
  136. synapse_sdk/plugins/templates/post_annotation/plugin/post_annotate.py.j2 +32 -0
  137. synapse_sdk/plugins/templates/pre_annotation/plugin/pre_annotate.py.j2 +32 -0
  138. synapse_sdk/plugins/templates/smart_tool/plugin/auto_label.py.j2 +44 -0
  139. synapse_sdk/plugins/templates/upload/plugin/upload.py.j2 +35 -0
  140. synapse_sdk/plugins/testing/__init__.py +25 -0
  141. synapse_sdk/plugins/testing/sample_actions.py +98 -0
  142. synapse_sdk/plugins/types.py +206 -0
  143. synapse_sdk/plugins/upload.py +595 -64
  144. synapse_sdk/plugins/utils.py +325 -37
  145. synapse_sdk/shared/__init__.py +25 -0
  146. synapse_sdk/utils/__init__.py +1 -0
  147. synapse_sdk/utils/auth.py +74 -0
  148. synapse_sdk/utils/file/__init__.py +58 -0
  149. synapse_sdk/utils/file/archive.py +449 -0
  150. synapse_sdk/utils/file/checksum.py +167 -0
  151. synapse_sdk/utils/file/download.py +286 -0
  152. synapse_sdk/utils/file/io.py +129 -0
  153. synapse_sdk/utils/file/requirements.py +36 -0
  154. synapse_sdk/utils/network.py +168 -0
  155. synapse_sdk/utils/storage/__init__.py +238 -0
  156. synapse_sdk/utils/storage/config.py +188 -0
  157. synapse_sdk/utils/storage/errors.py +52 -0
  158. synapse_sdk/utils/storage/providers/__init__.py +13 -0
  159. synapse_sdk/utils/storage/providers/base.py +76 -0
  160. synapse_sdk/utils/storage/providers/gcs.py +168 -0
  161. synapse_sdk/utils/storage/providers/http.py +250 -0
  162. synapse_sdk/utils/storage/providers/local.py +126 -0
  163. synapse_sdk/utils/storage/providers/s3.py +177 -0
  164. synapse_sdk/utils/storage/providers/sftp.py +208 -0
  165. synapse_sdk/utils/storage/registry.py +125 -0
  166. synapse_sdk/utils/websocket.py +99 -0
  167. synapse_sdk-2026.1.1b2.dist-info/METADATA +715 -0
  168. synapse_sdk-2026.1.1b2.dist-info/RECORD +172 -0
  169. {synapse_sdk-1.0.0a11.dist-info → synapse_sdk-2026.1.1b2.dist-info}/WHEEL +1 -1
  170. synapse_sdk-2026.1.1b2.dist-info/licenses/LICENSE +201 -0
  171. locale/en/LC_MESSAGES/messages.mo +0 -0
  172. locale/en/LC_MESSAGES/messages.po +0 -39
  173. locale/ko/LC_MESSAGES/messages.mo +0 -0
  174. locale/ko/LC_MESSAGES/messages.po +0 -34
  175. synapse_sdk/cli/create_plugin.py +0 -10
  176. synapse_sdk/clients/agent/core.py +0 -7
  177. synapse_sdk/clients/agent/service.py +0 -15
  178. synapse_sdk/clients/backend/dataset.py +0 -51
  179. synapse_sdk/clients/ray/__init__.py +0 -6
  180. synapse_sdk/clients/ray/core.py +0 -22
  181. synapse_sdk/clients/ray/serve.py +0 -20
  182. synapse_sdk/i18n.py +0 -35
  183. synapse_sdk/plugins/categories/__init__.py +0 -0
  184. synapse_sdk/plugins/categories/base.py +0 -235
  185. synapse_sdk/plugins/categories/data_validation/__init__.py +0 -0
  186. synapse_sdk/plugins/categories/data_validation/actions/__init__.py +0 -0
  187. synapse_sdk/plugins/categories/data_validation/actions/validation.py +0 -10
  188. synapse_sdk/plugins/categories/data_validation/templates/config.yaml +0 -3
  189. synapse_sdk/plugins/categories/data_validation/templates/plugin/__init__.py +0 -0
  190. synapse_sdk/plugins/categories/data_validation/templates/plugin/validation.py +0 -5
  191. synapse_sdk/plugins/categories/decorators.py +0 -13
  192. synapse_sdk/plugins/categories/export/__init__.py +0 -0
  193. synapse_sdk/plugins/categories/export/actions/__init__.py +0 -0
  194. synapse_sdk/plugins/categories/export/actions/export.py +0 -10
  195. synapse_sdk/plugins/categories/import/__init__.py +0 -0
  196. synapse_sdk/plugins/categories/import/actions/__init__.py +0 -0
  197. synapse_sdk/plugins/categories/import/actions/import.py +0 -10
  198. synapse_sdk/plugins/categories/neural_net/__init__.py +0 -0
  199. synapse_sdk/plugins/categories/neural_net/actions/__init__.py +0 -0
  200. synapse_sdk/plugins/categories/neural_net/actions/deployment.py +0 -45
  201. synapse_sdk/plugins/categories/neural_net/actions/inference.py +0 -18
  202. synapse_sdk/plugins/categories/neural_net/actions/test.py +0 -10
  203. synapse_sdk/plugins/categories/neural_net/actions/train.py +0 -143
  204. synapse_sdk/plugins/categories/neural_net/templates/config.yaml +0 -12
  205. synapse_sdk/plugins/categories/neural_net/templates/plugin/__init__.py +0 -0
  206. synapse_sdk/plugins/categories/neural_net/templates/plugin/inference.py +0 -4
  207. synapse_sdk/plugins/categories/neural_net/templates/plugin/test.py +0 -2
  208. synapse_sdk/plugins/categories/neural_net/templates/plugin/train.py +0 -14
  209. synapse_sdk/plugins/categories/post_annotation/__init__.py +0 -0
  210. synapse_sdk/plugins/categories/post_annotation/actions/__init__.py +0 -0
  211. synapse_sdk/plugins/categories/post_annotation/actions/post_annotation.py +0 -10
  212. synapse_sdk/plugins/categories/post_annotation/templates/config.yaml +0 -3
  213. synapse_sdk/plugins/categories/post_annotation/templates/plugin/__init__.py +0 -0
  214. synapse_sdk/plugins/categories/post_annotation/templates/plugin/post_annotation.py +0 -3
  215. synapse_sdk/plugins/categories/pre_annotation/__init__.py +0 -0
  216. synapse_sdk/plugins/categories/pre_annotation/actions/__init__.py +0 -0
  217. synapse_sdk/plugins/categories/pre_annotation/actions/pre_annotation.py +0 -10
  218. synapse_sdk/plugins/categories/pre_annotation/templates/config.yaml +0 -3
  219. synapse_sdk/plugins/categories/pre_annotation/templates/plugin/__init__.py +0 -0
  220. synapse_sdk/plugins/categories/pre_annotation/templates/plugin/pre_annotation.py +0 -3
  221. synapse_sdk/plugins/categories/registry.py +0 -16
  222. synapse_sdk/plugins/categories/smart_tool/__init__.py +0 -0
  223. synapse_sdk/plugins/categories/smart_tool/actions/__init__.py +0 -0
  224. synapse_sdk/plugins/categories/smart_tool/actions/auto_label.py +0 -37
  225. synapse_sdk/plugins/categories/smart_tool/templates/config.yaml +0 -7
  226. synapse_sdk/plugins/categories/smart_tool/templates/plugin/__init__.py +0 -0
  227. synapse_sdk/plugins/categories/smart_tool/templates/plugin/auto_label.py +0 -11
  228. synapse_sdk/plugins/categories/templates.py +0 -32
  229. synapse_sdk/plugins/cli/__init__.py +0 -21
  230. synapse_sdk/plugins/cli/publish.py +0 -37
  231. synapse_sdk/plugins/cli/run.py +0 -67
  232. synapse_sdk/plugins/exceptions.py +0 -22
  233. synapse_sdk/plugins/models.py +0 -121
  234. synapse_sdk/plugins/templates/cookiecutter.json +0 -11
  235. synapse_sdk/plugins/templates/hooks/post_gen_project.py +0 -3
  236. synapse_sdk/plugins/templates/hooks/pre_prompt.py +0 -21
  237. synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/.env +0 -24
  238. synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/.env.dist +0 -24
  239. synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/.gitignore +0 -27
  240. synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/.pre-commit-config.yaml +0 -7
  241. synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/README.md +0 -5
  242. synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/config.yaml +0 -6
  243. synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/main.py +0 -4
  244. synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/plugin/__init__.py +0 -0
  245. synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/pyproject.toml +0 -13
  246. synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/requirements.txt +0 -1
  247. synapse_sdk/shared/enums.py +0 -8
  248. synapse_sdk/utils/debug.py +0 -5
  249. synapse_sdk/utils/file.py +0 -87
  250. synapse_sdk/utils/module_loading.py +0 -29
  251. synapse_sdk/utils/pydantic/__init__.py +0 -0
  252. synapse_sdk/utils/pydantic/config.py +0 -4
  253. synapse_sdk/utils/pydantic/errors.py +0 -33
  254. synapse_sdk/utils/pydantic/validators.py +0 -7
  255. synapse_sdk/utils/storage.py +0 -91
  256. synapse_sdk/utils/string.py +0 -11
  257. synapse_sdk-1.0.0a11.dist-info/LICENSE +0 -21
  258. synapse_sdk-1.0.0a11.dist-info/METADATA +0 -43
  259. synapse_sdk-1.0.0a11.dist-info/RECORD +0 -111
  260. {synapse_sdk-1.0.0a11.dist-info → synapse_sdk-2026.1.1b2.dist-info}/entry_points.txt +0 -0
  261. {synapse_sdk-1.0.0a11.dist-info → synapse_sdk-2026.1.1b2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,178 @@
1
+ """Protocol definitions for HTTP clients.
2
+
3
+ This module defines protocols for sync and async HTTP clients,
4
+ enabling proper type hints in mixins with IDE autocompletion support.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from typing import TYPE_CHECKING, Any, Protocol, runtime_checkable
10
+
11
+ if TYPE_CHECKING:
12
+ from pydantic import BaseModel
13
+
14
+
15
+ @runtime_checkable
16
+ class ClientProtocol(Protocol):
17
+ """Protocol for synchronous HTTP clients.
18
+
19
+ This protocol enables proper type hints in mixin classes,
20
+ providing IDE autocompletion for client methods.
21
+
22
+ Attributes:
23
+ name: Client name for error messages.
24
+ base_url: Base URL for API requests.
25
+ page_size: Default page size for pagination.
26
+ """
27
+
28
+ name: str | None
29
+ base_url: str
30
+ page_size: int
31
+
32
+ def _get_headers(self) -> dict[str, str]:
33
+ """Return headers for requests."""
34
+ ...
35
+
36
+ def _get(
37
+ self,
38
+ path: str,
39
+ url_conversion: dict | None = None,
40
+ response_model: type[BaseModel] | None = None,
41
+ **kwargs,
42
+ ) -> Any:
43
+ """Perform a GET request."""
44
+ ...
45
+
46
+ def _post(
47
+ self,
48
+ path: str,
49
+ request_model: type[BaseModel] | None = None,
50
+ response_model: type[BaseModel] | None = None,
51
+ **kwargs,
52
+ ) -> Any:
53
+ """Perform a POST request."""
54
+ ...
55
+
56
+ def _put(
57
+ self,
58
+ path: str,
59
+ request_model: type[BaseModel] | None = None,
60
+ response_model: type[BaseModel] | None = None,
61
+ **kwargs,
62
+ ) -> Any:
63
+ """Perform a PUT request."""
64
+ ...
65
+
66
+ def _patch(
67
+ self,
68
+ path: str,
69
+ request_model: type[BaseModel] | None = None,
70
+ response_model: type[BaseModel] | None = None,
71
+ **kwargs,
72
+ ) -> Any:
73
+ """Perform a PATCH request."""
74
+ ...
75
+
76
+ def _delete(
77
+ self,
78
+ path: str,
79
+ request_model: type[BaseModel] | None = None,
80
+ response_model: type[BaseModel] | None = None,
81
+ **kwargs,
82
+ ) -> Any:
83
+ """Perform a DELETE request."""
84
+ ...
85
+
86
+ def _list(
87
+ self,
88
+ path: str,
89
+ url_conversion: dict | None = None,
90
+ list_all: bool = False,
91
+ params: dict | None = None,
92
+ **kwargs,
93
+ ) -> dict | tuple[Any, int]:
94
+ """List resources from a paginated API endpoint."""
95
+ ...
96
+
97
+
98
+ @runtime_checkable
99
+ class AsyncClientProtocol(Protocol):
100
+ """Protocol for asynchronous HTTP clients.
101
+
102
+ This protocol enables proper type hints in async mixin classes,
103
+ providing IDE autocompletion for async client methods.
104
+
105
+ Attributes:
106
+ name: Client name for error messages.
107
+ base_url: Base URL for API requests.
108
+ page_size: Default page size for pagination.
109
+ """
110
+
111
+ name: str | None
112
+ base_url: str
113
+ page_size: int
114
+
115
+ def _get_headers(self) -> dict[str, str]:
116
+ """Return headers for requests."""
117
+ ...
118
+
119
+ async def _get(
120
+ self,
121
+ path: str,
122
+ url_conversion: dict | None = None,
123
+ response_model: type[BaseModel] | None = None,
124
+ **kwargs,
125
+ ) -> Any:
126
+ """Perform a GET request."""
127
+ ...
128
+
129
+ async def _post(
130
+ self,
131
+ path: str,
132
+ request_model: type[BaseModel] | None = None,
133
+ response_model: type[BaseModel] | None = None,
134
+ **kwargs,
135
+ ) -> Any:
136
+ """Perform a POST request."""
137
+ ...
138
+
139
+ async def _put(
140
+ self,
141
+ path: str,
142
+ request_model: type[BaseModel] | None = None,
143
+ response_model: type[BaseModel] | None = None,
144
+ **kwargs,
145
+ ) -> Any:
146
+ """Perform a PUT request."""
147
+ ...
148
+
149
+ async def _patch(
150
+ self,
151
+ path: str,
152
+ request_model: type[BaseModel] | None = None,
153
+ response_model: type[BaseModel] | None = None,
154
+ **kwargs,
155
+ ) -> Any:
156
+ """Perform a PATCH request."""
157
+ ...
158
+
159
+ async def _delete(
160
+ self,
161
+ path: str,
162
+ request_model: type[BaseModel] | None = None,
163
+ response_model: type[BaseModel] | None = None,
164
+ **kwargs,
165
+ ) -> Any:
166
+ """Perform a DELETE request."""
167
+ ...
168
+
169
+ async def _list(
170
+ self,
171
+ path: str,
172
+ url_conversion: dict | None = None,
173
+ list_all: bool = False,
174
+ params: dict | None = None,
175
+ **kwargs,
176
+ ) -> dict | tuple[Any, int]:
177
+ """List resources from a paginated API endpoint."""
178
+ ...
@@ -1,10 +1,88 @@
1
- def get_default_url_conversion(url_conversion, **kwargs):
2
- defaults = {'files_fields': [], 'coerce': None, 'is_list': True}
3
- defaults.update(kwargs)
4
- if url_conversion:
5
- defaults.update(url_conversion)
6
- return defaults
1
+ """Shared utility functions for HTTP clients.
7
2
 
3
+ This module contains utility functions extracted from BaseClient
4
+ and AsyncBaseClient to reduce code duplication.
5
+ """
8
6
 
9
- def get_batched_list(object_list, batch_size):
10
- return [object_list[index : index + batch_size] for index in range(0, len(object_list), batch_size)]
7
+ from __future__ import annotations
8
+
9
+ import json
10
+ from typing import Any, Union
11
+
12
+ # Type alias for response objects (requests.Response or httpx.Response)
13
+ ResponseType = Any
14
+
15
+
16
+ def build_url(base_url: str, path: str, trailing_slash: bool = False) -> str:
17
+ """Construct a full URL from base URL and path.
18
+
19
+ Args:
20
+ base_url: The base URL (e.g., 'https://api.example.com').
21
+ path: The path to append (e.g., 'users/123').
22
+ trailing_slash: Whether to ensure the URL ends with a slash.
23
+
24
+ Returns:
25
+ The constructed URL.
26
+
27
+ Examples:
28
+ >>> build_url('https://api.example.com', 'users/123')
29
+ 'https://api.example.com/users/123'
30
+ >>> build_url('https://api.example.com/', '/users/123/')
31
+ 'https://api.example.com/users/123/'
32
+ >>> build_url('https://api.example.com', 'users', trailing_slash=True)
33
+ 'https://api.example.com/users/'
34
+ """
35
+ # If path is already a full URL, use it directly
36
+ if path.startswith(('http://', 'https://')):
37
+ url = path
38
+ else:
39
+ # Normalize: strip trailing slash from base and leading slash from path
40
+ base = base_url.rstrip('/')
41
+ clean_path = path.lstrip('/')
42
+ url = f'{base}/{clean_path}'
43
+
44
+ # Handle trailing slash
45
+ if trailing_slash and not url.endswith('/'):
46
+ url += '/'
47
+
48
+ return url
49
+
50
+
51
+ def extract_error_detail(response: ResponseType) -> Any:
52
+ """Extract error detail from response, preferring JSON.
53
+
54
+ Args:
55
+ response: A requests.Response or httpx.Response object.
56
+
57
+ Returns:
58
+ The parsed JSON response if available, otherwise the text content
59
+ or reason phrase.
60
+ """
61
+ try:
62
+ return response.json()
63
+ except (ValueError, json.JSONDecodeError):
64
+ # For requests.Response, use 'reason'; for httpx.Response, use 'reason_phrase'
65
+ text = getattr(response, 'text', '')
66
+ reason = getattr(response, 'reason', None) or getattr(response, 'reason_phrase', '')
67
+ return text or reason
68
+
69
+
70
+ def parse_json_response(response: ResponseType) -> Union[dict, str, None]:
71
+ """Parse response, preferring JSON.
72
+
73
+ Args:
74
+ response: A requests.Response or httpx.Response object.
75
+
76
+ Returns:
77
+ The parsed JSON response if available, otherwise the text content.
78
+ Returns None for 204 No Content responses.
79
+ """
80
+ # Handle 204 No Content
81
+ status_code = getattr(response, 'status_code', None)
82
+ if status_code == 204:
83
+ return None
84
+
85
+ try:
86
+ return response.json()
87
+ except (ValueError, json.JSONDecodeError):
88
+ return response.text
@@ -0,0 +1,58 @@
1
+ """Shared validation mixin for HTTP clients.
2
+
3
+ This module provides a mixin class with Pydantic validation methods
4
+ that can be used by both sync and async HTTP clients.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from typing import TYPE_CHECKING, Any
10
+
11
+ if TYPE_CHECKING:
12
+ from pydantic import BaseModel
13
+
14
+
15
+ class ValidationMixin:
16
+ """Mixin providing Pydantic validation methods for HTTP clients.
17
+
18
+ This mixin provides shared validation functionality for both
19
+ BaseClient and AsyncBaseClient, reducing code duplication.
20
+ """
21
+
22
+ def _validate_response(self, response: Any, model: type[BaseModel]) -> Any:
23
+ """Validate response against a Pydantic model.
24
+
25
+ Args:
26
+ response: The response data to validate.
27
+ model: The Pydantic model to validate against.
28
+
29
+ Returns:
30
+ The original response if validation passes.
31
+
32
+ Raises:
33
+ TypeError: If the model is not a Pydantic model.
34
+ ValidationError: If the response doesn't match the model.
35
+ """
36
+ if not hasattr(model, 'model_validate'):
37
+ raise TypeError(f'{model.__name__} is not a Pydantic model')
38
+ model.model_validate(response)
39
+ return response
40
+
41
+ def _validate_request(self, data: dict, model: type[BaseModel]) -> dict:
42
+ """Validate request data against a Pydantic model.
43
+
44
+ Args:
45
+ data: The request data to validate.
46
+ model: The Pydantic model to validate against.
47
+
48
+ Returns:
49
+ A dictionary with validated data, excluding None values.
50
+
51
+ Raises:
52
+ TypeError: If the model is not a Pydantic model.
53
+ ValidationError: If the data doesn't match the model.
54
+ """
55
+ if not hasattr(model, 'model_validate'):
56
+ raise TypeError(f'{model.__name__} is not a Pydantic model')
57
+ instance = model.model_validate(data)
58
+ return {k: v for k, v in instance.model_dump().items() if v is not None}
synapse_sdk/enums.py ADDED
@@ -0,0 +1,76 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ from pydantic import GetCoreSchemaHandler
6
+ from pydantic_core import CoreSchema, core_schema
7
+
8
+ from synapse_sdk.utils.file import download_file, get_temp_path
9
+
10
+
11
+ class FileField(str):
12
+ """Pydantic field type that automatically downloads files from URLs.
13
+
14
+ When used as a type annotation in a Pydantic model, URLs are automatically
15
+ downloaded during validation and replaced with local file paths.
16
+
17
+ The downloaded files are cached in /tmp/datamaker/media/ using a hash of
18
+ the URL as the filename, preventing redundant downloads.
19
+
20
+ Examples:
21
+ >>> from pydantic import BaseModel
22
+ >>> from synapse_sdk.enums import FileField
23
+ >>>
24
+ >>> class InferenceParams(BaseModel):
25
+ ... input_file: FileField
26
+ ... config_file: FileField | None = None
27
+ >>>
28
+ >>> # URL is automatically downloaded during validation
29
+ >>> params = InferenceParams(input_file="https://example.com/image.jpg")
30
+ >>> params.input_file # "/tmp/datamaker/media/abc123def.jpg"
31
+
32
+ Note:
33
+ - Downloads happen synchronously during validation
34
+ - Files are cached by URL hash (same URL = same local path)
35
+ - The field value becomes a string path to the local file
36
+ """
37
+
38
+ @classmethod
39
+ def __get_pydantic_core_schema__(
40
+ cls,
41
+ source_type: Any,
42
+ handler: GetCoreSchemaHandler,
43
+ ) -> CoreSchema:
44
+ return core_schema.with_info_before_validator_function(
45
+ cls._validate,
46
+ core_schema.str_schema(),
47
+ )
48
+
49
+ @classmethod
50
+ def _validate(cls, value: Any, info: core_schema.ValidationInfo) -> str:
51
+ """Download the file from URL and return local path.
52
+
53
+ Args:
54
+ value: The URL string to download from.
55
+ info: Pydantic validation context (unused but required by protocol).
56
+
57
+ Returns:
58
+ String path to the downloaded local file.
59
+
60
+ Raises:
61
+ requests.HTTPError: If download fails.
62
+ ValueError: If value is not a valid URL string.
63
+ """
64
+ if not isinstance(value, str):
65
+ raise ValueError(f'FileField expects a URL string, got {type(value).__name__}')
66
+
67
+ if not value:
68
+ raise ValueError('FileField URL cannot be empty')
69
+
70
+ path_download = get_temp_path('media')
71
+ path_download.mkdir(parents=True, exist_ok=True)
72
+
73
+ return str(download_file(value, path_download))
74
+
75
+
76
+ __all__ = ['FileField']
@@ -0,0 +1,168 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+
6
+ class ClientError(Exception):
7
+ """Base exception for all HTTP client errors.
8
+
9
+ This is the root of the exception hierarchy for HTTP client operations.
10
+ All client-related exceptions inherit from this class, allowing for
11
+ both broad and granular error handling.
12
+
13
+ Exception Hierarchy::
14
+
15
+ ClientError (base)
16
+ ├── ClientConnectionError # Network/connection failures
17
+ ├── ClientTimeoutError # Request timeouts
18
+ ├── HTTPError # HTTP status code errors
19
+ │ ├── AuthenticationError # 401 Unauthorized
20
+ │ ├── AuthorizationError # 403 Forbidden
21
+ │ ├── NotFoundError # 404 Not Found
22
+ │ ├── ValidationError # 400/422 Bad Request
23
+ │ ├── RateLimitError # 429 Too Many Requests
24
+ │ └── ServerError # 5xx Server Errors
25
+ └── StreamError # Streaming/WebSocket errors
26
+ ├── StreamLimitExceededError
27
+ └── WebSocketError
28
+
29
+ Attributes:
30
+ status_code: HTTP status code if applicable, None for non-HTTP errors.
31
+ detail: Error details from the response or underlying exception.
32
+
33
+ Example:
34
+ >>> from synapse_sdk.exceptions import ClientError, NotFoundError
35
+ >>>
36
+ >>> try:
37
+ ... result = client.get_resource(123)
38
+ ... except NotFoundError:
39
+ ... print("Resource not found")
40
+ ... except ClientError as e:
41
+ ... print(f"Client error: {e.status_code} - {e.detail}")
42
+ """
43
+
44
+ def __init__(self, status_code: int | None = None, detail: Any = None):
45
+ self.status_code = status_code
46
+ self.detail = detail
47
+ if status_code is not None:
48
+ super().__init__(f'{status_code}: {detail}')
49
+ else:
50
+ super().__init__(str(detail) if detail else '')
51
+
52
+ def __repr__(self) -> str:
53
+ return f'{self.__class__.__name__}(status_code={self.status_code}, detail={self.detail!r})'
54
+
55
+
56
+ class ClientConnectionError(ClientError):
57
+ """Connection failed."""
58
+
59
+ def __init__(self, detail: Any = None):
60
+ super().__init__(status_code=None, detail=detail)
61
+
62
+
63
+ class ClientTimeoutError(ClientError):
64
+ """Request timed out."""
65
+
66
+ def __init__(self, detail: Any = None):
67
+ super().__init__(status_code=408, detail=detail)
68
+
69
+
70
+ class HTTPError(ClientError):
71
+ """HTTP status code error."""
72
+
73
+ pass
74
+
75
+
76
+ class AuthenticationError(HTTPError):
77
+ """401 Unauthorized."""
78
+
79
+ def __init__(self, detail: Any = None):
80
+ super().__init__(status_code=401, detail=detail)
81
+
82
+
83
+ class AuthorizationError(HTTPError):
84
+ """403 Forbidden."""
85
+
86
+ def __init__(self, detail: Any = None):
87
+ super().__init__(status_code=403, detail=detail)
88
+
89
+
90
+ class NotFoundError(HTTPError):
91
+ """404 Not Found."""
92
+
93
+ def __init__(self, detail: Any = None):
94
+ super().__init__(status_code=404, detail=detail)
95
+
96
+
97
+ class ValidationError(HTTPError):
98
+ """400/422 Bad Request or Unprocessable Entity."""
99
+
100
+ def __init__(self, status_code: int = 400, detail: Any = None):
101
+ super().__init__(status_code=status_code, detail=detail)
102
+
103
+
104
+ class RateLimitError(HTTPError):
105
+ """429 Too Many Requests."""
106
+
107
+ def __init__(self, detail: Any = None):
108
+ super().__init__(status_code=429, detail=detail)
109
+
110
+
111
+ class ServerError(HTTPError):
112
+ """5xx Server Error."""
113
+
114
+ def __init__(self, status_code: int = 500, detail: Any = None):
115
+ super().__init__(status_code=status_code, detail=detail)
116
+
117
+
118
+ class StreamError(ClientError):
119
+ """Stream processing error."""
120
+
121
+ pass
122
+
123
+
124
+ class StreamLimitExceededError(StreamError):
125
+ """Stream limit exceeded."""
126
+
127
+ pass
128
+
129
+
130
+ class WebSocketError(StreamError):
131
+ """WebSocket connection error."""
132
+
133
+ pass
134
+
135
+
136
+ def raise_for_status(status_code: int, detail: Any = None) -> None:
137
+ """Raise an appropriate exception based on HTTP status code.
138
+
139
+ Args:
140
+ status_code: HTTP status code.
141
+ detail: Error detail from response.
142
+
143
+ Raises:
144
+ AuthenticationError: For 401 status.
145
+ AuthorizationError: For 403 status.
146
+ NotFoundError: For 404 status.
147
+ ValidationError: For 400 or 422 status.
148
+ RateLimitError: For 429 status.
149
+ ServerError: For 5xx status.
150
+ HTTPError: For other error status codes.
151
+ """
152
+ if status_code < 400:
153
+ return
154
+
155
+ if status_code == 401:
156
+ raise AuthenticationError(detail)
157
+ elif status_code == 403:
158
+ raise AuthorizationError(detail)
159
+ elif status_code == 404:
160
+ raise NotFoundError(detail)
161
+ elif status_code in (400, 422):
162
+ raise ValidationError(status_code, detail)
163
+ elif status_code == 429:
164
+ raise RateLimitError(detail)
165
+ elif status_code >= 500:
166
+ raise ServerError(status_code, detail)
167
+ else:
168
+ raise HTTPError(status_code, detail)
@@ -0,0 +1,74 @@
1
+ """Framework integrations for automatic logging.
2
+
3
+ This module provides automatic logging integrations for popular ML frameworks.
4
+ Enable autolog to automatically capture training progress, metrics, and artifacts.
5
+
6
+ Example:
7
+ >>> from synapse_sdk.plugins.actions.train import BaseTrainAction
8
+ >>> from ultralytics import YOLO
9
+ >>>
10
+ >>> class TrainAction(BaseTrainAction[TrainParams]):
11
+ ... def execute(self):
12
+ ... self.autolog('ultralytics') # Enable autologging
13
+ ...
14
+ ... model = YOLO('yolov8n.pt') # Callbacks auto-attached
15
+ ... model.train(epochs=100) # Metrics logged automatically
16
+ ...
17
+ ... return TrainResult(...)
18
+
19
+ Supported frameworks:
20
+ - ultralytics: YOLO object detection models
21
+ """
22
+
23
+ from __future__ import annotations
24
+
25
+ from typing import TYPE_CHECKING
26
+
27
+ from synapse_sdk.integrations._base import get_integration, list_integrations
28
+
29
+ if TYPE_CHECKING:
30
+ from synapse_sdk.plugins.action import BaseAction
31
+
32
+ # Import integrations to register them
33
+ from synapse_sdk.integrations import ultralytics as _ultralytics # noqa: F401
34
+
35
+
36
+ def autolog(framework: str, action: BaseAction) -> None:
37
+ """Enable automatic logging for an ML framework.
38
+
39
+ Call this before creating model objects. The SDK will automatically
40
+ attach callbacks to log progress, metrics, and artifacts.
41
+
42
+ Args:
43
+ framework: Framework name (e.g., 'ultralytics').
44
+ action: The current action instance (typically `self` in execute()).
45
+
46
+ Raises:
47
+ ValueError: If framework is not recognized.
48
+ ImportError: If framework package is not installed.
49
+
50
+ Example:
51
+ >>> class TrainAction(BaseTrainAction[TrainParams]):
52
+ ... def execute(self):
53
+ ... autolog('ultralytics', self)
54
+ ... model = YOLO('yolov8n.pt')
55
+ ... model.train(epochs=100)
56
+ """
57
+ integration = get_integration(framework)
58
+ integration.enable(action)
59
+
60
+
61
+ def disable_autolog(framework: str) -> None:
62
+ """Disable autologging for a framework.
63
+
64
+ Args:
65
+ framework: Framework name (e.g., 'ultralytics').
66
+
67
+ Raises:
68
+ ValueError: If framework is not recognized.
69
+ """
70
+ integration = get_integration(framework)
71
+ integration.disable()
72
+
73
+
74
+ __all__ = ['autolog', 'disable_autolog', 'list_integrations']