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
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
"""Rich console progress display for pipeline execution.
|
|
2
|
+
|
|
3
|
+
Provides a real-time progress display using the Rich library for
|
|
4
|
+
monitoring pipeline execution in the terminal. Supports both sync and async.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import TYPE_CHECKING
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from collections.abc import AsyncIterator, Iterator
|
|
13
|
+
|
|
14
|
+
from rich.panel import Panel
|
|
15
|
+
|
|
16
|
+
from synapse_sdk.plugins.models.logger import PipelineProgress
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _create_display_panel(
|
|
20
|
+
progress: 'PipelineProgress',
|
|
21
|
+
show_actions: bool = True,
|
|
22
|
+
) -> 'Panel':
|
|
23
|
+
"""Create the Rich display panel for progress."""
|
|
24
|
+
from rich.console import Group
|
|
25
|
+
from rich.panel import Panel
|
|
26
|
+
from rich.progress import BarColumn, Progress, SpinnerColumn, TextColumn
|
|
27
|
+
from rich.table import Table
|
|
28
|
+
|
|
29
|
+
from synapse_sdk.plugins.models.pipeline import ActionStatus, RunStatus
|
|
30
|
+
|
|
31
|
+
# Main progress bar
|
|
32
|
+
main_progress = Progress(
|
|
33
|
+
SpinnerColumn(),
|
|
34
|
+
TextColumn('[bold blue]{task.description}'),
|
|
35
|
+
BarColumn(),
|
|
36
|
+
TextColumn('[progress.percentage]{task.percentage:>3.0f}%'),
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
# Calculate overall progress including current action progress
|
|
40
|
+
total_actions = len(progress.actions) if progress.actions else 1
|
|
41
|
+
completed_actions = sum(1 for a in (progress.actions or []) if a.status == ActionStatus.COMPLETED)
|
|
42
|
+
|
|
43
|
+
# Find current running action and its progress
|
|
44
|
+
current_action_progress = 0.0
|
|
45
|
+
if progress.actions:
|
|
46
|
+
for a in progress.actions:
|
|
47
|
+
if a.status == ActionStatus.RUNNING and a.progress:
|
|
48
|
+
current_action_progress = a.progress
|
|
49
|
+
break
|
|
50
|
+
|
|
51
|
+
if progress.status == RunStatus.COMPLETED:
|
|
52
|
+
percentage = 100.0
|
|
53
|
+
elif progress.status == RunStatus.FAILED:
|
|
54
|
+
percentage = (completed_actions / total_actions) * 100
|
|
55
|
+
else:
|
|
56
|
+
# Include current action's partial progress
|
|
57
|
+
base_progress = (completed_actions / total_actions) * 100
|
|
58
|
+
action_contribution = (current_action_progress / total_actions) * 100
|
|
59
|
+
percentage = base_progress + action_contribution
|
|
60
|
+
|
|
61
|
+
main_progress.add_task(
|
|
62
|
+
description=f'Pipeline: {progress.run_id[:8]}...',
|
|
63
|
+
total=100,
|
|
64
|
+
completed=percentage,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
# Status text
|
|
68
|
+
status_colors = {
|
|
69
|
+
RunStatus.PENDING: 'yellow',
|
|
70
|
+
RunStatus.RUNNING: 'blue',
|
|
71
|
+
RunStatus.COMPLETED: 'green',
|
|
72
|
+
RunStatus.FAILED: 'red',
|
|
73
|
+
RunStatus.CANCELLED: 'orange3',
|
|
74
|
+
}
|
|
75
|
+
status_color = status_colors.get(progress.status, 'white')
|
|
76
|
+
status_text = f'[{status_color}]Status: {progress.status.value.upper()}[/]'
|
|
77
|
+
|
|
78
|
+
if progress.current_action:
|
|
79
|
+
status_text += f' | Current: [cyan]{progress.current_action}[/]'
|
|
80
|
+
|
|
81
|
+
# Find current action's detailed progress message
|
|
82
|
+
current_action_msg = None
|
|
83
|
+
if progress.actions:
|
|
84
|
+
for a in progress.actions:
|
|
85
|
+
if a.status == ActionStatus.RUNNING:
|
|
86
|
+
if a.message:
|
|
87
|
+
current_action_msg = a.message
|
|
88
|
+
elif a.progress_category and a.progress:
|
|
89
|
+
current_action_msg = f'{a.progress_category}: {a.progress * 100:.0f}%'
|
|
90
|
+
break
|
|
91
|
+
|
|
92
|
+
# Build content
|
|
93
|
+
content_parts: list = [main_progress, '', status_text]
|
|
94
|
+
|
|
95
|
+
# Add detailed progress message if available
|
|
96
|
+
if current_action_msg:
|
|
97
|
+
content_parts.append(f'[dim] {current_action_msg}[/]')
|
|
98
|
+
|
|
99
|
+
# Action table (if enabled and actions exist)
|
|
100
|
+
if show_actions and progress.actions:
|
|
101
|
+
action_table = Table(show_header=True, header_style='bold magenta')
|
|
102
|
+
action_table.add_column('#', style='dim', width=3)
|
|
103
|
+
action_table.add_column('Action', min_width=20)
|
|
104
|
+
action_table.add_column('Status', width=12)
|
|
105
|
+
action_table.add_column('Progress', width=15)
|
|
106
|
+
|
|
107
|
+
action_status_icons = {
|
|
108
|
+
ActionStatus.PENDING: '[dim]-[/]',
|
|
109
|
+
ActionStatus.RUNNING: '[blue]...[/]',
|
|
110
|
+
ActionStatus.COMPLETED: '[green]OK[/]',
|
|
111
|
+
ActionStatus.FAILED: '[red]FAIL[/]',
|
|
112
|
+
ActionStatus.SKIPPED: '[yellow]SKIP[/]',
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
for i, action in enumerate(progress.actions):
|
|
116
|
+
icon = action_status_icons.get(action.status, '?')
|
|
117
|
+
if action.message:
|
|
118
|
+
prog_text = action.message
|
|
119
|
+
elif action.progress:
|
|
120
|
+
prog_text = f'{action.progress * 100:.0f}%'
|
|
121
|
+
else:
|
|
122
|
+
prog_text = '-'
|
|
123
|
+
action_table.add_row(
|
|
124
|
+
str(i + 1),
|
|
125
|
+
action.name,
|
|
126
|
+
icon,
|
|
127
|
+
prog_text,
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
content_parts.extend(['', action_table])
|
|
131
|
+
|
|
132
|
+
# Error message (if any)
|
|
133
|
+
if progress.error:
|
|
134
|
+
content_parts.extend(['', f'[red]Error: {progress.error}[/]'])
|
|
135
|
+
|
|
136
|
+
return Panel(
|
|
137
|
+
Group(*content_parts),
|
|
138
|
+
title='[bold]Pipeline Progress[/]',
|
|
139
|
+
border_style='blue' if progress.status == RunStatus.RUNNING else 'green',
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def display_progress(
|
|
144
|
+
progress_stream: 'Iterator[PipelineProgress]',
|
|
145
|
+
*,
|
|
146
|
+
show_actions: bool = True,
|
|
147
|
+
refresh_rate: float = 4.0,
|
|
148
|
+
) -> 'PipelineProgress':
|
|
149
|
+
"""Display pipeline progress in the console using Rich (sync version).
|
|
150
|
+
|
|
151
|
+
Creates a live-updating display showing:
|
|
152
|
+
- Overall pipeline status and progress bar
|
|
153
|
+
- Current action being executed
|
|
154
|
+
- Individual action statuses in a table
|
|
155
|
+
|
|
156
|
+
Args:
|
|
157
|
+
progress_stream: Iterator yielding PipelineProgress updates.
|
|
158
|
+
show_actions: If True, show individual action statuses.
|
|
159
|
+
refresh_rate: Refreshes per second for the live display.
|
|
160
|
+
|
|
161
|
+
Returns:
|
|
162
|
+
Final PipelineProgress after completion.
|
|
163
|
+
|
|
164
|
+
Example:
|
|
165
|
+
>>> from synapse_sdk.plugins.pipelines.display import display_progress
|
|
166
|
+
>>> run_id = executor.submit(pipeline, params)
|
|
167
|
+
>>> final = display_progress(executor.stream_progress(run_id))
|
|
168
|
+
>>> print(f"Completed with status: {final.status}")
|
|
169
|
+
"""
|
|
170
|
+
try:
|
|
171
|
+
from rich.console import Console
|
|
172
|
+
from rich.live import Live
|
|
173
|
+
except ImportError as e:
|
|
174
|
+
raise ImportError('Rich library is required for progress display. Install it with: pip install rich') from e
|
|
175
|
+
|
|
176
|
+
console = Console()
|
|
177
|
+
last_progress: PipelineProgress | None = None
|
|
178
|
+
|
|
179
|
+
with Live(console=console, refresh_per_second=refresh_rate) as live:
|
|
180
|
+
for progress in progress_stream:
|
|
181
|
+
last_progress = progress
|
|
182
|
+
live.update(_create_display_panel(progress, show_actions))
|
|
183
|
+
|
|
184
|
+
if last_progress is None:
|
|
185
|
+
raise RuntimeError('No progress updates received')
|
|
186
|
+
|
|
187
|
+
return last_progress
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
async def display_progress_async(
|
|
191
|
+
progress_stream: 'AsyncIterator[PipelineProgress]',
|
|
192
|
+
*,
|
|
193
|
+
show_actions: bool = True,
|
|
194
|
+
refresh_rate: float = 4.0,
|
|
195
|
+
) -> 'PipelineProgress':
|
|
196
|
+
"""Display pipeline progress in the console using Rich (async version).
|
|
197
|
+
|
|
198
|
+
Creates a live-updating display showing:
|
|
199
|
+
- Overall pipeline status and progress bar
|
|
200
|
+
- Current action being executed
|
|
201
|
+
- Individual action statuses in a table
|
|
202
|
+
|
|
203
|
+
Args:
|
|
204
|
+
progress_stream: AsyncIterator yielding PipelineProgress updates.
|
|
205
|
+
show_actions: If True, show individual action statuses.
|
|
206
|
+
refresh_rate: Refreshes per second for the live display.
|
|
207
|
+
|
|
208
|
+
Returns:
|
|
209
|
+
Final PipelineProgress after completion.
|
|
210
|
+
|
|
211
|
+
Example:
|
|
212
|
+
>>> from synapse_sdk.plugins.pipelines.display import display_progress_async
|
|
213
|
+
>>> run_id = await executor.submit_async(pipeline, params)
|
|
214
|
+
>>> async for progress in executor.stream_progress_async(run_id):
|
|
215
|
+
... # Process updates
|
|
216
|
+
>>> final = await display_progress_async(executor.stream_progress_async(run_id))
|
|
217
|
+
"""
|
|
218
|
+
try:
|
|
219
|
+
from rich.console import Console
|
|
220
|
+
from rich.live import Live
|
|
221
|
+
except ImportError as e:
|
|
222
|
+
raise ImportError('Rich library is required for progress display. Install it with: pip install rich') from e
|
|
223
|
+
|
|
224
|
+
console = Console()
|
|
225
|
+
last_progress: PipelineProgress | None = None
|
|
226
|
+
|
|
227
|
+
with Live(console=console, refresh_per_second=refresh_rate) as live:
|
|
228
|
+
async for progress in progress_stream:
|
|
229
|
+
last_progress = progress
|
|
230
|
+
live.update(_create_display_panel(progress, show_actions))
|
|
231
|
+
|
|
232
|
+
if last_progress is None:
|
|
233
|
+
raise RuntimeError('No progress updates received')
|
|
234
|
+
|
|
235
|
+
return last_progress
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def print_progress_summary(progress: 'PipelineProgress') -> None:
|
|
239
|
+
"""Print a summary of pipeline execution.
|
|
240
|
+
|
|
241
|
+
Args:
|
|
242
|
+
progress: Final pipeline progress to summarize.
|
|
243
|
+
"""
|
|
244
|
+
try:
|
|
245
|
+
from rich.console import Console
|
|
246
|
+
from rich.table import Table
|
|
247
|
+
except ImportError:
|
|
248
|
+
# Fallback to plain print
|
|
249
|
+
print(f'Pipeline {progress.run_id}: {progress.status.value}')
|
|
250
|
+
return
|
|
251
|
+
|
|
252
|
+
console = Console()
|
|
253
|
+
from synapse_sdk.plugins.models.pipeline import ActionStatus, RunStatus
|
|
254
|
+
|
|
255
|
+
# Status emoji
|
|
256
|
+
status_emoji = {
|
|
257
|
+
RunStatus.COMPLETED: '[green]OK[/]',
|
|
258
|
+
RunStatus.FAILED: '[red]FAILED[/]',
|
|
259
|
+
RunStatus.CANCELLED: '[yellow]CANCELLED[/]',
|
|
260
|
+
RunStatus.RUNNING: '[blue]RUNNING[/]',
|
|
261
|
+
RunStatus.PENDING: '[dim]PENDING[/]',
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
console.print()
|
|
265
|
+
console.print(f'[bold]Pipeline:[/] {progress.run_id}')
|
|
266
|
+
console.print(f'[bold]Status:[/] {status_emoji.get(progress.status, progress.status.value)}')
|
|
267
|
+
|
|
268
|
+
if progress.started_at:
|
|
269
|
+
console.print(f'[bold]Started:[/] {progress.started_at.isoformat()}')
|
|
270
|
+
if progress.completed_at:
|
|
271
|
+
console.print(f'[bold]Completed:[/] {progress.completed_at.isoformat()}')
|
|
272
|
+
if progress.started_at:
|
|
273
|
+
duration = progress.completed_at - progress.started_at
|
|
274
|
+
console.print(f'[bold]Duration:[/] {duration}')
|
|
275
|
+
|
|
276
|
+
if progress.actions:
|
|
277
|
+
console.print()
|
|
278
|
+
table = Table(title='Actions', show_header=True)
|
|
279
|
+
table.add_column('Action', style='cyan')
|
|
280
|
+
table.add_column('Status')
|
|
281
|
+
table.add_column('Duration')
|
|
282
|
+
|
|
283
|
+
action_status_style = {
|
|
284
|
+
ActionStatus.COMPLETED: '[green]COMPLETED[/]',
|
|
285
|
+
ActionStatus.FAILED: '[red]FAILED[/]',
|
|
286
|
+
ActionStatus.RUNNING: '[blue]RUNNING[/]',
|
|
287
|
+
ActionStatus.PENDING: '[dim]PENDING[/]',
|
|
288
|
+
ActionStatus.SKIPPED: '[yellow]SKIPPED[/]',
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
for action in progress.actions:
|
|
292
|
+
duration = '-'
|
|
293
|
+
if action.started_at and action.completed_at:
|
|
294
|
+
duration = str(action.completed_at - action.started_at)
|
|
295
|
+
elif action.started_at:
|
|
296
|
+
duration = 'running...'
|
|
297
|
+
|
|
298
|
+
table.add_row(
|
|
299
|
+
action.name,
|
|
300
|
+
action_status_style.get(action.status, str(action.status)),
|
|
301
|
+
duration,
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
console.print(table)
|
|
305
|
+
|
|
306
|
+
if progress.error:
|
|
307
|
+
console.print()
|
|
308
|
+
console.print(f'[red bold]Error:[/] {progress.error}')
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
__all__ = ['display_progress', 'display_progress_async', 'print_progress_summary']
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import importlib
|
|
4
|
+
from collections.abc import Callable
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import TYPE_CHECKING, Any, Literal
|
|
7
|
+
|
|
8
|
+
from synapse_sdk.plugins.discovery import PluginDiscovery
|
|
9
|
+
from synapse_sdk.plugins.executors.local import LocalExecutor
|
|
10
|
+
from synapse_sdk.plugins.executors.ray.job import RayJobExecutor
|
|
11
|
+
from synapse_sdk.plugins.executors.ray.task import RayActorExecutor
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from synapse_sdk.plugins.action import BaseAction
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _discover_action(plugin_code: str, action: str) -> type[BaseAction] | Callable:
|
|
18
|
+
"""Discover action class from plugin code.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
plugin_code: Either a module path ('my_plugins.yolov8') or
|
|
22
|
+
a filesystem path to config.yaml ('/path/to/plugin')
|
|
23
|
+
action: Action name to load
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
Action class or decorated function
|
|
27
|
+
"""
|
|
28
|
+
path = Path(plugin_code)
|
|
29
|
+
|
|
30
|
+
# Check if it's a filesystem path (config.yaml or directory)
|
|
31
|
+
if path.exists() or (path.parent.exists() and path.suffix == '.yaml'):
|
|
32
|
+
discovery = PluginDiscovery.from_path(path)
|
|
33
|
+
else:
|
|
34
|
+
# Treat as module path - import and introspect
|
|
35
|
+
module = importlib.import_module(plugin_code)
|
|
36
|
+
discovery = PluginDiscovery.from_module(module)
|
|
37
|
+
|
|
38
|
+
return discovery.get_action_class(action)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def run_plugin(
|
|
42
|
+
plugin_code: str,
|
|
43
|
+
action: str,
|
|
44
|
+
params: dict[str, Any] | None = None,
|
|
45
|
+
*,
|
|
46
|
+
mode: Literal['local', 'task', 'job'] = 'local',
|
|
47
|
+
**executor_kwargs: Any,
|
|
48
|
+
) -> Any:
|
|
49
|
+
"""Run a plugin action.
|
|
50
|
+
|
|
51
|
+
This is the main entry point for executing plugin actions. It handles
|
|
52
|
+
plugin discovery, parameter validation, and execution delegation to
|
|
53
|
+
the appropriate executor based on the mode.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
plugin_code: Plugin identifier. Can be:
|
|
57
|
+
- Module path: 'my_plugins.yolov8' (discovers via @action decorators or BaseAction classes)
|
|
58
|
+
- Filesystem path: '/path/to/plugin' or '/path/to/config.yaml'
|
|
59
|
+
action: Action name to execute (e.g., 'train', 'infer', 'export').
|
|
60
|
+
params: Action parameters as a dictionary. Will be validated against
|
|
61
|
+
the action's params schema if defined.
|
|
62
|
+
mode: Execution mode:
|
|
63
|
+
- 'local': Run in the current process (default, good for dev).
|
|
64
|
+
- 'task': Run via Ray Actor pool (fast startup, <1s).
|
|
65
|
+
- 'job': Run via Ray Job API (for heavy/long-running workloads).
|
|
66
|
+
**executor_kwargs: Additional executor options:
|
|
67
|
+
- action_cls: Optional explicit action class (skips discovery).
|
|
68
|
+
- env: PluginEnvironment or dict for environment config.
|
|
69
|
+
- job_id: Optional job identifier for tracking.
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
For 'local' and 'task' modes: Action result (type depends on the action).
|
|
73
|
+
For 'job' mode: Job ID string for tracking (async submission).
|
|
74
|
+
|
|
75
|
+
Raises:
|
|
76
|
+
ActionNotFoundError: If the action doesn't exist in the plugin.
|
|
77
|
+
ValidationError: If params fail schema validation.
|
|
78
|
+
ExecutionError: If action execution fails.
|
|
79
|
+
|
|
80
|
+
Example:
|
|
81
|
+
>>> from synapse_sdk.plugins.runner import run_plugin
|
|
82
|
+
>>>
|
|
83
|
+
>>> # Auto-discover from module path
|
|
84
|
+
>>> result = run_plugin('my_plugins.yolov8', 'train', {'epochs': 10})
|
|
85
|
+
>>>
|
|
86
|
+
>>> # Auto-discover from config.yaml path
|
|
87
|
+
>>> result = run_plugin('/path/to/plugin', 'train', {'epochs': 10})
|
|
88
|
+
>>>
|
|
89
|
+
>>> # Explicit action class (skips discovery)
|
|
90
|
+
>>> result = run_plugin('yolov8', 'train', {'epochs': 10}, action_cls=TrainAction)
|
|
91
|
+
"""
|
|
92
|
+
params = params or {}
|
|
93
|
+
|
|
94
|
+
if mode == 'local':
|
|
95
|
+
action_cls = executor_kwargs.pop('action_cls', None)
|
|
96
|
+
if action_cls is None:
|
|
97
|
+
action_cls = _discover_action(plugin_code, action)
|
|
98
|
+
executor = LocalExecutor(**executor_kwargs)
|
|
99
|
+
return executor.execute(action_cls, params)
|
|
100
|
+
|
|
101
|
+
elif mode == 'task':
|
|
102
|
+
action_cls = executor_kwargs.pop('action_cls', None)
|
|
103
|
+
if action_cls is None:
|
|
104
|
+
action_cls = _discover_action(plugin_code, action)
|
|
105
|
+
executor = RayActorExecutor(**executor_kwargs)
|
|
106
|
+
return executor.execute(action_cls, params)
|
|
107
|
+
|
|
108
|
+
else: # mode == 'job'
|
|
109
|
+
executor = RayJobExecutor(**executor_kwargs)
|
|
110
|
+
# Job mode is async - submit and return job_id
|
|
111
|
+
return executor.submit(action, params)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
__all__ = ['run_plugin']
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""Common schema types for plugin actions."""
|
|
2
|
+
|
|
3
|
+
from synapse_sdk.plugins.schemas.results import (
|
|
4
|
+
ExportResult,
|
|
5
|
+
InferenceResult,
|
|
6
|
+
MetricsResult,
|
|
7
|
+
TrainResult,
|
|
8
|
+
UploadResult,
|
|
9
|
+
WeightsResult,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
'ExportResult',
|
|
14
|
+
'InferenceResult',
|
|
15
|
+
'MetricsResult',
|
|
16
|
+
'TrainResult',
|
|
17
|
+
'UploadResult',
|
|
18
|
+
'WeightsResult',
|
|
19
|
+
]
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"""Common result types for plugin actions.
|
|
2
|
+
|
|
3
|
+
These provide standardized schemas for common action outputs.
|
|
4
|
+
Plugin developers can use these directly or extend them for
|
|
5
|
+
custom result types.
|
|
6
|
+
|
|
7
|
+
Example usage:
|
|
8
|
+
>>> from synapse_sdk.plugins import BaseTrainAction
|
|
9
|
+
>>> from synapse_sdk.plugins.schemas import TrainResult
|
|
10
|
+
>>>
|
|
11
|
+
>>> class MyTrainAction(BaseTrainAction[MyParams, TrainResult]):
|
|
12
|
+
... def execute(self) -> TrainResult:
|
|
13
|
+
... return TrainResult(
|
|
14
|
+
... weights_path='/models/best.pt',
|
|
15
|
+
... final_epoch=100,
|
|
16
|
+
... train_metrics={'loss': 0.05},
|
|
17
|
+
... val_metrics={'mAP50': 0.85},
|
|
18
|
+
... )
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from __future__ import annotations
|
|
22
|
+
|
|
23
|
+
from typing import Any
|
|
24
|
+
|
|
25
|
+
from pydantic import BaseModel, Field
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class WeightsResult(BaseModel):
|
|
29
|
+
"""Result type for actions that produce model weights.
|
|
30
|
+
|
|
31
|
+
Use this for actions that output trained model weights.
|
|
32
|
+
|
|
33
|
+
Example:
|
|
34
|
+
>>> class TrainAction(BaseAction[TrainParams, WeightsResult]):
|
|
35
|
+
... def execute(self) -> WeightsResult:
|
|
36
|
+
... return WeightsResult(
|
|
37
|
+
... weights_path='/models/best.pt',
|
|
38
|
+
... checkpoint_paths=['/models/epoch_10.pt'],
|
|
39
|
+
... )
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
weights_path: str = Field(description='Path to the best/final model weights')
|
|
43
|
+
checkpoint_paths: list[str] = Field(default_factory=list, description='Paths to intermediate checkpoints')
|
|
44
|
+
format: str = Field(default='pt', description='Weights format (pt, onnx, safetensors, etc.)')
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class MetricsResult(BaseModel):
|
|
48
|
+
"""Result type for actions that produce metrics only.
|
|
49
|
+
|
|
50
|
+
Use this for evaluation/testing actions that output metrics.
|
|
51
|
+
|
|
52
|
+
Example:
|
|
53
|
+
>>> class EvalAction(BaseAction[EvalParams, MetricsResult]):
|
|
54
|
+
... def execute(self) -> MetricsResult:
|
|
55
|
+
... return MetricsResult(
|
|
56
|
+
... metrics={'mAP50': 0.85, 'mAP50-95': 0.72},
|
|
57
|
+
... category='validation',
|
|
58
|
+
... )
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
metrics: dict[str, float] = Field(description='Metric name to value mapping')
|
|
62
|
+
category: str = Field(default='default', description='Metrics category (train, validation, test)')
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class TrainResult(BaseModel):
|
|
66
|
+
"""Combined result type for training actions.
|
|
67
|
+
|
|
68
|
+
Includes both weights and training metrics. Use this for
|
|
69
|
+
standard training workflows.
|
|
70
|
+
|
|
71
|
+
Example:
|
|
72
|
+
>>> class TrainAction(BaseTrainAction[TrainParams, TrainResult]):
|
|
73
|
+
... def execute(self) -> TrainResult:
|
|
74
|
+
... return TrainResult(
|
|
75
|
+
... weights_path='/models/best.pt',
|
|
76
|
+
... final_epoch=100,
|
|
77
|
+
... best_epoch=85,
|
|
78
|
+
... train_metrics={'loss': 0.05},
|
|
79
|
+
... val_metrics={'mAP50': 0.85, 'mAP50-95': 0.72},
|
|
80
|
+
... )
|
|
81
|
+
"""
|
|
82
|
+
|
|
83
|
+
weights_path: str = Field(description='Path to trained model weights')
|
|
84
|
+
final_epoch: int = Field(description='Last completed epoch')
|
|
85
|
+
best_epoch: int | None = Field(default=None, description='Best epoch by validation metric')
|
|
86
|
+
train_metrics: dict[str, float] = Field(default_factory=dict, description='Final training metrics')
|
|
87
|
+
val_metrics: dict[str, float] = Field(default_factory=dict, description='Final validation metrics')
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class InferenceResult(BaseModel):
|
|
91
|
+
"""Result type for inference actions.
|
|
92
|
+
|
|
93
|
+
Generic container for inference outputs.
|
|
94
|
+
|
|
95
|
+
Example:
|
|
96
|
+
>>> class InferAction(BaseInferenceAction[InferParams, InferenceResult]):
|
|
97
|
+
... def execute(self) -> InferenceResult:
|
|
98
|
+
... return InferenceResult(
|
|
99
|
+
... predictions=[{'class': 'dog', 'confidence': 0.95}],
|
|
100
|
+
... processed_count=100,
|
|
101
|
+
... )
|
|
102
|
+
"""
|
|
103
|
+
|
|
104
|
+
predictions: list[dict[str, Any]] = Field(default_factory=list, description='List of prediction results')
|
|
105
|
+
processed_count: int = Field(default=0, description='Number of items processed')
|
|
106
|
+
output_path: str | None = Field(default=None, description='Path to output file if results were saved')
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
class ExportResult(BaseModel):
|
|
110
|
+
"""Result type for export actions.
|
|
111
|
+
|
|
112
|
+
Example:
|
|
113
|
+
>>> class ExportAction(BaseExportAction[ExportParams, ExportResult]):
|
|
114
|
+
... def execute(self) -> ExportResult:
|
|
115
|
+
... return ExportResult(
|
|
116
|
+
... output_path='/exports/dataset.zip',
|
|
117
|
+
... exported_count=1000,
|
|
118
|
+
... format='coco',
|
|
119
|
+
... )
|
|
120
|
+
"""
|
|
121
|
+
|
|
122
|
+
output_path: str = Field(description='Path to exported file/directory')
|
|
123
|
+
exported_count: int = Field(description='Number of items exported')
|
|
124
|
+
format: str = Field(description='Export format (coco, yolo, voc, csv, etc.)')
|
|
125
|
+
file_size_bytes: int | None = Field(default=None, description='Size of exported file in bytes')
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class UploadResult(BaseModel):
|
|
129
|
+
"""Result type for upload actions.
|
|
130
|
+
|
|
131
|
+
Example:
|
|
132
|
+
>>> class UploadAction(BaseUploadAction[UploadParams, UploadResult]):
|
|
133
|
+
... def execute(self) -> UploadResult:
|
|
134
|
+
... return UploadResult(
|
|
135
|
+
... uploaded_count=500,
|
|
136
|
+
... remote_path='s3://bucket/dataset/',
|
|
137
|
+
... )
|
|
138
|
+
"""
|
|
139
|
+
|
|
140
|
+
uploaded_count: int = Field(description='Number of items uploaded')
|
|
141
|
+
remote_path: str | None = Field(default=None, description='Remote path or URL where data was uploaded')
|
|
142
|
+
status: str = Field(default='completed', description='Upload status')
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
__all__ = [
|
|
146
|
+
'ExportResult',
|
|
147
|
+
'InferenceResult',
|
|
148
|
+
'MetricsResult',
|
|
149
|
+
'TrainResult',
|
|
150
|
+
'UploadResult',
|
|
151
|
+
'WeightsResult',
|
|
152
|
+
]
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""Step workflow module for Synapse SDK.
|
|
2
|
+
|
|
3
|
+
This module provides the core abstractions for building step-based workflows.
|
|
4
|
+
Classes here are not pipeline-specific and can be used standalone for any
|
|
5
|
+
action-based workflow.
|
|
6
|
+
|
|
7
|
+
Classes:
|
|
8
|
+
BaseStep: Abstract base class for implementing individual steps.
|
|
9
|
+
StepResult: Data class representing the result of a step execution.
|
|
10
|
+
BaseStepContext: Context shared between steps during execution.
|
|
11
|
+
StepRegistry: Registry for managing step registration and ordering.
|
|
12
|
+
Orchestrator: Executes steps in order and handles rollback on failure.
|
|
13
|
+
|
|
14
|
+
Utility Steps:
|
|
15
|
+
LoggingStep: Wrapper that adds logging to step execution.
|
|
16
|
+
TimingStep: Wrapper that adds timing measurement to step execution.
|
|
17
|
+
ValidationStep: Wrapper that adds pre-execution validation to steps.
|
|
18
|
+
|
|
19
|
+
Example:
|
|
20
|
+
>>> from synapse_sdk.plugins.steps import (
|
|
21
|
+
... BaseStep,
|
|
22
|
+
... BaseStepContext,
|
|
23
|
+
... Orchestrator,
|
|
24
|
+
... StepRegistry,
|
|
25
|
+
... StepResult,
|
|
26
|
+
... )
|
|
27
|
+
>>>
|
|
28
|
+
>>> @dataclass
|
|
29
|
+
... class MyContext(BaseStepContext):
|
|
30
|
+
... data: list[str] = field(default_factory=list)
|
|
31
|
+
>>>
|
|
32
|
+
>>> class LoadStep(BaseStep[MyContext]):
|
|
33
|
+
... @property
|
|
34
|
+
... def name(self) -> str:
|
|
35
|
+
... return 'load'
|
|
36
|
+
...
|
|
37
|
+
... @property
|
|
38
|
+
... def progress_weight(self) -> float:
|
|
39
|
+
... return 0.3
|
|
40
|
+
...
|
|
41
|
+
... def execute(self, context: MyContext) -> StepResult:
|
|
42
|
+
... context.data.append('loaded')
|
|
43
|
+
... return StepResult(success=True)
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
from synapse_sdk.plugins.steps.base import BaseStep, StepResult
|
|
47
|
+
from synapse_sdk.plugins.steps.context import BaseStepContext
|
|
48
|
+
from synapse_sdk.plugins.steps.orchestrator import Orchestrator
|
|
49
|
+
from synapse_sdk.plugins.steps.registry import StepRegistry
|
|
50
|
+
from synapse_sdk.plugins.steps.utils import LoggingStep, TimingStep, ValidationStep
|
|
51
|
+
|
|
52
|
+
__all__ = [
|
|
53
|
+
# Core
|
|
54
|
+
'BaseStep',
|
|
55
|
+
'BaseStepContext',
|
|
56
|
+
'Orchestrator',
|
|
57
|
+
'StepRegistry',
|
|
58
|
+
'StepResult',
|
|
59
|
+
# Utilities
|
|
60
|
+
'LoggingStep',
|
|
61
|
+
'TimingStep',
|
|
62
|
+
'ValidationStep',
|
|
63
|
+
]
|