hydraflow 0.14.4__tar.gz → 0.15.0__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.
Files changed (116) hide show
  1. {hydraflow-0.14.4 → hydraflow-0.15.0}/.github/workflows/ci.yaml +2 -2
  2. {hydraflow-0.14.4 → hydraflow-0.15.0}/PKG-INFO +11 -9
  3. {hydraflow-0.14.4 → hydraflow-0.15.0}/README.md +6 -4
  4. hydraflow-0.15.0/docs/index.md +117 -0
  5. hydraflow-0.15.0/docs/usage/quickstart.md +330 -0
  6. {hydraflow-0.14.4 → hydraflow-0.15.0}/mkdocs.yaml +8 -0
  7. {hydraflow-0.14.4 → hydraflow-0.15.0}/pyproject.toml +7 -12
  8. {hydraflow-0.14.4 → hydraflow-0.15.0}/src/hydraflow/__init__.py +3 -13
  9. {hydraflow-0.14.4 → hydraflow-0.15.0}/src/hydraflow/core/context.py +12 -32
  10. hydraflow-0.15.0/src/hydraflow/core/io.py +150 -0
  11. {hydraflow-0.14.4 → hydraflow-0.15.0}/src/hydraflow/core/main.py +3 -3
  12. hydraflow-0.15.0/src/hydraflow/core/run.py +341 -0
  13. hydraflow-0.15.0/src/hydraflow/core/run_collection.py +525 -0
  14. hydraflow-0.15.0/src/hydraflow/core/run_info.py +84 -0
  15. {hydraflow-0.14.4 → hydraflow-0.15.0}/tests/cli/app.py +3 -3
  16. {hydraflow-0.14.4 → hydraflow-0.15.0}/tests/cli/test_run.py +13 -20
  17. {hydraflow-0.14.4 → hydraflow-0.15.0}/tests/conftest.py +20 -4
  18. {hydraflow-0.14.4 → hydraflow-0.15.0}/tests/core/context/chdir.py +1 -1
  19. {hydraflow-0.14.4 → hydraflow-0.15.0}/tests/core/context/log_run.py +1 -1
  20. {hydraflow-0.14.4 → hydraflow-0.15.0}/tests/core/context/start_run.py +2 -2
  21. hydraflow-0.15.0/tests/core/context/test_chdir.py +24 -0
  22. hydraflow-0.15.0/tests/core/context/test_log_run.py +45 -0
  23. hydraflow-0.15.0/tests/core/context/test_start_run.py +29 -0
  24. {hydraflow-0.14.4 → hydraflow-0.15.0}/tests/core/main/default.py +3 -3
  25. hydraflow-0.15.0/tests/core/main/test_default.py +60 -0
  26. hydraflow-0.15.0/tests/core/main/test_force_new_run.py +29 -0
  27. hydraflow-0.15.0/tests/core/main/test_main.py +13 -0
  28. hydraflow-0.15.0/tests/core/main/test_match_overrides.py +15 -0
  29. hydraflow-0.15.0/tests/core/main/test_rerun_finished.py +20 -0
  30. hydraflow-0.15.0/tests/core/main/test_skip_finished.py +71 -0
  31. hydraflow-0.15.0/tests/core/run/run.py +31 -0
  32. hydraflow-0.15.0/tests/core/run/test_run.py +251 -0
  33. hydraflow-0.15.0/tests/core/run/test_run_collection.py +290 -0
  34. hydraflow-0.15.0/tests/core/run/test_run_info.py +48 -0
  35. hydraflow-0.14.4/tests/core/io/test_iter_dirs.py → hydraflow-0.15.0/tests/core/test_io.py +37 -21
  36. hydraflow-0.14.4/docs/index.md +0 -10
  37. hydraflow-0.14.4/docs/usage/quickstart.md +0 -143
  38. hydraflow-0.14.4/src/hydraflow/core/config.py +0 -122
  39. hydraflow-0.14.4/src/hydraflow/core/io.py +0 -229
  40. hydraflow-0.14.4/src/hydraflow/core/mlflow.py +0 -174
  41. hydraflow-0.14.4/src/hydraflow/core/param.py +0 -165
  42. hydraflow-0.14.4/src/hydraflow/entities/run_collection.py +0 -583
  43. hydraflow-0.14.4/src/hydraflow/entities/run_data.py +0 -61
  44. hydraflow-0.14.4/src/hydraflow/entities/run_info.py +0 -36
  45. hydraflow-0.14.4/tests/core/config/test_config.py +0 -54
  46. hydraflow-0.14.4/tests/core/config/test_params.py +0 -176
  47. hydraflow-0.14.4/tests/core/context/test_chdir.py +0 -30
  48. hydraflow-0.14.4/tests/core/context/test_log_run.py +0 -58
  49. hydraflow-0.14.4/tests/core/context/test_start_run.py +0 -34
  50. hydraflow-0.14.4/tests/core/io/hydra_dir.py +0 -34
  51. hydraflow-0.14.4/tests/core/io/test_hydra_dir.py +0 -64
  52. hydraflow-0.14.4/tests/core/io/test_run.py +0 -51
  53. hydraflow-0.14.4/tests/core/main/__init__.py +0 -0
  54. hydraflow-0.14.4/tests/core/main/test_default.py +0 -63
  55. hydraflow-0.14.4/tests/core/main/test_force_new_run.py +0 -36
  56. hydraflow-0.14.4/tests/core/main/test_match_overrides.py +0 -31
  57. hydraflow-0.14.4/tests/core/main/test_rerun_finished.py +0 -27
  58. hydraflow-0.14.4/tests/core/main/test_skip_finished.py +0 -60
  59. hydraflow-0.14.4/tests/core/param/__init__.py +0 -0
  60. hydraflow-0.14.4/tests/core/param/params.py +0 -39
  61. hydraflow-0.14.4/tests/core/param/test_param.py +0 -158
  62. hydraflow-0.14.4/tests/core/param/test_params.py +0 -49
  63. hydraflow-0.14.4/tests/core/test_mlflow.py +0 -83
  64. hydraflow-0.14.4/tests/entities/__init__.py +0 -0
  65. hydraflow-0.14.4/tests/entities/filter.py +0 -35
  66. hydraflow-0.14.4/tests/entities/test_collection.py +0 -417
  67. hydraflow-0.14.4/tests/entities/test_data.py +0 -44
  68. hydraflow-0.14.4/tests/entities/test_filter.py +0 -44
  69. hydraflow-0.14.4/tests/entities/test_info.py +0 -47
  70. hydraflow-0.14.4/tests/entities/test_values.py +0 -37
  71. hydraflow-0.14.4/tests/entities/values.py +0 -34
  72. hydraflow-0.14.4/tests/executor/__init__.py +0 -0
  73. {hydraflow-0.14.4 → hydraflow-0.15.0}/.devcontainer/devcontainer.json +0 -0
  74. {hydraflow-0.14.4 → hydraflow-0.15.0}/.devcontainer/postCreate.sh +0 -0
  75. {hydraflow-0.14.4 → hydraflow-0.15.0}/.devcontainer/starship.toml +0 -0
  76. {hydraflow-0.14.4 → hydraflow-0.15.0}/.gitattributes +0 -0
  77. {hydraflow-0.14.4 → hydraflow-0.15.0}/.github/workflows/docs.yaml +0 -0
  78. {hydraflow-0.14.4 → hydraflow-0.15.0}/.github/workflows/publish.yaml +0 -0
  79. {hydraflow-0.14.4 → hydraflow-0.15.0}/.gitignore +0 -0
  80. {hydraflow-0.14.4 → hydraflow-0.15.0}/LICENSE +0 -0
  81. {hydraflow-0.14.4 → hydraflow-0.15.0}/apps/quickstart.py +0 -0
  82. {hydraflow-0.14.4 → hydraflow-0.15.0}/src/hydraflow/cli.py +0 -0
  83. {hydraflow-0.14.4 → hydraflow-0.15.0}/src/hydraflow/core/__init__.py +0 -0
  84. {hydraflow-0.14.4/src/hydraflow/entities → hydraflow-0.15.0/src/hydraflow/executor}/__init__.py +0 -0
  85. {hydraflow-0.14.4 → hydraflow-0.15.0}/src/hydraflow/executor/aio.py +0 -0
  86. {hydraflow-0.14.4 → hydraflow-0.15.0}/src/hydraflow/executor/conf.py +0 -0
  87. {hydraflow-0.14.4 → hydraflow-0.15.0}/src/hydraflow/executor/io.py +0 -0
  88. {hydraflow-0.14.4 → hydraflow-0.15.0}/src/hydraflow/executor/job.py +0 -0
  89. {hydraflow-0.14.4 → hydraflow-0.15.0}/src/hydraflow/executor/parser.py +0 -0
  90. {hydraflow-0.14.4 → hydraflow-0.15.0}/src/hydraflow/py.typed +0 -0
  91. {hydraflow-0.14.4/src/hydraflow/executor → hydraflow-0.15.0/tests}/__init__.py +0 -0
  92. {hydraflow-0.14.4/tests → hydraflow-0.15.0/tests/cli}/__init__.py +0 -0
  93. {hydraflow-0.14.4 → hydraflow-0.15.0}/tests/cli/conftest.py +0 -0
  94. {hydraflow-0.14.4 → hydraflow-0.15.0}/tests/cli/hydraflow.yaml +0 -0
  95. {hydraflow-0.14.4 → hydraflow-0.15.0}/tests/cli/submit.py +0 -0
  96. {hydraflow-0.14.4 → hydraflow-0.15.0}/tests/cli/test_setup.py +0 -0
  97. {hydraflow-0.14.4 → hydraflow-0.15.0}/tests/cli/test_show.py +0 -0
  98. {hydraflow-0.14.4 → hydraflow-0.15.0}/tests/cli/test_version.py +0 -0
  99. {hydraflow-0.14.4/tests/cli → hydraflow-0.15.0/tests/core}/__init__.py +0 -0
  100. {hydraflow-0.14.4/tests/core → hydraflow-0.15.0/tests/core/context}/__init__.py +0 -0
  101. {hydraflow-0.14.4/tests/core/config → hydraflow-0.15.0/tests/core/main}/__init__.py +0 -0
  102. {hydraflow-0.14.4 → hydraflow-0.15.0}/tests/core/main/force_new_run.py +0 -0
  103. {hydraflow-0.14.4 → hydraflow-0.15.0}/tests/core/main/match_overrides.py +0 -0
  104. {hydraflow-0.14.4 → hydraflow-0.15.0}/tests/core/main/rerun_finished.py +0 -0
  105. {hydraflow-0.14.4 → hydraflow-0.15.0}/tests/core/main/skip_finished.py +0 -0
  106. {hydraflow-0.14.4/tests/core/context → hydraflow-0.15.0/tests/core/run}/__init__.py +0 -0
  107. {hydraflow-0.14.4/tests/core/io → hydraflow-0.15.0/tests/executor}/__init__.py +0 -0
  108. {hydraflow-0.14.4 → hydraflow-0.15.0}/tests/executor/conftest.py +0 -0
  109. {hydraflow-0.14.4 → hydraflow-0.15.0}/tests/executor/echo.py +0 -0
  110. {hydraflow-0.14.4 → hydraflow-0.15.0}/tests/executor/read.py +0 -0
  111. {hydraflow-0.14.4 → hydraflow-0.15.0}/tests/executor/test_aio.py +0 -0
  112. {hydraflow-0.14.4 → hydraflow-0.15.0}/tests/executor/test_args.py +0 -0
  113. {hydraflow-0.14.4 → hydraflow-0.15.0}/tests/executor/test_conf.py +0 -0
  114. {hydraflow-0.14.4 → hydraflow-0.15.0}/tests/executor/test_io.py +0 -0
  115. {hydraflow-0.14.4 → hydraflow-0.15.0}/tests/executor/test_job.py +0 -0
  116. {hydraflow-0.14.4 → hydraflow-0.15.0}/tests/executor/test_parser.py +0 -0
@@ -21,7 +21,7 @@ jobs:
21
21
  fail-fast: false
22
22
  matrix:
23
23
  os: [ubuntu-latest, windows-latest, macos-latest]
24
- python-version: ["3.10", "3.11", "3.12", "3.13"]
24
+ python-version: ["3.13"]
25
25
 
26
26
  steps:
27
27
  - uses: actions/checkout@v4
@@ -36,7 +36,7 @@ jobs:
36
36
  - name: Ruff check
37
37
  run: ruff check
38
38
  - name: Run test
39
- run: uv run pytest -v --junitxml=junit.xml
39
+ run: uv run pytest -v -n8 --junitxml=junit.xml
40
40
  - name: Upload Codecov Results
41
41
  if: success()
42
42
  uses: codecov/codecov-action@v4
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hydraflow
3
- Version: 0.14.4
3
+ Version: 0.15.0
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
@@ -36,40 +36,40 @@ Classifier: Intended Audience :: Science/Research
36
36
  Classifier: License :: OSI Approved :: MIT License
37
37
  Classifier: Operating System :: OS Independent
38
38
  Classifier: Programming Language :: Python
39
- Classifier: Programming Language :: Python :: 3.10
40
- Classifier: Programming Language :: Python :: 3.11
41
- Classifier: Programming Language :: Python :: 3.12
42
39
  Classifier: Programming Language :: Python :: 3.13
43
40
  Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
44
41
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
45
- Requires-Python: >=3.10
42
+ Requires-Python: >=3.13
46
43
  Requires-Dist: hydra-core>=1.3
44
+ Requires-Dist: joblib>=1.4.0
47
45
  Requires-Dist: mlflow>=2.15
48
46
  Requires-Dist: omegaconf>=2.3
47
+ Requires-Dist: polars>=1.26
49
48
  Requires-Dist: python-ulid>=3.0.0
50
49
  Requires-Dist: rich>=13.9
50
+ Requires-Dist: ruff>=0.11
51
51
  Requires-Dist: typer>=0.15
52
52
  Description-Content-Type: text/markdown
53
53
 
54
54
  # Hydraflow
55
55
 
56
56
  [![PyPI Version][pypi-v-image]][pypi-v-link]
57
- [![Python Version][python-v-image]][python-v-link]
58
57
  [![Build Status][GHAction-image]][GHAction-link]
59
58
  [![Coverage Status][codecov-image]][codecov-link]
60
59
  [![Documentation Status][docs-image]][docs-link]
60
+ [![Python Version][python-v-image]][python-v-link]
61
61
 
62
62
  <!-- Badges -->
63
63
  [pypi-v-image]: https://img.shields.io/pypi/v/hydraflow.svg
64
64
  [pypi-v-link]: https://pypi.org/project/hydraflow/
65
- [python-v-image]: https://img.shields.io/pypi/pyversions/hydraflow.svg
66
- [python-v-link]: https://pypi.org/project/hydraflow
67
65
  [GHAction-image]: https://github.com/daizutabi/hydraflow/actions/workflows/ci.yaml/badge.svg?branch=main&event=push
68
66
  [GHAction-link]: https://github.com/daizutabi/hydraflow/actions?query=event%3Apush+branch%3Amain
69
67
  [codecov-image]: https://codecov.io/github/daizutabi/hydraflow/coverage.svg?branch=main
70
68
  [codecov-link]: https://codecov.io/github/daizutabi/hydraflow?branch=main
71
- [docs-image]: https://readthedocs.org/projects/hydraflow/badge/?version=latest
69
+ [docs-image]: https://img.shields.io/badge/docs-latest-blue.svg
72
70
  [docs-link]: https://daizutabi.github.io/hydraflow/
71
+ [python-v-image]: https://img.shields.io/pypi/pyversions/hydraflow.svg
72
+ [python-v-link]: https://pypi.org/project/hydraflow
73
73
 
74
74
  ## Overview
75
75
 
@@ -101,6 +101,8 @@ You can install Hydraflow via pip:
101
101
  pip install hydraflow
102
102
  ```
103
103
 
104
+ **Requirements:** Python 3.13+
105
+
104
106
  ## Quick Start
105
107
 
106
108
  Here is a simple example to get you started with Hydraflow:
@@ -1,22 +1,22 @@
1
1
  # Hydraflow
2
2
 
3
3
  [![PyPI Version][pypi-v-image]][pypi-v-link]
4
- [![Python Version][python-v-image]][python-v-link]
5
4
  [![Build Status][GHAction-image]][GHAction-link]
6
5
  [![Coverage Status][codecov-image]][codecov-link]
7
6
  [![Documentation Status][docs-image]][docs-link]
7
+ [![Python Version][python-v-image]][python-v-link]
8
8
 
9
9
  <!-- Badges -->
10
10
  [pypi-v-image]: https://img.shields.io/pypi/v/hydraflow.svg
11
11
  [pypi-v-link]: https://pypi.org/project/hydraflow/
12
- [python-v-image]: https://img.shields.io/pypi/pyversions/hydraflow.svg
13
- [python-v-link]: https://pypi.org/project/hydraflow
14
12
  [GHAction-image]: https://github.com/daizutabi/hydraflow/actions/workflows/ci.yaml/badge.svg?branch=main&event=push
15
13
  [GHAction-link]: https://github.com/daizutabi/hydraflow/actions?query=event%3Apush+branch%3Amain
16
14
  [codecov-image]: https://codecov.io/github/daizutabi/hydraflow/coverage.svg?branch=main
17
15
  [codecov-link]: https://codecov.io/github/daizutabi/hydraflow?branch=main
18
- [docs-image]: https://readthedocs.org/projects/hydraflow/badge/?version=latest
16
+ [docs-image]: https://img.shields.io/badge/docs-latest-blue.svg
19
17
  [docs-link]: https://daizutabi.github.io/hydraflow/
18
+ [python-v-image]: https://img.shields.io/pypi/pyversions/hydraflow.svg
19
+ [python-v-link]: https://pypi.org/project/hydraflow
20
20
 
21
21
  ## Overview
22
22
 
@@ -48,6 +48,8 @@ You can install Hydraflow via pip:
48
48
  pip install hydraflow
49
49
  ```
50
50
 
51
+ **Requirements:** Python 3.13+
52
+
51
53
  ## Quick Start
52
54
 
53
55
  Here is a simple example to get you started with Hydraflow:
@@ -0,0 +1,117 @@
1
+ # HydraFlow: Seamless ML Experiment Management
2
+
3
+ <div class="grid cards" markdown>
4
+
5
+ - 🚀 **Streamlined Experimentation**
6
+ Create, run, and track ML experiments with minimal boilerplate
7
+ - ⚙️ **Hydra + MLflow Integration**
8
+ Combine powerful configuration management with robust experiment tracking
9
+ - 📈 **Rich Analysis Tools**
10
+ Filter, group, and visualize experiment results with intuitive APIs
11
+ - ⚡ **Performance Optimized**
12
+ Parallel processing support for handling thousands of experiments efficiently
13
+
14
+ </div>
15
+
16
+ ## What is HydraFlow?
17
+
18
+ HydraFlow seamlessly integrates [Hydra](https://hydra.cc/) and
19
+ [MLflow](https://mlflow.org/) to create a powerful framework for machine
20
+ learning experimentation. It solves common challenges in ML research and
21
+ production workflows:
22
+
23
+ - **Configuration Management**: Type-safe, hierarchical, and dynamic
24
+ configuration
25
+ - **Experiment Tracking**: Automatically log parameters, metrics, and artifacts
26
+ - **Results Analysis**: Flexible tools to filter, compare, and visualize
27
+ experiment results
28
+ - **Reproducibility**: Ensure experiments can be reliably reproduced with
29
+ exact parameters
30
+
31
+ ## Key Features
32
+
33
+ **At Development Time:**
34
+ - Type-safe configuration with IDE autocompletion
35
+ - Declarative experiment definition with dataclasses
36
+ - Seamless integration with existing ML pipelines
37
+
38
+ **During Execution:**
39
+ - Parameter sweeps with one command
40
+ - Automatic configuration logging
41
+ - De-duplication of identical experiments
42
+
43
+ **After Completion:**
44
+ - Powerful filtering and grouping of results
45
+ - Conversion to DataFrames for analysis
46
+ - Configuration-aware implementation loading
47
+
48
+ ## Quick Installation
49
+
50
+ ```bash
51
+ pip install hydraflow
52
+ ```
53
+
54
+ **Requirements:** Python 3.13+
55
+
56
+ ## Minimal Example
57
+
58
+ ```python
59
+ from dataclasses import dataclass
60
+ import hydraflow
61
+ import mlflow
62
+
63
+ @dataclass
64
+ class Config:
65
+ learning_rate: float = 0.001
66
+ batch_size: int = 32
67
+
68
+ @hydraflow.main(Config)
69
+ def experiment(run, cfg):
70
+ # Your experiment code here
71
+ mlflow.log_metric("accuracy", 0.95)
72
+
73
+ if __name__ == "__main__":
74
+ experiment()
75
+ ```
76
+
77
+ Run this with parameter variations in one command:
78
+
79
+ ```bash
80
+ python experiment.py -m learning_rate=0.01,0.001,0.0001 batch_size=16,32,64
81
+ ```
82
+
83
+ ## Post-experiment Analysis
84
+
85
+ After running your experiments, analyze the results with HydraFlow's
86
+ powerful API:
87
+
88
+ ```python
89
+ from hydraflow import Run, RunCollection
90
+
91
+ # Load all runs from the "experiment" experiment
92
+ runs = Run.load(hydraflow.iter_run_dirs("mlruns", "experiment"))
93
+
94
+ # Filter runs by configuration parameters
95
+ best_runs = runs.filter(learning_rate=0.001, batch_size=32)
96
+
97
+ # Convert to DataFrame for further analysis
98
+ df = runs.to_frame("learning_rate", "batch_size",
99
+ accuracy=lambda run: run.get("metrics.accuracy"))
100
+ ```
101
+
102
+ <!--
103
+ ## Explore HydraFlow
104
+
105
+ <div class="grid cards" markdown>
106
+
107
+ - 📖 [**Getting Started**](usage/quickstart.md)
108
+ Learn the basics of HydraFlow with a step-by-step guide
109
+ - 🧩 [**API Reference**](api/index.md)
110
+ Detailed documentation of HydraFlow's classes and functions
111
+ - 💻 [**CLI Tools**](cli/index.md)
112
+ Discover HydraFlow's command-line utilities
113
+ - 💡 [**Advanced Usage**](advanced/index.md)
114
+ Tips, tricks, and best practices for complex workflows
115
+
116
+ </div>
117
+ -->
@@ -0,0 +1,330 @@
1
+ # HydraFlow Quickstart Guide
2
+
3
+ HydraFlow seamlessly integrates MLflow (for experiment tracking)
4
+ with Hydra (for configuration management), creating a powerful
5
+ framework for machine learning experimentation.
6
+ This quickstart shows you how to get up and running with HydraFlow in minutes.
7
+
8
+ ## Hydra application
9
+
10
+ The following example demonstrates how to use a Hydraflow application.
11
+
12
+ ```python title="apps/quickstart.py" linenums="1"
13
+ --8<-- "apps/quickstart.py"
14
+ ```
15
+
16
+ ### Hydraflow's `main` decorator
17
+
18
+ [`hydraflow.main`][] starts a new MLflow run that logs the Hydra
19
+ configuration. The decorated function must have two arguments: `run` and
20
+ `cfg`. The `run` argument is the current MLflow run with type
21
+ `mlflow.entities.Run`. The `cfg` argument is the Hydra configuration
22
+ with type `omegaconf.DictConfig`. You can annotate the arguments with
23
+ `Run` and `Config` to get type checking and autocompletion in your IDE,
24
+ although the `cfg` argument is not actually an instance of `Config`
25
+ (duck typing is used).
26
+
27
+ ```python
28
+ @hydraflow.main(Config)
29
+ def app(run: Run, cfg: Config) -> None:
30
+ pass
31
+ ```
32
+
33
+ ## Run the application
34
+
35
+ ```bash exec="on"
36
+ rm -rf mlruns outputs multirun
37
+ ```
38
+
39
+ ### Single-run
40
+
41
+ Run the Hydraflow application as a normal Python script.
42
+
43
+ ```console exec="1" source="console"
44
+ $ python apps/quickstart.py
45
+ ```
46
+
47
+ Check the MLflow CLI to view the experiment.
48
+
49
+ ```console exec="1" source="console"
50
+ $ mlflow experiments search
51
+ ```
52
+
53
+ The experiment name comes from the name of the Hydra job.
54
+
55
+ ### Multi-run
56
+
57
+ Run the Hydraflow application with multiple configurations.
58
+
59
+ ```console exec="1" source="console"
60
+ $ python apps/quickstart.py -m width=400,600 height=100,200,300
61
+ ```
62
+
63
+ ## Use Hydraflow API
64
+
65
+ ### Iterate over run's directory
66
+
67
+ The [`hydraflow.iter_run_dirs`][] function iterates over the run
68
+ directories. The first argument is the path to the MLflow tracking root
69
+ directory (in most cases, this is `"mlruns"`).
70
+
71
+ ```pycon exec="1" source="console" session="quickstart"
72
+ >>> import hydraflow
73
+ >>> for run_dir in hydraflow.iter_run_dirs("mlruns"):
74
+ ... print(run_dir)
75
+ ```
76
+
77
+ Optionally, you can specify the experiment name(s) to filter the runs.
78
+
79
+ ```python
80
+ >>> hydraflow.iter_run_dirs("mlruns", "quickstart")
81
+ >>> hydraflow.iter_run_dirs("mlruns", ["quickstart1", "quickstart2"])
82
+ ```
83
+
84
+ ### Load a run
85
+
86
+ [`Run`][hydraflow.core.run.Run] is a class that represents a *Hydraflow*
87
+ run, not an MLflow run. A `Run` instance is created by passing a
88
+ `pathlib.Path` instance that points to the run directory to the `Run`
89
+ constructor.
90
+
91
+ ```pycon exec="1" source="console" session="quickstart"
92
+ >>> from hydraflow import Run
93
+ >>> run_dirs = hydraflow.iter_run_dirs("mlruns", "quickstart")
94
+ >>> run_dir = next(run_dirs) # run_dirs is an iterator
95
+ >>> run = Run(run_dir)
96
+ >>> print(run)
97
+ >>> print(type(run))
98
+ ```
99
+
100
+ You can use the [`load`][hydraflow.core.run.Run.load] class method to
101
+ load a `Run` instance, which accepts a `str` as well as `pathlib.Path`.
102
+
103
+ ```pycon exec="1" source="console" session="quickstart"
104
+ >>> Run.load(str(run_dir))
105
+ >>> print(run)
106
+ ```
107
+
108
+ !!! note
109
+ The use case of `Run.load` is to load multiple `Run` instances
110
+ from run directories as described below.
111
+
112
+
113
+ The `Run` instance has an `info` attribute that contains information
114
+ about the run.
115
+
116
+ ```pycon exec="1" source="console" session="quickstart"
117
+ >>> print(run.info.run_dir)
118
+ >>> print(run.info.run_id)
119
+ >>> print(run.info.job_name) # Hydra job name = MLflow experiment name
120
+ ```
121
+
122
+ The `Run` instance has a `cfg` attribute that contains the Hydra
123
+ configuration.
124
+
125
+ ```pycon exec="1" source="console" session="quickstart"
126
+ >>> print(run.cfg)
127
+ ```
128
+
129
+ ### Configuration type of the run
130
+
131
+ Optionally, you can specify the config type of the run using the
132
+ `Run[C]` class.
133
+
134
+ ```pycon exec="1" source="console" session="quickstart"
135
+ >>> from dataclasses import dataclass
136
+ >>> @dataclass
137
+ ... class Config:
138
+ ... width: int = 1024
139
+ ... height: int = 768
140
+ >>> run = Run[Config](run_dir)
141
+ >>> print(run)
142
+ >>> # autocompletion occurs below, for example, run.cfg.height
143
+ >>> # run.cfg.[TAB]
144
+ ```
145
+
146
+ The `Run[C]` class is a generic class that takes a config type `C` as a
147
+ type parameter. The `run.cfg` attribute is recognized as `C` type in
148
+ IDEs, which provides autocompletion and type checking.
149
+
150
+ ### Get a run's configuration
151
+
152
+ The `get` method can be used to get a run's configuration.
153
+
154
+ ```pycon exec="1" source="console" session="quickstart"
155
+ >>> print(run.get("width"))
156
+ >>> print(run.get("height"))
157
+ ```
158
+
159
+ ### Implementation of the run
160
+
161
+ Optionally, you can specify the implementation of the run. Use the
162
+ `Run[C, I]` class to specify the implementation type. The second
163
+ argument `impl_factory` is the implementation factory, which can be a
164
+ class or a function to generate the implementation. The `impl_factory`
165
+ is called with the run's artifacts directory as the first and only
166
+ argument.
167
+
168
+ ```pycon exec="1" source="console" session="quickstart"
169
+ >>> from pathlib import Path
170
+ >>> class Impl:
171
+ ... root_dir: Path
172
+ ... def __init__(self, root_dir: Path):
173
+ ... self.root_dir = root_dir
174
+ ... def __repr__(self) -> str:
175
+ ... return f"Impl({self.root_dir.stem!r})"
176
+ >>> run = Run[Config, Impl](run_dir, Impl)
177
+ >>> print(run)
178
+ ```
179
+
180
+ The representation of the `Run` instance includes the implementation
181
+ type as shown above.
182
+
183
+ If you specify the implementation type, the `run.impl` attribute is
184
+ lazily initialized at the first time of the `run.impl` attribute access.
185
+ The `run.impl` attribute is recognized as `I` type in IDEs, which
186
+ provides autocompletion and type checking.
187
+
188
+ ```pycon exec="1" source="console" session="quickstart"
189
+ >>> print(run.impl)
190
+ >>> print(run.impl.root_dir)
191
+ >>> # autocompletion occurs below, for example, run.impl.root_dir
192
+ >>> # run.impl.[TAB]
193
+ ```
194
+
195
+ The `impl_factory` can accept two arguments: the run's artifacts
196
+ directory and the run's configuration.
197
+
198
+ ```pycon exec="1" source="console" session="quickstart"
199
+ >>> from dataclasses import dataclass, field
200
+ >>> @dataclass
201
+ >>> class Size:
202
+ ... root_dir: Path = field(repr=False)
203
+ ... cfg: Config
204
+ ... size: int = field(init=False)
205
+ ... def __post_init__(self):
206
+ ... self.size = self.cfg.width * self.cfg.height
207
+ >>> run = Run[Config, Size].load(run_dir, Size)
208
+ >>> print(run)
209
+ >>> print(run.impl)
210
+ ```
211
+
212
+ ### Collect runs
213
+
214
+ You can collect multiple `Run` instances from run directories as a
215
+ collection of runs [`RunCollection`][hydraflow.RunCollection].
216
+
217
+ ```pycon exec="1" source="console" session="quickstart"
218
+ >>> from hydraflow import RunCollection
219
+ >>> run_dirs = hydraflow.iter_run_dirs("mlruns", "quickstart")
220
+ >>> rc = Run[Config, Size].load(run_dirs, Size)
221
+ >>> print(rc)
222
+ ```
223
+
224
+ In the above example, the `load` class method is called with an iterable
225
+ of run directories and the implementation type. The `load` class method
226
+ returns a `RunCollection` instance instead of a single `Run` instance.
227
+ The representation of the `RunCollection` instance includes the run
228
+ collection type and the number of runs in the collection.
229
+
230
+ ### Handle a run collection
231
+
232
+ The `RunCollection` instance has a [`first`][hydraflow.RunCollection.first]
233
+ and [`last`][hydraflow.RunCollection.last] method that returns the first
234
+ and last run in the collection.
235
+
236
+ ```pycon exec="1" source="console" session="quickstart"
237
+ >>> print(rc.first())
238
+ >>> print(rc.last())
239
+ ```
240
+
241
+ The [`filter`][hydraflow.RunCollection.filter] method filters the runs
242
+ by the given key-value pairs.
243
+
244
+ ```pycon exec="1" source="console" session="quickstart"
245
+ >>> print(rc.filter(width=400))
246
+ ```
247
+
248
+ If the value is a list, the run will be included if the value is in the
249
+ list.
250
+
251
+ ```pycon exec="1" source="console" session="quickstart"
252
+ >>> print(rc.filter(height=[100, 300]))
253
+ ```
254
+
255
+ If the value is a tuple, the run will be included if the value is
256
+ between the tuple. The start and end of the tuple are inclusive.
257
+
258
+ ```pycon exec="1" source="console" session="quickstart"
259
+ >>> print(rc.filter(height=(100, 300)))
260
+ ```
261
+
262
+ The [`get`][hydraflow.RunCollection.get] method returns a single `Run`
263
+ instance with the given key-value pairs.
264
+
265
+ ```pycon exec="1" source="console" session="quickstart"
266
+ >>> run = rc.get(width=(350, 450), height=(150, 250))
267
+ >>> print(run)
268
+ >>> print(run.impl)
269
+ ```
270
+
271
+ The [`to_frame`][hydraflow.RunCollection.to_frame] method returns a
272
+ polars DataFrame of the run collection.
273
+
274
+ ```pycon exec="1" source="console" session="quickstart"
275
+ >>> print(rc.to_frame("width", "height"))
276
+ ```
277
+
278
+ The `to_frame` method can take keyword arguments to customize the
279
+ DataFrame. Each keyword argument is a callable that takes a `Run`
280
+ instance and returns a value.
281
+
282
+ ```pycon exec="1" source="console" session="quickstart"
283
+ >>> print(rc.to_frame("width", size=lambda run: run.impl.size))
284
+ ```
285
+
286
+ The callable can return a list.
287
+
288
+ ```pycon exec="1" source="console" session="quickstart"
289
+ >>> def to_list(run: Run) -> list[int]:
290
+ ... return [2 * run.get("width"), 3 * run.get("height")]
291
+ >>> print(rc.to_frame("width", from_list=to_list))
292
+ ```
293
+
294
+ The callable can also return a dictionary.
295
+
296
+ ```pycon exec="1" source="console" session="quickstart"
297
+ >>> def to_dict(run: Run) -> dict[int, str]:
298
+ ... width2 = 2 * run.get("width")
299
+ ... name = f"h{run.get('height')}"
300
+ ... return {"width2": width2, "name": name}
301
+ >>> print(rc.to_frame("width", from_dict=to_dict))
302
+ ```
303
+
304
+ ### Group runs
305
+
306
+ The [`group_by`][hydraflow.RunCollection.group_by] method groups the
307
+ runs by the given key.
308
+
309
+ ```pycon exec="1" source="console" session="quickstart"
310
+ >>> grouped = rc.group_by("width")
311
+ >>> for key, group in grouped.items():
312
+ ... print(key, group)
313
+ ```
314
+
315
+ The `group_by` method can also take multiple keys.
316
+
317
+ ```pycon exec="1" source="console" session="quickstart"
318
+ >>> grouped = rc.group_by("width", "height")
319
+ >>> for key, group in grouped.items():
320
+ ... print(key, group)
321
+ ```
322
+
323
+ The `group_by` method can also take a callable which accepts a sequence
324
+ of runs and returns a value. In this case, the `group_by` method returns
325
+ a polars DataFrame.
326
+
327
+ ```pycon exec="1" source="console" session="quickstart"
328
+ >>> df = rc.group_by("width", n=lambda runs: len(runs))
329
+ >>> print(df)
330
+ ```
@@ -49,6 +49,14 @@ markdown_extensions:
49
49
  - pymdownx.superfences
50
50
  - pymdownx.tabbed:
51
51
  alternate_style: true
52
+ - attr_list
53
+ - md_in_html
54
+ - pymdownx.emoji:
55
+ emoji_index: !!python/name:material.extensions.emoji.twemoji
56
+ emoji_generator: !!python/name:material.extensions.emoji.to_svg
57
+ options:
58
+ custom_icons:
59
+ - overrides/.icons
52
60
  nav:
53
61
  - Home: index.md
54
62
  - Usage:
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "hydraflow"
7
- version = "0.14.4"
7
+ version = "0.15.0"
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" }
@@ -17,14 +17,11 @@ classifiers = [
17
17
  "License :: OSI Approved :: MIT License",
18
18
  "Operating System :: OS Independent",
19
19
  "Programming Language :: Python",
20
- "Programming Language :: Python :: 3.10",
21
- "Programming Language :: Python :: 3.11",
22
- "Programming Language :: Python :: 3.12",
23
20
  "Programming Language :: Python :: 3.13",
24
21
  "Topic :: Scientific/Engineering :: Artificial Intelligence",
25
22
  "Topic :: Software Development :: Libraries :: Python Modules",
26
23
  ]
27
- requires-python = ">=3.10"
24
+ requires-python = ">=3.13"
28
25
  keywords = [
29
26
  "machine-learning",
30
27
  "mlflow",
@@ -37,12 +34,14 @@ keywords = [
37
34
  "data-science",
38
35
  ]
39
36
  dependencies = [
40
-
41
37
  "hydra-core>=1.3",
38
+ "joblib>=1.4.0",
42
39
  "mlflow>=2.15",
43
40
  "omegaconf>=2.3",
41
+ "polars>=1.26",
44
42
  "python-ulid>=3.0.0",
45
43
  "rich>=13.9",
44
+ "ruff>=0.11",
46
45
  "typer>=0.15",
47
46
  ]
48
47
 
@@ -69,9 +68,7 @@ docs = ["markdown-exec[ansi]", "mkapi", "mkdocs-material"]
69
68
  addopts = [
70
69
  "--cov=hydraflow",
71
70
  "--cov-report=lcov:lcov.info",
72
- "--dist=loadgroup",
73
71
  "--doctest-modules",
74
- "-n8",
75
72
  ]
76
73
  filterwarnings = [
77
74
  "ignore:Support for class-based `config` is deprecated",
@@ -84,7 +81,7 @@ skip_covered = true
84
81
 
85
82
  [tool.ruff]
86
83
  line-length = 88
87
- target-version = "py310"
84
+ target-version = "py313"
88
85
 
89
86
  [tool.ruff.lint]
90
87
  select = ["ALL"]
@@ -102,6 +99,7 @@ ignore = [
102
99
  "EM101",
103
100
  "FBT001",
104
101
  "FBT002",
102
+ "PD",
105
103
  "PGH003",
106
104
  "PLR0911",
107
105
  "PLR0913",
@@ -123,6 +121,3 @@ ignore = [
123
121
 
124
122
  [tool.pyright]
125
123
  include = ["src", "tests"]
126
- strictDictionaryInference = true
127
- strictListInference = true
128
- strictSetInference = true
@@ -3,35 +3,25 @@
3
3
  from hydraflow.core.context import chdir_artifact, log_run, start_run
4
4
  from hydraflow.core.io import (
5
5
  get_artifact_dir,
6
- get_artifact_path,
7
- get_hydra_output_dir,
8
6
  iter_artifact_paths,
9
7
  iter_artifacts_dirs,
10
8
  iter_experiment_dirs,
11
9
  iter_run_dirs,
12
- load_config,
13
- remove_run,
14
10
  )
15
11
  from hydraflow.core.main import main
16
- from hydraflow.core.mlflow import list_run_ids, list_run_paths, list_runs
17
- from hydraflow.entities.run_collection import RunCollection
12
+ from hydraflow.core.run import Run
13
+ from hydraflow.core.run_collection import RunCollection
18
14
 
19
15
  __all__ = [
16
+ "Run",
20
17
  "RunCollection",
21
18
  "chdir_artifact",
22
19
  "get_artifact_dir",
23
- "get_artifact_path",
24
- "get_hydra_output_dir",
25
20
  "iter_artifact_paths",
26
21
  "iter_artifacts_dirs",
27
22
  "iter_experiment_dirs",
28
23
  "iter_run_dirs",
29
- "list_run_ids",
30
- "list_run_paths",
31
- "list_runs",
32
- "load_config",
33
24
  "log_run",
34
25
  "main",
35
- "remove_run",
36
26
  "start_run",
37
27
  ]