hydraflow 0.16.0__tar.gz → 0.16.2__tar.gz
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-0.16.0 → hydraflow-0.16.2}/PKG-INFO +2 -6
- {hydraflow-0.16.0 → hydraflow-0.16.2}/README.md +1 -5
- {hydraflow-0.16.0 → hydraflow-0.16.2}/docs/part1-applications/main-decorator.md +30 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/pyproject.toml +1 -1
- {hydraflow-0.16.0 → hydraflow-0.16.2}/src/hydraflow/core/io.py +33 -15
- {hydraflow-0.16.0 → hydraflow-0.16.2}/src/hydraflow/core/main.py +6 -1
- {hydraflow-0.16.0 → hydraflow-0.16.2}/src/hydraflow/core/run_info.py +3 -25
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/core/test_io.py +2 -2
- {hydraflow-0.16.0 → hydraflow-0.16.2}/.devcontainer/devcontainer.json +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/.devcontainer/postCreate.sh +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/.devcontainer/starship.toml +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/.gitattributes +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/.github/workflows/ci.yaml +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/.github/workflows/docs.yaml +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/.github/workflows/publish.yaml +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/.gitignore +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/LICENSE +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/docs/getting-started/concepts.md +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/docs/getting-started/index.md +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/docs/getting-started/installation.md +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/docs/index.md +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/docs/part1-applications/configuration.md +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/docs/part1-applications/execution.md +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/docs/part1-applications/index.md +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/docs/part2-advanced/index.md +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/docs/part2-advanced/job-configuration.md +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/docs/part2-advanced/sweep-syntax.md +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/docs/part3-analysis/index.md +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/docs/part3-analysis/run-class.md +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/docs/part3-analysis/run-collection.md +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/docs/part3-analysis/updating-runs.md +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/docs/practical-tutorials/advanced.md +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/docs/practical-tutorials/analysis.md +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/docs/practical-tutorials/applications.md +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/docs/practical-tutorials/index.md +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/examples/example.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/examples/hydraflow.yaml +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/examples/submit.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/mkdocs.yaml +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/src/hydraflow/__init__.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/src/hydraflow/cli.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/src/hydraflow/core/__init__.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/src/hydraflow/core/context.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/src/hydraflow/core/run.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/src/hydraflow/core/run_collection.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/src/hydraflow/executor/__init__.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/src/hydraflow/executor/aio.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/src/hydraflow/executor/conf.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/src/hydraflow/executor/io.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/src/hydraflow/executor/job.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/src/hydraflow/executor/parser.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/src/hydraflow/py.typed +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/__init__.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/cli/__init__.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/cli/app.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/cli/conftest.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/cli/hydraflow.yaml +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/cli/submit.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/cli/test_run.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/cli/test_setup.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/cli/test_show.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/cli/test_version.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/conftest.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/core/__init__.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/core/context/__init__.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/core/context/chdir.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/core/context/log_run.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/core/context/start_run.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/core/context/test_chdir.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/core/context/test_log_run.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/core/context/test_start_run.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/core/main/__init__.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/core/main/default.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/core/main/force_new_run.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/core/main/match_overrides.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/core/main/rerun_finished.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/core/main/skip_finished.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/core/main/test_default.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/core/main/test_force_new_run.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/core/main/test_main.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/core/main/test_match_overrides.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/core/main/test_rerun_finished.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/core/main/test_skip_finished.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/core/main/test_update.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/core/main/update.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/core/run/__init__.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/core/run/run.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/core/run/test_run.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/core/run/test_run_collection.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/core/run/test_run_info.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/executor/__init__.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/executor/conftest.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/executor/echo.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/executor/read.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/executor/test_aio.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/executor/test_args.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/executor/test_conf.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/executor/test_io.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/executor/test_job.py +0 -0
- {hydraflow-0.16.0 → hydraflow-0.16.2}/tests/executor/test_parser.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: hydraflow
|
3
|
-
Version: 0.16.
|
3
|
+
Version: 0.16.2
|
4
4
|
Summary: HydraFlow seamlessly integrates Hydra and MLflow to streamline ML experiment management, combining Hydra's configuration management with MLflow's tracking capabilities.
|
5
5
|
Project-URL: Documentation, https://daizutabi.github.io/hydraflow/
|
6
6
|
Project-URL: Source, https://github.com/daizutabi/hydraflow
|
@@ -194,10 +194,6 @@ For detailed documentation, visit our [documentation site](https://daizutabi.git
|
|
194
194
|
- [User Guide](https://daizutabi.github.io/hydraflow/part1-applications/) - Detailed documentation of HydraFlow's capabilities
|
195
195
|
- [API Reference](https://daizutabi.github.io/hydraflow/api/hydraflow/) - Complete API documentation
|
196
196
|
|
197
|
-
## Contributing
|
198
|
-
|
199
|
-
We welcome contributions! Please see our [contributing guide](CONTRIBUTING.md) for details.
|
200
|
-
|
201
197
|
## License
|
202
198
|
|
203
|
-
This project is licensed under the MIT License
|
199
|
+
This project is licensed under the MIT License.
|
@@ -141,10 +141,6 @@ For detailed documentation, visit our [documentation site](https://daizutabi.git
|
|
141
141
|
- [User Guide](https://daizutabi.github.io/hydraflow/part1-applications/) - Detailed documentation of HydraFlow's capabilities
|
142
142
|
- [API Reference](https://daizutabi.github.io/hydraflow/api/hydraflow/) - Complete API documentation
|
143
143
|
|
144
|
-
## Contributing
|
145
|
-
|
146
|
-
We welcome contributions! Please see our [contributing guide](CONTRIBUTING.md) for details.
|
147
|
-
|
148
144
|
## License
|
149
145
|
|
150
|
-
This project is licensed under the MIT License
|
146
|
+
This project is licensed under the MIT License.
|
@@ -242,6 +242,36 @@ This option is particularly useful when:
|
|
242
242
|
- You're iterating on experiments with command-line variations
|
243
243
|
- Your configuration contains volatile or automatically generated values
|
244
244
|
|
245
|
+
### Dynamic Configuration Updates (`update`)
|
246
|
+
|
247
|
+
Modify or enhance the configuration after it has been loaded by Hydra
|
248
|
+
but before the run starts:
|
249
|
+
|
250
|
+
```python
|
251
|
+
def update_config(cfg: Config) -> Config:
|
252
|
+
# Calculate derived values or add runtime information
|
253
|
+
if cfg.width > 0 and cfg.height > 0:
|
254
|
+
cfg.area = cfg.width * cfg.height
|
255
|
+
return cfg
|
256
|
+
|
257
|
+
@hydraflow.main(Config, update=update_config)
|
258
|
+
def train(run: Run, cfg: Config) -> None:
|
259
|
+
# Configuration has been updated with calculated area
|
260
|
+
print(f"Area: {cfg.area}")
|
261
|
+
```
|
262
|
+
|
263
|
+
This option is powerful when you need to:
|
264
|
+
|
265
|
+
- Calculate derived parameters based on existing configuration values
|
266
|
+
- Apply conditional logic to adjust parameters based on their relationships
|
267
|
+
- Ensure consistency between related parameters
|
268
|
+
- Adapt configurations to the current environment (e.g., hardware capabilities)
|
269
|
+
|
270
|
+
The `update` function should accept a configuration object and
|
271
|
+
return the same object (or None).
|
272
|
+
Any changes made to the configuration will be saved to the run's configuration file,
|
273
|
+
ensuring that the stored configuration accurately reflects all updates.
|
274
|
+
|
245
275
|
## Best Practices
|
246
276
|
|
247
277
|
1. **Keep Configuration Classes Focused**: Break down complex configurations
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
4
4
|
|
5
5
|
[project]
|
6
6
|
name = "hydraflow"
|
7
|
-
version = "0.16.
|
7
|
+
version = "0.16.2"
|
8
8
|
description = "HydraFlow seamlessly integrates Hydra and MLflow to streamline ML experiment management, combining Hydra's configuration management with MLflow's tracking capabilities."
|
9
9
|
readme = "README.md"
|
10
10
|
license = { file = "LICENSE" }
|
@@ -5,9 +5,12 @@ from __future__ import annotations
|
|
5
5
|
import fnmatch
|
6
6
|
import urllib.parse
|
7
7
|
import urllib.request
|
8
|
+
from functools import cache
|
8
9
|
from pathlib import Path
|
9
10
|
from typing import TYPE_CHECKING
|
10
11
|
|
12
|
+
from omegaconf import OmegaConf
|
13
|
+
|
11
14
|
if TYPE_CHECKING:
|
12
15
|
from collections.abc import Callable, Iterator
|
13
16
|
|
@@ -74,27 +77,37 @@ def log_text(run: Run, from_dir: Path, pattern: str = "*.log") -> None:
|
|
74
77
|
mlflow.log_text(text, file.name)
|
75
78
|
|
76
79
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
80
|
+
@cache
|
81
|
+
def get_experiment_name(experiment_dir: Path) -> str:
|
82
|
+
"""Get the job name from an experiment directory.
|
83
|
+
|
84
|
+
Extracts the job name from the meta.yaml file. Returns an empty string
|
85
|
+
if the file does not exist or if the job name cannot be found.
|
86
|
+
|
87
|
+
Args:
|
88
|
+
experiment_dir: Path to the experiment directory containing the meta.yaml file
|
89
|
+
|
90
|
+
Returns:
|
91
|
+
The job name as a string, or an empty string if the file does not exist
|
92
|
+
|
93
|
+
"""
|
94
|
+
path = experiment_dir / "meta.yaml"
|
95
|
+
if not path.exists():
|
96
|
+
return ""
|
97
|
+
|
98
|
+
meta = OmegaConf.load(experiment_dir / "meta.yaml")
|
99
|
+
return OmegaConf.select(meta, "name", default="")
|
87
100
|
|
88
101
|
|
89
102
|
def predicate_experiment_dir(
|
90
|
-
|
103
|
+
experiment_dir: Path,
|
91
104
|
experiment_names: list[str] | Callable[[str], bool] | None = None,
|
92
105
|
) -> bool:
|
93
106
|
"""Predicate an experiment directory based on the path and experiment names."""
|
94
|
-
if not
|
107
|
+
if not experiment_dir.is_dir() or experiment_dir.name in [".trash", "0"]:
|
95
108
|
return False
|
96
109
|
|
97
|
-
name = get_experiment_name(
|
110
|
+
name = get_experiment_name(experiment_dir)
|
98
111
|
if not name:
|
99
112
|
return False
|
100
113
|
|
@@ -108,9 +121,14 @@ def predicate_experiment_dir(
|
|
108
121
|
|
109
122
|
|
110
123
|
def get_experiment_names(tracking_dir: str | Path) -> list[str]:
|
111
|
-
"""Get the experiment names from the tracking directory.
|
124
|
+
"""Get the experiment names from the tracking directory.
|
125
|
+
|
126
|
+
Returns:
|
127
|
+
list[str]: A list of experiment names sorted by the name.
|
128
|
+
|
129
|
+
"""
|
112
130
|
names = [get_experiment_name(path) for path in Path(tracking_dir).iterdir()]
|
113
|
-
return
|
131
|
+
return sorted(name for name in names if name and name != "Default")
|
114
132
|
|
115
133
|
|
116
134
|
def iter_experiment_dirs(
|
@@ -82,7 +82,12 @@ def main[C](
|
|
82
82
|
rerun_finished: If True, allows rerunning completed runs. Defaults to
|
83
83
|
False.
|
84
84
|
update: A function that takes a configuration and returns a new
|
85
|
-
configuration.
|
85
|
+
configuration or None. The function can modify the configuration in-place
|
86
|
+
and/or return it. If the function returns None, the original (potentially
|
87
|
+
modified) configuration is used. Changes made by this function are saved
|
88
|
+
to the configuration file. This is useful for adding derived parameters,
|
89
|
+
ensuring consistency between related values, or adding runtime information
|
90
|
+
to the configuration. Defaults to None.
|
86
91
|
|
87
92
|
"""
|
88
93
|
import mlflow
|
@@ -11,11 +11,11 @@ was created.
|
|
11
11
|
from __future__ import annotations
|
12
12
|
|
13
13
|
from dataclasses import dataclass
|
14
|
-
from functools import
|
14
|
+
from functools import cached_property
|
15
15
|
from pathlib import Path
|
16
16
|
from typing import TYPE_CHECKING
|
17
17
|
|
18
|
-
from
|
18
|
+
from .io import get_experiment_name
|
19
19
|
|
20
20
|
if TYPE_CHECKING:
|
21
21
|
from pathlib import Path
|
@@ -50,7 +50,7 @@ class RunInfo:
|
|
50
50
|
Hydra configuration file (e.g., if the file does not exist or does not
|
51
51
|
contain the expected format).
|
52
52
|
"""
|
53
|
-
return
|
53
|
+
return get_experiment_name(self.run_dir.parent)
|
54
54
|
|
55
55
|
def to_dict(self) -> dict[str, Any]:
|
56
56
|
"""Convert the RunInfo to a dictionary."""
|
@@ -59,25 +59,3 @@ class RunInfo:
|
|
59
59
|
"run_dir": self.run_dir.as_posix(),
|
60
60
|
"job_name": self.job_name,
|
61
61
|
}
|
62
|
-
|
63
|
-
|
64
|
-
@cache
|
65
|
-
def get_job_name(experiment_dir: Path) -> str:
|
66
|
-
"""Get the job name from an experiment directory.
|
67
|
-
|
68
|
-
Extracts the job name from the meta.yaml file. Returns an empty string
|
69
|
-
if the file does not exist or if the job name cannot be found.
|
70
|
-
|
71
|
-
Args:
|
72
|
-
experiment_dir: Path to the experiment directory containing the meta.yaml file
|
73
|
-
|
74
|
-
Returns:
|
75
|
-
The job name as a string, or an empty string if the file does not exist
|
76
|
-
|
77
|
-
"""
|
78
|
-
path = experiment_dir / "meta.yaml"
|
79
|
-
if not path.exists():
|
80
|
-
return ""
|
81
|
-
|
82
|
-
meta = OmegaConf.load(experiment_dir / "meta.yaml")
|
83
|
-
return OmegaConf.select(meta, "name")
|
@@ -90,14 +90,14 @@ def test_predicate_experiment_dir():
|
|
90
90
|
def test_get_experiment_name_none(tracking_dir: Path):
|
91
91
|
from hydraflow.core.io import get_experiment_name
|
92
92
|
|
93
|
-
assert get_experiment_name(tracking_dir.parent)
|
93
|
+
assert get_experiment_name(tracking_dir.parent) == ""
|
94
94
|
|
95
95
|
|
96
96
|
def test_get_experiment_name_metafile_none(tracking_dir: Path):
|
97
97
|
from hydraflow.core.io import get_experiment_name
|
98
98
|
|
99
99
|
(tracking_dir / "meta.yaml").touch()
|
100
|
-
assert get_experiment_name(tracking_dir)
|
100
|
+
assert get_experiment_name(tracking_dir) == ""
|
101
101
|
|
102
102
|
|
103
103
|
def test_iter_run_dirs(tracking_dir: Path):
|
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
|
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
|
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
|
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
|