hydraflow 0.3.0__py3-none-any.whl → 0.3.1__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
hydraflow/__init__.py CHANGED
@@ -1,19 +1,15 @@
1
- """Provide a collection of MLflow runs."""
1
+ """Integrate Hydra and MLflow to manage and track machine learning experiments."""
2
2
 
3
- from .context import chdir_artifact, log_run, start_run, watch
4
- from .mlflow import (
5
- list_runs,
6
- search_runs,
7
- set_experiment,
8
- )
3
+ from .context import chdir_artifact, chdir_hydra, log_run, start_run, watch
4
+ from .mlflow import list_runs, search_runs, set_experiment
9
5
  from .progress import multi_tasks_progress, parallel_progress
10
6
  from .run_collection import RunCollection
11
- from .run_data import load_config
12
- from .run_info import get_artifact_dir, get_hydra_output_dir
7
+ from .utils import get_artifact_dir, get_hydra_output_dir, load_config
13
8
 
14
9
  __all__ = [
15
10
  "RunCollection",
16
11
  "chdir_artifact",
12
+ "chdir_hydra",
17
13
  "get_artifact_dir",
18
14
  "get_hydra_output_dir",
19
15
  "list_runs",
hydraflow/config.py CHANGED
@@ -54,7 +54,7 @@ def _iter_params(config: object, prefix: str = "") -> Iterator[tuple[str, Any]]:
54
54
  if isinstance(config, DictConfig):
55
55
  for key, value in config.items():
56
56
  if _is_param(value):
57
- yield f"{prefix}{key}", value
57
+ yield f"{prefix}{key}", _convert(value)
58
58
 
59
59
  else:
60
60
  yield from _iter_params(value, f"{prefix}{key}.")
@@ -62,7 +62,7 @@ def _iter_params(config: object, prefix: str = "") -> Iterator[tuple[str, Any]]:
62
62
  elif isinstance(config, ListConfig):
63
63
  for index, value in enumerate(config):
64
64
  if _is_param(value):
65
- yield f"{prefix}{index}", value
65
+ yield f"{prefix}{index}", _convert(value)
66
66
 
67
67
  else:
68
68
  yield from _iter_params(value, f"{prefix}{index}.")
@@ -78,3 +78,11 @@ def _is_param(value: object) -> bool:
78
78
  return False
79
79
 
80
80
  return True
81
+
82
+
83
+ def _convert(value: Any) -> Any:
84
+ """Convert the given value to a Python object."""
85
+ if isinstance(value, ListConfig):
86
+ return list(value)
87
+
88
+ return value
hydraflow/context.py CHANGED
@@ -238,6 +238,25 @@ class Handler(PatternMatchingEventHandler):
238
238
  self.func(file)
239
239
 
240
240
 
241
+ @contextmanager
242
+ def chdir_hydra() -> Iterator[Path]:
243
+ """Change the current working directory to the hydra output directory.
244
+
245
+ This context manager changes the current working directory to the hydra output
246
+ directory. It ensures that the directory is changed back to the original
247
+ directory after the context is exited.
248
+ """
249
+ curdir = Path.cwd()
250
+ path = HydraConfig.get().runtime.output_dir
251
+
252
+ os.chdir(path)
253
+ try:
254
+ yield Path(path)
255
+
256
+ finally:
257
+ os.chdir(curdir)
258
+
259
+
241
260
  @contextmanager
242
261
  def chdir_artifact(
243
262
  run: Run,
hydraflow/mlflow.py CHANGED
@@ -207,8 +207,14 @@ def _list_runs(
207
207
  if experiment := mlflow.get_experiment_by_name(name):
208
208
  loc = experiment.artifact_location
209
209
 
210
- if isinstance(loc, str) and loc.startswith("file://"):
211
- path = Path(mlflow.artifacts.download_artifacts(loc))
210
+ if isinstance(loc, str):
211
+ if loc.startswith("file://"):
212
+ path = Path(mlflow.artifacts.download_artifacts(loc))
213
+ elif Path(loc).is_dir():
214
+ path = Path(loc)
215
+ else:
216
+ continue
217
+
212
218
  run_ids.extend(file.stem for file in path.iterdir() if file.is_dir())
213
219
 
214
220
  it = (joblib.delayed(mlflow.get_run)(run_id) for run_id in run_ids)
hydraflow/run_data.py CHANGED
@@ -1,21 +1,19 @@
1
- """Provide information about MLflow runs."""
1
+ """Provide data about `RunCollection` instances."""
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
5
  from typing import TYPE_CHECKING
6
6
 
7
- from omegaconf import DictConfig, OmegaConf
8
-
9
- from hydraflow.run_info import get_artifact_dir
7
+ from hydraflow.utils import load_config
10
8
 
11
9
  if TYPE_CHECKING:
12
- from mlflow.entities import Run
10
+ from omegaconf import DictConfig
13
11
 
14
12
  from hydraflow.run_collection import RunCollection
15
13
 
16
14
 
17
15
  class RunCollectionData:
18
- """Provide information about MLflow runs."""
16
+ """Provide data about a `RunCollection` instance."""
19
17
 
20
18
  def __init__(self, runs: RunCollection) -> None:
21
19
  self._runs = runs
@@ -34,23 +32,3 @@ class RunCollectionData:
34
32
  def config(self) -> list[DictConfig]:
35
33
  """Get the configuration for each run in the collection."""
36
34
  return [load_config(run) for run in self._runs]
37
-
38
-
39
- def load_config(run: Run) -> DictConfig:
40
- """Load the configuration for a given run.
41
-
42
- This function loads the configuration for the provided Run instance
43
- by downloading the configuration file from the MLflow artifacts and
44
- loading it using OmegaConf. It returns an empty config if
45
- `.hydra/config.yaml` is not found in the run's artifact directory.
46
-
47
- Args:
48
- run (Run): The Run instance for which to load the configuration.
49
-
50
- Returns:
51
- The loaded configuration as a DictConfig object. Returns an empty
52
- DictConfig if the configuration file is not found.
53
-
54
- """
55
- path = get_artifact_dir(run) / ".hydra/config.yaml"
56
- return OmegaConf.load(path) # type: ignore
hydraflow/run_info.py CHANGED
@@ -1,23 +1,19 @@
1
- """Provide information about MLflow runs."""
1
+ """Provide information about `RunCollection` instances."""
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from pathlib import Path
6
5
  from typing import TYPE_CHECKING
7
6
 
8
- import mlflow
9
- from hydra.core.hydra_config import HydraConfig
10
- from mlflow.tracking import artifact_utils
11
- from omegaconf import OmegaConf
7
+ from hydraflow.utils import get_artifact_dir
12
8
 
13
9
  if TYPE_CHECKING:
14
- from mlflow.entities import Run
10
+ from pathlib import Path
15
11
 
16
12
  from hydraflow.run_collection import RunCollection
17
13
 
18
14
 
19
15
  class RunCollectionInfo:
20
- """Provide information about MLflow runs."""
16
+ """Provide information about a `RunCollection` instance."""
21
17
 
22
18
  def __init__(self, runs: RunCollection) -> None:
23
19
  self._runs = runs
@@ -36,56 +32,3 @@ class RunCollectionInfo:
36
32
  def artifact_dir(self) -> list[Path]:
37
33
  """Get the artifact directory for each run in the collection."""
38
34
  return [get_artifact_dir(run) for run in self._runs]
39
-
40
-
41
- def get_artifact_dir(run: Run | None = None) -> Path:
42
- """Retrieve the artifact directory for the given run.
43
-
44
- This function uses MLflow to get the artifact directory for the given run.
45
-
46
- Args:
47
- run (Run | None): The run object. Defaults to None.
48
-
49
- Returns:
50
- The local path to the directory where the artifacts are downloaded.
51
-
52
- """
53
- if run is None:
54
- uri = mlflow.get_artifact_uri()
55
- else:
56
- uri = artifact_utils.get_artifact_uri(run.info.run_id)
57
-
58
- return Path(mlflow.artifacts.download_artifacts(uri))
59
-
60
-
61
- def get_hydra_output_dir(run: Run | None = None) -> Path:
62
- """Retrieve the Hydra output directory for the given run.
63
-
64
- This function returns the Hydra output directory. If no run is provided,
65
- it retrieves the output directory from the current Hydra configuration.
66
- If a run is provided, it retrieves the artifact path for the run, loads
67
- the Hydra configuration from the downloaded artifacts, and returns the
68
- output directory specified in that configuration.
69
-
70
- Args:
71
- run (Run | None): The run object. Defaults to None.
72
-
73
- Returns:
74
- Path: The path to the Hydra output directory.
75
-
76
- Raises:
77
- FileNotFoundError: If the Hydra configuration file is not found
78
- in the artifacts.
79
-
80
- """
81
- if run is None:
82
- hc = HydraConfig.get()
83
- return Path(hc.runtime.output_dir)
84
-
85
- path = get_artifact_dir(run) / ".hydra/hydra.yaml"
86
-
87
- if path.exists():
88
- hc = OmegaConf.load(path)
89
- return Path(hc.hydra.runtime.output_dir)
90
-
91
- raise FileNotFoundError
hydraflow/utils.py ADDED
@@ -0,0 +1,88 @@
1
+ """Provide utility functions for HydraFlow."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+ from typing import TYPE_CHECKING
7
+
8
+ import mlflow
9
+ from hydra.core.hydra_config import HydraConfig
10
+ from mlflow.entities import Run
11
+ from mlflow.tracking import artifact_utils
12
+ from omegaconf import DictConfig, OmegaConf
13
+
14
+ if TYPE_CHECKING:
15
+ from mlflow.entities import Run
16
+
17
+
18
+ def get_artifact_dir(run: Run | None = None) -> Path:
19
+ """Retrieve the artifact directory for the given run.
20
+
21
+ This function uses MLflow to get the artifact directory for the given run.
22
+
23
+ Args:
24
+ run (Run | None): The run object. Defaults to None.
25
+
26
+ Returns:
27
+ The local path to the directory where the artifacts are downloaded.
28
+
29
+ """
30
+ if run is None:
31
+ uri = mlflow.get_artifact_uri()
32
+ else:
33
+ uri = artifact_utils.get_artifact_uri(run.info.run_id)
34
+
35
+ return Path(mlflow.artifacts.download_artifacts(uri))
36
+
37
+
38
+ def get_hydra_output_dir(run: Run | None = None) -> Path:
39
+ """Retrieve the Hydra output directory for the given run.
40
+
41
+ This function returns the Hydra output directory. If no run is provided,
42
+ it retrieves the output directory from the current Hydra configuration.
43
+ If a run is provided, it retrieves the artifact path for the run, loads
44
+ the Hydra configuration from the downloaded artifacts, and returns the
45
+ output directory specified in that configuration.
46
+
47
+ Args:
48
+ run (Run | None): The run object. Defaults to None.
49
+
50
+ Returns:
51
+ Path: The path to the Hydra output directory.
52
+
53
+ Raises:
54
+ FileNotFoundError: If the Hydra configuration file is not found
55
+ in the artifacts.
56
+
57
+ """
58
+ if run is None:
59
+ hc = HydraConfig.get()
60
+ return Path(hc.runtime.output_dir)
61
+
62
+ path = get_artifact_dir(run) / ".hydra/hydra.yaml"
63
+
64
+ if path.exists():
65
+ hc = OmegaConf.load(path)
66
+ return Path(hc.hydra.runtime.output_dir)
67
+
68
+ raise FileNotFoundError
69
+
70
+
71
+ def load_config(run: Run) -> DictConfig:
72
+ """Load the configuration for a given run.
73
+
74
+ This function loads the configuration for the provided Run instance
75
+ by downloading the configuration file from the MLflow artifacts and
76
+ loading it using OmegaConf. It returns an empty config if
77
+ `.hydra/config.yaml` is not found in the run's artifact directory.
78
+
79
+ Args:
80
+ run (Run): The Run instance for which to load the configuration.
81
+
82
+ Returns:
83
+ The loaded configuration as a DictConfig object. Returns an empty
84
+ DictConfig if the configuration file is not found.
85
+
86
+ """
87
+ path = get_artifact_dir(run) / ".hydra/config.yaml"
88
+ return OmegaConf.load(path) # type: ignore
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: hydraflow
3
- Version: 0.3.0
3
+ Version: 0.3.1
4
4
  Summary: Hydraflow integrates Hydra and MLflow to manage and track machine learning experiments.
5
5
  Project-URL: Documentation, https://github.com/daizutabi/hydraflow
6
6
  Project-URL: Source, https://github.com/daizutabi/hydraflow
@@ -0,0 +1,16 @@
1
+ hydraflow/__init__.py,sha256=6sfM1ashUkfrNf7lOR7raFYhG8YdOAJR-JgRNL_IVo8,698
2
+ hydraflow/asyncio.py,sha256=-i1C8KAmNDImrjHnk92Csaa1mpjdK8Vp4ZVaQV-l94s,6634
3
+ hydraflow/config.py,sha256=6V5omJ3-h9-ZwVpM5rTA4FqE_mu8urTy9OqV4zG79gw,2671
4
+ hydraflow/context.py,sha256=412884e84qIEYtbxJT4roYsKfldGaTKzgo6Q1FAsT5U,8733
5
+ hydraflow/mlflow.py,sha256=JELqXFCJ9MsEJaQWT5dyleTFk8BHL7cQwW_gzhkPoIg,8729
6
+ hydraflow/param.py,sha256=dvIXcKgc_MPiju3WEk9qz5FOUeK5qSj-YWN2ophCpUM,1938
7
+ hydraflow/progress.py,sha256=zvKX1HCN8_xDOsgYOEcLLhkhdPdep-U8vHrc0XZ-6SQ,6163
8
+ hydraflow/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ hydraflow/run_collection.py,sha256=Xv6-KD5ac-vv-4Q3PZrzJy1x84H_g7UoP7ZqZ8_DQeQ,24973
10
+ hydraflow/run_data.py,sha256=ZXVr0PHyufH9wwyQYWtpE4_MheAC2ArTW_J1TTMQ4iI,983
11
+ hydraflow/run_info.py,sha256=sMXOo20ClaRIommMEzuAbO_OrcXx7M1Yt4FMV7spxz0,998
12
+ hydraflow/utils.py,sha256=aRdBdToKfvHhN2qFiRzPHIdQxS7cTpZREQeP8HreAfI,2676
13
+ hydraflow-0.3.1.dist-info/METADATA,sha256=W38pNcCNy7Kmx1t9dwFoANsRjCk40-KBJUWux_BvHqA,3840
14
+ hydraflow-0.3.1.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
15
+ hydraflow-0.3.1.dist-info/licenses/LICENSE,sha256=IGdDrBPqz1O0v_UwCW-NJlbX9Hy9b3uJ11t28y2srmY,1062
16
+ hydraflow-0.3.1.dist-info/RECORD,,
@@ -1,15 +0,0 @@
1
- hydraflow/__init__.py,sha256=zlLTztJPXyBFJC5Z8G7_OnlfzAHJPRrfE1c2OoDvlTg,667
2
- hydraflow/asyncio.py,sha256=-i1C8KAmNDImrjHnk92Csaa1mpjdK8Vp4ZVaQV-l94s,6634
3
- hydraflow/config.py,sha256=Wx7jymwLVr5EfpzXBpvv3Ax3VhGhvWyA7Yy6EzsPYWk,2479
4
- hydraflow/context.py,sha256=IaDy-ZCdCfWwv95S-gyQNp062oBdtSVaz6dxGmO6Y8w,8226
5
- hydraflow/mlflow.py,sha256=GkOr_pXfpfY5USYBLrCigHcP13VgrAK_e9kheR1Wke4,8579
6
- hydraflow/param.py,sha256=dvIXcKgc_MPiju3WEk9qz5FOUeK5qSj-YWN2ophCpUM,1938
7
- hydraflow/progress.py,sha256=zvKX1HCN8_xDOsgYOEcLLhkhdPdep-U8vHrc0XZ-6SQ,6163
8
- hydraflow/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- hydraflow/run_collection.py,sha256=Xv6-KD5ac-vv-4Q3PZrzJy1x84H_g7UoP7ZqZ8_DQeQ,24973
10
- hydraflow/run_data.py,sha256=HgXGjV5oN6VxOAhrFRjubWz5ZiRqT1a2VdS5OcH2UQQ,1732
11
- hydraflow/run_info.py,sha256=4QrTmyPEQ_PVn7JKXJIa9NkXGAdqh8k5Sue1ggQS5aQ,2678
12
- hydraflow-0.3.0.dist-info/METADATA,sha256=DmC1Yjwuc3snUQiePCr5xvdtbfIevOapiA2sg8w6Aho,3840
13
- hydraflow-0.3.0.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
14
- hydraflow-0.3.0.dist-info/licenses/LICENSE,sha256=IGdDrBPqz1O0v_UwCW-NJlbX9Hy9b3uJ11t28y2srmY,1062
15
- hydraflow-0.3.0.dist-info/RECORD,,