synapse-sdk 1.0.0a11__py3-none-any.whl → 2026.1.1b2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of synapse-sdk might be problematic. Click here for more details.
- synapse_sdk/__init__.py +24 -0
- synapse_sdk/cli/__init__.py +9 -8
- synapse_sdk/cli/agent/__init__.py +25 -0
- synapse_sdk/cli/agent/config.py +104 -0
- synapse_sdk/cli/agent/select.py +197 -0
- synapse_sdk/cli/auth.py +104 -0
- synapse_sdk/cli/main.py +1025 -0
- synapse_sdk/cli/plugin/__init__.py +58 -0
- synapse_sdk/cli/plugin/create.py +566 -0
- synapse_sdk/cli/plugin/job.py +196 -0
- synapse_sdk/cli/plugin/publish.py +322 -0
- synapse_sdk/cli/plugin/run.py +131 -0
- synapse_sdk/cli/plugin/test.py +200 -0
- synapse_sdk/clients/README.md +239 -0
- synapse_sdk/clients/__init__.py +5 -0
- synapse_sdk/clients/_template.py +266 -0
- synapse_sdk/clients/agent/__init__.py +84 -29
- synapse_sdk/clients/agent/async_ray.py +289 -0
- synapse_sdk/clients/agent/container.py +83 -0
- synapse_sdk/clients/agent/plugin.py +101 -0
- synapse_sdk/clients/agent/ray.py +296 -39
- synapse_sdk/clients/backend/__init__.py +152 -12
- synapse_sdk/clients/backend/annotation.py +164 -22
- synapse_sdk/clients/backend/core.py +101 -0
- synapse_sdk/clients/backend/data_collection.py +292 -0
- synapse_sdk/clients/backend/hitl.py +87 -0
- synapse_sdk/clients/backend/integration.py +374 -46
- synapse_sdk/clients/backend/ml.py +134 -22
- synapse_sdk/clients/backend/models.py +247 -0
- synapse_sdk/clients/base.py +538 -59
- synapse_sdk/clients/exceptions.py +35 -7
- synapse_sdk/clients/pipeline/__init__.py +5 -0
- synapse_sdk/clients/pipeline/client.py +636 -0
- synapse_sdk/clients/protocols.py +178 -0
- synapse_sdk/clients/utils.py +86 -8
- synapse_sdk/clients/validation.py +58 -0
- synapse_sdk/enums.py +76 -0
- synapse_sdk/exceptions.py +168 -0
- synapse_sdk/integrations/__init__.py +74 -0
- synapse_sdk/integrations/_base.py +119 -0
- synapse_sdk/integrations/_context.py +53 -0
- synapse_sdk/integrations/ultralytics/__init__.py +78 -0
- synapse_sdk/integrations/ultralytics/_callbacks.py +126 -0
- synapse_sdk/integrations/ultralytics/_patches.py +124 -0
- synapse_sdk/loggers.py +476 -95
- synapse_sdk/mcp/MCP.md +69 -0
- synapse_sdk/mcp/__init__.py +48 -0
- synapse_sdk/mcp/__main__.py +6 -0
- synapse_sdk/mcp/config.py +349 -0
- synapse_sdk/mcp/prompts/__init__.py +4 -0
- synapse_sdk/mcp/resources/__init__.py +4 -0
- synapse_sdk/mcp/server.py +1352 -0
- synapse_sdk/mcp/tools/__init__.py +6 -0
- synapse_sdk/plugins/__init__.py +133 -9
- synapse_sdk/plugins/action.py +229 -0
- synapse_sdk/plugins/actions/__init__.py +82 -0
- synapse_sdk/plugins/actions/dataset/__init__.py +37 -0
- synapse_sdk/plugins/actions/dataset/action.py +471 -0
- synapse_sdk/plugins/actions/export/__init__.py +55 -0
- synapse_sdk/plugins/actions/export/action.py +183 -0
- synapse_sdk/plugins/actions/export/context.py +59 -0
- synapse_sdk/plugins/actions/inference/__init__.py +84 -0
- synapse_sdk/plugins/actions/inference/action.py +285 -0
- synapse_sdk/plugins/actions/inference/context.py +81 -0
- synapse_sdk/plugins/actions/inference/deployment.py +322 -0
- synapse_sdk/plugins/actions/inference/serve.py +252 -0
- synapse_sdk/plugins/actions/train/__init__.py +54 -0
- synapse_sdk/plugins/actions/train/action.py +326 -0
- synapse_sdk/plugins/actions/train/context.py +57 -0
- synapse_sdk/plugins/actions/upload/__init__.py +49 -0
- synapse_sdk/plugins/actions/upload/action.py +165 -0
- synapse_sdk/plugins/actions/upload/context.py +61 -0
- synapse_sdk/plugins/config.py +98 -0
- synapse_sdk/plugins/context/__init__.py +109 -0
- synapse_sdk/plugins/context/env.py +113 -0
- synapse_sdk/plugins/datasets/__init__.py +113 -0
- synapse_sdk/plugins/datasets/converters/__init__.py +76 -0
- synapse_sdk/plugins/datasets/converters/base.py +347 -0
- synapse_sdk/plugins/datasets/converters/yolo/__init__.py +9 -0
- synapse_sdk/plugins/datasets/converters/yolo/from_dm.py +468 -0
- synapse_sdk/plugins/datasets/converters/yolo/to_dm.py +381 -0
- synapse_sdk/plugins/datasets/formats/__init__.py +82 -0
- synapse_sdk/plugins/datasets/formats/dm.py +351 -0
- synapse_sdk/plugins/datasets/formats/yolo.py +240 -0
- synapse_sdk/plugins/decorators.py +83 -0
- synapse_sdk/plugins/discovery.py +790 -0
- synapse_sdk/plugins/docs/ACTION_DEV_GUIDE.md +933 -0
- synapse_sdk/plugins/docs/ARCHITECTURE.md +1225 -0
- synapse_sdk/plugins/docs/LOGGING_SYSTEM.md +683 -0
- synapse_sdk/plugins/docs/OVERVIEW.md +531 -0
- synapse_sdk/plugins/docs/PIPELINE_GUIDE.md +145 -0
- synapse_sdk/plugins/docs/README.md +513 -0
- synapse_sdk/plugins/docs/STEP.md +656 -0
- synapse_sdk/plugins/enums.py +70 -10
- synapse_sdk/plugins/errors.py +92 -0
- synapse_sdk/plugins/executors/__init__.py +43 -0
- synapse_sdk/plugins/executors/local.py +99 -0
- synapse_sdk/plugins/executors/ray/__init__.py +18 -0
- synapse_sdk/plugins/executors/ray/base.py +282 -0
- synapse_sdk/plugins/executors/ray/job.py +298 -0
- synapse_sdk/plugins/executors/ray/jobs_api.py +511 -0
- synapse_sdk/plugins/executors/ray/packaging.py +137 -0
- synapse_sdk/plugins/executors/ray/pipeline.py +792 -0
- synapse_sdk/plugins/executors/ray/task.py +257 -0
- synapse_sdk/plugins/models/__init__.py +26 -0
- synapse_sdk/plugins/models/logger.py +173 -0
- synapse_sdk/plugins/models/pipeline.py +25 -0
- synapse_sdk/plugins/pipelines/__init__.py +81 -0
- synapse_sdk/plugins/pipelines/action_pipeline.py +417 -0
- synapse_sdk/plugins/pipelines/context.py +107 -0
- synapse_sdk/plugins/pipelines/display.py +311 -0
- synapse_sdk/plugins/runner.py +114 -0
- synapse_sdk/plugins/schemas/__init__.py +19 -0
- synapse_sdk/plugins/schemas/results.py +152 -0
- synapse_sdk/plugins/steps/__init__.py +63 -0
- synapse_sdk/plugins/steps/base.py +128 -0
- synapse_sdk/plugins/steps/context.py +90 -0
- synapse_sdk/plugins/steps/orchestrator.py +128 -0
- synapse_sdk/plugins/steps/registry.py +103 -0
- synapse_sdk/plugins/steps/utils/__init__.py +20 -0
- synapse_sdk/plugins/steps/utils/logging.py +85 -0
- synapse_sdk/plugins/steps/utils/timing.py +71 -0
- synapse_sdk/plugins/steps/utils/validation.py +68 -0
- synapse_sdk/plugins/templates/__init__.py +50 -0
- synapse_sdk/plugins/templates/base/.gitignore.j2 +26 -0
- synapse_sdk/plugins/templates/base/.synapseignore.j2 +11 -0
- synapse_sdk/plugins/templates/base/README.md.j2 +26 -0
- synapse_sdk/plugins/templates/base/plugin/__init__.py.j2 +1 -0
- synapse_sdk/plugins/templates/base/pyproject.toml.j2 +14 -0
- synapse_sdk/plugins/templates/base/requirements.txt.j2 +1 -0
- synapse_sdk/plugins/templates/custom/plugin/main.py.j2 +18 -0
- synapse_sdk/plugins/templates/data_validation/plugin/validate.py.j2 +32 -0
- synapse_sdk/plugins/templates/export/plugin/export.py.j2 +36 -0
- synapse_sdk/plugins/templates/neural_net/plugin/inference.py.j2 +36 -0
- synapse_sdk/plugins/templates/neural_net/plugin/train.py.j2 +33 -0
- synapse_sdk/plugins/templates/post_annotation/plugin/post_annotate.py.j2 +32 -0
- synapse_sdk/plugins/templates/pre_annotation/plugin/pre_annotate.py.j2 +32 -0
- synapse_sdk/plugins/templates/smart_tool/plugin/auto_label.py.j2 +44 -0
- synapse_sdk/plugins/templates/upload/plugin/upload.py.j2 +35 -0
- synapse_sdk/plugins/testing/__init__.py +25 -0
- synapse_sdk/plugins/testing/sample_actions.py +98 -0
- synapse_sdk/plugins/types.py +206 -0
- synapse_sdk/plugins/upload.py +595 -64
- synapse_sdk/plugins/utils.py +325 -37
- synapse_sdk/shared/__init__.py +25 -0
- synapse_sdk/utils/__init__.py +1 -0
- synapse_sdk/utils/auth.py +74 -0
- synapse_sdk/utils/file/__init__.py +58 -0
- synapse_sdk/utils/file/archive.py +449 -0
- synapse_sdk/utils/file/checksum.py +167 -0
- synapse_sdk/utils/file/download.py +286 -0
- synapse_sdk/utils/file/io.py +129 -0
- synapse_sdk/utils/file/requirements.py +36 -0
- synapse_sdk/utils/network.py +168 -0
- synapse_sdk/utils/storage/__init__.py +238 -0
- synapse_sdk/utils/storage/config.py +188 -0
- synapse_sdk/utils/storage/errors.py +52 -0
- synapse_sdk/utils/storage/providers/__init__.py +13 -0
- synapse_sdk/utils/storage/providers/base.py +76 -0
- synapse_sdk/utils/storage/providers/gcs.py +168 -0
- synapse_sdk/utils/storage/providers/http.py +250 -0
- synapse_sdk/utils/storage/providers/local.py +126 -0
- synapse_sdk/utils/storage/providers/s3.py +177 -0
- synapse_sdk/utils/storage/providers/sftp.py +208 -0
- synapse_sdk/utils/storage/registry.py +125 -0
- synapse_sdk/utils/websocket.py +99 -0
- synapse_sdk-2026.1.1b2.dist-info/METADATA +715 -0
- synapse_sdk-2026.1.1b2.dist-info/RECORD +172 -0
- {synapse_sdk-1.0.0a11.dist-info → synapse_sdk-2026.1.1b2.dist-info}/WHEEL +1 -1
- synapse_sdk-2026.1.1b2.dist-info/licenses/LICENSE +201 -0
- locale/en/LC_MESSAGES/messages.mo +0 -0
- locale/en/LC_MESSAGES/messages.po +0 -39
- locale/ko/LC_MESSAGES/messages.mo +0 -0
- locale/ko/LC_MESSAGES/messages.po +0 -34
- synapse_sdk/cli/create_plugin.py +0 -10
- synapse_sdk/clients/agent/core.py +0 -7
- synapse_sdk/clients/agent/service.py +0 -15
- synapse_sdk/clients/backend/dataset.py +0 -51
- synapse_sdk/clients/ray/__init__.py +0 -6
- synapse_sdk/clients/ray/core.py +0 -22
- synapse_sdk/clients/ray/serve.py +0 -20
- synapse_sdk/i18n.py +0 -35
- synapse_sdk/plugins/categories/__init__.py +0 -0
- synapse_sdk/plugins/categories/base.py +0 -235
- synapse_sdk/plugins/categories/data_validation/__init__.py +0 -0
- synapse_sdk/plugins/categories/data_validation/actions/__init__.py +0 -0
- synapse_sdk/plugins/categories/data_validation/actions/validation.py +0 -10
- synapse_sdk/plugins/categories/data_validation/templates/config.yaml +0 -3
- synapse_sdk/plugins/categories/data_validation/templates/plugin/__init__.py +0 -0
- synapse_sdk/plugins/categories/data_validation/templates/plugin/validation.py +0 -5
- synapse_sdk/plugins/categories/decorators.py +0 -13
- synapse_sdk/plugins/categories/export/__init__.py +0 -0
- synapse_sdk/plugins/categories/export/actions/__init__.py +0 -0
- synapse_sdk/plugins/categories/export/actions/export.py +0 -10
- synapse_sdk/plugins/categories/import/__init__.py +0 -0
- synapse_sdk/plugins/categories/import/actions/__init__.py +0 -0
- synapse_sdk/plugins/categories/import/actions/import.py +0 -10
- synapse_sdk/plugins/categories/neural_net/__init__.py +0 -0
- synapse_sdk/plugins/categories/neural_net/actions/__init__.py +0 -0
- synapse_sdk/plugins/categories/neural_net/actions/deployment.py +0 -45
- synapse_sdk/plugins/categories/neural_net/actions/inference.py +0 -18
- synapse_sdk/plugins/categories/neural_net/actions/test.py +0 -10
- synapse_sdk/plugins/categories/neural_net/actions/train.py +0 -143
- synapse_sdk/plugins/categories/neural_net/templates/config.yaml +0 -12
- synapse_sdk/plugins/categories/neural_net/templates/plugin/__init__.py +0 -0
- synapse_sdk/plugins/categories/neural_net/templates/plugin/inference.py +0 -4
- synapse_sdk/plugins/categories/neural_net/templates/plugin/test.py +0 -2
- synapse_sdk/plugins/categories/neural_net/templates/plugin/train.py +0 -14
- synapse_sdk/plugins/categories/post_annotation/__init__.py +0 -0
- synapse_sdk/plugins/categories/post_annotation/actions/__init__.py +0 -0
- synapse_sdk/plugins/categories/post_annotation/actions/post_annotation.py +0 -10
- synapse_sdk/plugins/categories/post_annotation/templates/config.yaml +0 -3
- synapse_sdk/plugins/categories/post_annotation/templates/plugin/__init__.py +0 -0
- synapse_sdk/plugins/categories/post_annotation/templates/plugin/post_annotation.py +0 -3
- synapse_sdk/plugins/categories/pre_annotation/__init__.py +0 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/__init__.py +0 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/pre_annotation.py +0 -10
- synapse_sdk/plugins/categories/pre_annotation/templates/config.yaml +0 -3
- synapse_sdk/plugins/categories/pre_annotation/templates/plugin/__init__.py +0 -0
- synapse_sdk/plugins/categories/pre_annotation/templates/plugin/pre_annotation.py +0 -3
- synapse_sdk/plugins/categories/registry.py +0 -16
- synapse_sdk/plugins/categories/smart_tool/__init__.py +0 -0
- synapse_sdk/plugins/categories/smart_tool/actions/__init__.py +0 -0
- synapse_sdk/plugins/categories/smart_tool/actions/auto_label.py +0 -37
- synapse_sdk/plugins/categories/smart_tool/templates/config.yaml +0 -7
- synapse_sdk/plugins/categories/smart_tool/templates/plugin/__init__.py +0 -0
- synapse_sdk/plugins/categories/smart_tool/templates/plugin/auto_label.py +0 -11
- synapse_sdk/plugins/categories/templates.py +0 -32
- synapse_sdk/plugins/cli/__init__.py +0 -21
- synapse_sdk/plugins/cli/publish.py +0 -37
- synapse_sdk/plugins/cli/run.py +0 -67
- synapse_sdk/plugins/exceptions.py +0 -22
- synapse_sdk/plugins/models.py +0 -121
- synapse_sdk/plugins/templates/cookiecutter.json +0 -11
- synapse_sdk/plugins/templates/hooks/post_gen_project.py +0 -3
- synapse_sdk/plugins/templates/hooks/pre_prompt.py +0 -21
- synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/.env +0 -24
- synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/.env.dist +0 -24
- synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/.gitignore +0 -27
- synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/.pre-commit-config.yaml +0 -7
- synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/README.md +0 -5
- synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/config.yaml +0 -6
- synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/main.py +0 -4
- synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/plugin/__init__.py +0 -0
- synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/pyproject.toml +0 -13
- synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/requirements.txt +0 -1
- synapse_sdk/shared/enums.py +0 -8
- synapse_sdk/utils/debug.py +0 -5
- synapse_sdk/utils/file.py +0 -87
- synapse_sdk/utils/module_loading.py +0 -29
- synapse_sdk/utils/pydantic/__init__.py +0 -0
- synapse_sdk/utils/pydantic/config.py +0 -4
- synapse_sdk/utils/pydantic/errors.py +0 -33
- synapse_sdk/utils/pydantic/validators.py +0 -7
- synapse_sdk/utils/storage.py +0 -91
- synapse_sdk/utils/string.py +0 -11
- synapse_sdk-1.0.0a11.dist-info/LICENSE +0 -21
- synapse_sdk-1.0.0a11.dist-info/METADATA +0 -43
- synapse_sdk-1.0.0a11.dist-info/RECORD +0 -111
- {synapse_sdk-1.0.0a11.dist-info → synapse_sdk-2026.1.1b2.dist-info}/entry_points.txt +0 -0
- {synapse_sdk-1.0.0a11.dist-info → synapse_sdk-2026.1.1b2.dist-info}/top_level.txt +0 -0
synapse_sdk/plugins/utils.py
CHANGED
|
@@ -1,50 +1,338 @@
|
|
|
1
|
-
|
|
1
|
+
"""Plugin utilities for configuration parsing and action discovery."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import re
|
|
2
6
|
from pathlib import Path
|
|
7
|
+
from typing import TYPE_CHECKING, Any, get_args, get_origin
|
|
8
|
+
|
|
9
|
+
from pydantic import BaseModel
|
|
10
|
+
from pydantic.fields import FieldInfo
|
|
11
|
+
from pydantic_core import PydanticUndefined
|
|
12
|
+
|
|
13
|
+
from synapse_sdk.plugins.enums import RunMethod
|
|
14
|
+
from synapse_sdk.utils.file.requirements import read_requirements
|
|
15
|
+
|
|
16
|
+
if TYPE_CHECKING:
|
|
17
|
+
from synapse_sdk.plugins.config import PluginConfig
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def get_plugin_actions(config: dict | PluginConfig | Path | str) -> list[str]:
|
|
21
|
+
"""Extract action names from plugin configuration.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
config: Plugin config dict, PluginConfig instance, or path to config.yaml
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
List of action names. Returns empty list on error.
|
|
28
|
+
"""
|
|
29
|
+
from synapse_sdk.plugins.config import PluginConfig
|
|
30
|
+
|
|
31
|
+
if isinstance(config, (str, Path)):
|
|
32
|
+
config = _load_config_from_path(config)
|
|
33
|
+
if isinstance(config, PluginConfig):
|
|
34
|
+
return list(config.actions.keys())
|
|
35
|
+
if isinstance(config, dict):
|
|
36
|
+
return list(config.get('actions', {}).keys())
|
|
37
|
+
return []
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def get_action_method(config: dict | PluginConfig, action: str) -> RunMethod:
|
|
41
|
+
"""Get the run method for an action from config.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
config: Plugin config dict or PluginConfig instance
|
|
45
|
+
action: Action name
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
RunMethod enum value. Defaults to TASK if not found.
|
|
49
|
+
"""
|
|
50
|
+
from synapse_sdk.plugins.config import PluginConfig
|
|
51
|
+
|
|
52
|
+
if isinstance(config, PluginConfig):
|
|
53
|
+
action_config = config.actions.get(action)
|
|
54
|
+
if action_config:
|
|
55
|
+
return action_config.method
|
|
56
|
+
elif isinstance(config, dict):
|
|
57
|
+
actions = config.get('actions', {})
|
|
58
|
+
action_config = actions.get(action, {})
|
|
59
|
+
method = action_config.get('method', 'task')
|
|
60
|
+
return RunMethod(method)
|
|
61
|
+
return RunMethod.TASK
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def get_action_config(config: dict | PluginConfig, action: str) -> dict:
|
|
65
|
+
"""Get the full configuration for a specific action.
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
config: Plugin config dict or PluginConfig instance
|
|
69
|
+
action: Action name
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
Action configuration dictionary
|
|
73
|
+
|
|
74
|
+
Raises:
|
|
75
|
+
KeyError: If action not found
|
|
76
|
+
ValueError: If config type is invalid
|
|
77
|
+
"""
|
|
78
|
+
from synapse_sdk.plugins.config import PluginConfig
|
|
79
|
+
|
|
80
|
+
if isinstance(config, PluginConfig):
|
|
81
|
+
action_cfg = config.actions.get(action)
|
|
82
|
+
if action_cfg:
|
|
83
|
+
return action_cfg.model_dump()
|
|
84
|
+
raise KeyError(f"Action '{action}' not found. Available: {list(config.actions.keys())}")
|
|
85
|
+
elif isinstance(config, dict):
|
|
86
|
+
actions = config.get('actions', {})
|
|
87
|
+
if action in actions:
|
|
88
|
+
return actions[action]
|
|
89
|
+
raise KeyError(f"Action '{action}' not found. Available: {list(actions.keys())}")
|
|
90
|
+
raise ValueError('Invalid config type')
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _load_config_from_path(path: Path | str) -> dict:
|
|
94
|
+
"""Load plugin config from YAML file.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
path: Path to config.yaml or directory containing it
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
Parsed config dictionary
|
|
101
|
+
"""
|
|
102
|
+
import yaml
|
|
103
|
+
|
|
104
|
+
path = Path(path)
|
|
105
|
+
if path.is_dir():
|
|
106
|
+
path = path / 'config.yaml'
|
|
107
|
+
with path.open() as f:
|
|
108
|
+
return yaml.safe_load(f)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
# =============================================================================
|
|
112
|
+
# UI Schema Generation
|
|
113
|
+
# =============================================================================
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def _type_to_formkit(annotation: type | None) -> str:
|
|
117
|
+
"""Convert Python type annotation to FormKit input type.
|
|
118
|
+
|
|
119
|
+
Args:
|
|
120
|
+
annotation: Python type annotation (int, float, str, bool, etc.)
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
FormKit input type string
|
|
124
|
+
"""
|
|
125
|
+
if annotation is None:
|
|
126
|
+
return 'text'
|
|
127
|
+
|
|
128
|
+
# Handle Optional types
|
|
129
|
+
origin = get_origin(annotation)
|
|
130
|
+
if origin is type(None):
|
|
131
|
+
return 'text'
|
|
132
|
+
|
|
133
|
+
# Unwrap Optional/Union types
|
|
134
|
+
if origin is not None:
|
|
135
|
+
args = get_args(annotation)
|
|
136
|
+
# Filter out NoneType for Optional[X]
|
|
137
|
+
non_none_args = [a for a in args if a is not type(None)]
|
|
138
|
+
if non_none_args:
|
|
139
|
+
annotation = non_none_args[0]
|
|
140
|
+
|
|
141
|
+
# Map Python types to FormKit types
|
|
142
|
+
type_map: dict[type, str] = {
|
|
143
|
+
int: 'number',
|
|
144
|
+
float: 'number',
|
|
145
|
+
str: 'text',
|
|
146
|
+
bool: 'checkbox',
|
|
147
|
+
list: 'checkbox', # Multi-select
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return type_map.get(annotation, 'text') # type: ignore[arg-type]
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def _to_label(name: str) -> str:
|
|
154
|
+
"""Convert snake_case field name to Title Case label.
|
|
155
|
+
|
|
156
|
+
Args:
|
|
157
|
+
name: Field name in snake_case (e.g., "batch_size")
|
|
158
|
+
|
|
159
|
+
Returns:
|
|
160
|
+
Human-readable label (e.g., "Batch Size")
|
|
161
|
+
|
|
162
|
+
Example:
|
|
163
|
+
>>> _to_label("batch_size")
|
|
164
|
+
"Batch Size"
|
|
165
|
+
>>> _to_label("learning_rate")
|
|
166
|
+
"Learning Rate"
|
|
167
|
+
"""
|
|
168
|
+
return re.sub(r'_', ' ', name).title()
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def _extract_constraints(field_info: FieldInfo) -> dict[str, Any]:
|
|
172
|
+
"""Extract validation constraints from Pydantic FieldInfo.
|
|
173
|
+
|
|
174
|
+
Converts Pydantic constraints (ge, le, gt, lt) to FormKit validation rules.
|
|
175
|
+
|
|
176
|
+
Args:
|
|
177
|
+
field_info: Pydantic FieldInfo object
|
|
178
|
+
|
|
179
|
+
Returns:
|
|
180
|
+
Dict with min, max, step if applicable
|
|
181
|
+
"""
|
|
182
|
+
constraints: dict[str, Any] = {}
|
|
183
|
+
|
|
184
|
+
# Extract from metadata (Pydantic v2 style)
|
|
185
|
+
for meta in field_info.metadata:
|
|
186
|
+
meta_type = type(meta).__name__
|
|
187
|
+
|
|
188
|
+
if meta_type == 'Ge': # Greater than or equal
|
|
189
|
+
constraints['min'] = meta.ge
|
|
190
|
+
elif meta_type == 'Le': # Less than or equal
|
|
191
|
+
constraints['max'] = meta.le
|
|
192
|
+
elif meta_type == 'Gt': # Greater than (use as min)
|
|
193
|
+
constraints['min'] = meta.gt
|
|
194
|
+
elif meta_type == 'Lt': # Less than (use as max)
|
|
195
|
+
constraints['max'] = meta.lt
|
|
196
|
+
elif meta_type == 'MultipleOf': # Step value
|
|
197
|
+
constraints['step'] = meta.multiple_of
|
|
198
|
+
|
|
199
|
+
return constraints
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def pydantic_to_ui_schema(model: type[BaseModel]) -> list[dict[str, Any]]:
|
|
203
|
+
"""Convert a Pydantic model to FormKit UI schema format.
|
|
204
|
+
|
|
205
|
+
This generates a UI schema compatible with the legacy config.yaml format,
|
|
206
|
+
suitable for rendering forms in the frontend.
|
|
207
|
+
|
|
208
|
+
Args:
|
|
209
|
+
model: Pydantic BaseModel class with field definitions
|
|
210
|
+
|
|
211
|
+
Returns:
|
|
212
|
+
List of FormKit schema items, one per field
|
|
213
|
+
|
|
214
|
+
Example:
|
|
215
|
+
>>> from pydantic import BaseModel, Field
|
|
216
|
+
>>>
|
|
217
|
+
>>> class TrainParams(BaseModel):
|
|
218
|
+
... epochs: int = Field(default=50, ge=1, le=1000)
|
|
219
|
+
... batch_size: int = Field(default=8, ge=1, le=512)
|
|
220
|
+
... learning_rate: float = Field(default=0.001)
|
|
221
|
+
...
|
|
222
|
+
>>> schema = pydantic_to_ui_schema(TrainParams)
|
|
223
|
+
>>> schema[0]
|
|
224
|
+
{
|
|
225
|
+
'$formkit': 'number',
|
|
226
|
+
'name': 'epochs',
|
|
227
|
+
'label': 'Epochs',
|
|
228
|
+
'value': 50,
|
|
229
|
+
'placeholder': 50,
|
|
230
|
+
'min': 1,
|
|
231
|
+
'max': 1000,
|
|
232
|
+
'number': True
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
Custom UI via json_schema_extra:
|
|
236
|
+
>>> class Params(BaseModel):
|
|
237
|
+
... model_size: str = Field(
|
|
238
|
+
... default="medium",
|
|
239
|
+
... json_schema_extra={
|
|
240
|
+
... "formkit": "select",
|
|
241
|
+
... "options": ["small", "medium", "large"],
|
|
242
|
+
... "help": "Model size selection"
|
|
243
|
+
... }
|
|
244
|
+
... )
|
|
245
|
+
"""
|
|
246
|
+
schema: list[dict[str, Any]] = []
|
|
247
|
+
|
|
248
|
+
for name, field_info in model.model_fields.items():
|
|
249
|
+
# Start with basic item structure
|
|
250
|
+
item: dict[str, Any] = {
|
|
251
|
+
'$formkit': _type_to_formkit(field_info.annotation),
|
|
252
|
+
'name': name,
|
|
253
|
+
'label': _to_label(name),
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
# Add default value (check for PydanticUndefined)
|
|
257
|
+
if field_info.default is not PydanticUndefined and field_info.default is not None:
|
|
258
|
+
item['value'] = field_info.default
|
|
259
|
+
item['placeholder'] = field_info.default
|
|
260
|
+
|
|
261
|
+
# Add description as help text
|
|
262
|
+
if field_info.description:
|
|
263
|
+
item['help'] = field_info.description
|
|
264
|
+
|
|
265
|
+
# Check if field is required (no default)
|
|
266
|
+
if field_info.is_required():
|
|
267
|
+
item['required'] = True
|
|
268
|
+
|
|
269
|
+
# Add validation constraints
|
|
270
|
+
constraints = _extract_constraints(field_info)
|
|
271
|
+
item.update(constraints)
|
|
272
|
+
|
|
273
|
+
# Add number flag for numeric types
|
|
274
|
+
if item['$formkit'] == 'number':
|
|
275
|
+
item['number'] = True
|
|
276
|
+
|
|
277
|
+
# Apply custom overrides from json_schema_extra
|
|
278
|
+
if field_info.json_schema_extra:
|
|
279
|
+
extra = field_info.json_schema_extra
|
|
280
|
+
if callable(extra):
|
|
281
|
+
# Handle callable json_schema_extra
|
|
282
|
+
extra_dict: dict[str, Any] = {}
|
|
283
|
+
extra(extra_dict)
|
|
284
|
+
extra = extra_dict
|
|
3
285
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
286
|
+
if isinstance(extra, dict):
|
|
287
|
+
# Override formkit type if specified
|
|
288
|
+
if 'formkit' in extra:
|
|
289
|
+
item['$formkit'] = extra['formkit']
|
|
7
290
|
|
|
291
|
+
# Copy other properties
|
|
292
|
+
for key in ('options', 'help', 'required', 'step', 'min', 'max'):
|
|
293
|
+
if key in extra:
|
|
294
|
+
item[key] = extra[key]
|
|
8
295
|
|
|
9
|
-
|
|
10
|
-
if isinstance(params_data, str):
|
|
11
|
-
try:
|
|
12
|
-
params = json.loads(params_data)
|
|
13
|
-
except json.JSONDecodeError:
|
|
14
|
-
params = get_dict_from_file(params_data)
|
|
15
|
-
else:
|
|
16
|
-
params = params_data
|
|
296
|
+
schema.append(item)
|
|
17
297
|
|
|
18
|
-
|
|
19
|
-
if config_data:
|
|
20
|
-
if isinstance(config_data, str):
|
|
21
|
-
config = read_plugin_config(plugin_path=config_data)
|
|
22
|
-
else:
|
|
23
|
-
config = config_data
|
|
24
|
-
else:
|
|
25
|
-
config = read_plugin_config()
|
|
26
|
-
category = config['category']
|
|
27
|
-
return get_action_class(category, action)(params, config, *args, **kwargs)
|
|
298
|
+
return schema
|
|
28
299
|
|
|
29
300
|
|
|
30
|
-
def
|
|
31
|
-
|
|
32
|
-
|
|
301
|
+
def get_action_ui_schema(
|
|
302
|
+
model: type[BaseModel],
|
|
303
|
+
action_name: str | None = None,
|
|
304
|
+
) -> dict[str, Any]:
|
|
305
|
+
"""Get UI schema for an action's parameters.
|
|
33
306
|
|
|
307
|
+
Returns the schema in the format expected by the backend API.
|
|
34
308
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
309
|
+
Args:
|
|
310
|
+
model: Pydantic model class for action parameters
|
|
311
|
+
action_name: Optional action name for the response
|
|
38
312
|
|
|
313
|
+
Returns:
|
|
314
|
+
Dict with action name and ui_schemas list
|
|
39
315
|
|
|
40
|
-
|
|
41
|
-
|
|
316
|
+
Example:
|
|
317
|
+
>>> schema = get_action_ui_schema(TrainParams, 'train')
|
|
318
|
+
>>> schema
|
|
319
|
+
{
|
|
320
|
+
'action': 'train',
|
|
321
|
+
'ui_schemas': [...]
|
|
322
|
+
}
|
|
323
|
+
"""
|
|
324
|
+
return {
|
|
325
|
+
'action': action_name,
|
|
326
|
+
'ui_schemas': pydantic_to_ui_schema(model),
|
|
327
|
+
}
|
|
42
328
|
|
|
43
329
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
330
|
+
__all__ = [
|
|
331
|
+
'get_plugin_actions',
|
|
332
|
+
'get_action_method',
|
|
333
|
+
'get_action_config',
|
|
334
|
+
'read_requirements',
|
|
335
|
+
# Schema utilities
|
|
336
|
+
'pydantic_to_ui_schema',
|
|
337
|
+
'get_action_ui_schema',
|
|
338
|
+
]
|
synapse_sdk/shared/__init__.py
CHANGED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def needs_sentry_init():
|
|
5
|
+
return os.getenv('SENTRY_DSN') is not None
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def init_sentry():
|
|
9
|
+
import sentry_sdk
|
|
10
|
+
from sentry_sdk.integrations.ray import RayIntegration
|
|
11
|
+
|
|
12
|
+
dsn = os.getenv('SENTRY_DSN')
|
|
13
|
+
if dsn is None:
|
|
14
|
+
return
|
|
15
|
+
|
|
16
|
+
sentry_sdk.init(
|
|
17
|
+
dsn=dsn,
|
|
18
|
+
environment=os.getenv('DEPLOYMENT_TARGET', 'development'),
|
|
19
|
+
integrations=[RayIntegration()],
|
|
20
|
+
send_default_pii=True,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def worker_process_setup_hook(*_, **__):
|
|
25
|
+
init_sentry()
|
synapse_sdk/utils/__init__.py
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Synapse SDK utilities."""
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"""Authentication utilities for SDK."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import os
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import TYPE_CHECKING
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from synapse_sdk.clients.backend import BackendClient
|
|
12
|
+
|
|
13
|
+
# Environment variable names
|
|
14
|
+
ENV_SYNAPSE_HOST = 'SYNAPSE_HOST'
|
|
15
|
+
ENV_SYNAPSE_ACCESS_TOKEN = 'SYNAPSE_ACCESS_TOKEN'
|
|
16
|
+
|
|
17
|
+
# Default host
|
|
18
|
+
DEFAULT_HOST = 'https://api.synapse.sh'
|
|
19
|
+
|
|
20
|
+
# Config file path
|
|
21
|
+
CONFIG_FILE = Path.home() / '.synapse' / 'config.json'
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def load_credentials() -> tuple[str | None, str | None]:
|
|
25
|
+
"""Load credentials from environment or config file.
|
|
26
|
+
|
|
27
|
+
Priority:
|
|
28
|
+
1. Environment variables (SYNAPSE_HOST, SYNAPSE_ACCESS_TOKEN)
|
|
29
|
+
2. Config file (~/.synapse/config.json)
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
Tuple of (host, token). Either may be None if not found.
|
|
33
|
+
"""
|
|
34
|
+
host = os.environ.get(ENV_SYNAPSE_HOST)
|
|
35
|
+
token = os.environ.get(ENV_SYNAPSE_ACCESS_TOKEN)
|
|
36
|
+
|
|
37
|
+
# Fall back to config.json
|
|
38
|
+
if not token and CONFIG_FILE.exists():
|
|
39
|
+
try:
|
|
40
|
+
config = json.loads(CONFIG_FILE.read_text())
|
|
41
|
+
if not host:
|
|
42
|
+
host = config.get('host')
|
|
43
|
+
if not token:
|
|
44
|
+
token = config.get('access_token')
|
|
45
|
+
except (json.JSONDecodeError, OSError):
|
|
46
|
+
pass
|
|
47
|
+
|
|
48
|
+
return host, token
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def create_backend_client() -> BackendClient | None:
|
|
52
|
+
"""Create a BackendClient from environment/credentials if available.
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
BackendClient if credentials are available, None otherwise.
|
|
56
|
+
"""
|
|
57
|
+
host, token = load_credentials()
|
|
58
|
+
|
|
59
|
+
if not token:
|
|
60
|
+
return None
|
|
61
|
+
|
|
62
|
+
from synapse_sdk.clients.backend import BackendClient
|
|
63
|
+
|
|
64
|
+
return BackendClient(base_url=host or DEFAULT_HOST, access_token=token)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
__all__ = [
|
|
68
|
+
'ENV_SYNAPSE_HOST',
|
|
69
|
+
'ENV_SYNAPSE_ACCESS_TOKEN',
|
|
70
|
+
'DEFAULT_HOST',
|
|
71
|
+
'CONFIG_FILE',
|
|
72
|
+
'load_credentials',
|
|
73
|
+
'create_backend_client',
|
|
74
|
+
]
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""File utilities module."""
|
|
2
|
+
|
|
3
|
+
from .archive import (
|
|
4
|
+
ArchiveFilter,
|
|
5
|
+
ProgressCallback,
|
|
6
|
+
create_archive,
|
|
7
|
+
create_archive_from_git,
|
|
8
|
+
extract_archive,
|
|
9
|
+
get_archive_size,
|
|
10
|
+
list_archive_contents,
|
|
11
|
+
)
|
|
12
|
+
from .checksum import (
|
|
13
|
+
HashAlgorithm,
|
|
14
|
+
calculate_checksum,
|
|
15
|
+
calculate_checksum_from_bytes,
|
|
16
|
+
calculate_checksum_from_file_object,
|
|
17
|
+
verify_checksum,
|
|
18
|
+
)
|
|
19
|
+
from .download import (
|
|
20
|
+
adownload_file,
|
|
21
|
+
afiles_url_to_path,
|
|
22
|
+
afiles_url_to_path_from_objs,
|
|
23
|
+
download_file,
|
|
24
|
+
files_url_to_path,
|
|
25
|
+
files_url_to_path_from_objs,
|
|
26
|
+
)
|
|
27
|
+
from .io import get_dict_from_file, get_temp_path
|
|
28
|
+
from .requirements import read_requirements
|
|
29
|
+
|
|
30
|
+
__all__ = [
|
|
31
|
+
# I/O
|
|
32
|
+
'get_temp_path',
|
|
33
|
+
'get_dict_from_file',
|
|
34
|
+
# Download (sync)
|
|
35
|
+
'download_file',
|
|
36
|
+
'files_url_to_path',
|
|
37
|
+
'files_url_to_path_from_objs',
|
|
38
|
+
# Download (async)
|
|
39
|
+
'adownload_file',
|
|
40
|
+
'afiles_url_to_path',
|
|
41
|
+
'afiles_url_to_path_from_objs',
|
|
42
|
+
# Requirements
|
|
43
|
+
'read_requirements',
|
|
44
|
+
# Checksum
|
|
45
|
+
'HashAlgorithm',
|
|
46
|
+
'calculate_checksum',
|
|
47
|
+
'calculate_checksum_from_bytes',
|
|
48
|
+
'calculate_checksum_from_file_object',
|
|
49
|
+
'verify_checksum',
|
|
50
|
+
# Archive
|
|
51
|
+
'ProgressCallback',
|
|
52
|
+
'ArchiveFilter',
|
|
53
|
+
'create_archive',
|
|
54
|
+
'create_archive_from_git',
|
|
55
|
+
'extract_archive',
|
|
56
|
+
'list_archive_contents',
|
|
57
|
+
'get_archive_size',
|
|
58
|
+
]
|