hydraflow 0.3.0__py3-none-any.whl → 0.3.1__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.
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,,