hydraflow 0.2.18__py3-none-any.whl → 0.3.0__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 +4 -1
- hydraflow/config.py +14 -0
- hydraflow/context.py +1 -1
- hydraflow/run_collection.py +28 -5
- hydraflow/run_data.py +56 -0
- hydraflow/{info.py → run_info.py} +1 -36
- {hydraflow-0.2.18.dist-info → hydraflow-0.3.0.dist-info}/METADATA +2 -1
- hydraflow-0.3.0.dist-info/RECORD +15 -0
- hydraflow-0.2.18.dist-info/RECORD +0 -14
- {hydraflow-0.2.18.dist-info → hydraflow-0.3.0.dist-info}/WHEEL +0 -0
- {hydraflow-0.2.18.dist-info → hydraflow-0.3.0.dist-info}/licenses/LICENSE +0 -0
hydraflow/__init__.py
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
+
"""Provide a collection of MLflow runs."""
|
2
|
+
|
1
3
|
from .context import chdir_artifact, log_run, start_run, watch
|
2
|
-
from .info import get_artifact_dir, get_hydra_output_dir, load_config
|
3
4
|
from .mlflow import (
|
4
5
|
list_runs,
|
5
6
|
search_runs,
|
@@ -7,6 +8,8 @@ from .mlflow import (
|
|
7
8
|
)
|
8
9
|
from .progress import multi_tasks_progress, parallel_progress
|
9
10
|
from .run_collection import RunCollection
|
11
|
+
from .run_data import load_config
|
12
|
+
from .run_info import get_artifact_dir, get_hydra_output_dir
|
10
13
|
|
11
14
|
__all__ = [
|
12
15
|
"RunCollection",
|
hydraflow/config.py
CHANGED
@@ -11,6 +11,20 @@ if TYPE_CHECKING:
|
|
11
11
|
from typing import Any
|
12
12
|
|
13
13
|
|
14
|
+
def collect_params(config: object) -> dict[str, Any]:
|
15
|
+
"""Iterate over parameters and collect them into a dictionary.
|
16
|
+
|
17
|
+
Args:
|
18
|
+
config (object): The configuration object to iterate over.
|
19
|
+
prefix (str): The prefix to prepend to the parameter keys.
|
20
|
+
|
21
|
+
Returns:
|
22
|
+
dict[str, Any]: A dictionary of collected parameters.
|
23
|
+
|
24
|
+
"""
|
25
|
+
return dict(iter_params(config))
|
26
|
+
|
27
|
+
|
14
28
|
def iter_params(config: object, prefix: str = "") -> Iterator[tuple[str, Any]]:
|
15
29
|
"""Recursively iterate over the parameters in the given configuration object.
|
16
30
|
|
hydraflow/context.py
CHANGED
@@ -14,8 +14,8 @@ from hydra.core.hydra_config import HydraConfig
|
|
14
14
|
from watchdog.events import FileModifiedEvent, PatternMatchingEventHandler
|
15
15
|
from watchdog.observers import Observer
|
16
16
|
|
17
|
-
from hydraflow.info import get_artifact_dir
|
18
17
|
from hydraflow.mlflow import log_params
|
18
|
+
from hydraflow.run_info import get_artifact_dir
|
19
19
|
|
20
20
|
if TYPE_CHECKING:
|
21
21
|
from collections.abc import Callable, Iterator
|
hydraflow/run_collection.py
CHANGED
@@ -24,10 +24,12 @@ from itertools import chain
|
|
24
24
|
from typing import TYPE_CHECKING, Any, Concatenate, ParamSpec, TypeVar, overload
|
25
25
|
|
26
26
|
from mlflow.entities import RunStatus
|
27
|
+
from polars.dataframe import DataFrame
|
27
28
|
|
28
29
|
import hydraflow.param
|
29
|
-
from hydraflow.config import iter_params
|
30
|
-
from hydraflow.
|
30
|
+
from hydraflow.config import collect_params, iter_params
|
31
|
+
from hydraflow.run_data import RunCollectionData
|
32
|
+
from hydraflow.run_info import RunCollectionInfo
|
31
33
|
|
32
34
|
if TYPE_CHECKING:
|
33
35
|
from collections.abc import Callable, Iterator
|
@@ -61,8 +63,12 @@ class RunCollection:
|
|
61
63
|
_info: RunCollectionInfo = field(init=False)
|
62
64
|
"""An instance of `RunCollectionInfo`."""
|
63
65
|
|
66
|
+
_data: RunCollectionData = field(init=False)
|
67
|
+
"""An instance of `RunCollectionData`."""
|
68
|
+
|
64
69
|
def __post_init__(self) -> None:
|
65
70
|
self._info = RunCollectionInfo(self)
|
71
|
+
self._data = RunCollectionData(self)
|
66
72
|
|
67
73
|
def __repr__(self) -> str:
|
68
74
|
return f"{self.__class__.__name__}({len(self)})"
|
@@ -101,6 +107,11 @@ class RunCollection:
|
|
101
107
|
"""An instance of `RunCollectionInfo`."""
|
102
108
|
return self._info
|
103
109
|
|
110
|
+
@property
|
111
|
+
def data(self) -> RunCollectionData:
|
112
|
+
"""An instance of `RunCollectionData`."""
|
113
|
+
return self._data
|
114
|
+
|
104
115
|
def take(self, n: int) -> RunCollection:
|
105
116
|
"""Take the first n runs from the collection.
|
106
117
|
|
@@ -371,7 +382,7 @@ class RunCollection:
|
|
371
382
|
raise ValueError(msg)
|
372
383
|
|
373
384
|
def try_get(self, config: object | None = None, **kwargs) -> Run | None:
|
374
|
-
"""Try to
|
385
|
+
"""Try to get a specific `Run` instance based on the provided configuration.
|
375
386
|
|
376
387
|
This method filters the runs in the collection according to the
|
377
388
|
specified configuration object and returns the run that matches the
|
@@ -505,7 +516,7 @@ class RunCollection:
|
|
505
516
|
in the collection.
|
506
517
|
|
507
518
|
"""
|
508
|
-
return (func(config, *args, **kwargs) for config in self.
|
519
|
+
return (func(config, *args, **kwargs) for config in self.data.config)
|
509
520
|
|
510
521
|
def map_uri(
|
511
522
|
self,
|
@@ -584,6 +595,16 @@ class RunCollection:
|
|
584
595
|
|
585
596
|
return {key: RunCollection(runs) for key, runs in grouped_runs.items()}
|
586
597
|
|
598
|
+
@property
|
599
|
+
def config(self) -> DataFrame:
|
600
|
+
"""Get the runs' configurations as a polars DataFrame.
|
601
|
+
|
602
|
+
Returns:
|
603
|
+
A polars DataFrame containing the runs' configurations.
|
604
|
+
|
605
|
+
"""
|
606
|
+
return DataFrame(self.map_config(collect_params))
|
607
|
+
|
587
608
|
|
588
609
|
def _param_matches(run: Run, key: str, value: Any) -> bool:
|
589
610
|
params = run.data.params
|
@@ -634,8 +655,10 @@ def filter_runs(
|
|
634
655
|
"""
|
635
656
|
for key, value in chain(iter_params(config), kwargs.items()):
|
636
657
|
runs = [run for run in runs if _param_matches(run, key, value)]
|
658
|
+
if not runs:
|
659
|
+
return []
|
637
660
|
|
638
|
-
if
|
661
|
+
if status is None:
|
639
662
|
return runs
|
640
663
|
|
641
664
|
return filter_runs_by_status(runs, status)
|
hydraflow/run_data.py
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
"""Provide information about MLflow runs."""
|
2
|
+
|
3
|
+
from __future__ import annotations
|
4
|
+
|
5
|
+
from typing import TYPE_CHECKING
|
6
|
+
|
7
|
+
from omegaconf import DictConfig, OmegaConf
|
8
|
+
|
9
|
+
from hydraflow.run_info import get_artifact_dir
|
10
|
+
|
11
|
+
if TYPE_CHECKING:
|
12
|
+
from mlflow.entities import Run
|
13
|
+
|
14
|
+
from hydraflow.run_collection import RunCollection
|
15
|
+
|
16
|
+
|
17
|
+
class RunCollectionData:
|
18
|
+
"""Provide information about MLflow runs."""
|
19
|
+
|
20
|
+
def __init__(self, runs: RunCollection) -> None:
|
21
|
+
self._runs = runs
|
22
|
+
|
23
|
+
@property
|
24
|
+
def params(self) -> list[dict[str, str]]:
|
25
|
+
"""Get the parameters for each run in the collection."""
|
26
|
+
return [run.data.params for run in self._runs]
|
27
|
+
|
28
|
+
@property
|
29
|
+
def metrics(self) -> list[dict[str, float]]:
|
30
|
+
"""Get the metrics for each run in the collection."""
|
31
|
+
return [run.data.metrics for run in self._runs]
|
32
|
+
|
33
|
+
@property
|
34
|
+
def config(self) -> list[DictConfig]:
|
35
|
+
"""Get the configuration for each run in the collection."""
|
36
|
+
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
|
@@ -8,7 +8,7 @@ from typing import TYPE_CHECKING
|
|
8
8
|
import mlflow
|
9
9
|
from hydra.core.hydra_config import HydraConfig
|
10
10
|
from mlflow.tracking import artifact_utils
|
11
|
-
from omegaconf import
|
11
|
+
from omegaconf import OmegaConf
|
12
12
|
|
13
13
|
if TYPE_CHECKING:
|
14
14
|
from mlflow.entities import Run
|
@@ -27,16 +27,6 @@ class RunCollectionInfo:
|
|
27
27
|
"""Get the run ID for each run in the collection."""
|
28
28
|
return [run.info.run_id for run in self._runs]
|
29
29
|
|
30
|
-
@property
|
31
|
-
def params(self) -> list[dict[str, str]]:
|
32
|
-
"""Get the parameters for each run in the collection."""
|
33
|
-
return [run.data.params for run in self._runs]
|
34
|
-
|
35
|
-
@property
|
36
|
-
def metrics(self) -> list[dict[str, float]]:
|
37
|
-
"""Get the metrics for each run in the collection."""
|
38
|
-
return [run.data.metrics for run in self._runs]
|
39
|
-
|
40
30
|
@property
|
41
31
|
def artifact_uri(self) -> list[str | None]:
|
42
32
|
"""Get the artifact URI for each run in the collection."""
|
@@ -47,11 +37,6 @@ class RunCollectionInfo:
|
|
47
37
|
"""Get the artifact directory for each run in the collection."""
|
48
38
|
return [get_artifact_dir(run) for run in self._runs]
|
49
39
|
|
50
|
-
@property
|
51
|
-
def config(self) -> list[DictConfig]:
|
52
|
-
"""Get the configuration for each run in the collection."""
|
53
|
-
return [load_config(run) for run in self._runs]
|
54
|
-
|
55
40
|
|
56
41
|
def get_artifact_dir(run: Run | None = None) -> Path:
|
57
42
|
"""Retrieve the artifact directory for the given run.
|
@@ -104,23 +89,3 @@ def get_hydra_output_dir(run: Run | None = None) -> Path:
|
|
104
89
|
return Path(hc.hydra.runtime.output_dir)
|
105
90
|
|
106
91
|
raise FileNotFoundError
|
107
|
-
|
108
|
-
|
109
|
-
def load_config(run: Run) -> DictConfig:
|
110
|
-
"""Load the configuration for a given run.
|
111
|
-
|
112
|
-
This function loads the configuration for the provided Run instance
|
113
|
-
by downloading the configuration file from the MLflow artifacts and
|
114
|
-
loading it using OmegaConf. It returns an empty config if
|
115
|
-
`.hydra/config.yaml` is not found in the run's artifact directory.
|
116
|
-
|
117
|
-
Args:
|
118
|
-
run (Run): The Run instance for which to load the configuration.
|
119
|
-
|
120
|
-
Returns:
|
121
|
-
The loaded configuration as a DictConfig object. Returns an empty
|
122
|
-
DictConfig if the configuration file is not found.
|
123
|
-
|
124
|
-
"""
|
125
|
-
path = get_artifact_dir(run) / ".hydra/config.yaml"
|
126
|
-
return OmegaConf.load(path) # type: ignore
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: hydraflow
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.3.0
|
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
|
@@ -17,6 +17,7 @@ Requires-Python: >=3.10
|
|
17
17
|
Requires-Dist: hydra-core>=1.3
|
18
18
|
Requires-Dist: joblib
|
19
19
|
Requires-Dist: mlflow>=2.15
|
20
|
+
Requires-Dist: polars
|
20
21
|
Requires-Dist: rich
|
21
22
|
Requires-Dist: watchdog
|
22
23
|
Requires-Dist: watchfiles
|
@@ -0,0 +1,15 @@
|
|
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,,
|
@@ -1,14 +0,0 @@
|
|
1
|
-
hydraflow/__init__.py,sha256=B7rWSiGP5WwWjijcb41Bv9uuo5MQ6gbBbVWGAWYtK-k,598
|
2
|
-
hydraflow/asyncio.py,sha256=-i1C8KAmNDImrjHnk92Csaa1mpjdK8Vp4ZVaQV-l94s,6634
|
3
|
-
hydraflow/config.py,sha256=sBaEYPMAGSIOc_wdDsWm0k4y3AZyWIET8gqa_o95SDA,2089
|
4
|
-
hydraflow/context.py,sha256=ih_jnexaHoToNq1dZ6sBzhJWFluPiQluOlYTYOzNEgk,8222
|
5
|
-
hydraflow/info.py,sha256=Vzyz9dEWcU9ovRG3JWshxIazzod1cZoHF74bHhHL3AI,3946
|
6
|
-
hydraflow/mlflow.py,sha256=GkOr_pXfpfY5USYBLrCigHcP13VgrAK_e9kheR1Wke4,8579
|
7
|
-
hydraflow/param.py,sha256=dvIXcKgc_MPiju3WEk9qz5FOUeK5qSj-YWN2ophCpUM,1938
|
8
|
-
hydraflow/progress.py,sha256=zvKX1HCN8_xDOsgYOEcLLhkhdPdep-U8vHrc0XZ-6SQ,6163
|
9
|
-
hydraflow/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
10
|
-
hydraflow/run_collection.py,sha256=gsseBQ6a2YolNanISgEgkjei7o9U6ZGV-Tk50UYH850,24295
|
11
|
-
hydraflow-0.2.18.dist-info/METADATA,sha256=roL3lGtlIibF6rHbCp4aXrCphhq-OkNe0JwLxM1xtBY,3819
|
12
|
-
hydraflow-0.2.18.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
|
13
|
-
hydraflow-0.2.18.dist-info/licenses/LICENSE,sha256=IGdDrBPqz1O0v_UwCW-NJlbX9Hy9b3uJ11t28y2srmY,1062
|
14
|
-
hydraflow-0.2.18.dist-info/RECORD,,
|
File without changes
|
File without changes
|