flowyml 1.1.0__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.
- flowyml/__init__.py +207 -0
- flowyml/assets/__init__.py +22 -0
- flowyml/assets/artifact.py +40 -0
- flowyml/assets/base.py +209 -0
- flowyml/assets/dataset.py +100 -0
- flowyml/assets/featureset.py +301 -0
- flowyml/assets/metrics.py +104 -0
- flowyml/assets/model.py +82 -0
- flowyml/assets/registry.py +157 -0
- flowyml/assets/report.py +315 -0
- flowyml/cli/__init__.py +5 -0
- flowyml/cli/experiment.py +232 -0
- flowyml/cli/init.py +256 -0
- flowyml/cli/main.py +327 -0
- flowyml/cli/run.py +75 -0
- flowyml/cli/stack_cli.py +532 -0
- flowyml/cli/ui.py +33 -0
- flowyml/core/__init__.py +68 -0
- flowyml/core/advanced_cache.py +274 -0
- flowyml/core/approval.py +64 -0
- flowyml/core/cache.py +203 -0
- flowyml/core/checkpoint.py +148 -0
- flowyml/core/conditional.py +373 -0
- flowyml/core/context.py +155 -0
- flowyml/core/error_handling.py +419 -0
- flowyml/core/executor.py +354 -0
- flowyml/core/graph.py +185 -0
- flowyml/core/parallel.py +452 -0
- flowyml/core/pipeline.py +764 -0
- flowyml/core/project.py +253 -0
- flowyml/core/resources.py +424 -0
- flowyml/core/scheduler.py +630 -0
- flowyml/core/scheduler_config.py +32 -0
- flowyml/core/step.py +201 -0
- flowyml/core/step_grouping.py +292 -0
- flowyml/core/templates.py +226 -0
- flowyml/core/versioning.py +217 -0
- flowyml/integrations/__init__.py +1 -0
- flowyml/integrations/keras.py +134 -0
- flowyml/monitoring/__init__.py +1 -0
- flowyml/monitoring/alerts.py +57 -0
- flowyml/monitoring/data.py +102 -0
- flowyml/monitoring/llm.py +160 -0
- flowyml/monitoring/monitor.py +57 -0
- flowyml/monitoring/notifications.py +246 -0
- flowyml/registry/__init__.py +5 -0
- flowyml/registry/model_registry.py +491 -0
- flowyml/registry/pipeline_registry.py +55 -0
- flowyml/stacks/__init__.py +27 -0
- flowyml/stacks/base.py +77 -0
- flowyml/stacks/bridge.py +288 -0
- flowyml/stacks/components.py +155 -0
- flowyml/stacks/gcp.py +499 -0
- flowyml/stacks/local.py +112 -0
- flowyml/stacks/migration.py +97 -0
- flowyml/stacks/plugin_config.py +78 -0
- flowyml/stacks/plugins.py +401 -0
- flowyml/stacks/registry.py +226 -0
- flowyml/storage/__init__.py +26 -0
- flowyml/storage/artifacts.py +246 -0
- flowyml/storage/materializers/__init__.py +20 -0
- flowyml/storage/materializers/base.py +133 -0
- flowyml/storage/materializers/keras.py +185 -0
- flowyml/storage/materializers/numpy.py +94 -0
- flowyml/storage/materializers/pandas.py +142 -0
- flowyml/storage/materializers/pytorch.py +135 -0
- flowyml/storage/materializers/sklearn.py +110 -0
- flowyml/storage/materializers/tensorflow.py +152 -0
- flowyml/storage/metadata.py +931 -0
- flowyml/tracking/__init__.py +1 -0
- flowyml/tracking/experiment.py +211 -0
- flowyml/tracking/leaderboard.py +191 -0
- flowyml/tracking/runs.py +145 -0
- flowyml/ui/__init__.py +15 -0
- flowyml/ui/backend/Dockerfile +31 -0
- flowyml/ui/backend/__init__.py +0 -0
- flowyml/ui/backend/auth.py +163 -0
- flowyml/ui/backend/main.py +187 -0
- flowyml/ui/backend/routers/__init__.py +0 -0
- flowyml/ui/backend/routers/assets.py +45 -0
- flowyml/ui/backend/routers/execution.py +179 -0
- flowyml/ui/backend/routers/experiments.py +49 -0
- flowyml/ui/backend/routers/leaderboard.py +118 -0
- flowyml/ui/backend/routers/notifications.py +72 -0
- flowyml/ui/backend/routers/pipelines.py +110 -0
- flowyml/ui/backend/routers/plugins.py +192 -0
- flowyml/ui/backend/routers/projects.py +85 -0
- flowyml/ui/backend/routers/runs.py +66 -0
- flowyml/ui/backend/routers/schedules.py +222 -0
- flowyml/ui/backend/routers/traces.py +84 -0
- flowyml/ui/frontend/Dockerfile +20 -0
- flowyml/ui/frontend/README.md +315 -0
- flowyml/ui/frontend/dist/assets/index-DFNQnrUj.js +448 -0
- flowyml/ui/frontend/dist/assets/index-pWI271rZ.css +1 -0
- flowyml/ui/frontend/dist/index.html +16 -0
- flowyml/ui/frontend/index.html +15 -0
- flowyml/ui/frontend/nginx.conf +26 -0
- flowyml/ui/frontend/package-lock.json +3545 -0
- flowyml/ui/frontend/package.json +33 -0
- flowyml/ui/frontend/postcss.config.js +6 -0
- flowyml/ui/frontend/src/App.jsx +21 -0
- flowyml/ui/frontend/src/app/assets/page.jsx +397 -0
- flowyml/ui/frontend/src/app/dashboard/page.jsx +295 -0
- flowyml/ui/frontend/src/app/experiments/[experimentId]/page.jsx +255 -0
- flowyml/ui/frontend/src/app/experiments/page.jsx +360 -0
- flowyml/ui/frontend/src/app/leaderboard/page.jsx +133 -0
- flowyml/ui/frontend/src/app/pipelines/page.jsx +454 -0
- flowyml/ui/frontend/src/app/plugins/page.jsx +48 -0
- flowyml/ui/frontend/src/app/projects/page.jsx +292 -0
- flowyml/ui/frontend/src/app/runs/[runId]/page.jsx +682 -0
- flowyml/ui/frontend/src/app/runs/page.jsx +470 -0
- flowyml/ui/frontend/src/app/schedules/page.jsx +585 -0
- flowyml/ui/frontend/src/app/settings/page.jsx +314 -0
- flowyml/ui/frontend/src/app/tokens/page.jsx +456 -0
- flowyml/ui/frontend/src/app/traces/page.jsx +246 -0
- flowyml/ui/frontend/src/components/Layout.jsx +108 -0
- flowyml/ui/frontend/src/components/PipelineGraph.jsx +295 -0
- flowyml/ui/frontend/src/components/header/Header.jsx +72 -0
- flowyml/ui/frontend/src/components/plugins/AddPluginDialog.jsx +121 -0
- flowyml/ui/frontend/src/components/plugins/InstalledPlugins.jsx +124 -0
- flowyml/ui/frontend/src/components/plugins/PluginBrowser.jsx +167 -0
- flowyml/ui/frontend/src/components/plugins/PluginManager.jsx +60 -0
- flowyml/ui/frontend/src/components/sidebar/Sidebar.jsx +145 -0
- flowyml/ui/frontend/src/components/ui/Badge.jsx +26 -0
- flowyml/ui/frontend/src/components/ui/Button.jsx +34 -0
- flowyml/ui/frontend/src/components/ui/Card.jsx +44 -0
- flowyml/ui/frontend/src/components/ui/CodeSnippet.jsx +38 -0
- flowyml/ui/frontend/src/components/ui/CollapsibleCard.jsx +53 -0
- flowyml/ui/frontend/src/components/ui/DataView.jsx +175 -0
- flowyml/ui/frontend/src/components/ui/EmptyState.jsx +49 -0
- flowyml/ui/frontend/src/components/ui/ExecutionStatus.jsx +122 -0
- flowyml/ui/frontend/src/components/ui/KeyValue.jsx +25 -0
- flowyml/ui/frontend/src/components/ui/ProjectSelector.jsx +134 -0
- flowyml/ui/frontend/src/contexts/ProjectContext.jsx +79 -0
- flowyml/ui/frontend/src/contexts/ThemeContext.jsx +54 -0
- flowyml/ui/frontend/src/index.css +11 -0
- flowyml/ui/frontend/src/layouts/MainLayout.jsx +23 -0
- flowyml/ui/frontend/src/main.jsx +10 -0
- flowyml/ui/frontend/src/router/index.jsx +39 -0
- flowyml/ui/frontend/src/services/pluginService.js +90 -0
- flowyml/ui/frontend/src/utils/api.js +47 -0
- flowyml/ui/frontend/src/utils/cn.js +6 -0
- flowyml/ui/frontend/tailwind.config.js +31 -0
- flowyml/ui/frontend/vite.config.js +21 -0
- flowyml/ui/utils.py +77 -0
- flowyml/utils/__init__.py +67 -0
- flowyml/utils/config.py +308 -0
- flowyml/utils/debug.py +240 -0
- flowyml/utils/environment.py +346 -0
- flowyml/utils/git.py +319 -0
- flowyml/utils/logging.py +61 -0
- flowyml/utils/performance.py +314 -0
- flowyml/utils/stack_config.py +296 -0
- flowyml/utils/validation.py +270 -0
- flowyml-1.1.0.dist-info/METADATA +372 -0
- flowyml-1.1.0.dist-info/RECORD +159 -0
- flowyml-1.1.0.dist-info/WHEEL +4 -0
- flowyml-1.1.0.dist-info/entry_points.txt +3 -0
- flowyml-1.1.0.dist-info/licenses/LICENSE +17 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/** @type {import('tailwindcss').Config} */
|
|
2
|
+
export default {
|
|
3
|
+
content: [
|
|
4
|
+
"./index.html",
|
|
5
|
+
"./src/**/*.{js,ts,jsx,tsx}",
|
|
6
|
+
],
|
|
7
|
+
darkMode: 'class',
|
|
8
|
+
theme: {
|
|
9
|
+
extend: {
|
|
10
|
+
colors: {
|
|
11
|
+
primary: {
|
|
12
|
+
50: '#f0f9ff',
|
|
13
|
+
100: '#e0f2fe',
|
|
14
|
+
200: '#bae6fd',
|
|
15
|
+
300: '#7dd3fc',
|
|
16
|
+
400: '#38bdf8',
|
|
17
|
+
500: '#0ea5e9',
|
|
18
|
+
600: '#0284c7',
|
|
19
|
+
700: '#0369a1',
|
|
20
|
+
800: '#075985',
|
|
21
|
+
900: '#0c4a6e',
|
|
22
|
+
950: '#082f49',
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
fontFamily: {
|
|
26
|
+
sans: ['Inter', 'system-ui', 'sans-serif'],
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
plugins: [],
|
|
31
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { defineConfig } from 'vite'
|
|
2
|
+
import react from '@vitejs/plugin-react'
|
|
3
|
+
import path from 'path'
|
|
4
|
+
|
|
5
|
+
// https://vitejs.dev/config/
|
|
6
|
+
export default defineConfig({
|
|
7
|
+
plugins: [react()],
|
|
8
|
+
resolve: {
|
|
9
|
+
alias: {
|
|
10
|
+
"@": path.resolve(__dirname, "./src"),
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
server: {
|
|
14
|
+
proxy: {
|
|
15
|
+
'/api': {
|
|
16
|
+
target: 'http://localhost:8080',
|
|
17
|
+
changeOrigin: true,
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
})
|
flowyml/ui/utils.py
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"""UI utility functions for checking UI server status and getting URLs."""
|
|
2
|
+
|
|
3
|
+
import http.client
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def is_ui_running(host: str = "localhost", port: int = 8080) -> bool:
|
|
7
|
+
"""Check if the flowyml UI server is running.
|
|
8
|
+
|
|
9
|
+
Args:
|
|
10
|
+
host: Host to check (default: localhost)
|
|
11
|
+
port: Port to check (default: 8080)
|
|
12
|
+
|
|
13
|
+
Returns:
|
|
14
|
+
True if UI server is running and responding, False otherwise
|
|
15
|
+
"""
|
|
16
|
+
try:
|
|
17
|
+
conn = http.client.HTTPConnection(host, port, timeout=2)
|
|
18
|
+
conn.request("GET", "/api/health")
|
|
19
|
+
response = conn.getresponse()
|
|
20
|
+
conn.close()
|
|
21
|
+
|
|
22
|
+
# Check if response is successful and from flowyml
|
|
23
|
+
if response.status == 200:
|
|
24
|
+
data = response.read().decode("utf-8")
|
|
25
|
+
return "flowyml" in data.lower() or "ok" in data.lower()
|
|
26
|
+
return False
|
|
27
|
+
except Exception:
|
|
28
|
+
return False
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def get_ui_url(host: str = "localhost", port: int = 8080) -> str | None:
|
|
32
|
+
"""Get the URL of the running flowyml UI server.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
host: Host of the UI server (default: localhost)
|
|
36
|
+
port: Port of the UI server (default: 8080)
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
URL string if server is running, None otherwise
|
|
40
|
+
"""
|
|
41
|
+
if is_ui_running(host, port):
|
|
42
|
+
return f"http://{host}:{port}"
|
|
43
|
+
return None
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def get_run_url(run_id: str, host: str = "localhost", port: int = 8080) -> str | None:
|
|
47
|
+
"""Get the URL to view a specific pipeline run.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
run_id: ID of the pipeline run
|
|
51
|
+
host: Host of the UI server (default: localhost)
|
|
52
|
+
port: Port of the UI server (default: 8080)
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
URL string to the run view if server is running, None otherwise
|
|
56
|
+
"""
|
|
57
|
+
base_url = get_ui_url(host, port)
|
|
58
|
+
if base_url:
|
|
59
|
+
return f"{base_url}/runs/{run_id}"
|
|
60
|
+
return None
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def get_pipeline_url(pipeline_name: str, host: str = "localhost", port: int = 8080) -> str | None:
|
|
64
|
+
"""Get the URL to view a specific pipeline.
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
pipeline_name: Name of the pipeline
|
|
68
|
+
host: Host of the UI server (default: localhost)
|
|
69
|
+
port: Port of the UI server (default: 8080)
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
URL string to the pipeline view if server is running, None otherwise
|
|
73
|
+
"""
|
|
74
|
+
base_url = get_ui_url(host, port)
|
|
75
|
+
if base_url:
|
|
76
|
+
return f"{base_url}/pipelines/{pipeline_name}"
|
|
77
|
+
return None
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""Utility functions and helpers."""
|
|
2
|
+
|
|
3
|
+
from flowyml.utils.logging import setup_logger, get_logger
|
|
4
|
+
from flowyml.utils.config import (
|
|
5
|
+
get_config,
|
|
6
|
+
set_config,
|
|
7
|
+
reset_config,
|
|
8
|
+
update_config,
|
|
9
|
+
load_project_config,
|
|
10
|
+
save_project_config,
|
|
11
|
+
)
|
|
12
|
+
from flowyml.utils.validation import (
|
|
13
|
+
CacheStrategy,
|
|
14
|
+
ResourceRequirements,
|
|
15
|
+
RetryConfig,
|
|
16
|
+
StepConfig,
|
|
17
|
+
PipelineConfig,
|
|
18
|
+
ContextConfig,
|
|
19
|
+
StackConfig,
|
|
20
|
+
DatasetSchema,
|
|
21
|
+
ModelSchema,
|
|
22
|
+
MetricsSchema,
|
|
23
|
+
ExperimentConfig,
|
|
24
|
+
validate_step_config,
|
|
25
|
+
validate_pipeline_config,
|
|
26
|
+
validate_context_config,
|
|
27
|
+
validate_metrics,
|
|
28
|
+
)
|
|
29
|
+
from flowyml.utils.git import GitInfo, get_git_info, is_git_repo
|
|
30
|
+
from flowyml.utils.environment import capture_environment, save_environment
|
|
31
|
+
|
|
32
|
+
__all__ = [
|
|
33
|
+
# Logging
|
|
34
|
+
"setup_logger",
|
|
35
|
+
"get_logger",
|
|
36
|
+
# Configuration
|
|
37
|
+
"flowymlConfig",
|
|
38
|
+
"get_config",
|
|
39
|
+
"set_config",
|
|
40
|
+
"reset_config",
|
|
41
|
+
"update_config",
|
|
42
|
+
"load_project_config",
|
|
43
|
+
"save_project_config",
|
|
44
|
+
# Validation
|
|
45
|
+
"CacheStrategy",
|
|
46
|
+
"ResourceRequirements",
|
|
47
|
+
"RetryConfig",
|
|
48
|
+
"StepConfig",
|
|
49
|
+
"PipelineConfig",
|
|
50
|
+
"ContextConfig",
|
|
51
|
+
"StackConfig",
|
|
52
|
+
"DatasetSchema",
|
|
53
|
+
"ModelSchema",
|
|
54
|
+
"MetricsSchema",
|
|
55
|
+
"ExperimentConfig",
|
|
56
|
+
"validate_step_config",
|
|
57
|
+
"validate_pipeline_config",
|
|
58
|
+
"validate_context_config",
|
|
59
|
+
"validate_metrics",
|
|
60
|
+
# Git
|
|
61
|
+
"GitInfo",
|
|
62
|
+
"get_git_info",
|
|
63
|
+
"is_git_repo",
|
|
64
|
+
# Environment
|
|
65
|
+
"capture_environment",
|
|
66
|
+
"save_environment",
|
|
67
|
+
]
|
flowyml/utils/config.py
ADDED
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
"""Configuration management for flowyml."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import yaml
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Any
|
|
7
|
+
from dataclasses import dataclass, field
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass
|
|
11
|
+
class FlowymlConfig:
|
|
12
|
+
"""Global flowyml configuration."""
|
|
13
|
+
|
|
14
|
+
# Storage paths
|
|
15
|
+
flowyml_home: Path = field(default_factory=lambda: Path.home() / ".flowyml")
|
|
16
|
+
artifacts_dir: Path = field(default_factory=lambda: Path(".flowyml/artifacts"))
|
|
17
|
+
metadata_db: Path = field(default_factory=lambda: Path(".flowyml/metadata.db"))
|
|
18
|
+
cache_dir: Path = field(default_factory=lambda: Path(".flowyml/cache"))
|
|
19
|
+
runs_dir: Path = field(default_factory=lambda: Path(".flowyml/runs"))
|
|
20
|
+
experiments_dir: Path = field(default_factory=lambda: Path(".flowyml/experiments"))
|
|
21
|
+
|
|
22
|
+
# Execution settings
|
|
23
|
+
default_stack: str = "local"
|
|
24
|
+
execution_mode: str = "local" # local or remote
|
|
25
|
+
remote_server_url: str = ""
|
|
26
|
+
remote_ui_url: str = ""
|
|
27
|
+
enable_caching: bool = True
|
|
28
|
+
enable_logging: bool = True
|
|
29
|
+
log_level: str = "INFO"
|
|
30
|
+
max_cache_size_mb: int = 10000 # 10GB default
|
|
31
|
+
|
|
32
|
+
# UI settings
|
|
33
|
+
ui_host: str = "localhost"
|
|
34
|
+
ui_port: int = 8080
|
|
35
|
+
enable_ui: bool = False
|
|
36
|
+
|
|
37
|
+
# Experiment tracking
|
|
38
|
+
auto_log_params: bool = True
|
|
39
|
+
auto_log_metrics: bool = True
|
|
40
|
+
auto_log_artifacts: bool = True
|
|
41
|
+
track_git: bool = True
|
|
42
|
+
track_environment: bool = True
|
|
43
|
+
|
|
44
|
+
# Performance settings
|
|
45
|
+
max_parallel_steps: int = 4
|
|
46
|
+
step_timeout_seconds: int = 3600 # 1 hour default
|
|
47
|
+
retry_max_attempts: int = 3
|
|
48
|
+
|
|
49
|
+
# Advanced settings
|
|
50
|
+
debug_mode: bool = False
|
|
51
|
+
strict_validation: bool = True
|
|
52
|
+
allow_pickle: bool = True
|
|
53
|
+
|
|
54
|
+
def __post_init__(self):
|
|
55
|
+
"""Ensure all paths are Path objects."""
|
|
56
|
+
for field_name in [
|
|
57
|
+
"flowyml_home",
|
|
58
|
+
"artifacts_dir",
|
|
59
|
+
"metadata_db",
|
|
60
|
+
"cache_dir",
|
|
61
|
+
"runs_dir",
|
|
62
|
+
"experiments_dir",
|
|
63
|
+
]:
|
|
64
|
+
value = getattr(self, field_name)
|
|
65
|
+
if not isinstance(value, Path):
|
|
66
|
+
setattr(self, field_name, Path(value))
|
|
67
|
+
|
|
68
|
+
def create_directories(self) -> None:
|
|
69
|
+
"""Create necessary directories."""
|
|
70
|
+
self.flowyml_home.mkdir(parents=True, exist_ok=True)
|
|
71
|
+
self.artifacts_dir.mkdir(parents=True, exist_ok=True)
|
|
72
|
+
self.cache_dir.mkdir(parents=True, exist_ok=True)
|
|
73
|
+
self.runs_dir.mkdir(parents=True, exist_ok=True)
|
|
74
|
+
self.experiments_dir.mkdir(parents=True, exist_ok=True)
|
|
75
|
+
|
|
76
|
+
# Create metadata db parent dir
|
|
77
|
+
self.metadata_db.parent.mkdir(parents=True, exist_ok=True)
|
|
78
|
+
|
|
79
|
+
def to_dict(self) -> dict[str, Any]:
|
|
80
|
+
"""Convert config to dictionary."""
|
|
81
|
+
return {
|
|
82
|
+
"flowyml_home": str(self.flowyml_home),
|
|
83
|
+
"artifacts_dir": str(self.artifacts_dir),
|
|
84
|
+
"metadata_db": str(self.metadata_db),
|
|
85
|
+
"cache_dir": str(self.cache_dir),
|
|
86
|
+
"runs_dir": str(self.runs_dir),
|
|
87
|
+
"experiments_dir": str(self.experiments_dir),
|
|
88
|
+
"default_stack": self.default_stack,
|
|
89
|
+
"execution_mode": self.execution_mode,
|
|
90
|
+
"remote_server_url": self.remote_server_url,
|
|
91
|
+
"remote_ui_url": self.remote_ui_url,
|
|
92
|
+
"enable_caching": self.enable_caching,
|
|
93
|
+
"enable_logging": self.enable_logging,
|
|
94
|
+
"log_level": self.log_level,
|
|
95
|
+
"max_cache_size_mb": self.max_cache_size_mb,
|
|
96
|
+
"ui_host": self.ui_host,
|
|
97
|
+
"ui_port": self.ui_port,
|
|
98
|
+
"enable_ui": self.enable_ui,
|
|
99
|
+
"auto_log_params": self.auto_log_params,
|
|
100
|
+
"auto_log_metrics": self.auto_log_metrics,
|
|
101
|
+
"auto_log_artifacts": self.auto_log_artifacts,
|
|
102
|
+
"track_git": self.track_git,
|
|
103
|
+
"track_environment": self.track_environment,
|
|
104
|
+
"max_parallel_steps": self.max_parallel_steps,
|
|
105
|
+
"step_timeout_seconds": self.step_timeout_seconds,
|
|
106
|
+
"retry_max_attempts": self.retry_max_attempts,
|
|
107
|
+
"debug_mode": self.debug_mode,
|
|
108
|
+
"strict_validation": self.strict_validation,
|
|
109
|
+
"allow_pickle": self.allow_pickle,
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
@classmethod
|
|
113
|
+
def from_dict(cls, data: dict[str, Any]) -> "FlowymlConfig":
|
|
114
|
+
"""Create config from dictionary."""
|
|
115
|
+
return cls(**data)
|
|
116
|
+
|
|
117
|
+
def save(self, path: Path | None = None) -> None:
|
|
118
|
+
"""Save config to file.
|
|
119
|
+
|
|
120
|
+
Args:
|
|
121
|
+
path: Path to save config (defaults to ~/.flowyml/config.yaml)
|
|
122
|
+
"""
|
|
123
|
+
if path is None:
|
|
124
|
+
path = self.flowyml_home / "config.yaml"
|
|
125
|
+
|
|
126
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
127
|
+
|
|
128
|
+
with open(path, "w") as f:
|
|
129
|
+
yaml.dump(self.to_dict(), f, default_flow_style=False)
|
|
130
|
+
|
|
131
|
+
@classmethod
|
|
132
|
+
def load(cls, path: Path | None = None) -> "FlowymlConfig":
|
|
133
|
+
"""Load config from file.
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
path: Path to load config from (defaults to ~/.flowyml/config.yaml)
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
Loaded FlowymlConfig instance
|
|
140
|
+
"""
|
|
141
|
+
if path is None:
|
|
142
|
+
path = Path.home() / ".flowyml" / "config.yaml"
|
|
143
|
+
|
|
144
|
+
if not path.exists():
|
|
145
|
+
# Return default config
|
|
146
|
+
return cls()
|
|
147
|
+
|
|
148
|
+
with open(path) as f:
|
|
149
|
+
data = yaml.safe_load(f)
|
|
150
|
+
|
|
151
|
+
return cls.from_dict(data)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
# Global config instance
|
|
155
|
+
_global_config: FlowymlConfig | None = None
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def get_config() -> FlowymlConfig:
|
|
159
|
+
"""Get global flowyml configuration.
|
|
160
|
+
|
|
161
|
+
Returns:
|
|
162
|
+
Global FlowymlConfig instance
|
|
163
|
+
"""
|
|
164
|
+
global _global_config
|
|
165
|
+
|
|
166
|
+
if _global_config is None:
|
|
167
|
+
# Try to load from environment variable
|
|
168
|
+
config_path = os.environ.get("FLOWYML_CONFIG")
|
|
169
|
+
if config_path:
|
|
170
|
+
_global_config = FlowymlConfig.load(Path(config_path))
|
|
171
|
+
else:
|
|
172
|
+
# Load from default location
|
|
173
|
+
_global_config = FlowymlConfig.load()
|
|
174
|
+
|
|
175
|
+
# Create necessary directories
|
|
176
|
+
_global_config.create_directories()
|
|
177
|
+
|
|
178
|
+
return _global_config
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def set_config(config: FlowymlConfig) -> None:
|
|
182
|
+
"""Set global flowyml configuration.
|
|
183
|
+
|
|
184
|
+
Args:
|
|
185
|
+
config: FlowymlConfig instance to set as global
|
|
186
|
+
"""
|
|
187
|
+
global _global_config
|
|
188
|
+
_global_config = config
|
|
189
|
+
_global_config.create_directories()
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def reset_config() -> None:
|
|
193
|
+
"""Reset global configuration to defaults."""
|
|
194
|
+
global _global_config
|
|
195
|
+
_global_config = FlowymlConfig()
|
|
196
|
+
_global_config.create_directories()
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def update_config(**kwargs) -> None:
|
|
200
|
+
"""Update global configuration with new values.
|
|
201
|
+
|
|
202
|
+
Args:
|
|
203
|
+
**kwargs: Configuration values to update
|
|
204
|
+
"""
|
|
205
|
+
config = get_config()
|
|
206
|
+
for key, value in kwargs.items():
|
|
207
|
+
if hasattr(config, key):
|
|
208
|
+
setattr(config, key, value)
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def load_project_config(project_dir: Path | None = None) -> dict[str, Any]:
|
|
212
|
+
"""Load project-specific configuration.
|
|
213
|
+
|
|
214
|
+
Args:
|
|
215
|
+
project_dir: Project directory (defaults to current directory)
|
|
216
|
+
|
|
217
|
+
Returns:
|
|
218
|
+
Project configuration dictionary
|
|
219
|
+
"""
|
|
220
|
+
if project_dir is None:
|
|
221
|
+
project_dir = Path.cwd()
|
|
222
|
+
|
|
223
|
+
config_path = project_dir / "flowyml.yaml"
|
|
224
|
+
if not config_path.exists():
|
|
225
|
+
config_path = project_dir / "flowyml.yml"
|
|
226
|
+
|
|
227
|
+
if not config_path.exists():
|
|
228
|
+
return {}
|
|
229
|
+
|
|
230
|
+
with open(config_path) as f:
|
|
231
|
+
return yaml.safe_load(f) or {}
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def save_project_config(config: dict[str, Any], project_dir: Path | None = None) -> None:
|
|
235
|
+
"""Save project-specific configuration.
|
|
236
|
+
|
|
237
|
+
Args:
|
|
238
|
+
config: Configuration dictionary
|
|
239
|
+
project_dir: Project directory (defaults to current directory)
|
|
240
|
+
"""
|
|
241
|
+
if project_dir is None:
|
|
242
|
+
project_dir = Path.cwd()
|
|
243
|
+
|
|
244
|
+
config_path = project_dir / "flowyml.yaml"
|
|
245
|
+
|
|
246
|
+
with open(config_path, "w") as f:
|
|
247
|
+
yaml.dump(config, f, default_flow_style=False)
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
# Environment variable helpers
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def get_env_config() -> dict[str, Any]:
|
|
254
|
+
"""Get configuration from environment variables.
|
|
255
|
+
|
|
256
|
+
Returns:
|
|
257
|
+
Dictionary of configuration values from environment
|
|
258
|
+
"""
|
|
259
|
+
env_config = {}
|
|
260
|
+
|
|
261
|
+
# Map environment variables to config fields
|
|
262
|
+
env_mappings = {
|
|
263
|
+
"flowyml_HOME": "flowyml_home",
|
|
264
|
+
"flowyml_ARTIFACTS_DIR": "artifacts_dir",
|
|
265
|
+
"flowyml_METADATA_DB": "metadata_db",
|
|
266
|
+
"flowyml_CACHE_DIR": "cache_dir",
|
|
267
|
+
"flowyml_DEFAULT_STACK": "default_stack",
|
|
268
|
+
"flowyml_EXECUTION_MODE": "execution_mode",
|
|
269
|
+
"flowyml_REMOTE_SERVER_URL": "remote_server_url",
|
|
270
|
+
"flowyml_REMOTE_UI_URL": "remote_ui_url",
|
|
271
|
+
"flowyml_ENABLE_CACHING": "enable_caching",
|
|
272
|
+
"flowyml_LOG_LEVEL": "log_level",
|
|
273
|
+
"flowyml_UI_HOST": "ui_host",
|
|
274
|
+
"flowyml_UI_PORT": "ui_port",
|
|
275
|
+
"flowyml_DEBUG": "debug_mode",
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
for env_var, config_key in env_mappings.items():
|
|
279
|
+
value = os.environ.get(env_var)
|
|
280
|
+
if value is not None:
|
|
281
|
+
# Convert booleans
|
|
282
|
+
if value.lower() in ("true", "1", "yes"):
|
|
283
|
+
value = True
|
|
284
|
+
elif value.lower() in ("false", "0", "no"):
|
|
285
|
+
value = False
|
|
286
|
+
# Convert integers
|
|
287
|
+
elif value.isdigit():
|
|
288
|
+
value = int(value)
|
|
289
|
+
|
|
290
|
+
env_config[config_key] = value
|
|
291
|
+
|
|
292
|
+
return env_config
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
def init_config_from_env() -> FlowymlConfig:
|
|
296
|
+
"""Initialize configuration from environment variables.
|
|
297
|
+
|
|
298
|
+
Returns:
|
|
299
|
+
FlowymlConfig instance with values from environment
|
|
300
|
+
"""
|
|
301
|
+
env_config = get_env_config()
|
|
302
|
+
config = FlowymlConfig()
|
|
303
|
+
|
|
304
|
+
for key, value in env_config.items():
|
|
305
|
+
if hasattr(config, key):
|
|
306
|
+
setattr(config, key, value)
|
|
307
|
+
|
|
308
|
+
return config
|