hydraflow 0.4.4__tar.gz → 0.4.6__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. {hydraflow-0.4.4 → hydraflow-0.4.6}/.devcontainer/devcontainer.json +1 -0
  2. {hydraflow-0.4.4 → hydraflow-0.4.6}/.devcontainer/postCreate.sh +4 -3
  3. {hydraflow-0.4.4 → hydraflow-0.4.6}/PKG-INFO +25 -3
  4. {hydraflow-0.4.4 → hydraflow-0.4.6}/pyproject.toml +12 -5
  5. {hydraflow-0.4.4 → hydraflow-0.4.6}/src/hydraflow/__init__.py +2 -0
  6. {hydraflow-0.4.4 → hydraflow-0.4.6}/src/hydraflow/context.py +3 -2
  7. {hydraflow-0.4.4 → hydraflow-0.4.6}/src/hydraflow/utils.py +16 -6
  8. {hydraflow-0.4.4 → hydraflow-0.4.6}/tests/scripts/app.py +6 -4
  9. {hydraflow-0.4.4 → hydraflow-0.4.6}/tests/test_app.py +10 -6
  10. {hydraflow-0.4.4 → hydraflow-0.4.6}/tests/test_log_run.py +9 -3
  11. hydraflow-0.4.6/tests/test_utils.py +34 -0
  12. {hydraflow-0.4.4 → hydraflow-0.4.6}/.devcontainer/starship.toml +0 -0
  13. {hydraflow-0.4.4 → hydraflow-0.4.6}/.gitattributes +0 -0
  14. {hydraflow-0.4.4 → hydraflow-0.4.6}/.gitignore +0 -0
  15. {hydraflow-0.4.4 → hydraflow-0.4.6}/LICENSE +0 -0
  16. {hydraflow-0.4.4 → hydraflow-0.4.6}/README.md +0 -0
  17. {hydraflow-0.4.4 → hydraflow-0.4.6}/apps/quickstart.py +0 -0
  18. {hydraflow-0.4.4 → hydraflow-0.4.6}/mkdocs.yml +0 -0
  19. {hydraflow-0.4.4 → hydraflow-0.4.6}/src/hydraflow/asyncio.py +0 -0
  20. {hydraflow-0.4.4 → hydraflow-0.4.6}/src/hydraflow/config.py +0 -0
  21. {hydraflow-0.4.4 → hydraflow-0.4.6}/src/hydraflow/mlflow.py +0 -0
  22. {hydraflow-0.4.4 → hydraflow-0.4.6}/src/hydraflow/param.py +0 -0
  23. {hydraflow-0.4.4 → hydraflow-0.4.6}/src/hydraflow/progress.py +0 -0
  24. {hydraflow-0.4.4 → hydraflow-0.4.6}/src/hydraflow/py.typed +0 -0
  25. {hydraflow-0.4.4 → hydraflow-0.4.6}/src/hydraflow/run_collection.py +0 -0
  26. {hydraflow-0.4.4 → hydraflow-0.4.6}/src/hydraflow/run_data.py +0 -0
  27. {hydraflow-0.4.4 → hydraflow-0.4.6}/src/hydraflow/run_info.py +0 -0
  28. {hydraflow-0.4.4 → hydraflow-0.4.6}/tests/__init__.py +0 -0
  29. {hydraflow-0.4.4 → hydraflow-0.4.6}/tests/integ/__init__.py +0 -0
  30. {hydraflow-0.4.4 → hydraflow-0.4.6}/tests/integ/app.py +0 -0
  31. {hydraflow-0.4.4 → hydraflow-0.4.6}/tests/scripts/__init__.py +0 -0
  32. {hydraflow-0.4.4 → hydraflow-0.4.6}/tests/scripts/progress.py +0 -0
  33. {hydraflow-0.4.4 → hydraflow-0.4.6}/tests/scripts/watch.py +0 -0
  34. {hydraflow-0.4.4 → hydraflow-0.4.6}/tests/test_asyncio.py +0 -0
  35. {hydraflow-0.4.4 → hydraflow-0.4.6}/tests/test_config.py +0 -0
  36. {hydraflow-0.4.4 → hydraflow-0.4.6}/tests/test_context.py +0 -0
  37. {hydraflow-0.4.4 → hydraflow-0.4.6}/tests/test_mlflow.py +0 -0
  38. {hydraflow-0.4.4 → hydraflow-0.4.6}/tests/test_param.py +0 -0
  39. {hydraflow-0.4.4 → hydraflow-0.4.6}/tests/test_progress.py +0 -0
  40. {hydraflow-0.4.4 → hydraflow-0.4.6}/tests/test_run_collection.py +0 -0
  41. {hydraflow-0.4.4 → hydraflow-0.4.6}/tests/test_run_data.py +0 -0
  42. {hydraflow-0.4.4 → hydraflow-0.4.6}/tests/test_run_info.py +0 -0
  43. {hydraflow-0.4.4 → hydraflow-0.4.6}/tests/test_version.py +0 -0
  44. {hydraflow-0.4.4 → hydraflow-0.4.6}/tests/test_watch.py +0 -0
@@ -8,6 +8,7 @@
8
8
  "extensions": [
9
9
  "charliermarsh.ruff",
10
10
  "fill-labs.dependi",
11
+ "markis.code-coverage",
11
12
  "ms-python.python",
12
13
  "ms-python.vscode-pylance",
13
14
  "tamasfe.even-better-toml"
@@ -1,10 +1,11 @@
1
1
  #!/bin/bash
2
2
 
3
3
  echo 'eval "$(starship init bash)"' >> ~/.bashrc
4
- echo "alias ll='ls -alF'" >> ~/.bashrc
5
4
  mkdir -p ~/.config
6
5
  cp .devcontainer/starship.toml ~/.config
7
6
 
8
7
  curl -LsSf https://astral.sh/uv/install.sh | sh
9
- source $HOME/.cargo/env
10
- echo 'eval "$(uv generate-shell-completion bash)"' >> ~/.bashrc
8
+ echo 'eval "$(uv generate-shell-completion bash)"' >> ~/.bashrc
9
+ uv tool install ruff@latest
10
+ uv python install
11
+ uv sync -U
@@ -1,18 +1,40 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: hydraflow
3
- Version: 0.4.4
3
+ Version: 0.4.6
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
7
7
  Project-URL: Issues, https://github.com/daizutabi/hydraflow/issues
8
8
  Author-email: daizutabi <daizutabi@gmail.com>
9
- License: MIT
9
+ License: MIT License
10
+
11
+ Copyright (c) 2024 Daizu
12
+
13
+ Permission is hereby granted, free of charge, to any person obtaining a copy
14
+ of this software and associated documentation files (the "Software"), to deal
15
+ in the Software without restriction, including without limitation the rights
16
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
+ copies of the Software, and to permit persons to whom the Software is
18
+ furnished to do so, subject to the following conditions:
19
+
20
+ The above copyright notice and this permission notice shall be included in all
21
+ copies or substantial portions of the Software.
22
+
23
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29
+ SOFTWARE.
10
30
  License-File: LICENSE
11
31
  Classifier: Development Status :: 4 - Beta
32
+ Classifier: License :: OSI Approved :: MIT License
12
33
  Classifier: Programming Language :: Python
13
34
  Classifier: Programming Language :: Python :: 3.10
14
35
  Classifier: Programming Language :: Python :: 3.11
15
36
  Classifier: Programming Language :: Python :: 3.12
37
+ Classifier: Programming Language :: Python :: 3.13
16
38
  Requires-Python: >=3.10
17
39
  Requires-Dist: hydra-core>=1.3
18
40
  Requires-Dist: joblib
@@ -1,20 +1,22 @@
1
1
  [build-system]
2
- requires = ["hatchling"]
2
+ requires = ["hatchling>=1.26.1"]
3
3
  build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "hydraflow"
7
- version = "0.4.4"
7
+ version = "0.4.6"
8
8
  description = "Hydraflow integrates Hydra and MLflow to manage and track machine learning experiments."
9
9
  readme = "README.md"
10
- license = { text = "MIT" }
10
+ license = { file = "LICENSE" }
11
11
  authors = [{ name = "daizutabi", email = "daizutabi@gmail.com" }]
12
12
  classifiers = [
13
13
  "Development Status :: 4 - Beta",
14
+ "License :: OSI Approved :: MIT License",
14
15
  "Programming Language :: Python",
15
16
  "Programming Language :: Python :: 3.10",
16
17
  "Programming Language :: Python :: 3.11",
17
18
  "Programming Language :: Python :: 3.12",
19
+ "Programming Language :: Python :: 3.13",
18
20
  ]
19
21
  requires-python = ">=3.10"
20
22
  dependencies = [
@@ -43,7 +45,6 @@ dev-dependencies = [
43
45
  "pytest-cov",
44
46
  "pytest-randomly",
45
47
  "pytest-xdist",
46
- "ruff",
47
48
  ]
48
49
 
49
50
  [tool.hatch.build.targets.sdist]
@@ -59,11 +60,16 @@ addopts = [
59
60
  "--cov-report=lcov:lcov.info",
60
61
  ]
61
62
  doctest_optionflags = ["NORMALIZE_WHITESPACE", "IGNORE_EXCEPTION_DETAIL"]
62
- filterwarnings = ['ignore:pkg_resources is deprecated:DeprecationWarning']
63
+ filterwarnings = [
64
+ "ignore:pkg_resources is deprecated:DeprecationWarning",
65
+ "ignore:Support for class-based `config` is deprecated",
66
+ "ignore:Pydantic V1 style",
67
+ ]
63
68
  asyncio_default_fixture_loop_scope = "function"
64
69
 
65
70
  [tool.coverage.report]
66
71
  exclude_lines = ["no cov", "raise NotImplementedError", "if TYPE_CHECKING:"]
72
+ skip_covered = true
67
73
 
68
74
  [tool.ruff]
69
75
  line-length = 88
@@ -73,6 +79,7 @@ target-version = "py310"
73
79
  select = ["ALL"]
74
80
  unfixable = ["F401"]
75
81
  ignore = [
82
+ "A005",
76
83
  "ANN003",
77
84
  "ANN401",
78
85
  "ARG002",
@@ -11,6 +11,7 @@ from .utils import (
11
11
  get_overrides,
12
12
  load_config,
13
13
  load_overrides,
14
+ remove_run,
14
15
  )
15
16
 
16
17
  __all__ = [
@@ -26,6 +27,7 @@ __all__ = [
26
27
  "log_run",
27
28
  "multi_tasks_progress",
28
29
  "parallel_progress",
30
+ "remove_run",
29
31
  "search_runs",
30
32
  "select_config",
31
33
  "select_overrides",
@@ -69,8 +69,9 @@ def log_run(
69
69
  mlflow.log_artifact(local_path)
70
70
 
71
71
  try:
72
- with watch(log_artifact, output_dir, ignore_log=False):
73
- yield
72
+ yield
73
+ # with watch(log_artifact, output_dir, ignore_log=False):
74
+ # yield
74
75
 
75
76
  except Exception as e:
76
77
  msg = f"Error during log_run: {e}"
@@ -2,6 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import shutil
5
6
  from pathlib import Path
6
7
  from typing import TYPE_CHECKING
7
8
 
@@ -9,11 +10,10 @@ import mlflow
9
10
  import mlflow.artifacts
10
11
  from hydra.core.hydra_config import HydraConfig
11
12
  from mlflow.entities import Run
12
- from mlflow.tracking import artifact_utils
13
13
  from omegaconf import DictConfig, OmegaConf
14
14
 
15
15
  if TYPE_CHECKING:
16
- from mlflow.entities import Run
16
+ from collections.abc import Iterable
17
17
 
18
18
 
19
19
  def get_artifact_dir(run: Run | None = None) -> Path:
@@ -28,10 +28,10 @@ def get_artifact_dir(run: Run | None = None) -> Path:
28
28
  The local path to the directory where the artifacts are downloaded.
29
29
 
30
30
  """
31
- if run is None:
32
- uri = mlflow.get_artifact_uri()
33
- else:
34
- uri = artifact_utils.get_artifact_uri(run.info.run_id)
31
+ uri = mlflow.get_artifact_uri() if run is None else run.info.artifact_uri
32
+
33
+ if not (isinstance(uri, str) and uri.startswith("file://")):
34
+ raise NotImplementedError
35
35
 
36
36
  return Path(mlflow.artifacts.download_artifacts(uri))
37
37
 
@@ -112,3 +112,13 @@ def load_overrides(run: Run) -> list[str]:
112
112
  """
113
113
  path = get_artifact_dir(run) / ".hydra/overrides.yaml"
114
114
  return [str(x) for x in OmegaConf.load(path)]
115
+
116
+
117
+ def remove_run(run: Run | Iterable[Run]) -> None:
118
+ """Remove the given run from the MLflow tracking server."""
119
+ if not isinstance(run, Run):
120
+ for r in run:
121
+ remove_run(r)
122
+ return
123
+
124
+ shutil.rmtree(get_artifact_dir(run).parent)
@@ -52,9 +52,11 @@ def app(cfg: MySQLConfig):
52
52
  mlflow.log_text("A " + artifact_dir.as_posix(), "artifact_dir.txt")
53
53
  mlflow.log_text("B " + output_dir.as_posix(), "output_dir.txt")
54
54
 
55
- with hydraflow.watch(callback, ignore_patterns=["b.txt"]):
56
- (artifact_dir / "a.txt").write_text("abc")
57
- time.sleep(0.1)
55
+ # with hydraflow.watch(callback, ignore_patterns=["b.txt"]):
56
+ # (artifact_dir / "a.txt").write_text("abc")
57
+ # time.sleep(0.1)
58
+
59
+ (artifact_dir / "a.txt").write_text("abc")
58
60
 
59
61
  mlflow.log_metric("m", cfg.port + 1, 1)
60
62
  if cfg.host == "x":
@@ -71,7 +73,7 @@ def app(cfg: MySQLConfig):
71
73
  def callback(path: Path):
72
74
  log.info(f"WATCH, {path.as_posix()}")
73
75
  m = len(path.read_text()) # len("abc") == 3
74
- mlflow.log_metric("watch", m, 1, synchronous=True)
76
+ # mlflow.log_metric("watch", m, 1, synchronous=True)
75
77
 
76
78
 
77
79
  if __name__ == "__main__":
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import os
3
4
  import subprocess
4
5
  import sys
5
6
  from pathlib import Path
@@ -16,12 +17,14 @@ if TYPE_CHECKING:
16
17
  from hydraflow.run_collection import RunCollection
17
18
 
18
19
 
19
- @pytest.fixture
20
- def rc(monkeypatch, tmp_path):
20
+ @pytest.fixture(scope="module")
21
+ def rc(tmp_path_factory: pytest.TempPathFactory):
21
22
  import hydraflow
22
23
 
24
+ cwd = Path.cwd()
25
+
23
26
  file = Path("tests/scripts/app.py").absolute()
24
- monkeypatch.chdir(tmp_path)
27
+ os.chdir(tmp_path_factory.mktemp("test_app"))
25
28
 
26
29
  args = [sys.executable, file.as_posix(), "-m"]
27
30
  args += ["host=x,y", "port=1,2", "hydra.job.name=info"]
@@ -30,6 +33,8 @@ def rc(monkeypatch, tmp_path):
30
33
  mlflow.set_experiment("_info_")
31
34
  yield hydraflow.list_runs()
32
35
 
36
+ os.chdir(cwd)
37
+
33
38
 
34
39
  def test_list_runs_all(rc: RunCollection):
35
40
  from hydraflow.mlflow import list_runs
@@ -100,7 +105,7 @@ def test_app_data_params(rc: RunCollection):
100
105
  def test_app_data_metrics(rc: RunCollection):
101
106
  metrics = rc.data.metrics
102
107
  assert metrics["m"] == [11, 12, 2, 3]
103
- assert metrics["watch"] == [3, 3, 3, 3]
108
+ # assert metrics["watch"] == [3, 3, 3, 3] # noqa: ERA001
104
109
 
105
110
 
106
111
  def test_app_data_config(rc: RunCollection):
@@ -203,8 +208,7 @@ def test_log_run_error(monkeypatch, tmp_path):
203
208
  args = [sys.executable, file.as_posix()]
204
209
  args += ["host=error", "hydra.job.name=error"]
205
210
  cp = subprocess.run(args, check=False, capture_output=True)
206
- assert cp.returncode == 1
207
- assert b"Error during log_run: error" in cp.stdout
211
+ assert cp.returncode
208
212
 
209
213
 
210
214
  def test_chdir_artifact(rc: RunCollection):
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import os
3
4
  import subprocess
4
5
  import sys
5
6
  from pathlib import Path
@@ -10,10 +11,12 @@ from mlflow.artifacts import download_artifacts
10
11
  from mlflow.entities.run import Run
11
12
 
12
13
 
13
- @pytest.fixture
14
- def runs(monkeypatch, tmp_path):
14
+ @pytest.fixture(scope="module")
15
+ def runs(tmp_path_factory: pytest.TempPathFactory):
15
16
  file = Path("tests/scripts/app.py").absolute()
16
- monkeypatch.chdir(tmp_path)
17
+
18
+ cwd = Path.cwd()
19
+ os.chdir(tmp_path_factory.mktemp("test_log_run"))
17
20
 
18
21
  args = [sys.executable, file.as_posix(), "-m"]
19
22
  args += ["host=x,y", "port=1,2", "hydra.job.name=log_run"]
@@ -21,10 +24,13 @@ def runs(monkeypatch, tmp_path):
21
24
 
22
25
  mlflow.set_experiment("_log_run_")
23
26
  runs = mlflow.search_runs(output_format="list")
27
+
24
28
  assert len(runs) == 4
25
29
  assert isinstance(runs, list)
26
30
  yield runs
27
31
 
32
+ os.chdir(cwd)
33
+
28
34
 
29
35
  @pytest.fixture(params=range(4))
30
36
  def run(runs, request):
@@ -0,0 +1,34 @@
1
+ from __future__ import annotations
2
+
3
+ import mlflow
4
+ import pytest
5
+
6
+ from hydraflow.run_collection import RunCollection
7
+
8
+
9
+ @pytest.fixture
10
+ def rc(monkeypatch, tmp_path):
11
+ from hydraflow.mlflow import search_runs
12
+
13
+ monkeypatch.chdir(tmp_path)
14
+
15
+ mlflow.set_experiment("test_run")
16
+ for x in range(4):
17
+ with mlflow.start_run(run_name=f"{x}"):
18
+ pass
19
+
20
+ x = search_runs()
21
+ assert isinstance(x, RunCollection)
22
+ yield x
23
+
24
+
25
+ def test_remove_run(rc: RunCollection):
26
+ from hydraflow.utils import get_artifact_dir, remove_run
27
+
28
+ paths = [get_artifact_dir(r).parent for r in rc]
29
+
30
+ assert all(path.exists() for path in paths)
31
+
32
+ remove_run(rc)
33
+
34
+ assert not any(path.exists() for path in paths)
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