synapse-sdk 1.0.0a23__py3-none-any.whl → 2025.12.3__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.
- synapse_sdk/__init__.py +24 -0
- synapse_sdk/cli/__init__.py +310 -5
- synapse_sdk/cli/alias/__init__.py +22 -0
- synapse_sdk/cli/alias/create.py +36 -0
- synapse_sdk/cli/alias/dataclass.py +31 -0
- synapse_sdk/cli/alias/default.py +16 -0
- synapse_sdk/cli/alias/delete.py +15 -0
- synapse_sdk/cli/alias/list.py +19 -0
- synapse_sdk/cli/alias/read.py +15 -0
- synapse_sdk/cli/alias/update.py +17 -0
- synapse_sdk/cli/alias/utils.py +61 -0
- synapse_sdk/cli/code_server.py +687 -0
- synapse_sdk/cli/config.py +440 -0
- synapse_sdk/cli/devtools.py +90 -0
- synapse_sdk/cli/plugin/__init__.py +33 -0
- synapse_sdk/cli/{create_plugin.py → plugin/create.py} +2 -2
- synapse_sdk/{plugins/cli → cli/plugin}/publish.py +23 -15
- synapse_sdk/clients/agent/__init__.py +9 -3
- synapse_sdk/clients/agent/container.py +143 -0
- synapse_sdk/clients/agent/core.py +19 -0
- synapse_sdk/clients/agent/ray.py +298 -9
- synapse_sdk/clients/backend/__init__.py +30 -12
- synapse_sdk/clients/backend/annotation.py +13 -5
- synapse_sdk/clients/backend/core.py +31 -4
- synapse_sdk/clients/backend/data_collection.py +186 -0
- synapse_sdk/clients/backend/hitl.py +17 -0
- synapse_sdk/clients/backend/integration.py +16 -1
- synapse_sdk/clients/backend/ml.py +5 -1
- synapse_sdk/clients/backend/models.py +78 -0
- synapse_sdk/clients/base.py +384 -41
- synapse_sdk/clients/ray/serve.py +2 -0
- synapse_sdk/clients/validators/collections.py +31 -0
- synapse_sdk/devtools/config.py +94 -0
- synapse_sdk/devtools/server.py +41 -0
- synapse_sdk/devtools/streamlit_app/__init__.py +5 -0
- synapse_sdk/devtools/streamlit_app/app.py +128 -0
- synapse_sdk/devtools/streamlit_app/services/__init__.py +11 -0
- synapse_sdk/devtools/streamlit_app/services/job_service.py +233 -0
- synapse_sdk/devtools/streamlit_app/services/plugin_service.py +236 -0
- synapse_sdk/devtools/streamlit_app/services/serve_service.py +95 -0
- synapse_sdk/devtools/streamlit_app/ui/__init__.py +15 -0
- synapse_sdk/devtools/streamlit_app/ui/config_tab.py +76 -0
- synapse_sdk/devtools/streamlit_app/ui/deployment_tab.py +66 -0
- synapse_sdk/devtools/streamlit_app/ui/http_tab.py +125 -0
- synapse_sdk/devtools/streamlit_app/ui/jobs_tab.py +573 -0
- synapse_sdk/devtools/streamlit_app/ui/serve_tab.py +346 -0
- synapse_sdk/devtools/streamlit_app/ui/status_bar.py +118 -0
- synapse_sdk/devtools/streamlit_app/utils/__init__.py +40 -0
- synapse_sdk/devtools/streamlit_app/utils/json_viewer.py +197 -0
- synapse_sdk/devtools/streamlit_app/utils/log_formatter.py +38 -0
- synapse_sdk/devtools/streamlit_app/utils/styles.py +241 -0
- synapse_sdk/devtools/streamlit_app/utils/ui_components.py +289 -0
- synapse_sdk/devtools/streamlit_app.py +10 -0
- synapse_sdk/loggers.py +120 -9
- synapse_sdk/plugins/README.md +1340 -0
- synapse_sdk/plugins/__init__.py +0 -13
- synapse_sdk/plugins/categories/base.py +117 -11
- synapse_sdk/plugins/categories/data_validation/actions/validation.py +72 -0
- synapse_sdk/plugins/categories/data_validation/templates/plugin/validation.py +33 -5
- synapse_sdk/plugins/categories/export/actions/__init__.py +3 -0
- synapse_sdk/plugins/categories/export/actions/export/__init__.py +28 -0
- synapse_sdk/plugins/categories/export/actions/export/action.py +165 -0
- synapse_sdk/plugins/categories/export/actions/export/enums.py +113 -0
- synapse_sdk/plugins/categories/export/actions/export/exceptions.py +53 -0
- synapse_sdk/plugins/categories/export/actions/export/models.py +74 -0
- synapse_sdk/plugins/categories/export/actions/export/run.py +195 -0
- synapse_sdk/plugins/categories/export/actions/export/utils.py +187 -0
- synapse_sdk/plugins/categories/export/templates/config.yaml +21 -0
- synapse_sdk/plugins/categories/export/templates/plugin/__init__.py +390 -0
- synapse_sdk/plugins/categories/export/templates/plugin/export.py +160 -0
- synapse_sdk/plugins/categories/neural_net/actions/deployment.py +13 -12
- synapse_sdk/plugins/categories/neural_net/actions/train.py +1134 -31
- synapse_sdk/plugins/categories/neural_net/actions/tune.py +534 -0
- synapse_sdk/plugins/categories/neural_net/base/inference.py +1 -1
- synapse_sdk/plugins/categories/neural_net/templates/config.yaml +32 -4
- synapse_sdk/plugins/categories/neural_net/templates/plugin/inference.py +26 -10
- synapse_sdk/plugins/categories/pre_annotation/actions/__init__.py +4 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/pre_annotation/__init__.py +3 -0
- synapse_sdk/plugins/categories/{export/actions/export.py → pre_annotation/actions/pre_annotation/action.py} +4 -4
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/__init__.py +28 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/action.py +148 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/enums.py +269 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/exceptions.py +14 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/factory.py +76 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/models.py +100 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/orchestrator.py +248 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/run.py +64 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/__init__.py +17 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/annotation.py +265 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/base.py +170 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/extraction.py +83 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/metrics.py +92 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/preprocessor.py +243 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/validation.py +143 -0
- synapse_sdk/plugins/categories/pre_annotation/templates/config.yaml +19 -0
- synapse_sdk/plugins/categories/pre_annotation/templates/plugin/to_task.py +40 -0
- synapse_sdk/plugins/categories/smart_tool/templates/config.yaml +2 -0
- synapse_sdk/plugins/categories/upload/__init__.py +0 -0
- synapse_sdk/plugins/categories/upload/actions/__init__.py +0 -0
- synapse_sdk/plugins/categories/upload/actions/upload/__init__.py +19 -0
- synapse_sdk/plugins/categories/upload/actions/upload/action.py +236 -0
- synapse_sdk/plugins/categories/upload/actions/upload/context.py +185 -0
- synapse_sdk/plugins/categories/upload/actions/upload/enums.py +493 -0
- synapse_sdk/plugins/categories/upload/actions/upload/exceptions.py +36 -0
- synapse_sdk/plugins/categories/upload/actions/upload/factory.py +138 -0
- synapse_sdk/plugins/categories/upload/actions/upload/models.py +214 -0
- synapse_sdk/plugins/categories/upload/actions/upload/orchestrator.py +183 -0
- synapse_sdk/plugins/categories/upload/actions/upload/registry.py +113 -0
- synapse_sdk/plugins/categories/upload/actions/upload/run.py +179 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/__init__.py +1 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/base.py +107 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/cleanup.py +62 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/collection.py +63 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/generate.py +91 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/initialize.py +82 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/metadata.py +235 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/organize.py +201 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/upload.py +104 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/validate.py +71 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/__init__.py +1 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/base.py +82 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/data_unit/__init__.py +1 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/data_unit/batch.py +39 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/data_unit/single.py +29 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/file_discovery/__init__.py +1 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/file_discovery/flat.py +300 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/file_discovery/recursive.py +287 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/metadata/__init__.py +1 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/metadata/excel.py +174 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/metadata/none.py +16 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/upload/__init__.py +1 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/upload/sync.py +84 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/validation/__init__.py +1 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/validation/default.py +60 -0
- synapse_sdk/plugins/categories/upload/actions/upload/utils.py +250 -0
- synapse_sdk/plugins/categories/upload/templates/README.md +470 -0
- synapse_sdk/plugins/categories/upload/templates/config.yaml +33 -0
- synapse_sdk/plugins/categories/upload/templates/plugin/__init__.py +310 -0
- synapse_sdk/plugins/categories/upload/templates/plugin/upload.py +102 -0
- synapse_sdk/plugins/enums.py +3 -1
- synapse_sdk/plugins/models.py +148 -11
- synapse_sdk/plugins/templates/plugin-config-schema.json +406 -0
- synapse_sdk/plugins/templates/schema.json +491 -0
- synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/config.yaml +1 -0
- synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/requirements.txt +1 -1
- synapse_sdk/plugins/utils/__init__.py +46 -0
- synapse_sdk/plugins/utils/actions.py +119 -0
- synapse_sdk/plugins/utils/config.py +203 -0
- synapse_sdk/plugins/{utils.py → utils/legacy.py} +26 -46
- synapse_sdk/plugins/utils/ray_gcs.py +66 -0
- synapse_sdk/plugins/utils/registry.py +58 -0
- synapse_sdk/shared/__init__.py +25 -0
- synapse_sdk/shared/enums.py +93 -0
- synapse_sdk/types.py +19 -0
- synapse_sdk/utils/converters/__init__.py +240 -0
- synapse_sdk/utils/converters/coco/__init__.py +0 -0
- synapse_sdk/utils/converters/coco/from_dm.py +322 -0
- synapse_sdk/utils/converters/coco/to_dm.py +215 -0
- synapse_sdk/utils/converters/dm/__init__.py +57 -0
- synapse_sdk/utils/converters/dm/base.py +137 -0
- synapse_sdk/utils/converters/dm/from_v1.py +273 -0
- synapse_sdk/utils/converters/dm/to_v1.py +321 -0
- synapse_sdk/utils/converters/dm/tools/__init__.py +214 -0
- synapse_sdk/utils/converters/dm/tools/answer.py +95 -0
- synapse_sdk/utils/converters/dm/tools/bounding_box.py +132 -0
- synapse_sdk/utils/converters/dm/tools/bounding_box_3d.py +121 -0
- synapse_sdk/utils/converters/dm/tools/classification.py +75 -0
- synapse_sdk/utils/converters/dm/tools/keypoint.py +117 -0
- synapse_sdk/utils/converters/dm/tools/named_entity.py +111 -0
- synapse_sdk/utils/converters/dm/tools/polygon.py +122 -0
- synapse_sdk/utils/converters/dm/tools/polyline.py +124 -0
- synapse_sdk/utils/converters/dm/tools/prompt.py +94 -0
- synapse_sdk/utils/converters/dm/tools/relation.py +86 -0
- synapse_sdk/utils/converters/dm/tools/segmentation.py +141 -0
- synapse_sdk/utils/converters/dm/tools/segmentation_3d.py +83 -0
- synapse_sdk/utils/converters/dm/types.py +168 -0
- synapse_sdk/utils/converters/dm/utils.py +162 -0
- synapse_sdk/utils/converters/dm_legacy/__init__.py +56 -0
- synapse_sdk/utils/converters/dm_legacy/from_v1.py +627 -0
- synapse_sdk/utils/converters/dm_legacy/to_v1.py +367 -0
- synapse_sdk/utils/converters/pascal/__init__.py +0 -0
- synapse_sdk/utils/converters/pascal/from_dm.py +244 -0
- synapse_sdk/utils/converters/pascal/to_dm.py +214 -0
- synapse_sdk/utils/converters/yolo/__init__.py +0 -0
- synapse_sdk/utils/converters/yolo/from_dm.py +384 -0
- synapse_sdk/utils/converters/yolo/to_dm.py +267 -0
- synapse_sdk/utils/dataset.py +46 -0
- synapse_sdk/utils/encryption.py +158 -0
- synapse_sdk/utils/file/__init__.py +58 -0
- synapse_sdk/utils/file/archive.py +32 -0
- synapse_sdk/utils/file/checksum.py +56 -0
- synapse_sdk/utils/file/chunking.py +31 -0
- synapse_sdk/utils/file/download.py +385 -0
- synapse_sdk/utils/file/encoding.py +40 -0
- synapse_sdk/utils/file/io.py +22 -0
- synapse_sdk/utils/file/upload.py +165 -0
- synapse_sdk/utils/file/video/__init__.py +29 -0
- synapse_sdk/utils/file/video/transcode.py +307 -0
- synapse_sdk/utils/file.py.backup +301 -0
- synapse_sdk/utils/http.py +138 -0
- synapse_sdk/utils/network.py +309 -0
- synapse_sdk/utils/storage/__init__.py +72 -0
- synapse_sdk/utils/storage/providers/__init__.py +183 -0
- synapse_sdk/utils/storage/providers/file_system.py +134 -0
- synapse_sdk/utils/storage/providers/gcp.py +13 -0
- synapse_sdk/utils/storage/providers/http.py +190 -0
- synapse_sdk/utils/storage/providers/s3.py +91 -0
- synapse_sdk/utils/storage/providers/sftp.py +47 -0
- synapse_sdk/utils/storage/registry.py +17 -0
- synapse_sdk-2025.12.3.dist-info/METADATA +123 -0
- synapse_sdk-2025.12.3.dist-info/RECORD +279 -0
- {synapse_sdk-1.0.0a23.dist-info → synapse_sdk-2025.12.3.dist-info}/WHEEL +1 -1
- synapse_sdk/clients/backend/dataset.py +0 -51
- synapse_sdk/plugins/categories/import/actions/import.py +0 -10
- synapse_sdk/plugins/cli/__init__.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/main.py +0 -4
- synapse_sdk/utils/file.py +0 -168
- synapse_sdk/utils/storage.py +0 -91
- synapse_sdk-1.0.0a23.dist-info/METADATA +0 -44
- synapse_sdk-1.0.0a23.dist-info/RECORD +0 -114
- /synapse_sdk/{plugins/cli → cli/plugin}/run.py +0 -0
- /synapse_sdk/{plugins/categories/import → clients/validators}/__init__.py +0 -0
- /synapse_sdk/{plugins/categories/import/actions → devtools}/__init__.py +0 -0
- {synapse_sdk-1.0.0a23.dist-info → synapse_sdk-2025.12.3.dist-info}/entry_points.txt +0 -0
- {synapse_sdk-1.0.0a23.dist-info → synapse_sdk-2025.12.3.dist-info/licenses}/LICENSE +0 -0
- {synapse_sdk-1.0.0a23.dist-info → synapse_sdk-2025.12.3.dist-info}/top_level.txt +0 -0
synapse_sdk/__init__.py
CHANGED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Export / Import Guidelines
|
|
3
|
+
--------------------------
|
|
4
|
+
|
|
5
|
+
1. Do NOT import the top-level package directly.
|
|
6
|
+
- All imports must start from at least two levels below the root package.
|
|
7
|
+
(e.g., `project.module.submodule` is allowed,
|
|
8
|
+
`project` 또는 `project.module` 단일 import는 금지)
|
|
9
|
+
|
|
10
|
+
2. Wildcard import (`from x import *`) is strictly prohibited.
|
|
11
|
+
- 모든 외부 노출(export)은 명시적인 이름 기반으로 관리해야 한다.
|
|
12
|
+
- `__all__` 리스트를 통해 공개할 API를 명확히 정의할 것.
|
|
13
|
+
|
|
14
|
+
3. Public API 를 구성할 때:
|
|
15
|
+
- 하위 모듈에서 export할 항목만 `__all__`에 선언한다.
|
|
16
|
+
- 내부 구현용 함수/클래스는 `_` prefix 를 사용하거나 `__all__`에 포함하지 않는다.
|
|
17
|
+
|
|
18
|
+
4. 모듈 간 의존성은 최단 경로만 허용한다.
|
|
19
|
+
- 불필요한 상위/평행 패키지 import 경로는 금지하여 순환 의존성(circular dependency)을 방지한다.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from synapse_sdk.shared import worker_process_setup_hook
|
|
23
|
+
|
|
24
|
+
__all__ = ['worker_process_setup_hook']
|
synapse_sdk/cli/__init__.py
CHANGED
|
@@ -1,11 +1,316 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
1
3
|
import click
|
|
4
|
+
import inquirer
|
|
5
|
+
import requests
|
|
6
|
+
|
|
7
|
+
from .code_server import code_server
|
|
8
|
+
from .config import config
|
|
9
|
+
from .devtools import devtools
|
|
10
|
+
from .plugin import plugin
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def clear_screen():
|
|
14
|
+
"""Clear the terminal screen"""
|
|
15
|
+
os.system('cls' if os.name == 'nt' else 'clear')
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def check_backend_status():
|
|
19
|
+
"""Check backend connection status and token validity"""
|
|
20
|
+
from synapse_sdk.devtools.config import get_backend_config
|
|
21
|
+
|
|
22
|
+
backend_config = get_backend_config()
|
|
23
|
+
if not backend_config:
|
|
24
|
+
return 'not_configured', 'No backend configured'
|
|
25
|
+
|
|
26
|
+
try:
|
|
27
|
+
# Try an authenticated endpoint to verify token validity
|
|
28
|
+
# Use /users/me/ which requires authentication
|
|
29
|
+
response = requests.get(
|
|
30
|
+
f'{backend_config["host"]}/users/me/',
|
|
31
|
+
headers={'Synapse-Access-Token': f'Token {backend_config["token"]}'},
|
|
32
|
+
timeout=5,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
if response.status_code == 200:
|
|
36
|
+
return 'healthy', f'Connected to {backend_config["host"]}'
|
|
37
|
+
elif response.status_code == 401:
|
|
38
|
+
return 'auth_error', 'Invalid token (401)'
|
|
39
|
+
elif response.status_code == 403:
|
|
40
|
+
return 'forbidden', 'Access forbidden (403)'
|
|
41
|
+
elif response.status_code == 404:
|
|
42
|
+
# If /users/me/ doesn't exist, try /health as fallback
|
|
43
|
+
try:
|
|
44
|
+
health_response = requests.get(
|
|
45
|
+
f'{backend_config["host"]}/health',
|
|
46
|
+
headers={'Synapse-Access-Token': f'Token {backend_config["token"]}'},
|
|
47
|
+
timeout=3,
|
|
48
|
+
)
|
|
49
|
+
if health_response.status_code == 200:
|
|
50
|
+
return 'healthy', f'Connected to {backend_config["host"]}'
|
|
51
|
+
elif health_response.status_code == 401:
|
|
52
|
+
return 'auth_error', 'Invalid token (401)'
|
|
53
|
+
elif health_response.status_code == 403:
|
|
54
|
+
return 'forbidden', 'Access forbidden (403)'
|
|
55
|
+
else:
|
|
56
|
+
return 'error', f'HTTP {health_response.status_code}'
|
|
57
|
+
except: # noqa: E722
|
|
58
|
+
return 'error', 'Endpoint not found (404)'
|
|
59
|
+
else:
|
|
60
|
+
return 'error', f'HTTP {response.status_code}'
|
|
61
|
+
|
|
62
|
+
except requests.exceptions.Timeout:
|
|
63
|
+
return 'timeout', 'Connection timeout (>5s)'
|
|
64
|
+
except requests.exceptions.ConnectionError:
|
|
65
|
+
return 'connection_error', 'Connection failed'
|
|
66
|
+
except Exception as e:
|
|
67
|
+
return 'error', f'Connection error: {str(e)}'
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def check_agent_status():
|
|
71
|
+
"""Check agent configuration status"""
|
|
72
|
+
from synapse_sdk.devtools.config import load_devtools_config
|
|
73
|
+
|
|
74
|
+
config = load_devtools_config()
|
|
75
|
+
agent_config = config.get('agent', {})
|
|
76
|
+
|
|
77
|
+
if not agent_config.get('id'):
|
|
78
|
+
return 'not_configured', 'No agent selected'
|
|
79
|
+
|
|
80
|
+
return 'configured', f'{agent_config.get("name", "")} (ID: {agent_config["id"]})'
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def display_connection_status():
|
|
84
|
+
"""Display connection status for backend and agent"""
|
|
85
|
+
click.echo(click.style('Connection Status:', fg='white', bold=True))
|
|
86
|
+
|
|
87
|
+
# Check backend status (async with timeout)
|
|
88
|
+
backend_status, backend_msg = check_backend_status()
|
|
89
|
+
|
|
90
|
+
# Backend status with specific handling for auth errors
|
|
91
|
+
if backend_status == 'healthy':
|
|
92
|
+
click.echo(f'🟢 Backend: {click.style(backend_msg, fg="green")}')
|
|
93
|
+
elif backend_status == 'not_configured':
|
|
94
|
+
click.echo(f'🔴 Backend: {click.style(backend_msg, fg="yellow")}')
|
|
95
|
+
elif backend_status in ['auth_error', 'forbidden']:
|
|
96
|
+
click.echo(f'🔴 Backend: {click.style(backend_msg, fg="red", bold=True)}')
|
|
97
|
+
else:
|
|
98
|
+
click.echo(f'🔴 Backend: {click.style(backend_msg, fg="red")}')
|
|
99
|
+
|
|
100
|
+
# Agent status (config check only, no network call)
|
|
101
|
+
agent_status, agent_msg = check_agent_status()
|
|
102
|
+
if agent_status == 'configured':
|
|
103
|
+
click.echo(f'🟢 Agent: {click.style(agent_msg, fg="green")}')
|
|
104
|
+
else:
|
|
105
|
+
click.echo(f'🔴 Agent: {click.style(agent_msg, fg="yellow")}')
|
|
106
|
+
|
|
107
|
+
click.echo() # Empty line for spacing
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def run_devtools(build=True):
|
|
111
|
+
"""Run devtools with default settings"""
|
|
112
|
+
# Import the devtools command and run it
|
|
113
|
+
from .devtools import devtools
|
|
114
|
+
|
|
115
|
+
# Use default settings
|
|
116
|
+
ctx = click.Context(devtools)
|
|
117
|
+
ctx.invoke(devtools, host=None, port=None, debug=False)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
# build_frontend function removed - no longer needed with Streamlit
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def run_config():
|
|
124
|
+
"""Run the configuration menu"""
|
|
125
|
+
from .config import interactive_config
|
|
126
|
+
|
|
127
|
+
interactive_config()
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def run_plugin_management():
|
|
131
|
+
"""Run interactive plugin management"""
|
|
132
|
+
while True:
|
|
133
|
+
clear_screen()
|
|
134
|
+
click.echo(click.style('🔌 Plugin Management', fg='cyan', bold=True))
|
|
135
|
+
click.echo('Manage your Synapse plugins\n')
|
|
136
|
+
|
|
137
|
+
questions = [
|
|
138
|
+
inquirer.List(
|
|
139
|
+
'action',
|
|
140
|
+
message='What would you like to do?',
|
|
141
|
+
choices=[
|
|
142
|
+
('Create new plugin', 'create'),
|
|
143
|
+
('Run plugin locally', 'run'),
|
|
144
|
+
('Publish plugin', 'publish'),
|
|
145
|
+
('← Back to main menu', 'back'),
|
|
146
|
+
],
|
|
147
|
+
)
|
|
148
|
+
]
|
|
149
|
+
|
|
150
|
+
answers = inquirer.prompt(questions)
|
|
151
|
+
if not answers or answers['action'] == 'back':
|
|
152
|
+
clear_screen()
|
|
153
|
+
break
|
|
154
|
+
|
|
155
|
+
if answers['action'] == 'create':
|
|
156
|
+
click.echo('\nCreating new plugin...')
|
|
157
|
+
from .plugin.create import create
|
|
158
|
+
|
|
159
|
+
ctx = click.Context(create)
|
|
160
|
+
ctx.invoke(create)
|
|
161
|
+
click.echo('\nPress Enter to continue...')
|
|
162
|
+
input()
|
|
163
|
+
|
|
164
|
+
elif answers['action'] == 'run':
|
|
165
|
+
# Get plugin action and parameters
|
|
166
|
+
run_questions = [
|
|
167
|
+
inquirer.Text('action', message='Plugin action to run'),
|
|
168
|
+
inquirer.Text('params', message='Parameters (JSON format)', default='{}'),
|
|
169
|
+
inquirer.List(
|
|
170
|
+
'run_by',
|
|
171
|
+
message='Run by',
|
|
172
|
+
choices=[
|
|
173
|
+
('Script (local)', 'script'),
|
|
174
|
+
('Agent', 'agent'),
|
|
175
|
+
('Backend', 'backend'),
|
|
176
|
+
],
|
|
177
|
+
default='script',
|
|
178
|
+
),
|
|
179
|
+
]
|
|
180
|
+
|
|
181
|
+
run_answers = inquirer.prompt(run_questions)
|
|
182
|
+
if run_answers:
|
|
183
|
+
click.echo('\nRunning plugin...')
|
|
184
|
+
from .plugin.run import run
|
|
185
|
+
|
|
186
|
+
ctx = click.Context(run)
|
|
187
|
+
ctx.obj = {'DEBUG': False}
|
|
188
|
+
|
|
189
|
+
try:
|
|
190
|
+
if run_answers['run_by'] == 'script':
|
|
191
|
+
ctx.invoke(
|
|
192
|
+
run,
|
|
193
|
+
action=run_answers['action'],
|
|
194
|
+
params=run_answers['params'],
|
|
195
|
+
job_id=None,
|
|
196
|
+
direct=False,
|
|
197
|
+
run_by='script',
|
|
198
|
+
agent_host=None,
|
|
199
|
+
agent_token=None,
|
|
200
|
+
host=None,
|
|
201
|
+
agent=None,
|
|
202
|
+
user_token=None,
|
|
203
|
+
tenant=None,
|
|
204
|
+
)
|
|
205
|
+
else:
|
|
206
|
+
click.echo(click.style('\nNote: For agent/backend runs, use the command line:', fg='yellow'))
|
|
207
|
+
cmd = (
|
|
208
|
+
f"synapse plugin run {run_answers['action']} '{run_answers['params']}' "
|
|
209
|
+
f'--run-by {run_answers["run_by"]}'
|
|
210
|
+
)
|
|
211
|
+
click.echo(cmd)
|
|
212
|
+
except Exception as e:
|
|
213
|
+
click.echo(click.style(f'\nError: {str(e)}', fg='red'))
|
|
214
|
+
|
|
215
|
+
click.echo('\nPress Enter to continue...')
|
|
216
|
+
input()
|
|
217
|
+
|
|
218
|
+
elif answers['action'] == 'publish':
|
|
219
|
+
# Get backend configuration
|
|
220
|
+
from synapse_sdk.devtools.config import get_backend_config
|
|
221
|
+
|
|
222
|
+
backend_config = get_backend_config()
|
|
223
|
+
|
|
224
|
+
if not backend_config:
|
|
225
|
+
click.echo(click.style('\n⚠ No backend configured. Please configure backend first.', fg='yellow'))
|
|
226
|
+
click.echo('\nPress Enter to continue...')
|
|
227
|
+
input()
|
|
228
|
+
continue
|
|
229
|
+
|
|
230
|
+
publish_questions = [
|
|
231
|
+
inquirer.Confirm('debug', message='Publish in debug mode?', default=True),
|
|
232
|
+
inquirer.Confirm('confirm', message=f'Publish plugin to {backend_config["host"]}?', default=True),
|
|
233
|
+
]
|
|
234
|
+
|
|
235
|
+
publish_answers = inquirer.prompt(publish_questions)
|
|
236
|
+
if publish_answers and publish_answers['confirm']:
|
|
237
|
+
click.echo('\nPublishing plugin...')
|
|
238
|
+
from .plugin.publish import _publish
|
|
239
|
+
|
|
240
|
+
debug_mode = publish_answers.get('debug', True)
|
|
241
|
+
try:
|
|
242
|
+
_publish(backend_config['host'], backend_config['token'], debug=debug_mode)
|
|
243
|
+
except Exception as e:
|
|
244
|
+
click.echo(click.style(f'\nError: {str(e)}', fg='red'))
|
|
245
|
+
click.echo('\nPress Enter to continue...')
|
|
246
|
+
input()
|
|
247
|
+
else:
|
|
248
|
+
click.echo('\nPress Enter to continue...')
|
|
249
|
+
input()
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
@click.group(invoke_without_command=True)
|
|
253
|
+
@click.option('--dev-tools', is_flag=True, help='Start devtools immediately')
|
|
254
|
+
@click.pass_context
|
|
255
|
+
def cli(ctx, dev_tools):
|
|
256
|
+
"""Synapse SDK - Interactive CLI"""
|
|
257
|
+
|
|
258
|
+
# Handle --dev-tools flag
|
|
259
|
+
if dev_tools:
|
|
260
|
+
run_devtools()
|
|
261
|
+
return
|
|
262
|
+
|
|
263
|
+
if ctx.invoked_subcommand is None:
|
|
264
|
+
while True:
|
|
265
|
+
clear_screen() # Always clear screen at start of main menu loop
|
|
266
|
+
click.echo(click.style('🚀 Synapse SDK', fg='cyan', bold=True))
|
|
267
|
+
click.echo()
|
|
268
|
+
|
|
269
|
+
try:
|
|
270
|
+
questions = [
|
|
271
|
+
inquirer.List(
|
|
272
|
+
'choice',
|
|
273
|
+
message='Select an option:',
|
|
274
|
+
choices=[
|
|
275
|
+
('🌐 Run Dev Tools', 'devtools'),
|
|
276
|
+
('💻 Open Code-Server IDE', 'code_server'),
|
|
277
|
+
('⚙️ Configuration', 'config'),
|
|
278
|
+
('🔌 Plugin Management', 'plugin'),
|
|
279
|
+
('🚪 Exit', 'exit'),
|
|
280
|
+
],
|
|
281
|
+
)
|
|
282
|
+
]
|
|
283
|
+
|
|
284
|
+
answers = inquirer.prompt(questions)
|
|
285
|
+
if not answers or answers['choice'] == 'exit':
|
|
286
|
+
clear_screen()
|
|
287
|
+
click.echo(click.style('👋 Goodbye!', fg='green'))
|
|
288
|
+
break
|
|
2
289
|
|
|
3
|
-
|
|
290
|
+
if answers['choice'] == 'devtools':
|
|
291
|
+
run_devtools()
|
|
292
|
+
break # Exit after devtools finishes
|
|
293
|
+
elif answers['choice'] == 'code_server':
|
|
294
|
+
from .code_server import code_server
|
|
4
295
|
|
|
296
|
+
ctx.invoke(code_server)
|
|
297
|
+
click.echo('\nPress Enter to return to main menu...')
|
|
298
|
+
input()
|
|
299
|
+
# Continue to main menu loop
|
|
300
|
+
elif answers['choice'] == 'config':
|
|
301
|
+
run_config()
|
|
302
|
+
# Config menu returned, continue to main menu loop
|
|
303
|
+
elif answers['choice'] == 'plugin':
|
|
304
|
+
run_plugin_management()
|
|
305
|
+
# Don't break - continue to main menu loop
|
|
5
306
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
307
|
+
except (KeyboardInterrupt, EOFError):
|
|
308
|
+
clear_screen()
|
|
309
|
+
click.echo(click.style('👋 Goodbye!', fg='yellow'))
|
|
310
|
+
break
|
|
9
311
|
|
|
10
312
|
|
|
11
|
-
cli.add_command(
|
|
313
|
+
cli.add_command(plugin)
|
|
314
|
+
cli.add_command(config)
|
|
315
|
+
cli.add_command(devtools)
|
|
316
|
+
cli.add_command(code_server)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import click
|
|
2
|
+
|
|
3
|
+
from .create import create
|
|
4
|
+
from .default import default
|
|
5
|
+
from .delete import delete
|
|
6
|
+
from .list import list as list_cli
|
|
7
|
+
from .read import read
|
|
8
|
+
from .update import update
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@click.group()
|
|
12
|
+
def alias():
|
|
13
|
+
"""Manage aliases"""
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
alias.add_command(list_cli)
|
|
18
|
+
alias.add_command(create)
|
|
19
|
+
alias.add_command(read)
|
|
20
|
+
alias.add_command(update)
|
|
21
|
+
alias.add_command(delete)
|
|
22
|
+
alias.add_command(default)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import click
|
|
2
|
+
|
|
3
|
+
from .dataclass import ENV_VARS
|
|
4
|
+
from .utils import CONFIG_DIR, DEFAULT_FILE, ensure_config_dir, save_alias_field, set_default_alias
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@click.command()
|
|
8
|
+
def create():
|
|
9
|
+
"""Create a new alias."""
|
|
10
|
+
ensure_config_dir()
|
|
11
|
+
name = click.prompt('Enter alias name (eg. prod, test)', type=str)
|
|
12
|
+
alias_file = CONFIG_DIR / f'{name}.env'
|
|
13
|
+
if alias_file.exists():
|
|
14
|
+
click.echo(f"Alias '{name}' already exists.")
|
|
15
|
+
return
|
|
16
|
+
if alias_file.name == DEFAULT_FILE.name:
|
|
17
|
+
click.echo(f"Invalid alias name '{name}'.")
|
|
18
|
+
return
|
|
19
|
+
|
|
20
|
+
alias_data = {}
|
|
21
|
+
|
|
22
|
+
for key, value in ENV_VARS.items():
|
|
23
|
+
prompt_kwargs = {'text': value.name, 'type': value.type, 'show_default': value.show_default}
|
|
24
|
+
if bool(value.default):
|
|
25
|
+
prompt_kwargs['default'] = alias_data[value.default]
|
|
26
|
+
|
|
27
|
+
alias_data[key] = click.prompt(**prompt_kwargs)
|
|
28
|
+
|
|
29
|
+
for key, value in alias_data.items():
|
|
30
|
+
save_alias_field(name, key, value)
|
|
31
|
+
|
|
32
|
+
# Set the default alias if it is the first alias created
|
|
33
|
+
if not DEFAULT_FILE.exists():
|
|
34
|
+
set_default_alias(name)
|
|
35
|
+
|
|
36
|
+
click.echo(f"Alias '{name}' created.")
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import Union
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@dataclass
|
|
6
|
+
class EnvVar:
|
|
7
|
+
name: str
|
|
8
|
+
type = str
|
|
9
|
+
default: Union[str, None] = None
|
|
10
|
+
show_default: bool = True
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
ENV_VARS = {
|
|
14
|
+
'RAY_ADDRESS': EnvVar('RAY_ADDRESS'),
|
|
15
|
+
'RAY_DASHBOARD_ADDRESS': EnvVar('RAY_DASHBOARD_ADDRESS'),
|
|
16
|
+
'RAY_SERVE_ADDRESS': EnvVar('RAY_SERVE_ADDRESS'),
|
|
17
|
+
'SYNAPSE_PLUGIN_STORAGE': EnvVar('SYNAPSE_PLUGIN_STORAGE', default='', show_default=False),
|
|
18
|
+
'SYNAPSE_DEBUG_PLUGIN_PATH': EnvVar('SYNAPSE_DEBUG_PLUGIN_PATH', default='', show_default=False),
|
|
19
|
+
'SYNAPSE_DEBUG_MODULES': EnvVar('SYNAPSE_DEBUG_MODULES', default='', show_default=False),
|
|
20
|
+
'SYNAPSE_PLUGIN_PUBLISH_HOST': EnvVar('SYNAPSE_PLUGIN_PUBLISH_HOST'),
|
|
21
|
+
'SYNAPSE_PLUGIN_PUBLISH_USER_TOKEN': EnvVar('SYNAPSE_PLUGIN_PUBLISH_USER_TOKEN'),
|
|
22
|
+
'SYNAPSE_PLUGIN_PUBLISH_TENANT': EnvVar('SYNAPSE_PLUGIN_PUBLISH_TENANT'),
|
|
23
|
+
'SYNAPSE_PLUGIN_RUN_HOST': EnvVar('SYNAPSE_PLUGIN_RUN_HOST', default='SYNAPSE_PLUGIN_PUBLISH_HOST'),
|
|
24
|
+
'SYNAPSE_PLUGIN_RUN_AGENT': EnvVar('SYNAPSE_PLUGIN_RUN_AGENT', default='', show_default=False),
|
|
25
|
+
'SYNAPSE_PLUGIN_RUN_AGENT_TOKEN': EnvVar('SYNAPSE_PLUGIN_RUN_AGENT_TOKEN'),
|
|
26
|
+
'SYNAPSE_PLUGIN_RUN_AGENT_HOST': EnvVar('SYNAPSE_PLUGIN_RUN_AGENT_HOST'),
|
|
27
|
+
'SYNAPSE_PLUGIN_RUN_USER_TOKEN': EnvVar(
|
|
28
|
+
'SYNAPSE_PLUGIN_RUN_USER_TOKEN', default='SYNAPSE_PLUGIN_PUBLISH_USER_TOKEN'
|
|
29
|
+
),
|
|
30
|
+
'SYNAPSE_PLUGIN_RUN_TENANT': EnvVar('SYNAPSE_PLUGIN_RUN_TENANT', default='SYNAPSE_PLUGIN_PUBLISH_TENANT'),
|
|
31
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import click
|
|
2
|
+
|
|
3
|
+
from .utils import load_alias, set_default_alias
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@click.command()
|
|
7
|
+
@click.argument('name', required=True)
|
|
8
|
+
def default(name):
|
|
9
|
+
"""Set an alias as the default."""
|
|
10
|
+
alias_data = load_alias(name)
|
|
11
|
+
if not alias_data:
|
|
12
|
+
click.echo(f"Alias '{name}' does not exist.")
|
|
13
|
+
return
|
|
14
|
+
|
|
15
|
+
set_default_alias(name)
|
|
16
|
+
click.echo(f"Alias '{name}' is now the default.")
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import click
|
|
2
|
+
|
|
3
|
+
from .utils import delete_alias_file, load_alias
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@click.command()
|
|
7
|
+
@click.argument('name', required=True)
|
|
8
|
+
def delete(name):
|
|
9
|
+
"""Delete an alias."""
|
|
10
|
+
alias_data = load_alias(name)
|
|
11
|
+
if not alias_data:
|
|
12
|
+
click.echo(f"Alias '{name}' does not exist.")
|
|
13
|
+
return
|
|
14
|
+
delete_alias_file(name)
|
|
15
|
+
click.echo(f"Alias '{name}' deleted.")
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import click
|
|
2
|
+
|
|
3
|
+
from .utils import CONFIG_DIR, DEFAULT_FILE, ensure_config_dir, get_default_alias
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@click.command()
|
|
7
|
+
def list():
|
|
8
|
+
"""List all aliases."""
|
|
9
|
+
ensure_config_dir()
|
|
10
|
+
aliases = [f.stem for f in CONFIG_DIR.glob('*') if f.is_file() and f.stem != DEFAULT_FILE.stem]
|
|
11
|
+
default_alias = get_default_alias()
|
|
12
|
+
if not aliases:
|
|
13
|
+
click.echo('No aliases found.')
|
|
14
|
+
return
|
|
15
|
+
for alias_name in aliases:
|
|
16
|
+
if alias_name == default_alias:
|
|
17
|
+
click.echo(f'{alias_name} (default)')
|
|
18
|
+
else:
|
|
19
|
+
click.echo(alias_name)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import click
|
|
2
|
+
|
|
3
|
+
from .utils import load_alias
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@click.command()
|
|
7
|
+
@click.argument('name', required=True)
|
|
8
|
+
def read(name):
|
|
9
|
+
"""Read an alias."""
|
|
10
|
+
alias_data = load_alias(name)
|
|
11
|
+
if not alias_data:
|
|
12
|
+
click.echo(f"Alias '{name}' does not exist.")
|
|
13
|
+
return
|
|
14
|
+
for key, value in alias_data.items():
|
|
15
|
+
click.echo(f'{key}: {value}')
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import click
|
|
2
|
+
|
|
3
|
+
from .utils import load_alias, save_alias_field
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@click.command()
|
|
7
|
+
@click.argument('name', required=True)
|
|
8
|
+
@click.argument('field', required=True)
|
|
9
|
+
@click.argument('value', required=True)
|
|
10
|
+
def update(name, field, value):
|
|
11
|
+
"""Update a specific field in an alias."""
|
|
12
|
+
alias_data = load_alias(name)
|
|
13
|
+
if not alias_data:
|
|
14
|
+
click.echo(f"Alias '{name}' does not exist.")
|
|
15
|
+
return
|
|
16
|
+
save_alias_field(name, field.upper(), value)
|
|
17
|
+
click.echo(f"Alias '{name}' updated. Field '{field}' is now '{value}'.")
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
from dotenv import dotenv_values, load_dotenv, set_key, unset_key
|
|
4
|
+
|
|
5
|
+
CONFIG_DIR = Path.home() / '.config' / 'synapse'
|
|
6
|
+
DEFAULT_FILE = CONFIG_DIR / '__default__'
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def ensure_config_dir():
|
|
10
|
+
CONFIG_DIR.mkdir(parents=True, exist_ok=True)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def load_alias(alias_name):
|
|
14
|
+
ensure_config_dir()
|
|
15
|
+
alias_file = CONFIG_DIR / alias_name
|
|
16
|
+
if not alias_file.exists():
|
|
17
|
+
return None
|
|
18
|
+
return dotenv_values(alias_file)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# Save or update a field in an alias .env file
|
|
22
|
+
def save_alias_field(alias_name, key, value):
|
|
23
|
+
ensure_config_dir()
|
|
24
|
+
alias_file = CONFIG_DIR / alias_name
|
|
25
|
+
set_key(alias_file, key, value)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
# Delete a field from an alias .env file
|
|
29
|
+
def delete_alias_field(alias_name, key):
|
|
30
|
+
ensure_config_dir()
|
|
31
|
+
alias_file = CONFIG_DIR / alias_name
|
|
32
|
+
unset_key(alias_file, key)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
# Delete an alias .env file
|
|
36
|
+
def delete_alias_file(alias_name):
|
|
37
|
+
ensure_config_dir()
|
|
38
|
+
alias_file = CONFIG_DIR / alias_name
|
|
39
|
+
if alias_file.exists():
|
|
40
|
+
alias_file.unlink()
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def get_default_alias():
|
|
44
|
+
ensure_config_dir()
|
|
45
|
+
if DEFAULT_FILE.exists():
|
|
46
|
+
default_data = dotenv_values(DEFAULT_FILE)
|
|
47
|
+
return default_data.get('DEFAULT_ALIAS')
|
|
48
|
+
return None
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
# Set the default alias
|
|
52
|
+
def set_default_alias(alias_name):
|
|
53
|
+
ensure_config_dir()
|
|
54
|
+
with open(DEFAULT_FILE, 'w') as f:
|
|
55
|
+
f.write(f'DEFAULT_ALIAS={alias_name}\n')
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def load_dotenv_default_alias():
|
|
59
|
+
default_alias = get_default_alias()
|
|
60
|
+
if default_alias is not None:
|
|
61
|
+
load_dotenv(CONFIG_DIR / default_alias)
|