Skip to content

Commit

Permalink
New cli module
Browse files Browse the repository at this point in the history
  • Loading branch information
daizutabi committed Feb 6, 2025
1 parent cf26c8a commit 20dab48
Show file tree
Hide file tree
Showing 11 changed files with 187 additions and 1 deletion.
File renamed without changes.
File renamed without changes.
5 changes: 5 additions & 0 deletions hydraflow.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
a:
b: [1, 2]
c.d: 3m
c.e/3: 4
e: true
File renamed without changes.
7 changes: 6 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,23 @@ classifiers = [
"Programming Language :: Python :: 3.13",
]
requires-python = ">=3.10"
dependencies = ["hydra-core>=1.3", "mlflow>=2.15"]
dependencies = ["hydra-core>=1.3", "mlflow>=2.15", "omegaconf", "rich", "typer"]

[project.urls]
Documentation = "https://daizutabi.github.io/hydraflow/"
Source = "https://github.com/daizutabi/hydraflow"
Issues = "https://github.com/daizutabi/hydraflow/issues"

[project.scripts]
hydraflow = "hydraflow.cli:app"

[tool.uv]
dev-dependencies = [
"markdown-exec[ansi]",
"mkapi",
"mkdocs-material",
"mkdocs>=1.6",
"pytest-clarity",
"pytest-cov",
"pytest-order",
"pytest-randomly",
Expand Down Expand Up @@ -98,3 +102,4 @@ ignore = [
]
"apps/*.py" = ["D", "G", "INP"]
"src/hydraflow/main.py" = ["ANN201", "D401", "PLR0913"]
"src/hydraflow/cli.py" = ["ANN", "D"]
75 changes: 75 additions & 0 deletions src/hydraflow/cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
"""Hydraflow CLI."""

from __future__ import annotations

from pathlib import Path
from typing import Annotated

import typer
from omegaconf import DictConfig, OmegaConf
from rich.console import Console
from typer import Argument, Option

app = typer.Typer(add_completion=False)
console = Console()


@app.command()
def run(
names: Annotated[
list[str] | None,
Argument(help="Job names.", show_default=False),
] = None,
) -> None:
"""Run jobs."""
typer.echo(names)

cfg = load_config()
typer.echo(cfg)


@app.command()
def show() -> None:
"""Show the config."""
from rich.syntax import Syntax

cfg = load_config()
code = OmegaConf.to_yaml(cfg)
syntax = Syntax(code, "yaml")
console.print(syntax)


@app.callback(invoke_without_command=True)
def callback(
*,
version: Annotated[
bool,
Option("--version", help="Show the version and exit."),
] = False,
) -> None:
if version:
import importlib.metadata

typer.echo(f"hydraflow {importlib.metadata.version('hydraflow')}")
raise typer.Exit


def find_config() -> Path:
if Path("hydraflow.yaml").exists():
return Path("hydraflow.yaml")

if Path("hydraflow.yml").exists():
return Path("hydraflow.yml")

typer.echo("No config file found.")
raise typer.Exit(code=1)


def load_config() -> DictConfig:
cfg = OmegaConf.load(find_config())

if isinstance(cfg, DictConfig):
return cfg

typer.echo("Invalid config file.")
raise typer.Exit(code=1)
Empty file added tests/cli/__init__.py
Empty file.
9 changes: 9 additions & 0 deletions tests/cli/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from pathlib import Path

import pytest


@pytest.fixture(autouse=True)
def setup(monkeypatch: pytest.MonkeyPatch, tmp_path: Path):
monkeypatch.chdir(tmp_path)
yield
18 changes: 18 additions & 0 deletions tests/cli/test_run.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from pathlib import Path

from typer.testing import CliRunner

from hydraflow.cli import app

runner = CliRunner()


def test_invoke_error():
result = runner.invoke(app, ["run"])
assert result.exit_code == 1


def test_invoke():
Path("hydraflow.yaml").write_text("a:\n b: [1, 2]")
result = runner.invoke(app, ["run"])
assert result.exit_code == 0
54 changes: 54 additions & 0 deletions tests/cli/test_show.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
from pathlib import Path

import pytest
import typer
from typer.testing import CliRunner

from hydraflow.cli import app

runner = CliRunner()


@pytest.mark.parametrize("file", ["hydraflow.yaml", "hydraflow.yml"])
def test_find_config(file):
from hydraflow.cli import find_config

Path(file).touch()
assert find_config() == Path(file)


def test_find_config_error():
from hydraflow.cli import find_config

with pytest.raises(typer.Exit):
find_config()


def test_load_config():
from hydraflow.cli import load_config

Path("hydraflow.yaml").write_text("a:\n b: 1")
cfg = load_config()
assert cfg["a"]["b"] == 1


def test_load_config_error():
from hydraflow.cli import load_config

Path("hydraflow.yml").write_text("- 1\n- 2")

with pytest.raises(typer.Exit):
load_config()


def test_invoke_error():
result = runner.invoke(app, ["show"])
assert result.exit_code == 1


def test_invoke():
Path("hydraflow.yaml").write_text("a:\n b: [1, 2]")
result = runner.invoke(app, ["show"])
assert result.exit_code == 0
assert "a:" in result.stdout
assert "- 1" in result.stdout
20 changes: 20 additions & 0 deletions tests/cli/test_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import subprocess

from typer.testing import CliRunner

from hydraflow.cli import app

runner = CliRunner()


def test_invoke():
result = runner.invoke(app, ["--version"])
assert result.exit_code == 0
assert "hydraflow" in result.stdout
assert result.stdout.count(".") == 2


def test_command():
out = subprocess.check_output(["hydraflow", "--version"], text=True)
assert "hydraflow" in out
assert out.count(".") == 2

0 comments on commit 20dab48

Please sign in to comment.