synapse-sdk 1.0.0a35__py3-none-any.whl → 2025.11.7__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 (307) hide show
  1. synapse_sdk/__init__.py +24 -0
  2. synapse_sdk/cli/__init__.py +308 -5
  3. synapse_sdk/cli/alias/utils.py +1 -1
  4. synapse_sdk/cli/code_server.py +687 -0
  5. synapse_sdk/cli/config.py +440 -0
  6. synapse_sdk/cli/devtools.py +90 -0
  7. synapse_sdk/cli/plugin/publish.py +23 -15
  8. synapse_sdk/clients/agent/__init__.py +9 -3
  9. synapse_sdk/clients/agent/container.py +133 -0
  10. synapse_sdk/clients/agent/core.py +19 -0
  11. synapse_sdk/clients/agent/ray.py +298 -9
  12. synapse_sdk/clients/backend/__init__.py +28 -12
  13. synapse_sdk/clients/backend/annotation.py +9 -1
  14. synapse_sdk/clients/backend/core.py +31 -4
  15. synapse_sdk/clients/backend/data_collection.py +186 -0
  16. synapse_sdk/clients/backend/hitl.py +1 -1
  17. synapse_sdk/clients/backend/integration.py +4 -3
  18. synapse_sdk/clients/backend/ml.py +1 -1
  19. synapse_sdk/clients/backend/models.py +35 -1
  20. synapse_sdk/clients/base.py +309 -36
  21. synapse_sdk/clients/ray/serve.py +2 -0
  22. synapse_sdk/devtools/__init__.py +0 -0
  23. synapse_sdk/devtools/config.py +94 -0
  24. synapse_sdk/devtools/docs/.gitignore +20 -0
  25. synapse_sdk/devtools/docs/README.md +41 -0
  26. synapse_sdk/devtools/docs/blog/2019-05-28-first-blog-post.md +12 -0
  27. synapse_sdk/devtools/docs/blog/2019-05-29-long-blog-post.md +44 -0
  28. synapse_sdk/devtools/docs/blog/2021-08-01-mdx-blog-post.mdx +24 -0
  29. synapse_sdk/devtools/docs/blog/2021-08-26-welcome/docusaurus-plushie-banner.jpeg +0 -0
  30. synapse_sdk/devtools/docs/blog/2021-08-26-welcome/index.md +29 -0
  31. synapse_sdk/devtools/docs/blog/authors.yml +25 -0
  32. synapse_sdk/devtools/docs/blog/tags.yml +19 -0
  33. synapse_sdk/devtools/docs/docs/api/clients/agent.md +43 -0
  34. synapse_sdk/devtools/docs/docs/api/clients/annotation-mixin.md +378 -0
  35. synapse_sdk/devtools/docs/docs/api/clients/backend.md +420 -0
  36. synapse_sdk/devtools/docs/docs/api/clients/base.md +257 -0
  37. synapse_sdk/devtools/docs/docs/api/clients/core-mixin.md +477 -0
  38. synapse_sdk/devtools/docs/docs/api/clients/data-collection-mixin.md +422 -0
  39. synapse_sdk/devtools/docs/docs/api/clients/hitl-mixin.md +554 -0
  40. synapse_sdk/devtools/docs/docs/api/clients/index.md +391 -0
  41. synapse_sdk/devtools/docs/docs/api/clients/integration-mixin.md +571 -0
  42. synapse_sdk/devtools/docs/docs/api/clients/ml-mixin.md +578 -0
  43. synapse_sdk/devtools/docs/docs/api/clients/ray.md +342 -0
  44. synapse_sdk/devtools/docs/docs/api/index.md +52 -0
  45. synapse_sdk/devtools/docs/docs/api/plugins/categories.md +43 -0
  46. synapse_sdk/devtools/docs/docs/api/plugins/models.md +114 -0
  47. synapse_sdk/devtools/docs/docs/api/plugins/utils.md +328 -0
  48. synapse_sdk/devtools/docs/docs/categories.md +0 -0
  49. synapse_sdk/devtools/docs/docs/cli-usage.md +280 -0
  50. synapse_sdk/devtools/docs/docs/concepts/index.md +38 -0
  51. synapse_sdk/devtools/docs/docs/configuration.md +83 -0
  52. synapse_sdk/devtools/docs/docs/contributing.md +306 -0
  53. synapse_sdk/devtools/docs/docs/examples/index.md +29 -0
  54. synapse_sdk/devtools/docs/docs/faq.md +179 -0
  55. synapse_sdk/devtools/docs/docs/features/converters/index.md +455 -0
  56. synapse_sdk/devtools/docs/docs/features/index.md +24 -0
  57. synapse_sdk/devtools/docs/docs/features/utils/file.md +415 -0
  58. synapse_sdk/devtools/docs/docs/features/utils/network.md +378 -0
  59. synapse_sdk/devtools/docs/docs/features/utils/storage.md +57 -0
  60. synapse_sdk/devtools/docs/docs/features/utils/types.md +51 -0
  61. synapse_sdk/devtools/docs/docs/installation.md +94 -0
  62. synapse_sdk/devtools/docs/docs/introduction.md +47 -0
  63. synapse_sdk/devtools/docs/docs/plugins/categories/neural-net-plugins/train-action-overview.md +814 -0
  64. synapse_sdk/devtools/docs/docs/plugins/categories/pre-annotation-plugins/pre-annotation-plugin-overview.md +198 -0
  65. synapse_sdk/devtools/docs/docs/plugins/categories/pre-annotation-plugins/to-task-action-development.md +1645 -0
  66. synapse_sdk/devtools/docs/docs/plugins/categories/pre-annotation-plugins/to-task-overview.md +717 -0
  67. synapse_sdk/devtools/docs/docs/plugins/categories/pre-annotation-plugins/to-task-template-development.md +1380 -0
  68. synapse_sdk/devtools/docs/docs/plugins/categories/upload-plugins/upload-plugin-action.md +948 -0
  69. synapse_sdk/devtools/docs/docs/plugins/categories/upload-plugins/upload-plugin-overview.md +544 -0
  70. synapse_sdk/devtools/docs/docs/plugins/categories/upload-plugins/upload-plugin-template.md +766 -0
  71. synapse_sdk/devtools/docs/docs/plugins/export-plugins.md +1092 -0
  72. synapse_sdk/devtools/docs/docs/plugins/plugins.md +852 -0
  73. synapse_sdk/devtools/docs/docs/quickstart.md +78 -0
  74. synapse_sdk/devtools/docs/docs/troubleshooting.md +519 -0
  75. synapse_sdk/devtools/docs/docs/tutorial-basics/_category_.json +8 -0
  76. synapse_sdk/devtools/docs/docs/tutorial-basics/congratulations.md +23 -0
  77. synapse_sdk/devtools/docs/docs/tutorial-basics/create-a-blog-post.md +34 -0
  78. synapse_sdk/devtools/docs/docs/tutorial-basics/create-a-document.md +57 -0
  79. synapse_sdk/devtools/docs/docs/tutorial-basics/create-a-page.md +43 -0
  80. synapse_sdk/devtools/docs/docs/tutorial-basics/deploy-your-site.md +31 -0
  81. synapse_sdk/devtools/docs/docs/tutorial-basics/markdown-features.mdx +152 -0
  82. synapse_sdk/devtools/docs/docs/tutorial-extras/_category_.json +7 -0
  83. synapse_sdk/devtools/docs/docs/tutorial-extras/img/docsVersionDropdown.png +0 -0
  84. synapse_sdk/devtools/docs/docs/tutorial-extras/img/localeDropdown.png +0 -0
  85. synapse_sdk/devtools/docs/docs/tutorial-extras/manage-docs-versions.md +55 -0
  86. synapse_sdk/devtools/docs/docs/tutorial-extras/translate-your-site.md +88 -0
  87. synapse_sdk/devtools/docs/docusaurus.config.ts +148 -0
  88. synapse_sdk/devtools/docs/i18n/ko/code.json +325 -0
  89. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/agent.md +43 -0
  90. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/annotation-mixin.md +289 -0
  91. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/backend.md +420 -0
  92. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/base.md +257 -0
  93. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/core-mixin.md +417 -0
  94. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/data-collection-mixin.md +356 -0
  95. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/hitl-mixin.md +192 -0
  96. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/index.md +391 -0
  97. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/integration-mixin.md +479 -0
  98. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/ml-mixin.md +284 -0
  99. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/ray.md +342 -0
  100. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/index.md +52 -0
  101. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/plugins/models.md +114 -0
  102. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/categories.md +0 -0
  103. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/cli-usage.md +280 -0
  104. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/concepts/index.md +38 -0
  105. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/configuration.md +83 -0
  106. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/contributing.md +306 -0
  107. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/examples/index.md +29 -0
  108. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/faq.md +179 -0
  109. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/features/converters/index.md +30 -0
  110. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/features/index.md +24 -0
  111. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/features/utils/file.md +415 -0
  112. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/features/utils/network.md +378 -0
  113. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/features/utils/storage.md +60 -0
  114. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/features/utils/types.md +51 -0
  115. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/installation.md +94 -0
  116. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/introduction.md +47 -0
  117. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/neural-net-plugins/train-action-overview.md +815 -0
  118. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/pre-annotation-plugins/pre-annotation-plugin-overview.md +198 -0
  119. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/pre-annotation-plugins/to-task-action-development.md +1645 -0
  120. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/pre-annotation-plugins/to-task-overview.md +717 -0
  121. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/pre-annotation-plugins/to-task-template-development.md +1380 -0
  122. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/upload-plugins/upload-plugin-action.md +948 -0
  123. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/upload-plugins/upload-plugin-overview.md +544 -0
  124. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/upload-plugins/upload-plugin-template.md +766 -0
  125. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/export-plugins.md +1092 -0
  126. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/plugins.md +117 -0
  127. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/quickstart.md +78 -0
  128. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/troubleshooting.md +519 -0
  129. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current.json +34 -0
  130. synapse_sdk/devtools/docs/i18n/ko/docusaurus-theme-classic/footer.json +42 -0
  131. synapse_sdk/devtools/docs/i18n/ko/docusaurus-theme-classic/navbar.json +18 -0
  132. synapse_sdk/devtools/docs/package-lock.json +18784 -0
  133. synapse_sdk/devtools/docs/package.json +48 -0
  134. synapse_sdk/devtools/docs/sidebars.ts +122 -0
  135. synapse_sdk/devtools/docs/src/components/HomepageFeatures/index.tsx +71 -0
  136. synapse_sdk/devtools/docs/src/components/HomepageFeatures/styles.module.css +11 -0
  137. synapse_sdk/devtools/docs/src/css/custom.css +30 -0
  138. synapse_sdk/devtools/docs/src/pages/index.module.css +23 -0
  139. synapse_sdk/devtools/docs/src/pages/index.tsx +21 -0
  140. synapse_sdk/devtools/docs/src/pages/markdown-page.md +7 -0
  141. synapse_sdk/devtools/docs/static/.nojekyll +0 -0
  142. synapse_sdk/devtools/docs/static/img/docusaurus-social-card.jpg +0 -0
  143. synapse_sdk/devtools/docs/static/img/docusaurus.png +0 -0
  144. synapse_sdk/devtools/docs/static/img/favicon.ico +0 -0
  145. synapse_sdk/devtools/docs/static/img/logo.png +0 -0
  146. synapse_sdk/devtools/docs/static/img/undraw_docusaurus_mountain.svg +171 -0
  147. synapse_sdk/devtools/docs/static/img/undraw_docusaurus_react.svg +170 -0
  148. synapse_sdk/devtools/docs/static/img/undraw_docusaurus_tree.svg +40 -0
  149. synapse_sdk/devtools/docs/tsconfig.json +8 -0
  150. synapse_sdk/devtools/server.py +41 -0
  151. synapse_sdk/devtools/streamlit_app/__init__.py +5 -0
  152. synapse_sdk/devtools/streamlit_app/app.py +128 -0
  153. synapse_sdk/devtools/streamlit_app/services/__init__.py +11 -0
  154. synapse_sdk/devtools/streamlit_app/services/job_service.py +233 -0
  155. synapse_sdk/devtools/streamlit_app/services/plugin_service.py +236 -0
  156. synapse_sdk/devtools/streamlit_app/services/serve_service.py +95 -0
  157. synapse_sdk/devtools/streamlit_app/ui/__init__.py +15 -0
  158. synapse_sdk/devtools/streamlit_app/ui/config_tab.py +76 -0
  159. synapse_sdk/devtools/streamlit_app/ui/deployment_tab.py +66 -0
  160. synapse_sdk/devtools/streamlit_app/ui/http_tab.py +125 -0
  161. synapse_sdk/devtools/streamlit_app/ui/jobs_tab.py +573 -0
  162. synapse_sdk/devtools/streamlit_app/ui/serve_tab.py +346 -0
  163. synapse_sdk/devtools/streamlit_app/ui/status_bar.py +118 -0
  164. synapse_sdk/devtools/streamlit_app/utils/__init__.py +40 -0
  165. synapse_sdk/devtools/streamlit_app/utils/json_viewer.py +197 -0
  166. synapse_sdk/devtools/streamlit_app/utils/log_formatter.py +38 -0
  167. synapse_sdk/devtools/streamlit_app/utils/styles.py +241 -0
  168. synapse_sdk/devtools/streamlit_app/utils/ui_components.py +289 -0
  169. synapse_sdk/devtools/streamlit_app.py +10 -0
  170. synapse_sdk/loggers.py +65 -7
  171. synapse_sdk/plugins/README.md +1340 -0
  172. synapse_sdk/plugins/categories/base.py +73 -11
  173. synapse_sdk/plugins/categories/data_validation/actions/validation.py +72 -0
  174. synapse_sdk/plugins/categories/data_validation/templates/plugin/validation.py +33 -5
  175. synapse_sdk/plugins/categories/export/actions/__init__.py +3 -0
  176. synapse_sdk/plugins/categories/export/actions/export/__init__.py +28 -0
  177. synapse_sdk/plugins/categories/export/actions/export/action.py +165 -0
  178. synapse_sdk/plugins/categories/export/actions/export/enums.py +113 -0
  179. synapse_sdk/plugins/categories/export/actions/export/exceptions.py +53 -0
  180. synapse_sdk/plugins/categories/export/actions/export/models.py +74 -0
  181. synapse_sdk/plugins/categories/export/actions/export/run.py +195 -0
  182. synapse_sdk/plugins/categories/export/actions/{export.py → export/utils.py} +47 -82
  183. synapse_sdk/plugins/categories/export/templates/config.yaml +19 -1
  184. synapse_sdk/plugins/categories/export/templates/plugin/__init__.py +390 -0
  185. synapse_sdk/plugins/categories/export/templates/plugin/export.py +153 -129
  186. synapse_sdk/plugins/categories/neural_net/actions/deployment.py +9 -62
  187. synapse_sdk/plugins/categories/neural_net/actions/train.py +1062 -32
  188. synapse_sdk/plugins/categories/neural_net/actions/tune.py +534 -0
  189. synapse_sdk/plugins/categories/neural_net/templates/config.yaml +27 -5
  190. synapse_sdk/plugins/categories/neural_net/templates/plugin/inference.py +26 -10
  191. synapse_sdk/plugins/categories/pre_annotation/actions/__init__.py +4 -0
  192. synapse_sdk/plugins/categories/pre_annotation/actions/pre_annotation/__init__.py +3 -0
  193. synapse_sdk/plugins/categories/pre_annotation/actions/pre_annotation/action.py +10 -0
  194. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/__init__.py +28 -0
  195. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/action.py +145 -0
  196. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/enums.py +269 -0
  197. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/exceptions.py +14 -0
  198. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/factory.py +76 -0
  199. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/models.py +97 -0
  200. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/orchestrator.py +250 -0
  201. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/run.py +64 -0
  202. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/__init__.py +17 -0
  203. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/annotation.py +287 -0
  204. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/base.py +170 -0
  205. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/extraction.py +83 -0
  206. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/metrics.py +87 -0
  207. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/preprocessor.py +127 -0
  208. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/validation.py +143 -0
  209. synapse_sdk/plugins/categories/pre_annotation/actions/to_task.py +966 -0
  210. synapse_sdk/plugins/categories/pre_annotation/templates/config.yaml +19 -0
  211. synapse_sdk/plugins/categories/pre_annotation/templates/plugin/to_task.py +40 -0
  212. synapse_sdk/plugins/categories/upload/actions/upload/__init__.py +19 -0
  213. synapse_sdk/plugins/categories/upload/actions/upload/action.py +232 -0
  214. synapse_sdk/plugins/categories/upload/actions/upload/context.py +185 -0
  215. synapse_sdk/plugins/categories/upload/actions/upload/enums.py +471 -0
  216. synapse_sdk/plugins/categories/upload/actions/upload/exceptions.py +36 -0
  217. synapse_sdk/plugins/categories/upload/actions/upload/factory.py +138 -0
  218. synapse_sdk/plugins/categories/upload/actions/upload/models.py +203 -0
  219. synapse_sdk/plugins/categories/upload/actions/upload/orchestrator.py +183 -0
  220. synapse_sdk/plugins/categories/upload/actions/upload/registry.py +113 -0
  221. synapse_sdk/plugins/categories/upload/actions/upload/run.py +179 -0
  222. synapse_sdk/plugins/categories/upload/actions/upload/steps/__init__.py +1 -0
  223. synapse_sdk/plugins/categories/upload/actions/upload/steps/base.py +107 -0
  224. synapse_sdk/plugins/categories/upload/actions/upload/steps/cleanup.py +62 -0
  225. synapse_sdk/plugins/categories/upload/actions/upload/steps/collection.py +63 -0
  226. synapse_sdk/plugins/categories/upload/actions/upload/steps/generate.py +84 -0
  227. synapse_sdk/plugins/categories/upload/actions/upload/steps/initialize.py +82 -0
  228. synapse_sdk/plugins/categories/upload/actions/upload/steps/metadata.py +235 -0
  229. synapse_sdk/plugins/categories/upload/actions/upload/steps/organize.py +203 -0
  230. synapse_sdk/plugins/categories/upload/actions/upload/steps/upload.py +97 -0
  231. synapse_sdk/plugins/categories/upload/actions/upload/steps/validate.py +71 -0
  232. synapse_sdk/plugins/categories/upload/actions/upload/strategies/__init__.py +1 -0
  233. synapse_sdk/plugins/categories/upload/actions/upload/strategies/base.py +82 -0
  234. synapse_sdk/plugins/categories/upload/actions/upload/strategies/data_unit/__init__.py +1 -0
  235. synapse_sdk/plugins/categories/upload/actions/upload/strategies/data_unit/batch.py +39 -0
  236. synapse_sdk/plugins/categories/upload/actions/upload/strategies/data_unit/single.py +29 -0
  237. synapse_sdk/plugins/categories/upload/actions/upload/strategies/file_discovery/__init__.py +1 -0
  238. synapse_sdk/plugins/categories/upload/actions/upload/strategies/file_discovery/flat.py +258 -0
  239. synapse_sdk/plugins/categories/upload/actions/upload/strategies/file_discovery/recursive.py +281 -0
  240. synapse_sdk/plugins/categories/upload/actions/upload/strategies/metadata/__init__.py +1 -0
  241. synapse_sdk/plugins/categories/upload/actions/upload/strategies/metadata/excel.py +174 -0
  242. synapse_sdk/plugins/categories/upload/actions/upload/strategies/metadata/none.py +16 -0
  243. synapse_sdk/plugins/categories/upload/actions/upload/strategies/upload/__init__.py +1 -0
  244. synapse_sdk/plugins/categories/upload/actions/upload/strategies/upload/sync.py +84 -0
  245. synapse_sdk/plugins/categories/upload/actions/upload/strategies/validation/__init__.py +1 -0
  246. synapse_sdk/plugins/categories/upload/actions/upload/strategies/validation/default.py +60 -0
  247. synapse_sdk/plugins/categories/upload/actions/upload/utils.py +250 -0
  248. synapse_sdk/plugins/categories/upload/templates/README.md +470 -0
  249. synapse_sdk/plugins/categories/upload/templates/config.yaml +29 -2
  250. synapse_sdk/plugins/categories/upload/templates/plugin/__init__.py +294 -0
  251. synapse_sdk/plugins/categories/upload/templates/plugin/upload.py +88 -30
  252. synapse_sdk/plugins/models.py +122 -16
  253. synapse_sdk/plugins/templates/plugin-config-schema.json +406 -0
  254. synapse_sdk/plugins/templates/schema.json +491 -0
  255. synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/requirements.txt +1 -1
  256. synapse_sdk/plugins/utils/__init__.py +46 -0
  257. synapse_sdk/plugins/utils/actions.py +119 -0
  258. synapse_sdk/plugins/utils/config.py +203 -0
  259. synapse_sdk/plugins/{utils.py → utils/legacy.py} +26 -46
  260. synapse_sdk/plugins/utils/ray_gcs.py +66 -0
  261. synapse_sdk/plugins/utils/registry.py +58 -0
  262. synapse_sdk/shared/__init__.py +25 -0
  263. synapse_sdk/shared/enums.py +93 -0
  264. synapse_sdk/utils/converters/__init__.py +240 -0
  265. synapse_sdk/utils/converters/coco/__init__.py +0 -0
  266. synapse_sdk/utils/converters/coco/from_dm.py +322 -0
  267. synapse_sdk/utils/converters/coco/to_dm.py +215 -0
  268. synapse_sdk/utils/converters/dm/__init__.py +56 -0
  269. synapse_sdk/utils/converters/dm/from_v1.py +627 -0
  270. synapse_sdk/utils/converters/dm/to_v1.py +367 -0
  271. synapse_sdk/utils/converters/pascal/__init__.py +0 -0
  272. synapse_sdk/utils/converters/pascal/from_dm.py +244 -0
  273. synapse_sdk/utils/converters/pascal/to_dm.py +214 -0
  274. synapse_sdk/utils/converters/yolo/__init__.py +0 -0
  275. synapse_sdk/utils/converters/yolo/from_dm.py +384 -0
  276. synapse_sdk/utils/converters/yolo/to_dm.py +267 -0
  277. synapse_sdk/utils/dataset.py +46 -0
  278. synapse_sdk/utils/encryption.py +158 -0
  279. synapse_sdk/utils/file/__init__.py +39 -0
  280. synapse_sdk/utils/file/archive.py +32 -0
  281. synapse_sdk/utils/file/checksum.py +56 -0
  282. synapse_sdk/utils/file/chunking.py +31 -0
  283. synapse_sdk/utils/file/download.py +385 -0
  284. synapse_sdk/utils/file/encoding.py +40 -0
  285. synapse_sdk/utils/file/io.py +22 -0
  286. synapse_sdk/utils/file/video/__init__.py +29 -0
  287. synapse_sdk/utils/file/video/transcode.py +307 -0
  288. synapse_sdk/utils/{file.py → file.py.backup} +84 -2
  289. synapse_sdk/utils/http.py +138 -0
  290. synapse_sdk/utils/network.py +293 -0
  291. synapse_sdk/utils/storage/__init__.py +36 -2
  292. synapse_sdk/utils/storage/providers/__init__.py +141 -0
  293. synapse_sdk/utils/storage/providers/file_system.py +134 -0
  294. synapse_sdk/utils/storage/providers/http.py +190 -0
  295. synapse_sdk/utils/storage/providers/s3.py +54 -6
  296. synapse_sdk/utils/storage/providers/sftp.py +31 -0
  297. synapse_sdk/utils/storage/registry.py +6 -0
  298. synapse_sdk-2025.11.7.dist-info/METADATA +122 -0
  299. synapse_sdk-2025.11.7.dist-info/RECORD +386 -0
  300. {synapse_sdk-1.0.0a35.dist-info → synapse_sdk-2025.11.7.dist-info}/WHEEL +1 -1
  301. synapse_sdk/clients/backend/dataset.py +0 -102
  302. synapse_sdk/plugins/categories/upload/actions/upload.py +0 -293
  303. synapse_sdk-1.0.0a35.dist-info/METADATA +0 -47
  304. synapse_sdk-1.0.0a35.dist-info/RECORD +0 -137
  305. {synapse_sdk-1.0.0a35.dist-info → synapse_sdk-2025.11.7.dist-info}/entry_points.txt +0 -0
  306. {synapse_sdk-1.0.0a35.dist-info → synapse_sdk-2025.11.7.dist-info}/licenses/LICENSE +0 -0
  307. {synapse_sdk-1.0.0a35.dist-info → synapse_sdk-2025.11.7.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,766 @@
1
+ ---
2
+ id: upload-plugin-template
3
+ title: Upload Plugin Template Development
4
+ sidebar_position: 3
5
+ ---
6
+
7
+ # Upload Plugin Template Development with BaseUploader
8
+
9
+ This guide is for plugin developers who want to create custom upload plugins using the BaseUploader template. The BaseUploader provides a workflow-based foundation for file processing and organization within upload plugins.
10
+
11
+ ## Overview
12
+
13
+ The BaseUploader template (`synapse_sdk.plugins.categories.upload.templates.plugin`) provides a structured approach to building upload plugins. It handles the common upload workflow while allowing customization through method overrides.
14
+
15
+ ### BaseUploader Workflow
16
+
17
+ The BaseUploader implements a 6-step workflow pipeline:
18
+
19
+ ```
20
+ 1. setup_directories() # Create custom directory structures
21
+ 2. organize_files() # Organize and structure files
22
+ 3. before_process() # Pre-processing hooks
23
+ 4. process_files() # Main processing logic (REQUIRED)
24
+ 5. after_process() # Post-processing hooks
25
+ 6. validate_files() # Final validation
26
+ ```
27
+
28
+ ## Getting Started
29
+
30
+ ### Template Structure
31
+
32
+ When you create an upload plugin, you get this structure:
33
+
34
+ ```
35
+ synapse-{plugin-code}-plugin/
36
+ ├── config.yaml # Plugin metadata and configuration
37
+ ├── plugin/ # Source code directory
38
+ │ ├── __init__.py
39
+ │ └── upload.py # Main upload implementation with BaseUploader
40
+ ├── requirements.txt # Python dependencies
41
+ ├── pyproject.toml # Package configuration
42
+ └── README.md # Plugin documentation
43
+ ```
44
+
45
+ ### Basic Plugin Implementation
46
+
47
+ ```python
48
+ # plugin/__init__.py
49
+ from pathlib import Path
50
+ from typing import Any, Dict, List
51
+
52
+ class BaseUploader:
53
+ """Base class with common upload functionality."""
54
+
55
+ def __init__(self, run, path: Path, file_specification: List = None,
56
+ organized_files: List = None, extra_params: Dict = None):
57
+ self.run = run
58
+ self.path = path
59
+ self.file_specification = file_specification or []
60
+ self.organized_files = organized_files or []
61
+ self.extra_params = extra_params or {}
62
+
63
+ # Core workflow methods available for override
64
+ def setup_directories(self) -> None:
65
+ """Setup custom directories - override as needed."""
66
+ pass
67
+
68
+ def organize_files(self, files: List) -> List:
69
+ """Organize files - override for custom logic."""
70
+ return files
71
+
72
+ def before_process(self, organized_files: List) -> List:
73
+ """Pre-process hook - override as needed."""
74
+ return organized_files
75
+
76
+ def process_files(self, organized_files: List) -> List:
77
+ """Main processing - MUST be overridden."""
78
+ return organized_files
79
+
80
+ def after_process(self, processed_files: List) -> List:
81
+ """Post-process hook - override as needed."""
82
+ return processed_files
83
+
84
+ def validate_files(self, files: List) -> List:
85
+ """Validation - override for custom validation."""
86
+ return self._filter_valid_files(files)
87
+
88
+ def handle_upload_files(self) -> List:
89
+ """Main entry point - executes the workflow."""
90
+ self.setup_directories()
91
+ current_files = self.organized_files
92
+ current_files = self.organize_files(current_files)
93
+ current_files = self.before_process(current_files)
94
+ current_files = self.process_files(current_files)
95
+ current_files = self.after_process(current_files)
96
+ current_files = self.validate_files(current_files)
97
+ return current_files
98
+
99
+ # plugin/upload.py
100
+ from . import BaseUploader
101
+
102
+ class Uploader(BaseUploader):
103
+ """Custom upload plugin implementation."""
104
+
105
+ def process_files(self, organized_files: List) -> List:
106
+ """Required: Implement your file processing logic."""
107
+ # Your custom processing logic here
108
+ return organized_files
109
+ ```
110
+
111
+ ## Core Methods Reference
112
+
113
+ ### Required Method
114
+
115
+ #### `process_files(organized_files: List) -> List`
116
+
117
+ **Purpose**: Main processing method that must be implemented by all plugins.
118
+
119
+ **When to use**: Always - this is where your plugin's core logic goes.
120
+
121
+ **Example**:
122
+
123
+ ```python
124
+ def process_files(self, organized_files: List) -> List:
125
+ """Convert TIFF images to JPEG format."""
126
+ processed_files = []
127
+
128
+ for file_group in organized_files:
129
+ files_dict = file_group.get('files', {})
130
+ converted_files = {}
131
+
132
+ for spec_name, file_path in files_dict.items():
133
+ if file_path.suffix.lower() in ['.tif', '.tiff']:
134
+ # Convert TIFF to JPEG
135
+ jpeg_path = self.convert_tiff_to_jpeg(file_path)
136
+ converted_files[spec_name] = jpeg_path
137
+ self.run.log_message(f"Converted {file_path} to {jpeg_path}")
138
+ else:
139
+ converted_files[spec_name] = file_path
140
+
141
+ file_group['files'] = converted_files
142
+ processed_files.append(file_group)
143
+
144
+ return processed_files
145
+ ```
146
+
147
+ ### Optional Hook Methods
148
+
149
+ #### `setup_directories() -> None`
150
+
151
+ **Purpose**: Create custom directory structures before processing begins.
152
+
153
+ **When to use**: When your plugin needs specific directories for processing, temporary files, or output.
154
+
155
+ **Example**:
156
+
157
+ ```python
158
+ def setup_directories(self):
159
+ """Create processing directories."""
160
+ (self.path / 'temp').mkdir(exist_ok=True)
161
+ (self.path / 'processed').mkdir(exist_ok=True)
162
+ (self.path / 'thumbnails').mkdir(exist_ok=True)
163
+ self.run.log_message("Created processing directories")
164
+ ```
165
+
166
+ #### `organize_files(files: List) -> List`
167
+
168
+ **Purpose**: Reorganize and structure files before main processing.
169
+
170
+ **When to use**: When you need to group files differently, filter by criteria, or restructure the data.
171
+
172
+ **Example**:
173
+
174
+ ```python
175
+ def organize_files(self, files: List) -> List:
176
+ """Group files by size for optimized processing."""
177
+ large_files = []
178
+ small_files = []
179
+
180
+ for file_group in files:
181
+ total_size = sum(f.stat().st_size for f in file_group.get('files', {}).values())
182
+ if total_size > 100 * 1024 * 1024: # 100MB
183
+ large_files.append(file_group)
184
+ else:
185
+ small_files.append(file_group)
186
+
187
+ # Process large files first
188
+ return large_files + small_files
189
+ ```
190
+
191
+ #### `before_process(organized_files: List) -> List`
192
+
193
+ **Purpose**: Pre-processing hook for setup tasks before main processing.
194
+
195
+ **When to use**: For validation, preparation, or initialization tasks.
196
+
197
+ **Example**:
198
+
199
+ ```python
200
+ def before_process(self, organized_files: List) -> List:
201
+ """Validate and prepare files for processing."""
202
+ self.run.log_message(f"Starting processing of {len(organized_files)} file groups")
203
+
204
+ # Check available disk space
205
+ if not self.check_disk_space(organized_files):
206
+ raise Exception("Insufficient disk space for processing")
207
+
208
+ return organized_files
209
+ ```
210
+
211
+ #### `after_process(processed_files: List) -> List`
212
+
213
+ **Purpose**: Post-processing hook for cleanup and finalization.
214
+
215
+ **When to use**: For cleanup, final transformations, or resource deallocation.
216
+
217
+ **Example**:
218
+
219
+ ```python
220
+ def after_process(self, processed_files: List) -> List:
221
+ """Clean up temporary files and generate summary."""
222
+ # Remove temporary files
223
+ temp_dir = self.path / 'temp'
224
+ if temp_dir.exists():
225
+ shutil.rmtree(temp_dir)
226
+
227
+ # Generate processing summary
228
+ summary = {
229
+ 'total_processed': len(processed_files),
230
+ 'processing_time': time.time() - self.start_time
231
+ }
232
+
233
+ self.run.log_message(f"Processing complete: {summary}")
234
+ return processed_files
235
+ ```
236
+
237
+ #### `validate_files(files: List) -> List`
238
+
239
+ **Purpose**: Custom validation logic beyond type checking.
240
+
241
+ **When to use**: When you need additional validation rules beyond built-in file type validation.
242
+
243
+ **Example**:
244
+
245
+ ```python
246
+ def validate_files(self, files: List) -> List:
247
+ """Custom validation with size and format checks."""
248
+ # First apply built-in validation
249
+ validated_files = super().validate_files(files)
250
+
251
+ # Then apply custom validation
252
+ final_files = []
253
+ for file_group in validated_files:
254
+ if self.validate_file_group(file_group):
255
+ final_files.append(file_group)
256
+ else:
257
+ self.run.log_message(f"File group failed validation: {file_group}")
258
+
259
+ return final_files
260
+ ```
261
+
262
+ #### `filter_files(organized_file: Dict[str, Any]) -> bool`
263
+
264
+ **Purpose**: Filter individual files based on custom criteria.
265
+
266
+ **When to use**: When you need to exclude specific files from processing.
267
+
268
+ **Example**:
269
+
270
+ ```python
271
+ def filter_files(self, organized_file: Dict[str, Any]) -> bool:
272
+ """Filter out small files."""
273
+ files_dict = organized_file.get('files', {})
274
+ total_size = sum(f.stat().st_size for f in files_dict.values())
275
+
276
+ if total_size < 1024: # Skip files smaller than 1KB
277
+ self.run.log_message(f"Skipping small file group: {total_size} bytes")
278
+ return False
279
+
280
+ return True
281
+ ```
282
+
283
+ ## File Extension Filtering
284
+
285
+ The BaseUploader includes a built-in extension filtering system that automatically filters files based on their file type. This feature is integrated into the workflow and runs automatically during the validation step.
286
+
287
+ ### How It Works
288
+
289
+ 1. **Automatic Integration**: Extension filtering is automatically applied during the `ValidateFilesStep` in the upload workflow
290
+ 2. **Case-Insensitive**: Extensions are matched case-insensitively (`.mp4` matches `.MP4`, `.Mp4`, etc.)
291
+ 3. **Type-Based**: Filtering is done per file type (video, image, audio, etc.)
292
+ 4. **Automatic Logging**: Filtered files are logged with WARNING level showing which extensions were filtered
293
+
294
+ ### Default Backend Configuration
295
+
296
+ The system comes with sensible defaults that match backend file type restrictions:
297
+
298
+ ```python
299
+ def get_file_extensions_config(self) -> Dict[str, List[str]]:
300
+ """Get allowed file extensions configuration.
301
+
302
+ Override this method to restrict file extensions per file type.
303
+ Extensions are case-insensitive and must include the dot prefix.
304
+ """
305
+ return {
306
+ 'video': ['.mp4', '.avi', '.mov', '.mkv', '.webm', '.flv', '.wmv'],
307
+ 'image': ['.jpg', '.jpeg', '.png'],
308
+ 'pcd': ['.pcd'],
309
+ 'text': ['.txt', '.html'],
310
+ 'audio': ['.mp3', '.wav'],
311
+ 'data': ['.xml', '.bin', '.json', '.fbx'],
312
+ }
313
+ ```
314
+
315
+ ### Customizing Extension Filtering
316
+
317
+ To restrict file extensions for your plugin, simply modify the `get_file_extensions_config()` method in the plugin template file (`plugin/__init__.py`):
318
+
319
+ #### Example 1: Restrict to MP4 Videos Only
320
+
321
+ ```python
322
+ def get_file_extensions_config(self) -> Dict[str, List[str]]:
323
+ """Allow only MP4 videos."""
324
+ return {
325
+ 'video': ['.mp4'], # Only MP4 allowed
326
+ 'image': ['.jpg', '.jpeg', '.png'],
327
+ 'pcd': ['.pcd'],
328
+ 'text': ['.txt', '.html'],
329
+ 'audio': ['.mp3', '.wav'],
330
+ 'data': ['.xml', '.bin', '.json', '.fbx'],
331
+ }
332
+ ```
333
+
334
+ **Result**: When uploading, files with extensions `.avi`, `.mkv`, `.mov`, etc. will be automatically filtered out and logged:
335
+
336
+ ```
337
+ WARNING: Filtered 3 video files with unavailable extensions: .avi, .mkv, .mov (allowed: .mp4)
338
+ ```
339
+
340
+ #### Example 2: Add Support for Additional Formats
341
+
342
+ ```python
343
+ def get_file_extensions_config(self) -> Dict[str, List[str]]:
344
+ """Add support for additional video and image formats."""
345
+ return {
346
+ 'video': ['.mp4', '.avi', '.mov', '.mkv', '.webm', '.flv', '.wmv'],
347
+ 'image': ['.jpg', '.jpeg', '.png', '.tiff', '.bmp', '.gif'], # Added more formats
348
+ 'pcd': ['.pcd'],
349
+ 'text': ['.txt', '.html', '.md', '.csv'], # Added .md and .csv
350
+ 'audio': ['.mp3', '.wav', '.flac', '.aac'], # Added .flac and .aac
351
+ 'data': ['.xml', '.bin', '.json', '.fbx', '.yaml'], # Added .yaml
352
+ }
353
+ ```
354
+
355
+ #### Example 3: Completely Custom Configuration
356
+
357
+ ```python
358
+ def get_file_extensions_config(self) -> Dict[str, List[str]]:
359
+ """Custom configuration for specific project needs."""
360
+ return {
361
+ 'video': ['.mp4'], # Strict video format
362
+ 'image': ['.jpg'], # Strict image format
363
+ 'cad': ['.dwg', '.dxf', '.step'], # Custom CAD type
364
+ 'document': ['.pdf', '.docx'], # Custom document type
365
+ }
366
+ ```
367
+
368
+ ### Extension Filtering Workflow
369
+
370
+ ```
371
+ OrganizeFilesStep
372
+
373
+ ValidateFilesStep
374
+ ├─ Uploader.handle_upload_files()
375
+ │ └─ validate_files()
376
+ │ └─ validate_file_types() ← Extension filtering happens here
377
+ │ ├─ Read get_file_extensions_config()
378
+ │ ├─ Filter files by type
379
+ │ └─ Log filtered extensions
380
+ └─ Strategy validation
381
+ ```
382
+
383
+ ## Real-World Examples
384
+
385
+ ### Example 1: Image Processing Plugin
386
+
387
+ ```python
388
+ from pathlib import Path
389
+ from typing import List
390
+ from plugin import BaseUploader
391
+
392
+ class ImageProcessingUploader(BaseUploader):
393
+ """Converts TIFF images to JPEG and generates thumbnails."""
394
+
395
+ def setup_directories(self):
396
+ """Create directories for processed images."""
397
+ (self.path / 'processed').mkdir(exist_ok=True)
398
+ (self.path / 'thumbnails').mkdir(exist_ok=True)
399
+
400
+ def process_files(self, organized_files: List) -> List:
401
+ """Convert images and generate thumbnails."""
402
+ processed_files = []
403
+
404
+ for file_group in organized_files:
405
+ files_dict = file_group.get('files', {})
406
+ converted_files = {}
407
+
408
+ for spec_name, file_path in files_dict.items():
409
+ if file_path.suffix.lower() in ['.tif', '.tiff']:
410
+ # Convert to JPEG
411
+ jpeg_path = self.convert_to_jpeg(file_path)
412
+ converted_files[spec_name] = jpeg_path
413
+
414
+ # Generate thumbnail
415
+ thumbnail_path = self.generate_thumbnail(jpeg_path)
416
+ converted_files[f"{spec_name}_thumbnail"] = thumbnail_path
417
+
418
+ self.run.log_message(f"Processed {file_path.name}")
419
+ else:
420
+ converted_files[spec_name] = file_path
421
+
422
+ file_group['files'] = converted_files
423
+ processed_files.append(file_group)
424
+
425
+ return processed_files
426
+
427
+ def convert_to_jpeg(self, tiff_path: Path) -> Path:
428
+ """Convert TIFF to JPEG using PIL."""
429
+ from PIL import Image
430
+
431
+ output_path = self.path / 'processed' / f"{tiff_path.stem}.jpg"
432
+
433
+ with Image.open(tiff_path) as img:
434
+ if img.mode in ('RGBA', 'LA', 'P'):
435
+ img = img.convert('RGB')
436
+ img.save(output_path, 'JPEG', quality=95)
437
+
438
+ return output_path
439
+
440
+ def generate_thumbnail(self, image_path: Path) -> Path:
441
+ """Generate thumbnail."""
442
+ from PIL import Image
443
+
444
+ thumbnail_path = self.path / 'thumbnails' / f"{image_path.stem}_thumb.jpg"
445
+
446
+ with Image.open(image_path) as img:
447
+ img.thumbnail((200, 200), Image.Resampling.LANCZOS)
448
+ img.save(thumbnail_path, 'JPEG', quality=85)
449
+
450
+ return thumbnail_path
451
+ ```
452
+
453
+ ### Example 2: Data Validation Plugin
454
+
455
+ ```python
456
+ class DataValidationUploader(BaseUploader):
457
+ """Validates data files and generates quality reports."""
458
+
459
+ def __init__(self, run, path, file_specification=None,
460
+ organized_files=None, extra_params=None):
461
+ super().__init__(run, path, file_specification, organized_files, extra_params)
462
+
463
+ # Initialize from extra_params
464
+ self.validation_config = extra_params.get('validation_config', {})
465
+ self.strict_mode = extra_params.get('strict_validation', False)
466
+
467
+ def before_process(self, organized_files: List) -> List:
468
+ """Initialize validation engine."""
469
+ self.validation_results = []
470
+ self.run.log_message(f"Starting validation of {len(organized_files)} file groups")
471
+ return organized_files
472
+
473
+ def process_files(self, organized_files: List) -> List:
474
+ """Validate files and generate quality reports."""
475
+ processed_files = []
476
+
477
+ for file_group in organized_files:
478
+ validation_result = self.validate_file_group(file_group)
479
+
480
+ # Add validation metadata
481
+ file_group['validation'] = validation_result
482
+ file_group['quality_score'] = validation_result['score']
483
+
484
+ # Include file group based on validation results
485
+ if self.should_include_file_group(validation_result):
486
+ processed_files.append(file_group)
487
+ self.run.log_message(f"File group passed: score {validation_result['score']}")
488
+ else:
489
+ self.run.log_message(f"File group failed: {validation_result['errors']}")
490
+
491
+ return processed_files
492
+
493
+ def validate_file_group(self, file_group: Dict) -> Dict:
494
+ """Comprehensive validation of file group."""
495
+ files_dict = file_group.get('files', {})
496
+ errors = []
497
+ score = 100
498
+
499
+ for spec_name, file_path in files_dict.items():
500
+ # File existence
501
+ if not file_path.exists():
502
+ errors.append(f"File not found: {file_path}")
503
+ score -= 50
504
+ continue
505
+
506
+ # File size validation
507
+ file_size = file_path.stat().st_size
508
+ if file_size == 0:
509
+ errors.append(f"Empty file: {file_path}")
510
+ score -= 40
511
+ elif file_size > 1024 * 1024 * 1024: # 1GB
512
+ score -= 10
513
+
514
+ return {
515
+ 'score': max(0, score),
516
+ 'errors': errors,
517
+ 'validated_at': datetime.now().isoformat()
518
+ }
519
+
520
+ def should_include_file_group(self, validation_result: Dict) -> bool:
521
+ """Determine if file group should be included."""
522
+ if validation_result['errors'] and self.strict_mode:
523
+ return False
524
+
525
+ min_score = self.validation_config.get('min_score', 50)
526
+ return validation_result['score'] >= min_score
527
+ ```
528
+
529
+ ### Example 3: Batch Processing Plugin
530
+
531
+ ```python
532
+ class BatchProcessingUploader(BaseUploader):
533
+ """Processes files in configurable batches."""
534
+
535
+ def __init__(self, run, path, file_specification=None,
536
+ organized_files=None, extra_params=None):
537
+ super().__init__(run, path, file_specification, organized_files, extra_params)
538
+
539
+ self.batch_size = extra_params.get('batch_size', 10)
540
+ self.parallel_processing = extra_params.get('use_parallel', True)
541
+ self.max_workers = extra_params.get('max_workers', 4)
542
+
543
+ def organize_files(self, files: List) -> List:
544
+ """Organize files into processing batches."""
545
+ batches = []
546
+ current_batch = []
547
+
548
+ for file_group in files:
549
+ current_batch.append(file_group)
550
+
551
+ if len(current_batch) >= self.batch_size:
552
+ batches.append({
553
+ 'batch_id': len(batches) + 1,
554
+ 'files': current_batch,
555
+ 'batch_size': len(current_batch)
556
+ })
557
+ current_batch = []
558
+
559
+ # Add remaining files
560
+ if current_batch:
561
+ batches.append({
562
+ 'batch_id': len(batches) + 1,
563
+ 'files': current_batch,
564
+ 'batch_size': len(current_batch)
565
+ })
566
+
567
+ self.run.log_message(f"Organized into {len(batches)} batches")
568
+ return batches
569
+
570
+ def process_files(self, organized_files: List) -> List:
571
+ """Process files in batches."""
572
+ all_processed_files = []
573
+
574
+ if self.parallel_processing:
575
+ all_processed_files = self.process_batches_parallel(organized_files)
576
+ else:
577
+ all_processed_files = self.process_batches_sequential(organized_files)
578
+
579
+ return all_processed_files
580
+
581
+ def process_batches_sequential(self, batches: List) -> List:
582
+ """Process batches sequentially."""
583
+ all_files = []
584
+
585
+ for i, batch in enumerate(batches, 1):
586
+ self.run.log_message(f"Processing batch {i}/{len(batches)}")
587
+ processed_batch = self.process_single_batch(batch)
588
+ all_files.extend(processed_batch)
589
+
590
+ return all_files
591
+
592
+ def process_batches_parallel(self, batches: List) -> List:
593
+ """Process batches in parallel using ThreadPoolExecutor."""
594
+ from concurrent.futures import ThreadPoolExecutor, as_completed
595
+
596
+ all_files = []
597
+
598
+ with ThreadPoolExecutor(max_workers=self.max_workers) as executor:
599
+ future_to_batch = {
600
+ executor.submit(self.process_single_batch, batch): batch
601
+ for batch in batches
602
+ }
603
+
604
+ for future in as_completed(future_to_batch):
605
+ batch = future_to_batch[future]
606
+ try:
607
+ processed_files = future.result()
608
+ all_files.extend(processed_files)
609
+ self.run.log_message(f"Batch {batch['batch_id']} complete")
610
+ except Exception as e:
611
+ self.run.log_message(f"Batch {batch['batch_id']} failed: {e}")
612
+
613
+ return all_files
614
+
615
+ def process_single_batch(self, batch: Dict) -> List:
616
+ """Process a single batch of files."""
617
+ batch_files = batch['files']
618
+ processed_files = []
619
+
620
+ for file_group in batch_files:
621
+ # Add batch metadata
622
+ file_group['batch_processed'] = True
623
+ file_group['batch_id'] = batch['batch_id']
624
+ processed_files.append(file_group)
625
+
626
+ return processed_files
627
+ ```
628
+
629
+ ## Best Practices
630
+
631
+ ### 1. Code Organization
632
+
633
+ - Keep `process_files()` focused on core logic
634
+ - Use hook methods for setup, cleanup, and validation
635
+ - Separate concerns using helper methods
636
+
637
+ ### 2. Error Handling
638
+
639
+ - Implement comprehensive error handling
640
+ - Log errors with context information
641
+ - Fail gracefully when possible
642
+
643
+ ### 3. Performance
644
+
645
+ - Profile your processing logic
646
+ - Use appropriate data structures
647
+ - Consider memory usage for large files
648
+ - Implement async processing for I/O-heavy operations
649
+
650
+ ### 4. Testing
651
+
652
+ - Write unit tests for all methods
653
+ - Include integration tests with real files
654
+ - Test error conditions and edge cases
655
+
656
+ ### 5. Logging
657
+
658
+ - Log important operations and milestones
659
+ - Include timing information
660
+ - Use structured logging for analysis
661
+
662
+ ### 6. Configuration
663
+
664
+ - Use `extra_params` for plugin configuration
665
+ - Provide sensible defaults
666
+ - Validate configuration parameters
667
+
668
+ ## Integration with Upload Action
669
+
670
+ Your BaseUploader plugin integrates with the upload action workflow:
671
+
672
+ 1. **File Discovery**: Upload action discovers and organizes files
673
+ 2. **Plugin Invocation**: Your `handle_upload_files()` is called with organized files
674
+ 3. **Workflow Execution**: BaseUploader runs its 6-step workflow
675
+ 4. **Return Results**: Processed files are returned to upload action
676
+ 5. **Upload & Data Unit Creation**: Upload action completes the upload
677
+
678
+ ### Data Flow
679
+
680
+ ```
681
+ Upload Action (OrganizeFilesStep)
682
+ ↓ organized_files
683
+ BaseUploader.handle_upload_files()
684
+ ↓ setup_directories()
685
+ ↓ organize_files()
686
+ ↓ before_process()
687
+ ↓ process_files() ← Your custom logic
688
+ ↓ after_process()
689
+ ↓ validate_files()
690
+ ↓ processed_files
691
+ Upload Action (UploadFilesStep, GenerateDataUnitsStep)
692
+ ```
693
+
694
+ ## Configuration
695
+
696
+ ### Plugin Configuration (config.yaml)
697
+
698
+ ```yaml
699
+ code: "my-upload-plugin"
700
+ name: "My Upload Plugin"
701
+ version: "1.0.0"
702
+ category: "upload"
703
+
704
+ package_manager: "pip"
705
+
706
+ actions:
707
+ upload:
708
+ entrypoint: "plugin.upload.Uploader"
709
+ method: "job"
710
+ ```
711
+
712
+ ### Dependencies (requirements.txt)
713
+
714
+ ```txt
715
+ synapse-sdk>=1.0.0
716
+ pillow>=10.0.0 # For image processing
717
+ pandas>=2.0.0 # For data processing
718
+ ```
719
+
720
+ ## Testing Your Plugin
721
+
722
+ ### Unit Testing
723
+
724
+ ```python
725
+ import pytest
726
+ from unittest.mock import Mock
727
+ from pathlib import Path
728
+ from plugin.upload import Uploader
729
+
730
+ class TestUploader:
731
+
732
+ def setup_method(self):
733
+ self.mock_run = Mock()
734
+ self.test_path = Path('/tmp/test')
735
+ self.file_spec = [{'name': 'image_1', 'file_type': 'image'}]
736
+
737
+ def test_process_files(self):
738
+ """Test file processing."""
739
+ uploader = Uploader(
740
+ run=self.mock_run,
741
+ path=self.test_path,
742
+ file_specification=self.file_spec,
743
+ organized_files=[{'files': {}}]
744
+ )
745
+
746
+ result = uploader.process_files([{'files': {}}])
747
+ assert isinstance(result, list)
748
+ ```
749
+
750
+ ### Integration Testing
751
+
752
+ ```bash
753
+ # Test with sample data
754
+ synapse plugin run upload '{
755
+ "name": "Test Upload",
756
+ "use_single_path": true,
757
+ "path": "/test/data",
758
+ "storage": 1,
759
+ "data_collection": 5
760
+ }' --plugin my-upload-plugin --debug
761
+ ```
762
+
763
+ ## See Also
764
+
765
+ - [Upload Plugin Overview](./upload-plugin-overview.md) - User guide and configuration reference
766
+ - [Upload Action Development](./upload-plugin-action.md) - SDK developer guide for action architecture and internals