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
@@ -1,8 +1,10 @@
1
1
  import json
2
- import os
2
+ import threading
3
3
  from pathlib import Path
4
4
 
5
5
  import requests
6
+ from requests.adapters import HTTPAdapter
7
+ from urllib3.util.retry import Retry
6
8
 
7
9
  from synapse_sdk.clients.exceptions import ClientError
8
10
  from synapse_sdk.utils.file import files_url_to_path_from_objs
@@ -11,16 +13,75 @@ from synapse_sdk.utils.file import files_url_to_path_from_objs
11
13
  class BaseClient:
12
14
  name = None
13
15
  base_url = None
16
+ page_size = 100
14
17
 
15
- def __init__(self, base_url):
16
- self.base_url = base_url
17
- requests_session = requests.Session()
18
- self.requests_session = requests_session
18
+ # TODO: Ensure that the Upload plugin's threading behavior works correctly within tasks and that progress management works properly.
19
+ def __init__(self, base_url, timeout=None):
20
+ self.base_url = base_url.rstrip('/')
21
+ # Set reasonable default timeouts for better UX
22
+ self.timeout = timeout or {
23
+ 'connect': 5, # Connection timeout: 5 seconds
24
+ 'read': 15, # Read timeout: 15 seconds
25
+ }
19
26
 
20
- def _get_url(self, path):
21
- if not path.startswith(self.base_url):
22
- return os.path.join(self.base_url, path)
23
- return path
27
+ # Use thread-local storage for sessions to ensure thread safety
28
+ # Each thread gets its own requests.Session instance
29
+ self._thread_local = threading.local()
30
+
31
+ # Store retry configuration for creating sessions
32
+ self._retry_config = {
33
+ 'total': 3, # Total retries
34
+ 'backoff_factor': 1, # Backoff factor between retries
35
+ 'status_forcelist': [502, 503, 504], # HTTP status codes to retry
36
+ 'allowed_methods': ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
37
+ }
38
+
39
+ def _create_session(self):
40
+ """Create a new requests session with retry strategy.
41
+
42
+ This is called once per thread to create a thread-local session.
43
+ """
44
+ session = requests.Session()
45
+
46
+ # Configure retry strategy for transient failures
47
+ retry_strategy = Retry(**self._retry_config)
48
+
49
+ adapter = HTTPAdapter(max_retries=retry_strategy)
50
+ session.mount('http://', adapter)
51
+ session.mount('https://', adapter)
52
+
53
+ return session
54
+
55
+ @property
56
+ def requests_session(self):
57
+ """Get the thread-local requests session.
58
+
59
+ Returns a thread-local session instance, creating one if it doesn't exist
60
+ for the current thread. This ensures thread safety when using the client
61
+ in multi-threaded environments (e.g., async uploads).
62
+ """
63
+ if not hasattr(self._thread_local, 'session'):
64
+ self._thread_local.session = self._create_session()
65
+ return self._thread_local.session
66
+
67
+ def _get_url(self, path, trailing_slash=False):
68
+ """Construct a full URL from a path.
69
+
70
+ Args:
71
+ path (str): URL path or full URL
72
+ trailing_slash (bool): Whether to ensure URL ends with trailing slash
73
+
74
+ Returns:
75
+ str: Complete URL
76
+ """
77
+ # Use the path as-is if it's already a full URL, otherwise construct from base_url and path
78
+ url = path if path.startswith(('http://', 'https://')) else f'{self.base_url}/{path.lstrip("/")}'
79
+
80
+ # Add trailing slash if requested and not present
81
+ if trailing_slash and not url.endswith('/'):
82
+ url += '/'
83
+
84
+ return url
24
85
 
25
86
  def _get_headers(self):
26
87
  return {}
@@ -40,6 +101,10 @@ class BaseClient:
40
101
  headers = self._get_headers()
41
102
  headers.update(kwargs.pop('headers', {}))
42
103
 
104
+ # Set timeout if not provided in kwargs
105
+ if 'timeout' not in kwargs:
106
+ kwargs['timeout'] = (self.timeout['connect'], self.timeout['read'])
107
+
43
108
  # List to store opened files to close after request
44
109
  opened_files = []
45
110
 
@@ -70,8 +135,21 @@ class BaseClient:
70
135
  raise ClientError(
71
136
  response.status_code, response.json() if response.status_code == 400 else response.reason
72
137
  )
73
- except requests.ConnectionError:
74
- raise ClientError(408, f'{self.name} is not responding')
138
+ except requests.exceptions.ConnectTimeout:
139
+ raise ClientError(408, f'{self.name} connection timeout (>{self.timeout["connect"]}s)')
140
+ except requests.exceptions.ReadTimeout:
141
+ raise ClientError(408, f'{self.name} read timeout (>{self.timeout["read"]}s)')
142
+ except requests.exceptions.ConnectionError as e:
143
+ # More specific error handling for different connection issues
144
+ if 'Name or service not known' in str(e) or 'nodename nor servname provided' in str(e):
145
+ raise ClientError(503, f'{self.name} host unreachable')
146
+ elif 'Connection refused' in str(e):
147
+ raise ClientError(503, f'{self.name} connection refused')
148
+ else:
149
+ raise ClientError(503, f'{self.name} connection error: {str(e)[:100]}')
150
+ except requests.exceptions.RequestException as e:
151
+ # Catch all other requests exceptions
152
+ raise ClientError(500, f'{self.name} request failed: {str(e)[:100]}')
75
153
 
76
154
  # Close all opened files
77
155
  for opened_file in opened_files:
@@ -85,14 +163,14 @@ class BaseClient:
85
163
  except ValueError:
86
164
  return response.text
87
165
 
88
- def _get(self, path, url_conversion=None, pydantic_model=None, **kwargs):
89
- """
90
- Perform a GET request and optionally convert response to a pydantic model.
166
+ def _get(self, path, url_conversion=None, response_model=None, **kwargs):
167
+ """Perform a GET request and optionally convert response to a pydantic model.
91
168
 
92
169
  Args:
93
170
  path (str): URL path to request.
94
171
  url_conversion (dict, optional): Configuration for URL to path conversion.
95
- pydantic_model (Type, optional): Pydantic model to convert the response to.
172
+ request_model (pydantic.BaseModel, optional): Pydantic model to validate the request.
173
+ response_model (pydantic.BaseModel, optional): Pydantic model to validate the response.
96
174
  **kwargs: Additional keyword arguments to pass to the request.
97
175
 
98
176
  Returns:
@@ -106,51 +184,230 @@ class BaseClient:
106
184
  else:
107
185
  files_url_to_path_from_objs(response, **url_conversion)
108
186
 
109
- if pydantic_model:
110
- return self._validate_response_with_pydantic_model(response, pydantic_model)
187
+ if response_model:
188
+ return self._validate_response_with_pydantic_model(response, response_model)
111
189
 
112
190
  return response
113
191
 
114
- def _post(self, path, pydantic_model=None, **kwargs):
192
+ def _post(self, path, request_model=None, response_model=None, **kwargs):
193
+ """Perform a POST request and optionally convert response to a pydantic model.
194
+
195
+ Args:
196
+ path (str): URL path to request.
197
+ request_model (pydantic.BaseModel, optional): Pydantic model to validate the request.
198
+ response_model (pydantic.BaseModel, optional): Pydantic model to validate the response.
199
+ **kwargs: Additional keyword arguments to pass to the request.
200
+
201
+ Returns:
202
+ The response data, optionally converted to a pydantic model.
203
+ """
204
+ if kwargs.get('data') and request_model:
205
+ kwargs['data'] = self._validate_request_body_with_pydantic_model(kwargs['data'], request_model)
115
206
  response = self._request('post', path, **kwargs)
116
- if pydantic_model:
117
- return self._validate_response_with_pydantic_model(response, pydantic_model)
207
+ if response_model:
208
+ return self._validate_response_with_pydantic_model(response, response_model)
118
209
  else:
119
210
  return response
120
211
 
121
- def _put(self, path, pydantic_model=None, **kwargs):
212
+ def _put(self, path, request_model=None, response_model=None, **kwargs):
213
+ """Perform a PUT request to the specified path.
214
+
215
+ Args:
216
+ path (str): The URL path for the request.
217
+ request_model (Optional[Type[BaseModel]]): A Pydantic model class to validate the request body against.
218
+ response_model (Optional[Type[BaseModel]]): A Pydantic model class to validate and parse the response.
219
+ **kwargs: Additional arguments to pass to the request method.
220
+ - data: The request body to be sent. If provided along with request_model, it will be validated.
221
+
222
+ Returns:
223
+ Union[dict, BaseModel]:
224
+ If response_model is provided, returns an instance of that model populated with the response data.
225
+ """
226
+ if kwargs.get('data') and request_model:
227
+ kwargs['data'] = self._validate_request_body_with_pydantic_model(kwargs['data'], request_model)
122
228
  response = self._request('put', path, **kwargs)
123
- if pydantic_model:
124
- return self._validate_response_with_pydantic_model(response, pydantic_model)
229
+ if response_model:
230
+ return self._validate_response_with_pydantic_model(response, response_model)
125
231
  else:
126
232
  return response
127
233
 
128
- def _patch(self, path, pydantic_model=None, **kwargs):
234
+ def _patch(self, path, request_model=None, response_model=None, **kwargs):
235
+ """Perform a PATCH HTTP request to the specified path.
236
+
237
+ Args:
238
+ path (str): The API endpoint path to make the request to.
239
+ request_model (Optional[Type[BaseModel]]): A Pydantic model class used to validate the request body.
240
+ response_model (Optional[Type[BaseModel]]): A Pydantic model class used to validate and parse the response.
241
+ **kwargs: Additional keyword arguments to pass to the request method.
242
+ - data: The request body data. If provided along with request_model, it will be validated.
243
+
244
+ Returns:
245
+ Union[dict, BaseModel]: If response_model is provided, returns an instance of that model.
246
+ Otherwise, returns the raw response data.
247
+ """
248
+ if kwargs.get('data') and request_model:
249
+ kwargs['data'] = self._validate_request_body_with_pydantic_model(kwargs['data'], request_model)
129
250
  response = self._request('patch', path, **kwargs)
130
- if pydantic_model:
131
- return self._validate_response_with_pydantic_model(response, pydantic_model)
251
+ if response_model:
252
+ return self._validate_response_with_pydantic_model(response, response_model)
132
253
  else:
133
254
  return response
134
255
 
135
- def _delete(self, path, pydantic_model=None, **kwargs):
256
+ def _delete(self, path, request_model=None, response_model=None, **kwargs):
257
+ """Performs a DELETE request to the specified path.
258
+
259
+ Args:
260
+ path (str): The API endpoint path to send the DELETE request to.
261
+ request_model (Optional[Type[BaseModel]]): Pydantic model to validate the request data against.
262
+ response_model (Optional[Type[BaseModel]]): Pydantic model to validate and convert the response data.
263
+ **kwargs: Additional keyword arguments passed to the request method.
264
+ - data: Request payload to send. Will be validated against request_model if both are provided.
265
+
266
+ Returns:
267
+ Union[dict, BaseModel]: If response_model is provided, returns an instance of that model.
268
+ Otherwise, returns the raw response data as a dictionary.
269
+ """
270
+ if kwargs.get('data') and request_model:
271
+ kwargs['data'] = self._validate_request_body_with_pydantic_model(kwargs['data'], request_model)
136
272
  response = self._request('delete', path, **kwargs)
137
- if pydantic_model:
138
- return self._validate_response_with_pydantic_model(response, pydantic_model)
273
+ if response_model:
274
+ return self._validate_response_with_pydantic_model(response, response_model)
139
275
  else:
140
276
  return response
141
277
 
142
- def _list(self, path, url_conversion=None, list_all=False, **kwargs):
143
- response = self._get(path, **kwargs)
278
+ def _list(self, path, url_conversion=None, list_all=False, params=None, **kwargs):
279
+ """List resources from a paginated API endpoint.
280
+
281
+ Args:
282
+ path (str): URL path to request.
283
+ url_conversion (dict, optional): Configuration for URL to path conversion.
284
+ Used to convert file URLs to local paths in the response.
285
+ Example: {'files_fields': ['files'], 'is_list': True}
286
+ This will convert file URLs in the 'files' field of each result.
287
+ list_all (bool): If True, returns a generator yielding all results across all pages.
288
+ Default is False, which returns only the first page.
289
+ params (dict, optional): Query parameters to pass to the request.
290
+ Example: {'status': 'active', 'project': 123}
291
+ **kwargs: Additional keyword arguments to pass to the request.
292
+
293
+ Returns:
294
+ If list_all is False: dict response from the API containing:
295
+ - 'results': list of items on the current page
296
+ - 'count': total number of items
297
+ - 'next': URL to the next page (or None)
298
+ - 'previous': URL to the previous page (or None)
299
+ If list_all is True: tuple of (generator, count) where:
300
+ - generator: yields individual items from all pages
301
+ - count: total number of items across all pages
302
+
303
+ Examples:
304
+ Get first page only:
305
+ >>> response = client._list('api/tasks/')
306
+ >>> tasks = response['results'] # List of tasks on first page
307
+ >>> total_count = response['count'] # Total number of tasks
308
+
309
+ Get all results across all pages:
310
+ >>> generator, count = client._list('api/tasks/', list_all=True)
311
+ >>> all_tasks = list(generator) # Fetches all pages
312
+
313
+ With filters and url_conversion:
314
+ >>> url_conversion = {'files_fields': ['files'], 'is_list': True}
315
+ >>> params = {'status': 'active'}
316
+ >>> generator, count = client._list(
317
+ ... 'api/data_units/',
318
+ ... url_conversion=url_conversion,
319
+ ... list_all=True,
320
+ ... params=params
321
+ ... )
322
+ >>> active_units = list(generator) # All active units with file URLs converted
323
+ """
324
+ if params is None:
325
+ params = {}
326
+
144
327
  if list_all:
145
- return self._list_all(path, url_conversion, **kwargs), response['count']
328
+ response = self._get(path, params=params, **kwargs)
329
+ return self._list_all(path, url_conversion, params=params, **kwargs), response.get('count')
146
330
  else:
331
+ response = self._get(path, params=params, **kwargs)
147
332
  return response
148
333
 
149
334
  def _list_all(self, path, url_conversion=None, params=None, **kwargs):
150
- response = self._get(path, url_conversion, params=params, **kwargs)
151
- yield from response['results']
152
- if response['next']:
153
- yield from self._list_all(response['next'], url_conversion, **kwargs)
335
+ """Generator that yields all results from a paginated API endpoint.
336
+
337
+ This method handles pagination automatically by following the 'next' URLs
338
+ returned by the API until all pages have been fetched. It uses an iterative
339
+ approach (while loop) instead of recursion to avoid stack overflow with
340
+ deep pagination.
341
+
342
+ Args:
343
+ path (str): Initial URL path to request.
344
+ url_conversion (dict, optional): Configuration for URL to path conversion.
345
+ Applied to all pages. Common structure:
346
+ - 'files_fields': List of field names containing file URLs
347
+ - 'is_list': Whether the response is a list (True for paginated results)
348
+ Example: {'files_fields': ['files', 'images'], 'is_list': True}
349
+ params (dict, optional): Query parameters for the first request only.
350
+ Subsequent requests use the 'next' URL which already includes
351
+ all necessary parameters. If 'page_size' is not specified,
352
+ it defaults to self.page_size (100).
353
+ Example: {'status': 'active', 'page_size': 50}
354
+ **kwargs: Additional keyword arguments to pass to requests.
355
+ Example: timeout, headers, etc.
356
+
357
+ Yields:
358
+ dict: Individual result items from all pages. Each item is yielded
359
+ as soon as it's fetched, allowing for memory-efficient processing
360
+ of large datasets.
361
+
362
+ Examples:
363
+ Basic usage - fetch all tasks:
364
+ >>> for task in client._list_all('api/tasks/'):
365
+ ... process_task(task)
366
+
367
+ With filters:
368
+ >>> params = {'status': 'pending', 'priority': 'high'}
369
+ >>> for task in client._list_all('api/tasks/', params=params):
370
+ ... print(task['id'])
371
+
372
+ With url_conversion for file fields:
373
+ >>> url_conversion = {'files_fields': ['files'], 'is_list': True}
374
+ >>> for data_unit in client._list_all('api/data_units/', url_conversion):
375
+ ... # File URLs in 'files' field are converted to local paths
376
+ ... print(data_unit['files'])
377
+
378
+ Collecting results into a list:
379
+ >>> all_tasks = list(client._list_all('api/tasks/'))
380
+ >>> print(f"Total tasks: {len(all_tasks)}")
381
+
382
+ Note:
383
+ - This is a generator function, so results are fetched lazily as you iterate
384
+ - The first page is fetched with the provided params
385
+ - Subsequent pages use the 'next' URL from the API response
386
+ - No duplicate page_size parameters are added to subsequent requests
387
+ - Memory efficient: processes one item at a time rather than loading all at once
388
+ """
389
+ if params is None:
390
+ params = {}
391
+
392
+ # Set page_size only if not already specified by user
393
+ request_params = params.copy()
394
+ if 'page_size' not in request_params:
395
+ request_params['page_size'] = self.page_size
396
+
397
+ next_url = path
398
+ is_first_request = True
399
+
400
+ while next_url:
401
+ # First request uses params, subsequent requests use next URL directly
402
+ if is_first_request:
403
+ response = self._get(next_url, url_conversion, params=request_params, **kwargs)
404
+ is_first_request = False
405
+ else:
406
+ # next URL already contains all necessary query parameters
407
+ response = self._get(next_url, url_conversion, **kwargs)
408
+
409
+ yield from response['results']
410
+ next_url = response.get('next')
154
411
 
155
412
  def exists(self, api, *args, **kwargs):
156
413
  return getattr(self, api)(*args, **kwargs)['count'] > 0
@@ -168,3 +425,19 @@ class BaseClient:
168
425
  else:
169
426
  # Not a pydantic model
170
427
  raise TypeError('The provided model is not a pydantic model')
428
+
429
+ def _validate_request_body_with_pydantic_model(self, request_body, pydantic_model):
430
+ """Validate a request body with a pydantic model."""
431
+ # Check if model is a pydantic model (has the __pydantic_model__ attribute)
432
+ if (
433
+ hasattr(pydantic_model, '__pydantic_model__')
434
+ or hasattr(pydantic_model, 'model_validate')
435
+ or hasattr(pydantic_model, 'parse_obj')
436
+ ):
437
+ # Validate the request body and convert to model instance
438
+ model_instance = pydantic_model.model_validate(request_body)
439
+ # Convert model to dict and remove None values
440
+ return {k: v for k, v in model_instance.model_dump().items() if v is not None}
441
+ else:
442
+ # Not a pydantic model
443
+ raise TypeError('The provided model is not a pydantic model')
@@ -8,6 +8,7 @@ class ServeClientMixin(BaseClient):
8
8
  response = self._get(path, params=params)
9
9
  for key, item in response['applications'].items():
10
10
  response['applications'][key]['deployments'] = list(item['deployments'].values())
11
+ response['applications'][key]['route_prefix'] = item['route_prefix']
11
12
  return list(response['applications'].values())
12
13
 
13
14
  def get_serve_application(self, pk, params=None):
@@ -15,6 +16,7 @@ class ServeClientMixin(BaseClient):
15
16
  response = self._get(path, params=params)
16
17
  try:
17
18
  response['applications'][pk]['deployments'] = list(response['applications'][pk]['deployments'].values())
19
+ response['applications'][pk]['route_prefix'] = response['applications'][pk]['route_prefix']
18
20
  return response['applications'][pk]
19
21
  except KeyError:
20
22
  raise ClientError(404, 'Serve Application Not Found')
File without changes
@@ -0,0 +1,94 @@
1
+ import json
2
+ from pathlib import Path
3
+ from typing import Dict, Optional
4
+
5
+ CONFIG_DIR = Path.home() / '.config' / 'synapse'
6
+ DEVTOOLS_CONFIG_FILE = CONFIG_DIR / 'devtools.json'
7
+
8
+
9
+ def ensure_config_dir():
10
+ """Ensure the config directory exists"""
11
+ CONFIG_DIR.mkdir(parents=True, exist_ok=True)
12
+
13
+
14
+ def load_devtools_config() -> Dict:
15
+ """Load devtools configuration from file"""
16
+ ensure_config_dir()
17
+
18
+ # Handle both Path and string types for testing
19
+ config_file = Path(DEVTOOLS_CONFIG_FILE) if isinstance(DEVTOOLS_CONFIG_FILE, str) else DEVTOOLS_CONFIG_FILE
20
+
21
+ if not config_file.exists():
22
+ return {}
23
+
24
+ try:
25
+ with open(config_file, 'r') as f:
26
+ return json.load(f)
27
+ except (json.JSONDecodeError, IOError):
28
+ return {}
29
+
30
+
31
+ def save_devtools_config(config: Dict):
32
+ """Save devtools configuration to file"""
33
+ ensure_config_dir()
34
+
35
+ # Handle both Path and string types for testing
36
+ config_file = Path(DEVTOOLS_CONFIG_FILE) if isinstance(DEVTOOLS_CONFIG_FILE, str) else DEVTOOLS_CONFIG_FILE
37
+
38
+ try:
39
+ with open(config_file, 'w') as f:
40
+ json.dump(config, f, indent=2)
41
+ except IOError:
42
+ pass
43
+
44
+
45
+ def get_backend_config() -> Optional[Dict]:
46
+ """Get backend configuration (host and token)"""
47
+ config = load_devtools_config()
48
+ backend = config.get('backend', {})
49
+
50
+ host = backend.get('host')
51
+ token = backend.get('token')
52
+
53
+ if host and token:
54
+ return {'host': host, 'token': token}
55
+
56
+ return None
57
+
58
+
59
+ def set_backend_config(host: str, token: str):
60
+ """Set backend configuration"""
61
+ config = load_devtools_config()
62
+ config['backend'] = {'host': host, 'token': token}
63
+ save_devtools_config(config)
64
+
65
+
66
+ def clear_backend_config():
67
+ """Clear backend configuration"""
68
+ config = load_devtools_config()
69
+ if 'backend' in config:
70
+ del config['backend']
71
+ save_devtools_config(config)
72
+
73
+
74
+ def get_server_config() -> Dict:
75
+ """Get server configuration (host and port)"""
76
+ config = load_devtools_config()
77
+ server = config.get('server', {})
78
+
79
+ return {'host': server.get('host', '0.0.0.0'), 'port': server.get('port', 8080)}
80
+
81
+
82
+ def set_server_config(host: str = None, port: int = None):
83
+ """Set server configuration"""
84
+ config = load_devtools_config()
85
+
86
+ if 'server' not in config:
87
+ config['server'] = {}
88
+
89
+ if host is not None:
90
+ config['server']['host'] = host
91
+ if port is not None:
92
+ config['server']['port'] = port
93
+
94
+ save_devtools_config(config)
@@ -0,0 +1,20 @@
1
+ # Dependencies
2
+ /node_modules
3
+
4
+ # Production
5
+ /build
6
+
7
+ # Generated files
8
+ .docusaurus
9
+ .cache-loader
10
+
11
+ # Misc
12
+ .DS_Store
13
+ .env.local
14
+ .env.development.local
15
+ .env.test.local
16
+ .env.production.local
17
+
18
+ npm-debug.log*
19
+ yarn-debug.log*
20
+ yarn-error.log*
@@ -0,0 +1,41 @@
1
+ # Website
2
+
3
+ This website is built using [Docusaurus](https://docusaurus.io/), a modern static website generator.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ yarn
9
+ ```
10
+
11
+ ## Local Development
12
+
13
+ ```bash
14
+ yarn start
15
+ ```
16
+
17
+ This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.
18
+
19
+ ## Build
20
+
21
+ ```bash
22
+ yarn build
23
+ ```
24
+
25
+ This command generates static content into the `build` directory and can be served using any static contents hosting service.
26
+
27
+ ## Deployment
28
+
29
+ Using SSH:
30
+
31
+ ```bash
32
+ USE_SSH=true yarn deploy
33
+ ```
34
+
35
+ Not using SSH:
36
+
37
+ ```bash
38
+ GIT_USER=<Your GitHub username> yarn deploy
39
+ ```
40
+
41
+ If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch.
@@ -0,0 +1,12 @@
1
+ ---
2
+ slug: first-blog-post
3
+ title: First Blog Post
4
+ authors: [slorber, yangshun]
5
+ tags: [hola, docusaurus]
6
+ ---
7
+
8
+ Lorem ipsum dolor sit amet...
9
+
10
+ <!-- truncate -->
11
+
12
+ ...consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
@@ -0,0 +1,44 @@
1
+ ---
2
+ slug: long-blog-post
3
+ title: Long Blog Post
4
+ authors: yangshun
5
+ tags: [hello, docusaurus]
6
+ ---
7
+
8
+ This is the summary of a very long blog post,
9
+
10
+ Use a `<!--` `truncate` `-->` comment to limit blog post size in the list view.
11
+
12
+ <!-- truncate -->
13
+
14
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
15
+
16
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
17
+
18
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
19
+
20
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
21
+
22
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
23
+
24
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
25
+
26
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
27
+
28
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
29
+
30
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
31
+
32
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
33
+
34
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
35
+
36
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
37
+
38
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
39
+
40
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
41
+
42
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
43
+
44
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet