hydraflow 0.7.3__tar.gz → 0.7.4__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. hydraflow-0.7.4/.github/workflows/ci.yaml +51 -0
  2. hydraflow-0.7.4/.github/workflows/docs.yaml +25 -0
  3. {hydraflow-0.7.3 → hydraflow-0.7.4}/PKG-INFO +4 -1
  4. hydraflow-0.7.4/docs/index.md +10 -0
  5. hydraflow-0.7.4/docs/usage/quickstart.md +150 -0
  6. hydraflow-0.7.4/hydraflow.yaml +5 -0
  7. {hydraflow-0.7.3 → hydraflow-0.7.4}/pyproject.toml +12 -17
  8. hydraflow-0.7.4/src/hydraflow/cli.py +75 -0
  9. hydraflow-0.7.4/tests/cli/conftest.py +9 -0
  10. hydraflow-0.7.4/tests/cli/test_run.py +18 -0
  11. hydraflow-0.7.4/tests/cli/test_show.py +52 -0
  12. hydraflow-0.7.4/tests/cli/test_version.py +20 -0
  13. hydraflow-0.7.4/tests/utils/__init__.py +0 -0
  14. {hydraflow-0.7.3 → hydraflow-0.7.4}/.devcontainer/devcontainer.json +0 -0
  15. {hydraflow-0.7.3 → hydraflow-0.7.4}/.devcontainer/postCreate.sh +0 -0
  16. {hydraflow-0.7.3 → hydraflow-0.7.4}/.devcontainer/starship.toml +0 -0
  17. {hydraflow-0.7.3 → hydraflow-0.7.4}/.gitattributes +0 -0
  18. {hydraflow-0.7.3 → hydraflow-0.7.4}/.gitignore +0 -0
  19. {hydraflow-0.7.3 → hydraflow-0.7.4}/LICENSE +0 -0
  20. {hydraflow-0.7.3 → hydraflow-0.7.4}/README.md +0 -0
  21. {hydraflow-0.7.3 → hydraflow-0.7.4}/apps/quickstart.py +0 -0
  22. /hydraflow-0.7.3/mkdocs.yml → /hydraflow-0.7.4/mkdocs.yaml +0 -0
  23. {hydraflow-0.7.3 → hydraflow-0.7.4}/src/hydraflow/__init__.py +0 -0
  24. {hydraflow-0.7.3 → hydraflow-0.7.4}/src/hydraflow/config.py +0 -0
  25. {hydraflow-0.7.3 → hydraflow-0.7.4}/src/hydraflow/context.py +0 -0
  26. {hydraflow-0.7.3 → hydraflow-0.7.4}/src/hydraflow/main.py +0 -0
  27. {hydraflow-0.7.3 → hydraflow-0.7.4}/src/hydraflow/mlflow.py +0 -0
  28. {hydraflow-0.7.3 → hydraflow-0.7.4}/src/hydraflow/param.py +0 -0
  29. {hydraflow-0.7.3 → hydraflow-0.7.4}/src/hydraflow/py.typed +0 -0
  30. {hydraflow-0.7.3 → hydraflow-0.7.4}/src/hydraflow/run_collection.py +0 -0
  31. {hydraflow-0.7.3 → hydraflow-0.7.4}/src/hydraflow/run_data.py +0 -0
  32. {hydraflow-0.7.3 → hydraflow-0.7.4}/src/hydraflow/run_info.py +0 -0
  33. {hydraflow-0.7.3 → hydraflow-0.7.4}/src/hydraflow/utils.py +0 -0
  34. {hydraflow-0.7.3 → hydraflow-0.7.4}/tests/__init__.py +0 -0
  35. {hydraflow-0.7.3/tests/config → hydraflow-0.7.4/tests/cli}/__init__.py +0 -0
  36. {hydraflow-0.7.3/tests/context → hydraflow-0.7.4/tests/config}/__init__.py +0 -0
  37. {hydraflow-0.7.3 → hydraflow-0.7.4}/tests/config/overrides.py +0 -0
  38. {hydraflow-0.7.3 → hydraflow-0.7.4}/tests/config/test_config.py +0 -0
  39. {hydraflow-0.7.3 → hydraflow-0.7.4}/tests/config/test_overrides.py +0 -0
  40. {hydraflow-0.7.3 → hydraflow-0.7.4}/tests/config/test_params.py +0 -0
  41. {hydraflow-0.7.3 → hydraflow-0.7.4}/tests/conftest.py +0 -0
  42. {hydraflow-0.7.3/tests/main → hydraflow-0.7.4/tests/context}/__init__.py +0 -0
  43. {hydraflow-0.7.3 → hydraflow-0.7.4}/tests/context/chdir.py +0 -0
  44. {hydraflow-0.7.3 → hydraflow-0.7.4}/tests/context/context.py +0 -0
  45. {hydraflow-0.7.3 → hydraflow-0.7.4}/tests/context/logging.py +0 -0
  46. {hydraflow-0.7.3 → hydraflow-0.7.4}/tests/context/rerun.py +0 -0
  47. {hydraflow-0.7.3 → hydraflow-0.7.4}/tests/context/test_chdir.py +0 -0
  48. {hydraflow-0.7.3 → hydraflow-0.7.4}/tests/context/test_context.py +0 -0
  49. {hydraflow-0.7.3 → hydraflow-0.7.4}/tests/context/test_logging.py +0 -0
  50. {hydraflow-0.7.3 → hydraflow-0.7.4}/tests/context/test_rerun.py +0 -0
  51. {hydraflow-0.7.3/tests/param → hydraflow-0.7.4/tests/main}/__init__.py +0 -0
  52. {hydraflow-0.7.3 → hydraflow-0.7.4}/tests/main/base.py +0 -0
  53. {hydraflow-0.7.3 → hydraflow-0.7.4}/tests/main/force_new_run.py +0 -0
  54. {hydraflow-0.7.3 → hydraflow-0.7.4}/tests/main/restart.py +0 -0
  55. {hydraflow-0.7.3 → hydraflow-0.7.4}/tests/main/skip.py +0 -0
  56. {hydraflow-0.7.3 → hydraflow-0.7.4}/tests/main/test_base.py +0 -0
  57. {hydraflow-0.7.3 → hydraflow-0.7.4}/tests/main/test_force_new_run.py +0 -0
  58. {hydraflow-0.7.3 → hydraflow-0.7.4}/tests/main/test_restart.py +0 -0
  59. {hydraflow-0.7.3 → hydraflow-0.7.4}/tests/main/test_skip.py +0 -0
  60. {hydraflow-0.7.3/tests/run → hydraflow-0.7.4/tests/param}/__init__.py +0 -0
  61. {hydraflow-0.7.3 → hydraflow-0.7.4}/tests/param/params.py +0 -0
  62. {hydraflow-0.7.3 → hydraflow-0.7.4}/tests/param/test_param.py +0 -0
  63. {hydraflow-0.7.3 → hydraflow-0.7.4}/tests/param/test_params.py +0 -0
  64. {hydraflow-0.7.3/tests/utils → hydraflow-0.7.4/tests/run}/__init__.py +0 -0
  65. {hydraflow-0.7.3 → hydraflow-0.7.4}/tests/run/filter.py +0 -0
  66. {hydraflow-0.7.3 → hydraflow-0.7.4}/tests/run/run.py +0 -0
  67. {hydraflow-0.7.3 → hydraflow-0.7.4}/tests/run/test_collection.py +0 -0
  68. {hydraflow-0.7.3 → hydraflow-0.7.4}/tests/run/test_data.py +0 -0
  69. {hydraflow-0.7.3 → hydraflow-0.7.4}/tests/run/test_filter.py +0 -0
  70. {hydraflow-0.7.3 → hydraflow-0.7.4}/tests/run/test_info.py +0 -0
  71. {hydraflow-0.7.3 → hydraflow-0.7.4}/tests/run/test_run.py +0 -0
  72. {hydraflow-0.7.3 → hydraflow-0.7.4}/tests/test_mlflow.py +0 -0
  73. {hydraflow-0.7.3 → hydraflow-0.7.4}/tests/utils/test_run.py +0 -0
  74. {hydraflow-0.7.3 → hydraflow-0.7.4}/tests/utils/test_utils.py +0 -0
  75. {hydraflow-0.7.3 → hydraflow-0.7.4}/tests/utils/utils.py +0 -0
@@ -0,0 +1,51 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ concurrency:
9
+ group: test-${{ github.head_ref }}
10
+ cancel-in-progress: true
11
+
12
+ env:
13
+ PYTHONUNBUFFERED: "1"
14
+ FORCE_COLOR: "1"
15
+
16
+ jobs:
17
+ run:
18
+ name: Python ${{ matrix.python-version }} on ${{ startsWith(matrix.os, 'macos-') && 'macOS' || startsWith(matrix.os, 'windows-') && 'Windows' || 'Linux' }}
19
+ runs-on: ${{ matrix.os }}
20
+ strategy:
21
+ fail-fast: false
22
+ matrix:
23
+ os: [ubuntu-latest, windows-latest, macos-latest]
24
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
25
+
26
+ steps:
27
+ - uses: actions/checkout@v4
28
+ - name: Set up Python ${{ matrix.python-version }}
29
+ uses: actions/setup-python@v5
30
+ with:
31
+ python-version: ${{ matrix.python-version }}
32
+ allow-prereleases: true
33
+ - name: Install uv and ruff
34
+ run: pip install uv ruff
35
+ - name: Install the project
36
+ run: uv sync
37
+ - name: Ruff check
38
+ run: ruff check
39
+ - name: Run test
40
+ run: uv run pytest -v --junitxml=junit.xml
41
+ - name: Upload Codecov Results
42
+ if: success()
43
+ uses: codecov/codecov-action@v4
44
+ with:
45
+ token: ${{ secrets.CODECOV_TOKEN }}
46
+ file: lcov.info
47
+ - name: Upload test results to Codecov
48
+ if: ${{ !cancelled() }}
49
+ uses: codecov/test-results-action@v1
50
+ with:
51
+ token: ${{ secrets.CODECOV_TOKEN }}
@@ -0,0 +1,25 @@
1
+ name: Documentation
2
+ on:
3
+ push:
4
+ branches: [main]
5
+ tags: ["*"]
6
+ permissions:
7
+ contents: write
8
+ jobs:
9
+ deploy:
10
+ name: Documentation
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+ - name: Configure Git Credentials
15
+ run: |
16
+ git config user.name github-actions[bot]
17
+ git config user.email 41898282+github-actions[bot]@users.noreply.github.com
18
+ - name: Set up Python 3.11
19
+ uses: actions/setup-python@v5
20
+ with:
21
+ python-version: 3.11
22
+ - name: Install package
23
+ run: pip install -e . mkapi markdown-exec[ansi]
24
+ - name: Deploy documentation
25
+ run: mkdocs gh-deploy --force
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hydraflow
3
- Version: 0.7.3
3
+ Version: 0.7.4
4
4
  Summary: Hydraflow integrates Hydra and MLflow to manage and track machine learning experiments.
5
5
  Project-URL: Documentation, https://daizutabi.github.io/hydraflow/
6
6
  Project-URL: Source, https://github.com/daizutabi/hydraflow
@@ -38,6 +38,9 @@ Classifier: Programming Language :: Python :: 3.13
38
38
  Requires-Python: >=3.10
39
39
  Requires-Dist: hydra-core>=1.3
40
40
  Requires-Dist: mlflow>=2.15
41
+ Requires-Dist: omegaconf
42
+ Requires-Dist: rich
43
+ Requires-Dist: typer
41
44
  Description-Content-Type: text/markdown
42
45
 
43
46
  # Hydraflow
@@ -0,0 +1,10 @@
1
+ # Hydraflow Documentation
2
+
3
+ Hydraflow integrates [Hydra](https://hydra.cc/) and [MLflow](https://mlflow.org/)
4
+ to manage and track machine learning experiments.
5
+
6
+ ## Installation
7
+
8
+ ```bash
9
+ pip install hydraflow
10
+ ```
@@ -0,0 +1,150 @@
1
+ # Quickstart
2
+
3
+ ## Hydra application
4
+
5
+ The following example demonstrates how to use Hydraflow with a Hydra application.
6
+ There are two main steps to using Hydraflow:
7
+
8
+ 1. Set the MLflow experiment using the Hydra job name.
9
+ 2. Start a new MLflow run that logs the Hydra configuration.
10
+
11
+ ```python title="apps/quickstart.py" linenums="1" hl_lines="24 26"
12
+ --8<-- "apps/quickstart.py"
13
+ ```
14
+
15
+ ### Set the MLflow experiment
16
+
17
+ [`hydraflow.set_experiment`][] sets the MLflow experiment using the Hydra job name.
18
+ Optionally, it can also set the tracking URI with `uri` argument.
19
+ For example,
20
+
21
+ ```python
22
+ hydraflow.set_experiment(uri="sqlite:///mlruns.db")
23
+ ```
24
+
25
+ ### Start a new MLflow run
26
+
27
+ [`hydraflow.start_run`][] starts a new MLflow run that logs the Hydra configuration.
28
+ It returns the started run so that it can be used to log metrics, parameters, and artifacts
29
+ within the context of the run.
30
+
31
+ ```python
32
+ with hydraflow.start_run(cfg) as run:
33
+ pass
34
+ ```
35
+
36
+ ## Run the application
37
+
38
+ ```bash exec="on"
39
+ rm -rf mlruns outputs multirun
40
+ ```
41
+
42
+ ### Single-run
43
+
44
+ Run the Hydra application as a normal Python script.
45
+
46
+ ```console exec="1" source="console"
47
+ $ python apps/quickstart.py
48
+ ```
49
+
50
+ Check the MLflow CLI to view the experiment.
51
+
52
+ ```console exec="1" source="console"
53
+ $ mlflow experiments search
54
+ ```
55
+
56
+ ### Multi-run
57
+
58
+ ```console exec="1" source="console"
59
+ $ python apps/quickstart.py -m width=400,600 height=100,200,300
60
+ ```
61
+
62
+ ## Use Hydraflow API
63
+
64
+ ### Run collection
65
+
66
+ ```pycon exec="1" source="console" session="quickstart"
67
+ >>> import mlflow
68
+ >>> mlflow.set_experiment("quickstart")
69
+ >>> import hydraflow
70
+ >>> rc = hydraflow.list_runs()
71
+ >>> print(rc)
72
+ ```
73
+
74
+ ### Retrieve a run
75
+
76
+ ```pycon exec="1" source="console" session="quickstart"
77
+ >>> run = rc.first()
78
+ >>> print(type(run))
79
+ ```
80
+
81
+ ```pycon exec="1" source="console" session="quickstart"
82
+ >>> cfg = hydraflow.load_config(run)
83
+ >>> print(type(cfg))
84
+ >>> print(cfg)
85
+ ```
86
+
87
+ ```pycon exec="1" source="console" session="quickstart"
88
+ >>> run = rc.last()
89
+ >>> cfg = hydraflow.load_config(run)
90
+ >>> print(cfg)
91
+ ```
92
+
93
+ ### Filter runs
94
+
95
+ ```pycon exec="1" source="console" session="quickstart"
96
+ >>> filtered = rc.filter(width=400)
97
+ >>> print(filtered)
98
+ ```
99
+
100
+ ```pycon exec="1" source="console" session="quickstart"
101
+ >>> filtered = rc.filter(height=[100, 300])
102
+ >>> print(filtered)
103
+ ```
104
+
105
+ ```pycon exec="1" source="console" session="quickstart"
106
+ >>> filtered = rc.filter(height=(100, 300))
107
+ >>> print(filtered)
108
+ ```
109
+
110
+ ```pycon exec="1" source="console" session="quickstart"
111
+ >>> run = rc.find(height=100)
112
+ >>> print(run.data.params)
113
+ ```
114
+
115
+ ```pycon exec="1" source="console" session="quickstart"
116
+ >>> run = rc.find_last(height=100)
117
+ >>> print(run.data.params)
118
+ ```
119
+
120
+ ### Map runs
121
+
122
+ ```pycon exec="1" source="console" session="quickstart"
123
+ >>> params = rc.map(lambda x: x.data.params)
124
+ >>> for p in params:
125
+ ... print(p)
126
+ ```
127
+
128
+ ```pycon exec="1" source="console" session="quickstart"
129
+ >>> list(rc.map_id(print))
130
+ ```
131
+
132
+ ### Group runs
133
+
134
+ ```pycon exec="1" source="console" session="quickstart"
135
+ >>> grouped = rc.groupby("width")
136
+ >>> for key, group in grouped.items():
137
+ ... print(key, group)
138
+ ```
139
+
140
+ ```pycon exec="1" source="console" session="quickstart"
141
+ >>> grouped = rc.groupby(["height"])
142
+ >>> for key, group in grouped.items():
143
+ ... print(key, group)
144
+ ```
145
+
146
+ ### Config dataframe
147
+
148
+ ```pycon exec="1" source="console" session="quickstart"
149
+ >>> print(rc.data.config)
150
+ ```
@@ -0,0 +1,5 @@
1
+ a:
2
+ b: [1, 2]
3
+ c.d: 3m
4
+ c.e/3: 4
5
+ e: true
@@ -1,10 +1,10 @@
1
1
  [build-system]
2
- requires = ["hatchling>=1.26.1"]
2
+ requires = ["hatchling"]
3
3
  build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "hydraflow"
7
- version = "0.7.3"
7
+ version = "0.7.4"
8
8
  description = "Hydraflow integrates Hydra and MLflow to manage and track machine learning experiments."
9
9
  readme = "README.md"
10
10
  license = { file = "LICENSE" }
@@ -19,40 +19,34 @@ classifiers = [
19
19
  "Programming Language :: Python :: 3.13",
20
20
  ]
21
21
  requires-python = ">=3.10"
22
- dependencies = ["hydra-core>=1.3", "mlflow>=2.15"]
22
+ dependencies = ["hydra-core>=1.3", "mlflow>=2.15", "omegaconf", "rich", "typer"]
23
23
 
24
24
  [project.urls]
25
25
  Documentation = "https://daizutabi.github.io/hydraflow/"
26
26
  Source = "https://github.com/daizutabi/hydraflow"
27
27
  Issues = "https://github.com/daizutabi/hydraflow/issues"
28
28
 
29
- [tool.uv]
30
- dev-dependencies = [
31
- "markdown-exec[ansi]",
32
- "mkapi",
33
- "mkdocs-material",
34
- "mkdocs>=1.6",
29
+ [project.scripts]
30
+ hydraflow = "hydraflow.cli:app"
31
+
32
+ [dependency-groups]
33
+ dev = [
34
+ "pytest-clarity",
35
35
  "pytest-cov",
36
36
  "pytest-order",
37
37
  "pytest-randomly",
38
38
  "pytest-xdist",
39
39
  ]
40
-
41
- [tool.hatch.build.targets.sdist]
42
- exclude = ["/.github", "/docs"]
43
-
44
- [tool.hatch.build.targets.wheel]
45
- packages = ["src/hydraflow"]
40
+ docs = ["markdown-exec[ansi]", "mkapi", "mkdocs-material"]
46
41
 
47
42
  [tool.pytest.ini_options]
48
43
  addopts = [
49
44
  "--cov=hydraflow",
50
45
  "--cov-report=lcov:lcov.info",
51
- "-n8",
52
46
  "--dist=loadgroup",
47
+ "-n8",
53
48
  ]
54
49
  filterwarnings = [
55
- "ignore:pkg_resources is deprecated:DeprecationWarning",
56
50
  "ignore:Support for class-based `config` is deprecated",
57
51
  "ignore:Pydantic V1 style",
58
52
  ]
@@ -98,3 +92,4 @@ ignore = [
98
92
  ]
99
93
  "apps/*.py" = ["D", "G", "INP"]
100
94
  "src/hydraflow/main.py" = ["ANN201", "D401", "PLR0913"]
95
+ "src/hydraflow/cli.py" = ["ANN", "D"]
@@ -0,0 +1,75 @@
1
+ """Hydraflow CLI."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+ from typing import Annotated
7
+
8
+ import typer
9
+ from omegaconf import DictConfig, OmegaConf
10
+ from rich.console import Console
11
+ from typer import Argument, Option
12
+
13
+ app = typer.Typer(add_completion=False)
14
+ console = Console()
15
+
16
+
17
+ @app.command()
18
+ def run(
19
+ names: Annotated[
20
+ list[str] | None,
21
+ Argument(help="Job names.", show_default=False),
22
+ ] = None,
23
+ ) -> None:
24
+ """Run jobs."""
25
+ typer.echo(names)
26
+
27
+ cfg = load_config()
28
+ typer.echo(cfg)
29
+
30
+
31
+ @app.command()
32
+ def show() -> None:
33
+ """Show the config."""
34
+ from rich.syntax import Syntax
35
+
36
+ cfg = load_config()
37
+ code = OmegaConf.to_yaml(cfg)
38
+ syntax = Syntax(code, "yaml")
39
+ console.print(syntax)
40
+
41
+
42
+ @app.callback(invoke_without_command=True)
43
+ def callback(
44
+ *,
45
+ version: Annotated[
46
+ bool,
47
+ Option("--version", help="Show the version and exit."),
48
+ ] = False,
49
+ ) -> None:
50
+ if version:
51
+ import importlib.metadata
52
+
53
+ typer.echo(f"hydraflow {importlib.metadata.version('hydraflow')}")
54
+ raise typer.Exit
55
+
56
+
57
+ def find_config() -> Path:
58
+ if Path("hydraflow.yaml").exists():
59
+ return Path("hydraflow.yaml")
60
+
61
+ if Path("hydraflow.yml").exists():
62
+ return Path("hydraflow.yml")
63
+
64
+ typer.echo("No config file found.")
65
+ raise typer.Exit(code=1)
66
+
67
+
68
+ def load_config() -> DictConfig:
69
+ cfg = OmegaConf.load(find_config())
70
+
71
+ if isinstance(cfg, DictConfig):
72
+ return cfg
73
+
74
+ typer.echo("Invalid config file.")
75
+ raise typer.Exit(code=1)
@@ -0,0 +1,9 @@
1
+ from pathlib import Path
2
+
3
+ import pytest
4
+
5
+
6
+ @pytest.fixture(autouse=True)
7
+ def setup(monkeypatch: pytest.MonkeyPatch, tmp_path: Path):
8
+ monkeypatch.chdir(tmp_path)
9
+ yield
@@ -0,0 +1,18 @@
1
+ from pathlib import Path
2
+
3
+ from typer.testing import CliRunner
4
+
5
+ from hydraflow.cli import app
6
+
7
+ runner = CliRunner()
8
+
9
+
10
+ def test_invoke_error():
11
+ result = runner.invoke(app, ["run"])
12
+ assert result.exit_code == 1
13
+
14
+
15
+ def test_invoke():
16
+ Path("hydraflow.yaml").write_text("a:\n b: [1, 2]")
17
+ result = runner.invoke(app, ["run"])
18
+ assert result.exit_code == 0
@@ -0,0 +1,52 @@
1
+ from pathlib import Path
2
+
3
+ import pytest
4
+ import typer
5
+ from typer.testing import CliRunner
6
+
7
+ from hydraflow.cli import app
8
+
9
+ runner = CliRunner()
10
+
11
+
12
+ @pytest.mark.parametrize("file", ["hydraflow.yaml", "hydraflow.yml"])
13
+ def test_find_config(file):
14
+ from hydraflow.cli import find_config
15
+
16
+ Path(file).touch()
17
+ assert find_config() == Path(file)
18
+
19
+
20
+ def test_find_config_error():
21
+ from hydraflow.cli import find_config
22
+
23
+ with pytest.raises(typer.Exit):
24
+ find_config()
25
+
26
+
27
+ def test_load_config():
28
+ from hydraflow.cli import load_config
29
+
30
+ Path("hydraflow.yaml").write_text("a:\n b: 1")
31
+ cfg = load_config()
32
+ assert cfg["a"]["b"] == 1
33
+
34
+
35
+ def test_load_config_error():
36
+ from hydraflow.cli import load_config
37
+
38
+ Path("hydraflow.yml").write_text("- 1\n- 2")
39
+
40
+ with pytest.raises(typer.Exit):
41
+ load_config()
42
+
43
+
44
+ def test_invoke_error():
45
+ result = runner.invoke(app, ["show"])
46
+ assert result.exit_code == 1
47
+
48
+
49
+ def test_invoke():
50
+ Path("hydraflow.yaml").write_text("a:\n b: [1, 2]")
51
+ result = runner.invoke(app, ["show"])
52
+ assert result.exit_code == 0
@@ -0,0 +1,20 @@
1
+ import subprocess
2
+
3
+ from typer.testing import CliRunner
4
+
5
+ from hydraflow.cli import app
6
+
7
+ runner = CliRunner()
8
+
9
+
10
+ def test_invoke():
11
+ result = runner.invoke(app, ["--version"])
12
+ assert result.exit_code == 0
13
+ assert "hydraflow" in result.stdout
14
+ assert result.stdout.count(".") == 2
15
+
16
+
17
+ def test_command():
18
+ out = subprocess.check_output(["hydraflow", "--version"], text=True)
19
+ assert "hydraflow" in out
20
+ assert out.count(".") == 2
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