hydraflow 0.2.11__tar.gz → 0.2.13__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
- {hydraflow-0.2.11 → hydraflow-0.2.13}/PKG-INFO +1 -3
- {hydraflow-0.2.11 → hydraflow-0.2.13}/pyproject.toml +1 -3
- {hydraflow-0.2.11 → hydraflow-0.2.13}/src/hydraflow/mlflow.py +30 -4
- {hydraflow-0.2.11 → hydraflow-0.2.13}/tests/test_app.py +14 -0
- {hydraflow-0.2.11 → hydraflow-0.2.13}/tests/test_run_collection.py +2 -2
- {hydraflow-0.2.11 → hydraflow-0.2.13}/.devcontainer/devcontainer.json +0 -0
- {hydraflow-0.2.11 → hydraflow-0.2.13}/.devcontainer/postCreate.sh +0 -0
- {hydraflow-0.2.11 → hydraflow-0.2.13}/.devcontainer/starship.toml +0 -0
- {hydraflow-0.2.11 → hydraflow-0.2.13}/.gitattributes +0 -0
- {hydraflow-0.2.11 → hydraflow-0.2.13}/.gitignore +0 -0
- {hydraflow-0.2.11 → hydraflow-0.2.13}/LICENSE +0 -0
- {hydraflow-0.2.11 → hydraflow-0.2.13}/README.md +0 -0
- {hydraflow-0.2.11 → hydraflow-0.2.13}/src/hydraflow/__init__.py +0 -0
- {hydraflow-0.2.11 → hydraflow-0.2.13}/src/hydraflow/asyncio.py +0 -0
- {hydraflow-0.2.11 → hydraflow-0.2.13}/src/hydraflow/config.py +0 -0
- {hydraflow-0.2.11 → hydraflow-0.2.13}/src/hydraflow/context.py +0 -0
- {hydraflow-0.2.11 → hydraflow-0.2.13}/src/hydraflow/info.py +0 -0
- {hydraflow-0.2.11 → hydraflow-0.2.13}/src/hydraflow/progress.py +0 -0
- {hydraflow-0.2.11 → hydraflow-0.2.13}/src/hydraflow/run_collection.py +0 -0
- {hydraflow-0.2.11 → hydraflow-0.2.13}/tests/scripts/__init__.py +0 -0
- {hydraflow-0.2.11 → hydraflow-0.2.13}/tests/scripts/app.py +0 -0
- {hydraflow-0.2.11 → hydraflow-0.2.13}/tests/scripts/progress.py +0 -0
- {hydraflow-0.2.11 → hydraflow-0.2.13}/tests/scripts/watch.py +0 -0
- {hydraflow-0.2.11 → hydraflow-0.2.13}/tests/test_asyncio.py +0 -0
- {hydraflow-0.2.11 → hydraflow-0.2.13}/tests/test_config.py +0 -0
- {hydraflow-0.2.11 → hydraflow-0.2.13}/tests/test_context.py +0 -0
- {hydraflow-0.2.11 → hydraflow-0.2.13}/tests/test_info.py +0 -0
- {hydraflow-0.2.11 → hydraflow-0.2.13}/tests/test_log_run.py +0 -0
- {hydraflow-0.2.11 → hydraflow-0.2.13}/tests/test_mlflow.py +0 -0
- {hydraflow-0.2.11 → hydraflow-0.2.13}/tests/test_progress.py +0 -0
- {hydraflow-0.2.11 → hydraflow-0.2.13}/tests/test_version.py +0 -0
- {hydraflow-0.2.11 → hydraflow-0.2.13}/tests/test_watch.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: hydraflow
|
3
|
-
Version: 0.2.
|
3
|
+
Version: 0.2.13
|
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
|
@@ -13,8 +13,6 @@ Classifier: Programming Language :: Python
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.10
|
14
14
|
Classifier: Programming Language :: Python :: 3.11
|
15
15
|
Classifier: Programming Language :: Python :: 3.12
|
16
|
-
Classifier: Topic :: Documentation
|
17
|
-
Classifier: Topic :: Software Development :: Documentation
|
18
16
|
Requires-Python: >=3.10
|
19
17
|
Requires-Dist: hydra-core>1.3
|
20
18
|
Requires-Dist: joblib
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
4
4
|
|
5
5
|
[project]
|
6
6
|
name = "hydraflow"
|
7
|
-
version = "0.2.
|
7
|
+
version = "0.2.13"
|
8
8
|
description = "Hydraflow integrates Hydra and MLflow to manage and track machine learning experiments."
|
9
9
|
readme = "README.md"
|
10
10
|
license = "MIT"
|
@@ -15,8 +15,6 @@ classifiers = [
|
|
15
15
|
"Programming Language :: Python :: 3.10",
|
16
16
|
"Programming Language :: Python :: 3.11",
|
17
17
|
"Programming Language :: Python :: 3.12",
|
18
|
-
"Topic :: Documentation",
|
19
|
-
"Topic :: Software Development :: Documentation",
|
20
18
|
]
|
21
19
|
requires-python = ">=3.10"
|
22
20
|
dependencies = [
|
@@ -22,6 +22,7 @@ from __future__ import annotations
|
|
22
22
|
from pathlib import Path
|
23
23
|
from typing import TYPE_CHECKING
|
24
24
|
|
25
|
+
import joblib
|
25
26
|
import mlflow
|
26
27
|
from hydra.core.hydra_config import HydraConfig
|
27
28
|
from mlflow.entities import ViewType
|
@@ -146,7 +147,9 @@ def search_runs(
|
|
146
147
|
return RunCollection(runs) # type: ignore
|
147
148
|
|
148
149
|
|
149
|
-
def list_runs(
|
150
|
+
def list_runs(
|
151
|
+
experiment_names: str | list[str] | None = None, n_jobs: int = 0
|
152
|
+
) -> RunCollection:
|
150
153
|
"""
|
151
154
|
List all runs for the specified experiments.
|
152
155
|
|
@@ -166,10 +169,33 @@ def list_runs(experiment_names: list[str] | None = None) -> RunCollection:
|
|
166
169
|
the "Default" experiment.
|
167
170
|
|
168
171
|
Returns:
|
169
|
-
A `RunCollection`
|
172
|
+
RunCollection: A `RunCollection` instance containing the runs for the
|
173
|
+
specified experiments.
|
170
174
|
"""
|
171
|
-
if experiment_names
|
175
|
+
if isinstance(experiment_names, str):
|
176
|
+
experiment_names = [experiment_names]
|
177
|
+
|
178
|
+
elif experiment_names == []:
|
172
179
|
experiments = mlflow.search_experiments()
|
173
180
|
experiment_names = [e.name for e in experiments if e.name != "Default"]
|
174
181
|
|
175
|
-
|
182
|
+
if n_jobs == 0:
|
183
|
+
return search_runs(experiment_names=experiment_names)
|
184
|
+
|
185
|
+
if experiment_names is None:
|
186
|
+
raise NotImplementedError
|
187
|
+
|
188
|
+
run_ids = []
|
189
|
+
|
190
|
+
for name in experiment_names:
|
191
|
+
if experiment := mlflow.get_experiment_by_name(name):
|
192
|
+
loc = experiment.artifact_location
|
193
|
+
|
194
|
+
if isinstance(loc, str) and loc.startswith("file://"):
|
195
|
+
path = Path(mlflow.artifacts.download_artifacts(loc))
|
196
|
+
run_ids.extend(file.stem for file in path.iterdir() if file.is_dir())
|
197
|
+
|
198
|
+
it = (joblib.delayed(mlflow.get_run)(run_id) for run_id in run_ids)
|
199
|
+
runs = joblib.Parallel(n_jobs, prefer="threads")(it)
|
200
|
+
runs = sorted(runs, key=lambda run: run.info.start_time) # type: ignore
|
201
|
+
return RunCollection(runs) # type: ignore
|
@@ -26,6 +26,20 @@ def rc(monkeypatch, tmp_path):
|
|
26
26
|
yield hydraflow.list_runs()
|
27
27
|
|
28
28
|
|
29
|
+
@pytest.mark.parametrize("n_jobs", [0, 1, 2, 4, -1])
|
30
|
+
def test_list_runs_parallel(rc: RunCollection, n_jobs: int):
|
31
|
+
from hydraflow.mlflow import list_runs
|
32
|
+
|
33
|
+
rc_ = list_runs("_info_", n_jobs=n_jobs)
|
34
|
+
assert len(rc) == len(rc_)
|
35
|
+
|
36
|
+
for a, b in zip(rc, rc_):
|
37
|
+
assert a.info.run_id == b.info.run_id
|
38
|
+
assert a.info.start_time == b.info.start_time
|
39
|
+
assert a.info.status == b.info.status
|
40
|
+
assert a.info.artifact_uri == b.info.artifact_uri
|
41
|
+
|
42
|
+
|
29
43
|
def test_app_info_run_id(rc: RunCollection):
|
30
44
|
assert len(rc.info.run_id) == 4
|
31
45
|
|
@@ -364,14 +364,14 @@ def test_list_runs_empty_list(runs, runs2):
|
|
364
364
|
def test_list_runs_list(runs, runs2, name, n):
|
365
365
|
from hydraflow.mlflow import list_runs
|
366
366
|
|
367
|
-
filtered_runs = list_runs(
|
367
|
+
filtered_runs = list_runs(name)
|
368
368
|
assert len(filtered_runs) == n
|
369
369
|
|
370
370
|
|
371
371
|
def test_list_runs_none(runs, runs2):
|
372
372
|
from hydraflow.mlflow import list_runs
|
373
373
|
|
374
|
-
no_runs = list_runs(
|
374
|
+
no_runs = list_runs(["non_existent_experiment"])
|
375
375
|
assert len(no_runs) == 0
|
376
376
|
|
377
377
|
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|