ml-dash 0.6.3__tar.gz → 0.6.5__tar.gz
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.
- {ml_dash-0.6.3 → ml_dash-0.6.5}/PKG-INFO +1 -1
- {ml_dash-0.6.3 → ml_dash-0.6.5}/pyproject.toml +4 -1
- {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/__init__.py +1 -1
- {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/cli_commands/api.py +10 -1
- {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/cli_commands/download.py +19 -2
- {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/cli_commands/list.py +18 -1
- {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/cli_commands/upload.py +23 -2
- {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/client.py +565 -83
- {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/experiment.py +114 -54
- {ml_dash-0.6.3 → ml_dash-0.6.5}/LICENSE +0 -0
- {ml_dash-0.6.3 → ml_dash-0.6.5}/README.md +0 -0
- {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/auth/__init__.py +0 -0
- {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/auth/constants.py +0 -0
- {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/auth/device_flow.py +0 -0
- {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/auth/device_secret.py +0 -0
- {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/auth/exceptions.py +0 -0
- {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/auth/token_storage.py +0 -0
- {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/auto_start.py +0 -0
- {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/cli.py +0 -0
- {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/cli_commands/__init__.py +0 -0
- {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/cli_commands/login.py +0 -0
- {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/cli_commands/logout.py +0 -0
- {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/cli_commands/profile.py +0 -0
- {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/config.py +0 -0
- {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/files.py +0 -0
- {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/log.py +0 -0
- {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/metric.py +0 -0
- {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/params.py +0 -0
- {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/py.typed +0 -0
- {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/remote_auto_start.py +0 -0
- {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/run.py +0 -0
- {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/snowflake.py +0 -0
- {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/storage.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "ml-dash"
|
|
3
|
-
version = "0.6.
|
|
3
|
+
version = "0.6.5"
|
|
4
4
|
description = "ML experiment tracking and data storage"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.9"
|
|
@@ -60,6 +60,9 @@ dev = [
|
|
|
60
60
|
"mypy>=1.9.0",
|
|
61
61
|
]
|
|
62
62
|
|
|
63
|
+
[tool.ruff]
|
|
64
|
+
indent-width = 2
|
|
65
|
+
|
|
63
66
|
[tool.uv]
|
|
64
67
|
|
|
65
68
|
[build-system]
|
|
@@ -56,6 +56,12 @@ Notes:
|
|
|
56
56
|
type=str,
|
|
57
57
|
help="ML-Dash server URL (default: https://api.dash.ml)",
|
|
58
58
|
)
|
|
59
|
+
parser.add_argument(
|
|
60
|
+
"--namespace",
|
|
61
|
+
type=str,
|
|
62
|
+
required=True,
|
|
63
|
+
help="Namespace to use for queries (required)",
|
|
64
|
+
)
|
|
59
65
|
|
|
60
66
|
|
|
61
67
|
def extract_path(data, path: str):
|
|
@@ -131,9 +137,12 @@ def cmd_api(args) -> int:
|
|
|
131
137
|
# Get remote URL
|
|
132
138
|
remote_url = args.dash_url or config.remote_url or "https://api.dash.ml"
|
|
133
139
|
|
|
140
|
+
# Get namespace
|
|
141
|
+
namespace = args.namespace
|
|
142
|
+
|
|
134
143
|
try:
|
|
135
144
|
# Initialize client
|
|
136
|
-
client = RemoteClient(base_url=remote_url)
|
|
145
|
+
client = RemoteClient(base_url=remote_url, namespace=namespace)
|
|
137
146
|
|
|
138
147
|
# Determine query type and build query
|
|
139
148
|
if args.mutation:
|
|
@@ -240,7 +240,9 @@ class ExperimentDownloader:
|
|
|
240
240
|
"""Get thread-local remote client for safe concurrent access."""
|
|
241
241
|
if not hasattr(self._thread_local, "client"):
|
|
242
242
|
self._thread_local.client = RemoteClient(
|
|
243
|
-
base_url=self.remote.base_url,
|
|
243
|
+
base_url=self.remote.base_url,
|
|
244
|
+
namespace=self.remote.namespace,
|
|
245
|
+
api_key=self.remote.api_key
|
|
244
246
|
)
|
|
245
247
|
return self._thread_local.client
|
|
246
248
|
|
|
@@ -630,8 +632,23 @@ def cmd_download(args: argparse.Namespace) -> int:
|
|
|
630
632
|
console.print("[red]Error:[/red] --dash-url is required (or set in config)")
|
|
631
633
|
return 1
|
|
632
634
|
|
|
635
|
+
# Extract namespace from project argument
|
|
636
|
+
namespace = None
|
|
637
|
+
if args.project:
|
|
638
|
+
# Parse namespace from project filter (format: "owner/project" or "owner/project/exp")
|
|
639
|
+
project_parts = args.project.strip("/").split("/")
|
|
640
|
+
if len(project_parts) >= 2: # Has at least "owner/project"
|
|
641
|
+
namespace = project_parts[0]
|
|
642
|
+
|
|
643
|
+
if not namespace:
|
|
644
|
+
console.print(
|
|
645
|
+
"[red]Error:[/red] --project must be in format 'namespace/project' or 'namespace/project/exp'"
|
|
646
|
+
)
|
|
647
|
+
console.print("Example: ml-dash download --project alice/my-project")
|
|
648
|
+
return 1
|
|
649
|
+
|
|
633
650
|
# Initialize clients (RemoteClient will auto-load token if api_key is None)
|
|
634
|
-
remote_client = RemoteClient(base_url=remote_url, api_key=api_key)
|
|
651
|
+
remote_client = RemoteClient(base_url=remote_url, namespace=namespace, api_key=api_key)
|
|
635
652
|
local_storage = LocalStorage(root_path=Path(args.path))
|
|
636
653
|
|
|
637
654
|
# Load or create state
|
|
@@ -260,9 +260,26 @@ def cmd_list(args: argparse.Namespace) -> int:
|
|
|
260
260
|
# Get API key (command line > config > auto-loaded from storage)
|
|
261
261
|
api_key = args.api_key or config.api_key
|
|
262
262
|
|
|
263
|
+
# Extract namespace from project argument
|
|
264
|
+
namespace = None
|
|
265
|
+
if args.project:
|
|
266
|
+
# Parse namespace from project filter (format: "namespace/project")
|
|
267
|
+
project_parts = args.project.strip("/").split("/")
|
|
268
|
+
# For simple patterns without '/', treat as project-only pattern
|
|
269
|
+
if '/' in args.project and len(project_parts) >= 2:
|
|
270
|
+
namespace = project_parts[0]
|
|
271
|
+
|
|
272
|
+
if not namespace:
|
|
273
|
+
console.print(
|
|
274
|
+
"[red]Error:[/red] --project must be in format 'namespace/project'"
|
|
275
|
+
)
|
|
276
|
+
console.print("Example: ml-dash list --project alice/my-project")
|
|
277
|
+
console.print("Or use glob patterns: ml-dash list --project alice/proj-*")
|
|
278
|
+
return 1
|
|
279
|
+
|
|
263
280
|
# Create remote client
|
|
264
281
|
try:
|
|
265
|
-
remote_client = RemoteClient(base_url=remote_url, api_key=api_key)
|
|
282
|
+
remote_client = RemoteClient(base_url=remote_url, namespace=namespace, api_key=api_key)
|
|
266
283
|
except Exception as e:
|
|
267
284
|
console.print(f"[red]Error connecting to remote:[/red] {e}")
|
|
268
285
|
return 1
|
|
@@ -632,7 +632,9 @@ class ExperimentUploader:
|
|
|
632
632
|
# Create a new client for this thread
|
|
633
633
|
# Use graphql_base_url (without /api) since RemoteClient.__init__ will add /api
|
|
634
634
|
self._thread_local.client = RemoteClient(
|
|
635
|
-
base_url=self.remote.graphql_base_url,
|
|
635
|
+
base_url=self.remote.graphql_base_url,
|
|
636
|
+
namespace=self.remote.namespace,
|
|
637
|
+
api_key=self.remote.api_key
|
|
636
638
|
)
|
|
637
639
|
return self._thread_local.client
|
|
638
640
|
|
|
@@ -1231,8 +1233,27 @@ def cmd_upload(args: argparse.Namespace) -> int:
|
|
|
1231
1233
|
f"[green]{len(valid_experiments)} experiment(s) ready to upload[/green]"
|
|
1232
1234
|
)
|
|
1233
1235
|
|
|
1236
|
+
# Extract namespace from target or first experiment
|
|
1237
|
+
namespace = None
|
|
1238
|
+
if args.target:
|
|
1239
|
+
# Parse namespace from target prefix (format: "owner/project/...")
|
|
1240
|
+
target_parts = args.target.strip("/").split("/")
|
|
1241
|
+
if len(target_parts) >= 1:
|
|
1242
|
+
namespace = target_parts[0]
|
|
1243
|
+
if not namespace and valid_experiments:
|
|
1244
|
+
# Parse namespace from first experiment's prefix
|
|
1245
|
+
first_prefix = valid_experiments[0].prefix
|
|
1246
|
+
if first_prefix:
|
|
1247
|
+
prefix_parts = first_prefix.strip("/").split("/")
|
|
1248
|
+
if len(prefix_parts) >= 1:
|
|
1249
|
+
namespace = prefix_parts[0]
|
|
1250
|
+
|
|
1251
|
+
if not namespace:
|
|
1252
|
+
console.print("[red]Error:[/red] Could not determine namespace from experiments or target")
|
|
1253
|
+
return 1
|
|
1254
|
+
|
|
1234
1255
|
# Initialize remote client and local storage
|
|
1235
|
-
remote_client = RemoteClient(base_url=remote_url, api_key=api_key)
|
|
1256
|
+
remote_client = RemoteClient(base_url=remote_url, namespace=namespace, api_key=api_key)
|
|
1236
1257
|
local_storage = LocalStorage(root_path=local_path)
|
|
1237
1258
|
|
|
1238
1259
|
# Upload experiments with progress tracking
|