ml-dash 0.6.4__py3-none-any.whl → 0.6.6__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/run.py CHANGED
@@ -22,14 +22,43 @@ Usage:
22
22
  exp.logs.info(f"Running {RUN.name}")
23
23
  """
24
24
 
25
+ import functools
25
26
  import os
26
27
  import sys
28
+ import typing
27
29
  from datetime import datetime
28
30
  from pathlib import Path
29
- from typing import Union
31
+ from typing import Optional, Union
30
32
 
31
33
  from params_proto import EnvVar, proto
32
34
 
35
+
36
+ def requires_open(func):
37
+ """
38
+ Decorator that ensures the experiment is open before executing a method.
39
+
40
+ Raises:
41
+ RuntimeError: If experiment is not started
42
+ """
43
+
44
+ @functools.wraps(func)
45
+ def wrapper(self, *args, **kwargs):
46
+ if not self._is_open:
47
+ raise RuntimeError(
48
+ "Experiment not started. Use 'with experiment.run:' or call experiment.run.start() first.\n"
49
+ "Example:\n"
50
+ " with dxp.run:\n"
51
+ " dxp.params.set(lr=0.001)"
52
+ )
53
+ return func(self, *args, **kwargs)
54
+
55
+ return wrapper
56
+
57
+ if typing.TYPE_CHECKING:
58
+ from .client import RemoteClient
59
+ from .experiment import Experiment
60
+ from .storage import LocalStorage
61
+
33
62
  PROJECT_ROOT_FILES = ("pyproject.toml", "requirements.txt", "setup.py", "setup.cfg")
34
63
 
35
64
 
@@ -77,12 +106,19 @@ def find_project_root(
77
106
  @proto.prefix
78
107
  class RUN:
79
108
  """
80
- Global Experiment Run Configuration.
109
+ Global Experiment Run Configuration and
110
+ Lifecycle manager for experiments
81
111
 
82
112
  This class is the single source of truth for experiment metadata.
83
113
  Configure it before starting an experiment, or through the Experiment
84
114
  constructor.
85
115
 
116
+ Supports three usage patterns:
117
+ 1. Method calls: experiment.run.start(), experiment.run.complete()
118
+ 2. Context manager: with Experiment(...).run as exp:
119
+ 3. Decorator: @exp.run or @Experiment(...).run
120
+
121
+
86
122
  Default prefix template:
87
123
  {project}/{now:%Y/%m-%d}/{path_stem}/{job_name}
88
124
 
@@ -156,10 +192,21 @@ class RUN:
156
192
  debug = "pydevd" in sys.modules
157
193
  "set to True automatically for pyCharm"
158
194
 
195
+ _experiment: "Experiment" = None
196
+ _client: Optional["RemoteClient"] = None
197
+ _storage: Optional["LocalStorage"] = None
198
+
199
+ # Prefix components (parsed from prefix)
200
+ owner: Optional[str] = None
201
+ name: Optional[str] = None
202
+ _folder_path: Optional[str] = None
203
+
159
204
  def __post_init__(self):
160
205
  """
206
+
161
207
  Initialize RUN with auto-detected prefix from entry path.
162
208
 
209
+
163
210
  Args:
164
211
  entry: Path to entry file/directory (e.g., __file__ or directory
165
212
  containing sweep.jsonl). If not provided, uses caller's
@@ -179,7 +226,6 @@ class RUN:
179
226
  RUN.__post_init__(entry=__file__)
180
227
  # Result: RUN.prefix = "vision/resnet", RUN.name = "resnet"
181
228
  """
182
-
183
229
  # Use provided entry or try to auto-detect from caller
184
230
  if self.entry is None:
185
231
  import inspect
@@ -221,6 +267,49 @@ class RUN:
221
267
  # for k, v in data.items():
222
268
  # print(f"> {k:>30}: {v}")
223
269
 
270
+ # Parse prefix into components: {owner}/{project}/path.../[name]
271
+ if self.prefix:
272
+ self._folder_path = self.prefix
273
+ parts = self.prefix.strip("/").split("/")
274
+ if len(parts) >= 2:
275
+ self.owner = parts[0]
276
+ self.project = parts[1]
277
+ # self.name is the last segment
278
+ self.name = parts[-1] if len(parts) > 2 else parts[1]
279
+
280
+ def start(self) -> "Experiment":
281
+ """
282
+ Start the experiment (sets status to RUNNING).
283
+
284
+ Returns:
285
+ The experiment instance for chaining
286
+ """
287
+ return self._experiment._open()
288
+
289
+ def complete(self) -> None:
290
+ """Mark experiment as completed (status: COMPLETED)."""
291
+ self._experiment._close(status="COMPLETED")
292
+
293
+ def fail(self) -> None:
294
+ """Mark experiment as failed (status: FAILED)."""
295
+ self._experiment._close(status="FAILED")
296
+
297
+ def cancel(self) -> None:
298
+ """Mark experiment as cancelled (status: CANCELLED)."""
299
+ self._experiment._close(status="CANCELLED")
300
+
301
+ def __enter__(self) -> "Experiment":
302
+ """Context manager entry - starts the experiment."""
303
+ return self.start()
304
+
305
+ def __exit__(self, exc_type, exc_val, exc_tb):
306
+ """Context manager exit - completes or fails the experiment."""
307
+ if exc_type is not None:
308
+ self.fail()
309
+ else:
310
+ self.complete()
311
+ return False
312
+
224
313
 
225
314
  if __name__ == "__main__":
226
315
  RUN.description = ""
ml_dash/storage.py CHANGED
@@ -84,7 +84,6 @@ class LocalStorage:
84
84
 
85
85
  def create_experiment(
86
86
  self,
87
- owner: str,
88
87
  project: str,
89
88
  prefix: str,
90
89
  description: Optional[str] = None,
@@ -99,7 +98,6 @@ class LocalStorage:
99
98
  where prefix = owner/project/folder_1/.../exp_name
100
99
 
101
100
  Args:
102
- owner: Owner/user (extracted from prefix, kept for API compatibility)
103
101
  project: Project name (extracted from prefix, kept for API compatibility)
104
102
  prefix: Full experiment path (owner/project/folder_1/.../exp_name)
105
103
  description: Optional description
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: ml-dash
3
- Version: 0.6.4
3
+ Version: 0.6.6
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,33 +1,34 @@
1
- ml_dash/__init__.py,sha256=XJym_-vgqFVwyAD-VsPZF9WWepTZ4w-Lwui5ns1gmJI,1583
1
+ ml_dash/__init__.py,sha256=B1oYUXt2DnCctz5nWEqkg1M_XtbJNxaOPxbg54C0Vdc,1555
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
5
5
  ml_dash/auth/device_secret.py,sha256=qUsz6M9S1GEIukvmz57eJEp57srSx74O4MU9mZEeDlE,1158
6
6
  ml_dash/auth/exceptions.py,sha256=IeBwUzoaTyFtPwd4quFOIel49inIzuabe_ChEeEXEWI,725
7
7
  ml_dash/auth/token_storage.py,sha256=L18W8J7D1LlCDlY3Q32l0RXeNh0o7YVDQeeGYm64Dgw,8163
8
- ml_dash/auto_start.py,sha256=62_eZG1qBNAwu6AXduTSo4niCVZ27X52ZK0WEr3yS1o,1812
9
- ml_dash/cli.py,sha256=BoaBulcqnM88XuV5BQEx_-AQAXJAYSJqpvnHggEII_I,2559
8
+ ml_dash/auto_start.py,sha256=FHTTui33bxfk5rHf-VY2RFcd2JQ_LsNpkUu7Qtpc-GY,1721
9
+ ml_dash/cli.py,sha256=X8LsQA8Wfa1XuXsbvePaGo6NYer7f8CNzy33VT3jrqg,2740
10
10
  ml_dash/cli_commands/__init__.py,sha256=bjAmV7MsW-bhtW_4SnLJ0Cfkt9h82vMDC8ebW1Ke8KE,38
11
11
  ml_dash/cli_commands/api.py,sha256=NekZEJGWNpIfB6YrsrOw7kw7rZKjVudwgJWPZIy6ANQ,4535
12
+ ml_dash/cli_commands/create.py,sha256=i6LPA6vefpHUeXncBNzQsLnwF5EM2uF6IX4g7vTDYXo,4400
12
13
  ml_dash/cli_commands/download.py,sha256=LeZXjQSEPIxZALuo90fj8RHjFWIbtGPE0F625sD3cU8,28054
13
14
  ml_dash/cli_commands/list.py,sha256=oc_yJXFhsvGgr3JedG2j7747yX69Qc546geIi4DQ54k,16129
14
15
  ml_dash/cli_commands/login.py,sha256=zX-urtUrfzg2qOGtKNYQgj6UloN9kzj4zEO6h_xwuNs,6782
15
16
  ml_dash/cli_commands/logout.py,sha256=lTUUNyRXqvo61qNkCd4KBrPUujDAHnNqsHkU6bHie0U,1332
16
17
  ml_dash/cli_commands/profile.py,sha256=BaSM6BAN3YM4tw95iKV_nypKZxwsB3PoAAejQcYip5E,2351
17
- ml_dash/cli_commands/upload.py,sha256=_607CcGjvjnwTgGzyxHaDG0qDAlSLlpZDoq6Sy-3paQ,44828
18
- ml_dash/client.py,sha256=kuLOJcBifgyBKQwQpI3jTvPlaUinJu_fCXROfGE3zGk,38328
18
+ ml_dash/cli_commands/upload.py,sha256=1kTmnw4hAevl5mtB1GKlzEh2sPoudv0LTUNhCg0dIXs,45459
19
+ ml_dash/client.py,sha256=VYOW-JNtHEonHoeS7InbyMXKRSrWFcRjo7onhqkGXKg,54659
19
20
  ml_dash/config.py,sha256=oz2xvoBh2X_xUXWr92cPD5nFxXMT5LxVNypv5B5O0fA,3116
20
- ml_dash/experiment.py,sha256=1uDCKNDlgGkKoogao3sEFz1sUhmiRvX3ZPGoQ7H3ozE,41361
21
+ ml_dash/experiment.py,sha256=JCLSWJMOSHQ-dAfR4hOwB07BpNoXzbWTY9lk4VOVRKY,37678
21
22
  ml_dash/files.py,sha256=bihUHKpdknytLGuGgkcvhh585nziZrvYjiHl6rHnoD0,49227
22
23
  ml_dash/log.py,sha256=E-DLg0vejVLLEyShJ_r0LneDMI0XU7XTH5iKWYJe9jI,5298
23
24
  ml_dash/metric.py,sha256=ghD1jnuv6dbjV1Jlo7q0mx9UEzpdto2Y1-oDWrSfg04,25809
24
25
  ml_dash/params.py,sha256=pPFvknJAJX5uhckzjO1r-HNnKbQFFKDISFmOXNET5eY,9046
25
26
  ml_dash/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
27
  ml_dash/remote_auto_start.py,sha256=5fvQDHv1CWEKFb6WAa5_uyEInwV_SvotXjOO_6i6ZKE,1687
27
- ml_dash/run.py,sha256=C0quTLZXKDAlwstzEiJ75CWCX1pwYrmtMZH3z-ia6Pw,6310
28
+ ml_dash/run.py,sha256=_a1l5qswwMgrhvajx_lI-I5IXhfHDeH3hfLAJ7Uk_Gs,8847
28
29
  ml_dash/snowflake.py,sha256=14rEpRU5YltsmmmZW0EMUy_hdv5S5ME9gWVtmdmwfiU,4917
29
- ml_dash/storage.py,sha256=9mG42pvvWkkracbjCr9Xdp890Nm4XSxL7_JeFbBe28g,33020
30
- ml_dash-0.6.4.dist-info/WHEEL,sha256=z-mOpxbJHqy3cq6SvUThBZdaLGFZzdZPtgWLcP2NKjQ,79
31
- ml_dash-0.6.4.dist-info/entry_points.txt,sha256=dYs2EHX1uRNO7AQGNnVaJJpgiy0Z9q7tiy4fHSyaf3Q,46
32
- ml_dash-0.6.4.dist-info/METADATA,sha256=KB2IyFCHFl4pMG9CR7k4UWQb6EzSRAsN3ZZ-OPTg2hA,7203
33
- ml_dash-0.6.4.dist-info/RECORD,,
30
+ ml_dash/storage.py,sha256=jJ0mYCeBIMQ_dQeNLaCiW0fndsliG68w-TmCI1HyYZc,32926
31
+ ml_dash-0.6.6.dist-info/WHEEL,sha256=z-mOpxbJHqy3cq6SvUThBZdaLGFZzdZPtgWLcP2NKjQ,79
32
+ ml_dash-0.6.6.dist-info/entry_points.txt,sha256=dYs2EHX1uRNO7AQGNnVaJJpgiy0Z9q7tiy4fHSyaf3Q,46
33
+ ml_dash-0.6.6.dist-info/METADATA,sha256=ARlHyG-ZdMBqW-WSJjjaKuqwo2bm2M5X7ENkZ-yI0Z0,7203
34
+ ml_dash-0.6.6.dist-info/RECORD,,