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.
Files changed (33) hide show
  1. {ml_dash-0.6.3 → ml_dash-0.6.5}/PKG-INFO +1 -1
  2. {ml_dash-0.6.3 → ml_dash-0.6.5}/pyproject.toml +4 -1
  3. {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/__init__.py +1 -1
  4. {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/cli_commands/api.py +10 -1
  5. {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/cli_commands/download.py +19 -2
  6. {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/cli_commands/list.py +18 -1
  7. {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/cli_commands/upload.py +23 -2
  8. {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/client.py +565 -83
  9. {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/experiment.py +114 -54
  10. {ml_dash-0.6.3 → ml_dash-0.6.5}/LICENSE +0 -0
  11. {ml_dash-0.6.3 → ml_dash-0.6.5}/README.md +0 -0
  12. {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/auth/__init__.py +0 -0
  13. {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/auth/constants.py +0 -0
  14. {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/auth/device_flow.py +0 -0
  15. {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/auth/device_secret.py +0 -0
  16. {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/auth/exceptions.py +0 -0
  17. {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/auth/token_storage.py +0 -0
  18. {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/auto_start.py +0 -0
  19. {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/cli.py +0 -0
  20. {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/cli_commands/__init__.py +0 -0
  21. {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/cli_commands/login.py +0 -0
  22. {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/cli_commands/logout.py +0 -0
  23. {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/cli_commands/profile.py +0 -0
  24. {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/config.py +0 -0
  25. {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/files.py +0 -0
  26. {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/log.py +0 -0
  27. {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/metric.py +0 -0
  28. {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/params.py +0 -0
  29. {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/py.typed +0 -0
  30. {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/remote_auto_start.py +0 -0
  31. {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/run.py +0 -0
  32. {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/snowflake.py +0 -0
  33. {ml_dash-0.6.3 → ml_dash-0.6.5}/src/ml_dash/storage.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: ml-dash
3
- Version: 0.6.3
3
+ Version: 0.6.5
4
4
  Summary: ML experiment tracking and data storage
5
5
  Keywords: machine-learning,experiment-tracking,mlops,data-storage
6
6
  Author: Ge Yang, Tom Tao
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "ml-dash"
3
- version = "0.6.3"
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]
@@ -43,7 +43,7 @@ from .params import ParametersBuilder
43
43
  from .run import RUN
44
44
  from .storage import LocalStorage
45
45
 
46
- __version__ = "0.6.3"
46
+ __version__ = "0.6.4"
47
47
 
48
48
  __all__ = [
49
49
  "Experiment",
@@ -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, api_key=self.remote.api_key
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, api_key=self.remote.api_key
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