ml-dash 0.6.12__py3-none-any.whl → 0.6.13__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.
ml_dash/__init__.py CHANGED
@@ -43,18 +43,19 @@ from .params import ParametersBuilder
43
43
  from .run import RUN
44
44
  from .storage import LocalStorage
45
45
 
46
- __version__ = "0.6.10"
46
+ __version__ = "0.6.13"
47
47
 
48
- # Minimum version required - blocks older versions
49
- MINIMUM_REQUIRED_VERSION = "0.6.10"
48
+ # Required version - MUST match exactly (blocks all older versions)
49
+ # Update this with EVERY release to force users to upgrade
50
+ REQUIRED_VERSION = "0.6.13"
50
51
 
51
52
 
52
53
  def _check_version_compatibility():
53
54
  """
54
- Enforce minimum version requirement.
55
+ Enforce strict version requirement.
55
56
 
56
- Raises ImportError if installed version is below minimum required version.
57
- This ensures users have the latest features (userinfo, namespace auto-detection, etc.)
57
+ Raises ImportError if installed version doesn't match the required version.
58
+ This ensures all users are on the latest version with newest features and bug fixes.
58
59
  """
59
60
  try:
60
61
  from packaging import version
@@ -64,25 +65,26 @@ def _check_version_compatibility():
64
65
  return
65
66
 
66
67
  current = version.parse(__version__)
67
- minimum = version.parse(MINIMUM_REQUIRED_VERSION)
68
+ required = version.parse(REQUIRED_VERSION)
68
69
 
69
- if current < minimum:
70
+ if current < required:
70
71
  raise ImportError(
71
72
  f"\n"
72
73
  f"{'=' * 80}\n"
73
- f"ERROR: ml-dash version {__version__} is too old!\n"
74
+ f"ERROR: ml-dash version {__version__} is outdated!\n"
74
75
  f"{'=' * 80}\n"
75
76
  f"\n"
76
- f"This version of ml-dash ({__version__}) is no longer supported.\n"
77
- f"Minimum required version: {MINIMUM_REQUIRED_VERSION}\n"
77
+ f"Your installed version ({__version__}) is no longer supported.\n"
78
+ f"Required version: {REQUIRED_VERSION}\n"
78
79
  f"\n"
79
80
  f"Please upgrade to the latest version:\n"
80
81
  f"\n"
81
82
  f" pip install --upgrade ml-dash\n"
82
83
  f"\n"
83
- f"Or install specific version:\n"
84
+ f"Or with uv:\n"
84
85
  f"\n"
85
- f" pip install ml-dash>={MINIMUM_REQUIRED_VERSION}\n"
86
+ f" uv pip install --upgrade ml-dash\n"
87
+ f" uv sync --upgrade-package ml-dash\n"
86
88
  f"\n"
87
89
  f"{'=' * 80}\n"
88
90
  )
@@ -1217,7 +1217,7 @@ def cmd_upload(args: argparse.Namespace) -> int:
1217
1217
  Exit code (0 for success, 1 for error)
1218
1218
  """
1219
1219
  # Handle track upload if --tracks is specified
1220
- if args.tracks:
1220
+ if getattr(args, 'tracks', False):
1221
1221
  return cmd_upload_track(args)
1222
1222
 
1223
1223
  # Load config
ml_dash/run.py CHANGED
@@ -158,6 +158,16 @@ class RUN:
158
158
  now = datetime.now()
159
159
  """Timestamp at import time. Does not change during the session."""
160
160
 
161
+ @property
162
+ def date(self) -> str:
163
+ """Date string in YYYYMMDD format."""
164
+ return self.now.strftime("%Y%m%d")
165
+
166
+ @property
167
+ def datetime_str(self) -> str:
168
+ """DateTime string in YYYYMMDD.HHMMSS format."""
169
+ return self.now.strftime("%Y%m%d.%H%M%S")
170
+
161
171
  timestamp: str = None
162
172
  """Timestamp created at instantiation"""
163
173
 
@@ -277,6 +287,61 @@ class RUN:
277
287
  # self.name is the last segment
278
288
  self.name = parts[-1] if len(parts) > 2 else parts[1]
279
289
 
290
+ def __setattr__(self, name: str, value):
291
+ """
292
+ Intercept attribute setting to expand {EXP.attr} templates in prefix.
293
+
294
+ When prefix is set, expands any {EXP.name}, {EXP.id}, {EXP.date}, etc. templates
295
+ using current instance's attributes. Also syncs back to class-level RUN attributes.
296
+ """
297
+ # Prevent prefix changes after experiment has started
298
+ if name == "prefix" and isinstance(value, str):
299
+ experiment = getattr(self, "_experiment", None)
300
+ if experiment is not None and getattr(experiment, "_is_open", False):
301
+ raise RuntimeError(
302
+ "Cannot change prefix after experiment has been initialized. "
303
+ "Set prefix before calling experiment.run.start() or entering the context manager."
304
+ )
305
+
306
+ # Expand templates if setting prefix
307
+ if name == "prefix" and isinstance(value, str):
308
+ # Check if value contains {EXP. templates
309
+ if "{EXP." in value:
310
+ import re
311
+
312
+ def replace_match(match):
313
+ attr_name = match.group(1)
314
+ # Special handling for id - generate if needed
315
+ if attr_name == "id" and not getattr(self, "id", None):
316
+ from ml_dash.snowflake import generate_id
317
+ object.__setattr__(self, "id", generate_id())
318
+
319
+ # Get attribute, raising error if not found
320
+ try:
321
+ attr_value = getattr(self, attr_name)
322
+ if attr_value is None:
323
+ raise AttributeError(f"Attribute '{attr_name}' is None")
324
+ return str(attr_value)
325
+ except AttributeError:
326
+ raise AttributeError(f"RUN has no attribute '{attr_name}'")
327
+
328
+ # Match {EXP.attr_name} pattern
329
+ pattern = r"\{EXP\.(\w+)\}"
330
+ value = re.sub(pattern, replace_match, value)
331
+
332
+ # Always update _folder_path when prefix changes
333
+ object.__setattr__(self, "_folder_path", value)
334
+
335
+ # Parse and update owner, project, name from new prefix
336
+ parts = value.strip("/").split("/")
337
+ if len(parts) >= 2:
338
+ object.__setattr__(self, "owner", parts[0])
339
+ object.__setattr__(self, "project", parts[1])
340
+ object.__setattr__(self, "name", parts[-1] if len(parts) > 2 else parts[1])
341
+
342
+ # Use object.__setattr__ to set the value
343
+ object.__setattr__(self, name, value)
344
+
280
345
  def start(self) -> "Experiment":
281
346
  """
282
347
  Start the experiment (sets status to RUNNING).
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: ml-dash
3
- Version: 0.6.12
3
+ Version: 0.6.13
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,4 +1,4 @@
1
- ml_dash/__init__.py,sha256=bsn9dwFrkXyZNcm6A4pAKS3ow1Q-2C5Z1jpak-at0Wo,2995
1
+ ml_dash/__init__.py,sha256=S-Q1EK0mKvV0WAOB-QjQF7NjLvYntB3_LIAbzKA45LA,3060
2
2
  ml_dash/auth/__init__.py,sha256=3lwM-Y8UBHPU1gFW2JNpmXlPVTnkGudWLKNFFKulQfo,1200
3
3
  ml_dash/auth/constants.py,sha256=ku4QzQUMNjvyJwjy7AUdywMAZd59jXSxNHZxDiagUWU,280
4
4
  ml_dash/auth/device_flow.py,sha256=DQOdPNlZCuU1umZOA_A6WXdRM3zWphnyo9IntToBl_A,7921
@@ -17,7 +17,7 @@ ml_dash/cli_commands/login.py,sha256=zX-urtUrfzg2qOGtKNYQgj6UloN9kzj4zEO6h_xwuNs
17
17
  ml_dash/cli_commands/logout.py,sha256=lTUUNyRXqvo61qNkCd4KBrPUujDAHnNqsHkU6bHie0U,1332
18
18
  ml_dash/cli_commands/profile.py,sha256=PoRO1XA4bnOINptj4AO0SyNDBADeryPJBfgC74327e4,5997
19
19
  ml_dash/cli_commands/remove.py,sha256=AtDlUWkNeGcnZWN0Wbg6XoyYhFHkCFMPdxsGA33v38c,5325
20
- ml_dash/cli_commands/upload.py,sha256=8i1ZVkQQ7VBzGV3GxlW-71GaETtTdUshexII2GTz5JM,49640
20
+ ml_dash/cli_commands/upload.py,sha256=o5D1be3V_wrzoVI3QHrKzyw2fG6ocD33MSZjzRsS60w,49659
21
21
  ml_dash/client.py,sha256=sQokhvofq56JxpmUBVUsfjjn5qKqyUXM9F3uxsUbUbA,66608
22
22
  ml_dash/config.py,sha256=oz2xvoBh2X_xUXWr92cPD5nFxXMT5LxVNypv5B5O0fA,3116
23
23
  ml_dash/experiment.py,sha256=JqNYsoAOsvqIRMVl6gHFodlZ79b0X2rUFGz6NRixKic,43726
@@ -27,11 +27,11 @@ ml_dash/metric.py,sha256=ghD1jnuv6dbjV1Jlo7q0mx9UEzpdto2Y1-oDWrSfg04,25809
27
27
  ml_dash/params.py,sha256=pPFvknJAJX5uhckzjO1r-HNnKbQFFKDISFmOXNET5eY,9046
28
28
  ml_dash/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
29
29
  ml_dash/remote_auto_start.py,sha256=5fvQDHv1CWEKFb6WAa5_uyEInwV_SvotXjOO_6i6ZKE,1687
30
- ml_dash/run.py,sha256=Hlt_YHaN95TC3TDejzLjFmW9EWyKWi6ruibw-eiPm2U,8833
30
+ ml_dash/run.py,sha256=yAKZ9HtU4cidtbWMAY1IiDPVWwluVlicD5hsmVT89U0,11361
31
31
  ml_dash/snowflake.py,sha256=14rEpRU5YltsmmmZW0EMUy_hdv5S5ME9gWVtmdmwfiU,4917
32
32
  ml_dash/storage.py,sha256=x1W-dK6wQY36-LVOJ4kA8Dn07ObNQuIErQWJ3b0PoGY,44910
33
33
  ml_dash/track.py,sha256=Dfg1ZnmKZ_FlE5ZfG8Qld_wN4RIMs3nrOxrxwf3thiY,8164
34
- ml_dash-0.6.12.dist-info/WHEEL,sha256=z-mOpxbJHqy3cq6SvUThBZdaLGFZzdZPtgWLcP2NKjQ,79
35
- ml_dash-0.6.12.dist-info/entry_points.txt,sha256=dYs2EHX1uRNO7AQGNnVaJJpgiy0Z9q7tiy4fHSyaf3Q,46
36
- ml_dash-0.6.12.dist-info/METADATA,sha256=u31huYFuxz_NMIuFiaUyE373GXMRbYCzpBB61D6KFu4,9536
37
- ml_dash-0.6.12.dist-info/RECORD,,
34
+ ml_dash-0.6.13.dist-info/WHEEL,sha256=z-mOpxbJHqy3cq6SvUThBZdaLGFZzdZPtgWLcP2NKjQ,79
35
+ ml_dash-0.6.13.dist-info/entry_points.txt,sha256=dYs2EHX1uRNO7AQGNnVaJJpgiy0Z9q7tiy4fHSyaf3Q,46
36
+ ml_dash-0.6.13.dist-info/METADATA,sha256=bKRP7yW8ULvNc5kqdeO0USgqCOWhXuV3EuhViNKOZIU,9536
37
+ ml_dash-0.6.13.dist-info/RECORD,,