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,948 @@
1
+ ---
2
+ id: upload-plugin-action
3
+ title: 업로드 액션 개발
4
+ sidebar_position: 2
5
+ ---
6
+
7
+ # 업로드 액션 개발
8
+
9
+ 이 가이드는 업로드 액션 아키텍처를 이해, 확장 또는 사용자 정의하려는 SDK 개발자 및 기여자를 위한 것입니다.
10
+
11
+ ## 아키텍처 개요
12
+
13
+ 업로드 시스템은 입증된 디자인 패턴을 기반으로 한 현대적이고 확장 가능한 아키텍처를 사용합니다. 리팩토링된 구현은 이전의 모놀리식 접근 방식을 명확한 관심사 분리를 가진 모듈식, 전략 기반 시스템으로 변환합니다.
14
+
15
+ ### 디자인 패턴
16
+
17
+ 아키텍처는 몇 가지 주요 디자인 패턴을 활용합니다:
18
+
19
+ - **전략 패턴**: 검증, 파일 검색, 메타데이터 처리, 업로드 작업 및 데이터 단위 생성을 위한 플러그형 동작
20
+ - **퍼사드 패턴**: UploadOrchestrator는 복잡한 워크플로우를 조정하기 위한 단순화된 인터페이스를 제공합니다.
21
+ - **팩토리 패턴**: StrategyFactory는 런타임 매개변수를 기반으로 적절한 전략 구현을 생성합니다.
22
+ - **컨텍스트 패턴**: UploadContext는 워크플로우 구성 요소 간의 공유 상태 및 통신을 유지합니다.
23
+
24
+ ### 구성 요소 아키텍처
25
+
26
+ ```mermaid
27
+ classDiagram
28
+ %% 라이트/다크 모드 호환 색상
29
+ classDef coreClass fill:#e3f2fd,stroke:#1976d2,stroke-width:2px,color:#000000
30
+ classDef strategyClass fill:#e8f5e8,stroke:#388e3c,stroke-width:2px,color:#000000
31
+ classDef stepClass fill:#fff9c4,stroke:#f57c00,stroke-width:2px,color:#000000
32
+ classDef contextClass fill:#ffebee,stroke:#d32f2f,stroke-width:2px,color:#000000
33
+
34
+ class UploadAction {
35
+ +name: str = "upload"
36
+ +category: PluginCategory.UPLOAD
37
+ +method: RunMethod.JOB
38
+ +run_class: UploadRun
39
+ +params_model: UploadParams
40
+ +progress_categories: dict
41
+ +metrics_categories: dict
42
+ +strategy_factory: StrategyFactory
43
+ +step_registry: StepRegistry
44
+
45
+ +start() dict
46
+ +get_workflow_summary() dict
47
+ +_configure_workflow() None
48
+ +_configure_strategies() dict
49
+ }
50
+
51
+ class UploadOrchestrator {
52
+ +context: UploadContext
53
+ +step_registry: StepRegistry
54
+ +strategies: dict
55
+ +executed_steps: list
56
+ +current_step_index: int
57
+ +rollback_executed: bool
58
+
59
+ +execute() dict
60
+ +get_workflow_summary() dict
61
+ +get_executed_steps() list
62
+ +is_rollback_executed() bool
63
+ +_execute_step(step) StepResult
64
+ +_handle_step_failure(step, error) None
65
+ +_rollback_executed_steps() None
66
+ }
67
+
68
+ class UploadContext {
69
+ +params: dict
70
+ +run: UploadRun
71
+ +client: Any
72
+ +storage: Any
73
+ +pathlib_cwd: Path
74
+ +metadata: dict
75
+ +file_specifications: dict
76
+ +organized_files: list
77
+ +uploaded_files: list
78
+ +data_units: list
79
+ +metrics: dict
80
+ +errors: list
81
+ +strategies: dict
82
+ +rollback_data: dict
83
+
84
+ +update(result: StepResult) None
85
+ +get_result() dict
86
+ +has_errors() bool
87
+ +update_metrics(category, metrics) None
88
+ }
89
+
90
+ class StepRegistry {
91
+ +_steps: list
92
+ +register(step: BaseStep) None
93
+ +get_steps() list
94
+ +get_total_progress_weight() float
95
+ +clear() None
96
+ }
97
+
98
+ class StrategyFactory {
99
+ +create_validation_strategy(params, context) BaseValidationStrategy
100
+ +create_file_discovery_strategy(params, context) BaseFileDiscoveryStrategy
101
+ +create_metadata_strategy(params, context) BaseMetadataStrategy
102
+ +create_upload_strategy(params, context) BaseUploadStrategy
103
+ +create_data_unit_strategy(params, context) BaseDataUnitStrategy
104
+ +get_available_strategies() dict
105
+ }
106
+
107
+ class BaseStep {
108
+ <<abstract>>
109
+ +name: str
110
+ +progress_weight: float
111
+ +execute(context: UploadContext) StepResult
112
+ +can_skip(context: UploadContext) bool
113
+ +rollback(context: UploadContext) None
114
+ +create_success_result(data) StepResult
115
+ +create_error_result(error) StepResult
116
+ +create_skip_result() StepResult
117
+ }
118
+
119
+ class ExcelSecurityConfig {
120
+ +max_file_size_mb: int = 10
121
+ +max_rows: int = 100000
122
+ +max_columns: int = 50
123
+ +max_file_size_bytes: int
124
+ +from_action_config(action_config) ExcelSecurityConfig
125
+ }
126
+
127
+ class StepResult {
128
+ +success: bool
129
+ +data: dict
130
+ +error: str
131
+ +rollback_data: dict
132
+ +skipped: bool
133
+ +original_exception: Exception
134
+ +timestamp: datetime
135
+ }
136
+
137
+ %% 전략 기본 클래스
138
+ class BaseValidationStrategy {
139
+ <<abstract>>
140
+ +validate_files(files, context) bool
141
+ +validate_security(file_path) bool
142
+ }
143
+
144
+ class BaseFileDiscoveryStrategy {
145
+ <<abstract>>
146
+ +discover_files(path, context) list
147
+ +organize_files(files, specs, context) list
148
+ }
149
+
150
+ class BaseMetadataStrategy {
151
+ <<abstract>>
152
+ +process_metadata(context) dict
153
+ +extract_metadata(file_path) dict
154
+ }
155
+
156
+ class BaseUploadStrategy {
157
+ <<abstract>>
158
+ +upload_files(files, context) list
159
+ +upload_batch(batch, context) list
160
+ }
161
+
162
+ class BaseDataUnitStrategy {
163
+ <<abstract>>
164
+ +generate_data_units(files, context) list
165
+ +create_data_unit_batch(batch, context) list
166
+ }
167
+
168
+ %% 워크플로우 단계
169
+ class InitializeStep {
170
+ +name = "initialize"
171
+ +progress_weight = 0.05
172
+ }
173
+
174
+ class ProcessMetadataStep {
175
+ +name = "process_metadata"
176
+ +progress_weight = 0.05
177
+ }
178
+
179
+ class AnalyzeCollectionStep {
180
+ +name = "analyze_collection"
181
+ +progress_weight = 0.05
182
+ }
183
+
184
+ class OrganizeFilesStep {
185
+ +name = "organize_files"
186
+ +progress_weight = 0.10
187
+ }
188
+
189
+ class ValidateFilesStep {
190
+ +name = "validate_files"
191
+ +progress_weight = 0.05
192
+ }
193
+
194
+ class UploadFilesStep {
195
+ +name = "upload_files"
196
+ +progress_weight = 0.30
197
+ }
198
+
199
+ class GenerateDataUnitsStep {
200
+ +name = "generate_data_units"
201
+ +progress_weight = 0.35
202
+ }
203
+
204
+ class CleanupStep {
205
+ +name = "cleanup"
206
+ +progress_weight = 0.05
207
+ }
208
+
209
+ %% 관계
210
+ UploadAction --> UploadRun : 사용
211
+ UploadAction --> UploadParams : 검증
212
+ UploadAction --> ExcelSecurityConfig : 구성
213
+ UploadAction --> UploadOrchestrator : 생성 및 실행
214
+ UploadAction --> StrategyFactory : 전략 구성
215
+ UploadAction --> StepRegistry : 워크플로우 단계 관리
216
+ UploadOrchestrator --> UploadContext : 상태 조정
217
+ UploadOrchestrator --> StepRegistry : 단계 실행
218
+ UploadOrchestrator --> BaseStep : 실행
219
+ BaseStep --> StepResult : 반환
220
+ UploadContext --> StepResult : 업데이트
221
+ StrategyFactory --> BaseValidationStrategy : 생성
222
+ StrategyFactory --> BaseFileDiscoveryStrategy : 생성
223
+ StrategyFactory --> BaseMetadataStrategy : 생성
224
+ StrategyFactory --> BaseUploadStrategy : 생성
225
+ StrategyFactory --> BaseDataUnitStrategy : 생성
226
+ StepRegistry --> BaseStep : 포함
227
+
228
+ %% 단계 상속
229
+ InitializeStep --|> BaseStep : 확장
230
+ ProcessMetadataStep --|> BaseStep : 확장
231
+ AnalyzeCollectionStep --|> BaseStep : 확장
232
+ OrganizeFilesStep --|> BaseStep : 확장
233
+ ValidateFilesStep --|> BaseStep : 확장
234
+ UploadFilesStep --|> BaseStep : 확장
235
+ GenerateDataUnitsStep --|> BaseStep : 확장
236
+ CleanupStep --|> BaseStep : 확장
237
+ ```
238
+
239
+ ### 단계 기반 워크플로우 실행
240
+
241
+ 리팩토링된 아키텍처는 UploadOrchestrator에 의해 조정되는 단계 기반 워크플로우를 사용합니다. 각 단계는 정의된 책임과 진행 가중치를 가집니다.
242
+
243
+ #### 워크플로우 단계 개요
244
+
245
+ | 단계 | 이름 | 가중치 | 책임 |
246
+ | ---- | ------------------- | ------ | -------------------------------------------- |
247
+ | 1 | Initialize | 5% | 스토리지, pathlib 설정 및 기본 검증 |
248
+ | 2 | Process Metadata | 5% | 제공된 경우 Excel 메타데이터 처리 |
249
+ | 3 | Analyze Collection | 5% | 데이터 컬렉션 사양 검색 및 검증 |
250
+ | 4 | Organize Files | 10% | 유형별 파일 검색 및 구성 |
251
+ | 5 | Validate Files | 5% | 보안 및 내용 검증 |
252
+ | 6 | Upload Files | 30% | 스토리지에 파일 업로드 |
253
+ | 7 | Generate Data Units | 35% | 업로드된 파일에서 데이터 단위 생성 |
254
+ | 8 | Cleanup | 5% | 임시 리소스 정리 |
255
+
256
+ #### 실행 흐름
257
+
258
+ ```mermaid
259
+ flowchart TD
260
+ %% 시작
261
+ A["🚀 업로드 액션 시작"] --> B["📋 UploadContext 생성"]
262
+ B --> C["⚙️ 전략 구성"]
263
+ C --> D["📝 워크플로우 단계 등록"]
264
+ D --> E["🎯 UploadOrchestrator 생성"]
265
+
266
+ %% 전략 주입
267
+ E --> F["💉 컨텍스트에 전략 주입"]
268
+ F --> G["📊 진행 상황 추적 초기화"]
269
+
270
+ %% 단계 실행 루프
271
+ G --> H["🔄 단계 실행 루프 시작"]
272
+ H --> I["📍 다음 단계 가져오기"]
273
+ I --> J{"🤔 단계를 건너뛸 수 있는가?"}
274
+ J -->|예| K["⏭️ 단계 건너뛰기"]
275
+ J -->|아니요| L["▶️ 단계 실행"]
276
+
277
+ %% 단계 실행
278
+ L --> M{"✅ 단계 성공?"}
279
+ M -->|예| N["📈 진행 상황 업데이트"]
280
+ M -->|아니요| O["❌ 단계 실패 처리"]
281
+
282
+ %% 성공 경로
283
+ N --> P["💾 단계 결과 저장"]
284
+ P --> Q["📝 실행된 단계에 추가"]
285
+ Q --> R{"🏁 더 많은 단계가 있는가?"}
286
+ R -->|예| I
287
+ R -->|아니요| S["🎉 워크플로우 완료"]
288
+
289
+ %% 건너뛰기 경로
290
+ K --> T["📊 진행 상황 업데이트 (건너뛰기)"]
291
+ T --> R
292
+
293
+ %% 오류 처리
294
+ O --> U["🔙 롤백 프로세스 시작"]
295
+ U --> V["⏪ 실행된 단계 롤백"]
296
+ V --> W["📝 롤백 결과 기록"]
297
+ W --> X["💥 예외 전파"]
298
+
299
+ %% 최종 결과
300
+ S --> Y["📊 최종 메트릭 수집"]
301
+ Y --> Z["📋 결과 요약 생성"]
302
+ Z --> AA["🔄 UploadAction으로 반환"]
303
+
304
+ %% 스타일 적용 - 라이트/다크 모드 호환
305
+ classDef startNode fill:#e3f2fd,stroke:#1976d2,stroke-width:2px,color:#000000
306
+ classDef processNode fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px,color:#000000
307
+ classDef decisionNode fill:#fff3e0,stroke:#f57c00,stroke-width:2px,color:#000000
308
+ classDef successNode fill:#e8f5e8,stroke:#388e3c,stroke-width:2px,color:#000000
309
+ classDef errorNode fill:#ffebee,stroke:#d32f2f,stroke-width:2px,color:#000000
310
+
311
+ class A,B,E startNode
312
+ class C,D,F,G,H,I,L,N,P,Q,T,Y,Z,AA processNode
313
+ class J,M,R decisionNode
314
+ class K,S successNode
315
+ class O,U,V,W,X errorNode
316
+ ```
317
+
318
+ #### 전략 통합 지점
319
+
320
+ 전략은 특정 지점에서 워크플로우에 주입됩니다:
321
+
322
+ - **검증 전략**: ValidateFilesStep에서 사용
323
+ - **파일 검색 전략**: OrganizeFilesStep에서 사용
324
+ - **메타데이터 전략**: ProcessMetadataStep에서 사용
325
+ - **업로드 전략**: UploadFilesStep에서 사용
326
+ - **데이터 단위 전략**: GenerateDataUnitsStep에서 사용
327
+
328
+ #### 오류 처리 및 롤백
329
+
330
+ 오케스트레이터는 자동 롤백 기능을 제공합니다:
331
+
332
+ 1. **예외 캡처**: 디버깅을 위해 원래 예외를 보존합니다.
333
+ 2. **롤백 실행**: 성공적으로 실행된 모든 단계에 대해 역순으로 `rollback()`을 호출합니다.
334
+ 3. **점진적 성능 저하**: 개별 단계 롤백이 실패하더라도 롤백을 계속합니다.
335
+ 4. **상태 보존**: 실패 후 분석을 위해 실행 상태를 유지합니다.
336
+
337
+ ## 개발 가이드
338
+
339
+ 이 섹션은 사용자 정의 전략 및 워크플로우 단계로 업로드 액션을 확장하기 위한 포괄적인 지침을 제공합니다.
340
+
341
+ ### 사용자 정의 전략 생성
342
+
343
+ 전략은 업로드 프로세스의 다양한 측면에 대한 특정 동작을 구현합니다. 각 전략 유형에는 잘 정의된 인터페이스가 있습니다.
344
+
345
+ #### 사용자 정의 검증 전략
346
+
347
+ ```python
348
+ from synapse_sdk.plugins.categories.upload.actions.upload.strategies.validation.base import BaseValidationStrategy
349
+ from synapse_sdk.plugins.categories.upload.actions.upload.context import UploadContext
350
+ from pathlib import Path
351
+ from typing import List
352
+
353
+ class CustomValidationStrategy(BaseValidationStrategy):
354
+ """고급 보안 검사를 포함한 사용자 정의 검증 전략."""
355
+
356
+ def validate_files(self, files: List[Path], context: UploadContext) -> bool:
357
+ """사용자 정의 비즈니스 규칙을 사용하여 파일을 검증합니다."""
358
+ for file_path in files:
359
+ # 사용자 정의 검증 로직
360
+ if not self._validate_custom_rules(file_path):
361
+ return False
362
+
363
+ # 보안 검증 호출
364
+ if not self.validate_security(file_path):
365
+ return False
366
+ return True
367
+
368
+ def validate_security(self, file_path: Path) -> bool:
369
+ """사용자 정의 보안 검증."""
370
+ # 사용자 정의 보안 검사 구현
371
+ if file_path.suffix in ['.exe', '.bat', '.sh']:
372
+ return False
373
+
374
+ # 파일 크기 확인
375
+ if file_path.stat().st_size > 100 * 1024 * 1024: # 100MB
376
+ return False
377
+
378
+ return True
379
+
380
+ def _validate_custom_rules(self, file_path: Path) -> bool:
381
+ """도메인별 검증 규칙을 구현합니다."""
382
+ # 사용자 정의 비즈니스 로직
383
+ return True
384
+ ```
385
+
386
+ #### 사용자 정의 파일 검색 전략
387
+
388
+ ```python
389
+ from synapse_sdk.plugins.categories.upload.actions.upload.strategies.file_discovery.base import BaseFileDiscoveryStrategy
390
+ from pathlib import Path
391
+ from typing import List, Dict, Any
392
+
393
+ class CustomFileDiscoveryStrategy(BaseFileDiscoveryStrategy):
394
+ """고급 필터링을 사용한 사용자 정의 파일 검색 전략."""
395
+
396
+ def discover_files(self, path: Path, context: UploadContext) -> List[Path]:
397
+ """사용자 정의 필터링 규칙으로 파일을 검색합니다."""
398
+ files = []
399
+
400
+ if context.get_param('is_recursive', False):
401
+ files = list(path.rglob('*'))
402
+ else:
403
+ files = list(path.iterdir())
404
+
405
+ # 사용자 정의 필터링 적용
406
+ return self._apply_custom_filters(files, context)
407
+
408
+ def organize_files(self, files: List[Path], specs: Dict[str, Any], context: UploadContext) -> List[Dict[str, Any]]:
409
+ """사용자 정의 분류를 사용하여 파일을 구성합니다."""
410
+ organized = []
411
+
412
+ for file_path in files:
413
+ if file_path.is_file():
414
+ category = self._determine_category(file_path)
415
+ organized.append({
416
+ 'file_path': file_path,
417
+ 'category': category,
418
+ 'metadata': self._extract_file_metadata(file_path)
419
+ })
420
+
421
+ return organized
422
+
423
+ def _apply_custom_filters(self, files: List[Path], context: UploadContext) -> List[Path]:
424
+ """도메인별 파일 필터를 적용합니다."""
425
+ filtered = []
426
+ for file_path in files:
427
+ if self._should_include_file(file_path):
428
+ filtered.append(file_path)
429
+ return filtered
430
+
431
+ def _determine_category(self, file_path: Path) -> str:
432
+ """사용자 정의 로직을 사용하여 파일 카테고리를 결정합니다."""
433
+ ext = file_path.suffix.lower()
434
+ if ext in ['.jpg', '.png', '.gif']:
435
+ return 'images'
436
+ elif ext in ['.pdf', '.doc', '.docx']:
437
+ return 'documents'
438
+ else:
439
+ return 'other'
440
+ ```
441
+
442
+ #### 사용자 정의 업로드 전략
443
+
444
+ ```python
445
+ from synapse_sdk.plugins.categories.upload.actions.upload.strategies.upload.base import BaseUploadStrategy
446
+ from typing import List, Dict, Any
447
+ import time
448
+
449
+ class CustomUploadStrategy(BaseUploadStrategy):
450
+ """고급 재시도 로직을 사용한 사용자 정의 업로드 전략."""
451
+
452
+ def upload_files(self, files: List[Dict[str, Any]], context: UploadContext) -> List[Dict[str, Any]]:
453
+ """사용자 정의 배치 및 재시도 로직으로 파일을 업로드합니다."""
454
+ uploaded_files = []
455
+ batch_size = context.get_param('upload_batch_size', 10)
456
+
457
+ # 사용자 정의 배치로 처리
458
+ for i in range(0, len(files), batch_size):
459
+ batch = files[i:i + batch_size]
460
+ batch_results = self.upload_batch(batch, context)
461
+ uploaded_files.extend(batch_results)
462
+
463
+ return uploaded_files
464
+
465
+ def upload_batch(self, batch: List[Dict[str, Any]], context: UploadContext) -> List[Dict[str, Any]]:
466
+ """재시도 로직으로 파일 배치를 업로드합니다."""
467
+ results = []
468
+
469
+ for file_info in batch:
470
+ max_retries = 3
471
+ for attempt in range(max_retries):
472
+ try:
473
+ result = self._upload_single_file(file_info, context)
474
+ results.append(result)
475
+ break
476
+ except Exception as e:
477
+ if attempt == max_retries - 1:
478
+ # 마지막 시도 실패
479
+ context.add_error(f"{file_info['file_path']} 업로드 실패: {e}")
480
+ else:
481
+ # 재시도 전 대기
482
+ time.sleep(2 ** attempt)
483
+
484
+ return results
485
+
486
+ def _upload_single_file(self, file_info: Dict[str, Any], context: UploadContext) -> Dict[str, Any]:
487
+ """사용자 정의 로직으로 단일 파일을 업로드합니다."""
488
+ file_path = file_info['file_path']
489
+ storage = context.storage
490
+
491
+ # 여기에 사용자 정의 업로드 로직
492
+ uploaded_file = {
493
+ 'file_path': str(file_path),
494
+ 'storage_path': f"uploads/{file_path.name}",
495
+ 'size': file_path.stat().st_size,
496
+ 'checksum': self._calculate_checksum(file_path)
497
+ }
498
+
499
+ return uploaded_file
500
+ ```
501
+
502
+ ### 사용자 정의 워크플로우 단계 생성
503
+
504
+ 사용자 정의 워크플로우 단계는 기본 단계 클래스를 확장하고 필요한 인터페이스를 구현합니다.
505
+
506
+ #### 사용자 정의 처리 단계
507
+
508
+ ```python
509
+ from synapse_sdk.plugins.categories.upload.actions.upload.steps.base import BaseStep
510
+ from synapse_sdk.plugins.categories.upload.actions.upload.context import UploadContext, StepResult
511
+ from pathlib import Path
512
+ from typing import List, Dict
513
+ from datetime import datetime
514
+
515
+ class CustomProcessingStep(BaseStep):
516
+ """특수 파일 처리를 위한 사용자 정의 처리 단계."""
517
+
518
+ @property
519
+ def name(self) -> str:
520
+ return 'custom_processing'
521
+
522
+ @property
523
+ def progress_weight(self) -> float:
524
+ return 0.15 # 전체 워크플로우의 15%
525
+
526
+ def execute(self, context: UploadContext) -> StepResult:
527
+ """사용자 정의 처리 로직을 실행합니다."""
528
+ try:
529
+ # 사용자 정의 처리 로직
530
+ processed_files = self._process_files(context)
531
+
532
+ # 결과로 컨텍스트 업데이트
533
+ return self.create_success_result({
534
+ 'processed_files': processed_files,
535
+ 'processing_stats': self._get_processing_stats()
536
+ })
537
+
538
+ except Exception as e:
539
+ return self.create_error_result(f'사용자 정의 처리 실패: {str(e)}')
540
+
541
+ def can_skip(self, context: UploadContext) -> bool:
542
+ """단계가 건너뛸 수 있는지 결정합니다."""
543
+ # 처리할 파일이 없으면 건너뛰기
544
+ return len(context.organized_files) == 0
545
+
546
+ def rollback(self, context: UploadContext) -> None:
547
+ """사용자 정의 처리 작업을 롤백합니다."""
548
+ # 처리 중에 생성된 모든 리소스 정리
549
+ self._cleanup_processing_resources(context)
550
+
551
+ def _process_files(self, context: UploadContext) -> List[Dict]:
552
+ """사용자 정의 파일 처리를 구현합니다."""
553
+ processed = []
554
+
555
+ for file_info in context.organized_files:
556
+ # 사용자 정의 처리 로직
557
+ result = self._process_single_file(file_info)
558
+ processed.append(result)
559
+
560
+ return processed
561
+
562
+ def _process_single_file(self, file_info: Dict) -> Dict:
563
+ """단일 파일을 처리합니다."""
564
+ return {
565
+ 'original': file_info,
566
+ 'processed': True,
567
+ 'timestamp': datetime.now()
568
+ }
569
+
570
+ def _get_processing_stats(self) -> Dict:
571
+ """처리 통계를 가져옵니다."""
572
+ return {}
573
+
574
+ def _cleanup_processing_resources(self, context: UploadContext) -> None:
575
+ """처리 리소스를 정리합니다."""
576
+ pass
577
+ ```
578
+
579
+ ### 전략 팩토리 확장
580
+
581
+ 사용자 정의 전략을 사용 가능하게 하려면 StrategyFactory를 확장합니다:
582
+
583
+ ```python
584
+ from synapse_sdk.plugins.categories.upload.actions.upload.factory import StrategyFactory
585
+ from typing import Dict
586
+
587
+ class CustomStrategyFactory(StrategyFactory):
588
+ """사용자 정의 전략을 포함한 확장된 팩토리."""
589
+
590
+ def create_validation_strategy(self, params: Dict, context=None):
591
+ """사용자 정의 옵션으로 검증 전략을 생성합니다."""
592
+ validation_type = params.get('custom_validation_type', 'default')
593
+
594
+ if validation_type == 'strict':
595
+ return CustomValidationStrategy()
596
+ else:
597
+ return super().create_validation_strategy(params, context)
598
+
599
+ def create_file_discovery_strategy(self, params: Dict, context=None):
600
+ """사용자 정의 옵션으로 파일 검색 전략을 생성합니다."""
601
+ discovery_mode = params.get('discovery_mode', 'default')
602
+
603
+ if discovery_mode == 'advanced':
604
+ return CustomFileDiscoveryStrategy()
605
+ else:
606
+ return super().create_file_discovery_strategy(params, context)
607
+ ```
608
+
609
+ ### 사용자 정의 업로드 액션
610
+
611
+ 포괄적인 사용자 정의를 위해 UploadAction 자체를 확장합니다:
612
+
613
+ ```python
614
+ from synapse_sdk.plugins.categories.upload.actions.upload.action import UploadAction
615
+ from synapse_sdk.plugins.categories.decorators import register_action
616
+ from typing import Dict, Any
617
+
618
+ @register_action
619
+ class CustomUploadAction(UploadAction):
620
+ """확장된 워크플로우를 가진 사용자 정의 업로드 액션."""
621
+
622
+ name = 'custom_upload'
623
+
624
+ def __init__(self, *args, **kwargs):
625
+ super().__init__(*args, **kwargs)
626
+ # 사용자 정의 전략 팩토리 사용
627
+ self.strategy_factory = CustomStrategyFactory()
628
+
629
+ def _configure_workflow(self) -> None:
630
+ """추가 단계로 사용자 정의 워크플로우를 구성합니다."""
631
+ # 표준 단계 등록
632
+ super()._configure_workflow()
633
+
634
+ # 사용자 정의 처리 단계 추가
635
+ self.step_registry.register(CustomProcessingStep())
636
+
637
+ def _configure_strategies(self, context=None) -> Dict[str, Any]:
638
+ """사용자 정의 매개변수로 전략을 구성합니다."""
639
+ strategies = super()._configure_strategies(context)
640
+
641
+ # 사용자 정의 전략 추가
642
+ strategies['custom_processing'] = self._create_custom_processing_strategy()
643
+
644
+ return strategies
645
+
646
+ def _create_custom_processing_strategy(self):
647
+ """사용자 정의 처리 전략을 생성합니다."""
648
+ return CustomProcessingStrategy(self.params)
649
+ ```
650
+
651
+ ### 사용자 정의 구성 요소 테스트
652
+
653
+ #### 사용자 정의 전략 테스트
654
+
655
+ ```python
656
+ import pytest
657
+ from unittest.mock import Mock
658
+ from pathlib import Path
659
+
660
+ class TestCustomValidationStrategy:
661
+
662
+ def setup_method(self):
663
+ self.strategy = CustomValidationStrategy()
664
+ self.context = Mock()
665
+
666
+ def test_validate_files_success(self):
667
+ """성공적인 파일 검증 테스트."""
668
+ files = [Path('/test/file1.txt'), Path('/test/file2.jpg')]
669
+ result = self.strategy.validate_files(files, self.context)
670
+ assert result is True
671
+
672
+ def test_validate_files_security_failure(self):
673
+ """보안상의 이유로 검증 실패 테스트."""
674
+ files = [Path('/test/malware.exe')]
675
+ result = self.strategy.validate_files(files, self.context)
676
+ assert result is False
677
+
678
+ def test_validate_large_file_failure(self):
679
+ """큰 파일에 대한 검증 실패 테스트."""
680
+ # 큰 크기를 반환하도록 파일 상태 모의
681
+ large_file = Mock(spec=Path)
682
+ large_file.suffix = '.txt'
683
+ large_file.stat.return_value.st_size = 200 * 1024 * 1024 # 200MB
684
+
685
+ result = self.strategy.validate_security(large_file)
686
+ assert result is False
687
+ ```
688
+
689
+ #### 사용자 정의 단계 테스트
690
+
691
+ ```python
692
+ class TestCustomProcessingStep:
693
+
694
+ def setup_method(self):
695
+ self.step = CustomProcessingStep()
696
+ self.context = Mock()
697
+ self.context.organized_files = [
698
+ {'file_path': '/test/file1.txt'},
699
+ {'file_path': '/test/file2.jpg'}
700
+ ]
701
+
702
+ def test_execute_success(self):
703
+ """성공적인 단계 실행 테스트."""
704
+ result = self.step.execute(self.context)
705
+
706
+ assert result.success is True
707
+ assert 'processed_files' in result.data
708
+ assert len(result.data['processed_files']) == 2
709
+
710
+ def test_can_skip_with_no_files(self):
711
+ """단계 건너뛰기 로직 테스트."""
712
+ self.context.organized_files = []
713
+ assert self.step.can_skip(self.context) is True
714
+
715
+ def test_rollback_cleanup(self):
716
+ """롤백 정리 테스트."""
717
+ # 예외가 발생하지 않아야 함
718
+ self.step.rollback(self.context)
719
+ ```
720
+
721
+ ## API 참조
722
+
723
+ ### 핵심 구성 요소
724
+
725
+ #### UploadAction
726
+
727
+ 전략 및 퍼사드 패턴을 구현하는 주요 업로드 액션 클래스.
728
+
729
+ **클래스 속성:**
730
+
731
+ - `name = 'upload'` - 액션 식별자
732
+ - `category = PluginCategory.UPLOAD` - 플러그인 카테고리
733
+ - `method = RunMethod.JOB` - 실행 방법
734
+ - `run_class = UploadRun` - 전문화된 실행 관리
735
+ - `params_model = UploadParams` - 매개변수 검증 모델
736
+ - `strategy_factory: StrategyFactory` - 전략 구현 생성
737
+ - `step_registry: StepRegistry` - 워크플로우 단계 관리
738
+
739
+ **주요 메서드:**
740
+
741
+ - `start() -> Dict[str, Any]` - 조정된 업로드 워크플로우 실행
742
+ - `get_workflow_summary() -> Dict[str, Any]` - 구성된 워크플로우 요약 가져오기
743
+ - `_configure_workflow() -> None` - 워크플로우 단계 등록
744
+ - `_configure_strategies(context=None) -> Dict[str, Any]` - 전략 인스턴스 생성
745
+
746
+ #### UploadOrchestrator
747
+
748
+ 자동 롤백 기능으로 전체 업로드 워크플로우를 조정하는 퍼사드 구성 요소.
749
+
750
+ **속성:**
751
+
752
+ - `context: UploadContext` - 공유 상태
753
+ - `step_registry: StepRegistry` - 워크플로우 단계
754
+ - `strategies: Dict[str, Any]` - 전략 구현
755
+ - `executed_steps: List[BaseStep]` - 성공적으로 실행된 단계
756
+ - `rollback_executed: bool` - 롤백 수행 여부
757
+
758
+ **주요 메서드:**
759
+
760
+ - `execute() -> Dict[str, Any]` - 전체 워크플로우 실행
761
+ - `get_workflow_summary() -> Dict[str, Any]` - 실행 요약 가져오기
762
+ - `_execute_step(step: BaseStep) -> StepResult` - 개별 단계 실행
763
+ - `_rollback_executed_steps() -> None` - 역순으로 롤백
764
+
765
+ #### UploadContext
766
+
767
+ 워크플로우 구성 요소 간의 공유 상태를 유지하는 컨텍스트 객체.
768
+
769
+ **상태 속성:**
770
+
771
+ - `params: Dict` - 업로드 매개변수
772
+ - `storage: Any` - 스토리지 구성
773
+ - `metadata: Dict[str, Dict[str, Any]]` - 파일 메타데이터
774
+ - `file_specifications: Dict[str, Any]` - 데이터 컬렉션 사양
775
+ - `organized_files: List[Dict[str, Any]]` - 구성된 파일
776
+ - `uploaded_files: List[Dict[str, Any]]` - 업로드된 파일
777
+ - `data_units: List[Dict[str, Any]]` - 생성된 데이터 단위
778
+
779
+ **주요 메서드:**
780
+
781
+ - `update(result: StepResult) -> None` - 단계 결과로 업데이트
782
+ - `get_result() -> Dict[str, Any]` - 최종 결과 생성
783
+ - `has_errors() -> bool` - 오류 확인
784
+ - `update_metrics(category: str, metrics: Dict) -> None` - 메트릭 업데이트
785
+
786
+ ### 워크플로우 단계
787
+
788
+ #### BaseStep (추상)
789
+
790
+ 모든 워크플로우 단계의 기본 클래스.
791
+
792
+ **추상 속성:**
793
+
794
+ - `name: str` - 고유한 단계 식별자
795
+ - `progress_weight: float` - 진행률 계산을 위한 가중치
796
+
797
+ **추상 메서드:**
798
+
799
+ - `execute(context: UploadContext) -> StepResult` - 단계 로직 실행
800
+ - `can_skip(context: UploadContext) -> bool` - 건너뛸 수 있는지 결정
801
+ - `rollback(context: UploadContext) -> None` - 작업 롤백
802
+
803
+ **유틸리티 메서드:**
804
+
805
+ - `create_success_result(data: Dict = None) -> StepResult`
806
+ - `create_error_result(error: str, exception: Exception = None) -> StepResult`
807
+ - `create_skip_result() -> StepResult`
808
+
809
+ #### 구체적인 단계
810
+
811
+ **InitializeStep** (`name: "initialize"`, `weight: 0.05`)
812
+
813
+ - 스토리지 및 작업 디렉토리 설정
814
+
815
+ **ProcessMetadataStep** (`name: "process_metadata"`, `weight: 0.05`)
816
+
817
+ - 제공된 경우 Excel 메타데이터 처리
818
+
819
+ **AnalyzeCollectionStep** (`name: "analyze_collection"`, `weight: 0.05`)
820
+
821
+ - 데이터 컬렉션 사양 검색
822
+
823
+ **OrganizeFilesStep** (`name: "organize_files"`, `weight: 0.10`)
824
+
825
+ - 유형별 파일 검색 및 구성
826
+
827
+ **ValidateFilesStep** (`name: "validate_files"`, `weight: 0.05`)
828
+
829
+ - 검증 전략을 사용하여 파일 검증
830
+
831
+ **UploadFilesStep** (`name: "upload_files"`, `weight: 0.30`)
832
+
833
+ - 업로드 전략을 사용하여 파일 업로드
834
+
835
+ **GenerateDataUnitsStep** (`name: "generate_data_units"`, `weight: 0.35`)
836
+
837
+ - 데이터 단위 전략을 사용하여 데이터 단위 생성
838
+
839
+ **CleanupStep** (`name: "cleanup"`, `weight: 0.05`)
840
+
841
+ - 임시 리소스 정리
842
+
843
+ ### 전략 기본 클래스
844
+
845
+ #### BaseValidationStrategy (추상)
846
+
847
+ **추상 메서드:**
848
+
849
+ - `validate_files(files: List[Path], context: UploadContext) -> bool`
850
+ - `validate_security(file_path: Path) -> bool`
851
+
852
+ #### BaseFileDiscoveryStrategy (추상)
853
+
854
+ **추상 메서드:**
855
+
856
+ - `discover_files(path: Path, context: UploadContext) -> List[Path]`
857
+ - `organize_files(files: List[Path], specs: Dict, context: UploadContext) -> List[Dict]`
858
+
859
+ #### BaseMetadataStrategy (추상)
860
+
861
+ **추상 메서드:**
862
+
863
+ - `process_metadata(context: UploadContext) -> Dict[str, Any]`
864
+ - `extract_metadata(file_path: Path) -> Dict[str, Any]`
865
+
866
+ #### BaseUploadStrategy (추상)
867
+
868
+ **추상 메서드:**
869
+
870
+ - `upload_files(files: List[Dict], context: UploadContext) -> List[Dict]`
871
+ - `upload_batch(batch: List[Dict], context: UploadContext) -> List[Dict]`
872
+
873
+ #### BaseDataUnitStrategy (추상)
874
+
875
+ **추상 메서드:**
876
+
877
+ - `generate_data_units(files: List[Dict], context: UploadContext) -> List[Dict]`
878
+ - `create_data_unit_batch(batch: List[Dict], context: UploadContext) -> List[Dict]`
879
+
880
+ ## 모범 사례
881
+
882
+ ### 아키텍처 패턴
883
+
884
+ 1. **전략 선택**: 요구 사항에 따라 적절한 전략 선택
885
+ 2. **단계 순서**: 논리적 단계 종속성 유지
886
+ 3. **컨텍스트 관리**: 상태 공유를 위해 UploadContext 활용
887
+
888
+ ### 성능 최적화
889
+
890
+ 1. **배치 처리**: 최적의 배치 크기 구성
891
+ 2. **비동기 작업**: I/O 바운드 작업에 비동기 활성화
892
+ 3. **메모리 관리**: 사용자 정의 전략에서 메모리 사용량 모니터링
893
+
894
+ ### 보안 고려 사항
895
+
896
+ 1. **입력 검증**: 모든 매개변수 및 파일 경로 검증
897
+ 2. **파일 내용 보안**: 내용 기반 검사 구현
898
+ 3. **경로 살균**: 모든 경로 검증 및 살균
899
+
900
+ ### 오류 처리 및 복구
901
+
902
+ 1. **점진적 성능 저하**: 부분적 실패 시나리오를 위한 설계
903
+ 2. **롤백 설계**: 포괄적인 롤백 전략 구현
904
+ 3. **상세 로깅**: 디버깅을 위한 구조화된 로깅 사용
905
+
906
+ ## 레거시로부터의 마이그레이션
907
+
908
+ 업로드 액션은 100% 하위 호환성을 유지합니다. 기존 코드는 변경 없이 계속 작동합니다.
909
+
910
+ ### 주요 변경 사항
911
+
912
+ **이전 (레거시):**
913
+
914
+ - 단일 900+ 라인 액션 클래스
915
+ - 하드 코딩된 동작
916
+ - 확장성 없음
917
+
918
+ **이후 (리팩토링):**
919
+
920
+ - 8개의 워크플로우 단계로 깔끔하게 분리
921
+ - 플러그형 전략
922
+ - 자동 롤백
923
+
924
+ ### 이점
925
+
926
+ - 자동 롤백으로 더 나은 오류 처리
927
+ - 상세한 진행 상황 추적
928
+ - 사용자 정의 전략으로 확장성
929
+ - 더 나은 테스트 용이성
930
+
931
+ ## 최근 아키텍처 개선사항
932
+
933
+ ### 업로드 로직 리팩토링
934
+
935
+ **문제**: 원래 구현에서 검증 단계가 파일 처리/필터링 작업을 수행하는 불분명한 관심사 분리가 있었습니다.
936
+
937
+ **해결책**: 파일 처리 로직을 검증 단계에서 업로드 전략으로 이동하여 적절한 관심사 분리를 보장하도록 리팩토링했습니다.
938
+
939
+ **변경사항**:
940
+
941
+ 1. **ValidateFilesStep** - 이제 사양 기반 검증만 수행
942
+ 2. **UploadStrategy** - 업로드 전에 플러그인 파일 처리를 처리하기 위해 `_process_files_with_uploader()` 통합
943
+ 3. **이점**: 명확한 워크플로우, 더 나은 유지보수성, 하위 호환성 유지
944
+
945
+ ## 참조
946
+
947
+ - [업로드 플러그인 개요](./upload-plugin-overview.md) - 사용자 가이드 및 구성 참조
948
+ - [BaseUploader 템플릿 가이드](./upload-plugin-template.md) - BaseUploader 템플릿을 사용한 플러그인 개발