From eb3d766dd4953a23edefeb2460939c4ab184fa6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vincent=20Gr=C3=A9goire?= Date: Sat, 22 Aug 2026 12:32:10 -0400 Subject: [PATCH 1/4] add iolaus logo to readme and docs home page image lives under docs/assets so mkdocs copies it into the built site. the readme references it by absolute raw.githubusercontent url because pypi does not resolve relative paths, so a repo-relative src would render broken there. also set it as the material header logo and favicon. Co-Authored-By: Claude Opus 5 (1M context) --- README.md | 5 +++++ docs/assets/iolaus.webp | Bin 0 -> 41944 bytes docs/index.md | 4 ++++ mkdocs.yml | 2 ++ 4 files changed, 11 insertions(+) create mode 100644 docs/assets/iolaus.webp diff --git a/README.md b/README.md index 4d02d9e..171cc19 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,8 @@ +

+ Iolaus, the companion who helped Heracles defeat the Hydra +

+ # Iolaus > **Warning:** This project is under active development and is not yet stable. APIs may change without notice. diff --git a/docs/assets/iolaus.webp b/docs/assets/iolaus.webp new file mode 100644 index 0000000000000000000000000000000000000000..a6943659da4249faeb6f5c7b6519e993e20306d1 GIT binary patch literal 41944 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 AJ^%m! literal 0 HcmV?d00001 diff --git a/docs/index.md b/docs/index.md index 0896d97..2857d5d 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,3 +1,7 @@ +

+ Iolaus, the companion who helped Heracles defeat the Hydra +

+ # Iolaus **Iolaus** is a lightweight Python framework for research data analysis projects. It wires together [Dynaconf](https://www.dynaconf.com/), [Typer](https://typer.tiangolo.com/), and a custom run-logging system into a single decorator-based API. diff --git a/mkdocs.yml b/mkdocs.yml index 385bb2b..649a0a2 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -6,6 +6,8 @@ repo_name: vgreg/iolaus theme: name: material + logo: assets/iolaus.webp + favicon: assets/iolaus.webp palette: - scheme: default primary: indigo From 072d92b2b4eee19c59375a4d21eba1946c81adb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vincent=20Gr=C3=A9goire?= Date: Sat, 22 Aug 2026 12:32:10 -0400 Subject: [PATCH 2/4] update actions to node 24 runtimes actions/checkout v4 and setup-uv v5 target node 20, which the runners now force onto node 24 with a deprecation warning. bump every action to its latest major. setup-uv stopped publishing floating major tags after v7, so v10 is pinned to the exact v10.0.1 release. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/ci.yml | 6 +++--- .github/workflows/docs.yml | 8 ++++---- .github/workflows/publish.yml | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3b1f8a2..6f6cfe1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,15 +12,15 @@ jobs: matrix: python-version: ["3.11", "3.12", "3.13", "3.14"] steps: - - uses: actions/checkout@v4 - - uses: astral-sh/setup-uv@v5 + - uses: actions/checkout@v7 + - uses: astral-sh/setup-uv@v10.0.1 with: python-version: ${{ matrix.python-version }} - run: uv sync --all-extras - run: uv run ruff check src/ tests/ - run: uv run mypy src/ - run: uv run pytest --cov=iolaus --cov-report=xml - - uses: codecov/codecov-action@v4 + - uses: codecov/codecov-action@v7 if: matrix.python-version == '3.14' with: token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index cdbb6ed..3eaae6a 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -15,12 +15,12 @@ jobs: name: github-pages url: ${{ steps.deployment.outputs.page_url }} steps: - - uses: actions/checkout@v4 - - uses: astral-sh/setup-uv@v5 + - uses: actions/checkout@v7 + - uses: astral-sh/setup-uv@v10.0.1 - run: uv sync --extra docs - run: uv run mkdocs build --strict - - uses: actions/upload-pages-artifact@v3 + - uses: actions/upload-pages-artifact@v5 with: path: site/ - id: deployment - uses: actions/deploy-pages@v4 + uses: actions/deploy-pages@v5 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 1de90d3..57ecb6e 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -17,9 +17,9 @@ jobs: id-token: write # required for PyPI Trusted Publishing steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 - - uses: astral-sh/setup-uv@v5 + - uses: astral-sh/setup-uv@v10.0.1 - run: uv sync --all-extras From f7b84f46b7f9e17d1fbe740dc64f34102d23456a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vincent=20Gr=C3=A9goire?= Date: Sat, 22 Aug 2026 13:04:26 -0400 Subject: [PATCH 3/4] parse --set overrides as toml so values keep their types merged.set() was called without tomlfy, so every cli override arrived as a string: --set model__lr=0.01 gave '0.01' rather than 0.01, silently changing the type of a key that came from the config file as a float. values that are not valid toml still fall back to str. the existing tests coerced with float(merged.model.lr), which hid this; they now assert on the value directly and three of them fail without the fix. Co-Authored-By: Claude Opus 5 (1M context) --- src/iolaus/settings.py | 5 ++++- tests/test_settings.py | 37 +++++++++++++++++++++++++++++++++---- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/src/iolaus/settings.py b/src/iolaus/settings.py index b570fbb..6273e26 100644 --- a/src/iolaus/settings.py +++ b/src/iolaus/settings.py @@ -34,6 +34,9 @@ def build_settings( for item in overrides: key, _, value = item.partition("=") - merged.set(key.replace("__", "."), value) + # tomlfy parses the value as TOML so numbers, booleans, and lists keep + # their types instead of arriving as bare strings. Values that are not + # valid TOML (bare paths, unquoted text) fall back to str. + merged.set(key.replace("__", "."), value, tomlfy=True) return merged diff --git a/tests/test_settings.py b/tests/test_settings.py index 3e4f400..2e219f2 100644 --- a/tests/test_settings.py +++ b/tests/test_settings.py @@ -11,7 +11,7 @@ def test_build_settings_base_only(base_settings: Dynaconf) -> None: """Base settings are preserved when no extras are provided.""" merged = build_settings(base_settings, extra_config=None, overrides=[]) - assert float(merged.model.lr) == pytest.approx(0.001) + assert merged.model.lr == pytest.approx(0.001) assert merged.db.host == "localhost" @@ -22,7 +22,7 @@ def test_build_settings_extra_config(base_settings: Dynaconf, tmp_path: Path) -> merged = build_settings(base_settings, extra_config=extra, overrides=[]) assert merged.db.host == "remote" # Non-overridden keys should still be present - assert float(merged.model.lr) == pytest.approx(0.001) + assert merged.model.lr == pytest.approx(0.001) def test_build_settings_overrides(base_settings: Dynaconf) -> None: @@ -30,7 +30,7 @@ def test_build_settings_overrides(base_settings: Dynaconf) -> None: merged = build_settings( base_settings, extra_config=None, overrides=["model__lr=0.1"] ) - assert float(merged.model.lr) == pytest.approx(0.1) + assert merged.model.lr == pytest.approx(0.1) def test_build_settings_nested_override(base_settings: Dynaconf) -> None: @@ -41,7 +41,7 @@ def test_build_settings_nested_override(base_settings: Dynaconf) -> None: overrides=["db__host=newhost", "model__lr=0.5"], ) assert merged.db.host == "newhost" - assert float(merged.model.lr) == pytest.approx(0.5) + assert merged.model.lr == pytest.approx(0.5) def test_build_settings_extra_and_overrides( @@ -54,3 +54,32 @@ def test_build_settings_extra_and_overrides( base_settings, extra_config=extra, overrides=["db__host=production"] ) assert merged.db.host == "production" + + +def test_build_settings_override_preserves_types(base_settings: Dynaconf) -> None: + """Overrides are parsed as TOML so they keep their types, not bare strings.""" + merged = build_settings( + base_settings, + extra_config=None, + overrides=["model__lr=0.01", "model__epochs=50", "debug=true"], + ) + assert isinstance(merged.model.lr, float) + assert isinstance(merged.model.epochs, int) + assert isinstance(merged.debug, bool) + assert merged.model.lr == pytest.approx(0.01) + assert merged.model.epochs == 50 + assert merged.debug is True + + +def test_build_settings_override_non_toml_stays_string( + base_settings: Dynaconf, +) -> None: + """Values that are not valid TOML fall back to plain strings.""" + merged = build_settings( + base_settings, + extra_config=None, + overrides=["db__host=remote", "out__path=/tmp/data.csv", "note=a=b"], + ) + assert merged.db.host == "remote" + assert merged.out.path == "/tmp/data.csv" + assert merged.note == "a=b" From 2fdce877670ee0669542126f5a0a866ca3f28d31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vincent=20Gr=C3=A9goire?= Date: Sat, 22 Aug 2026 13:04:26 -0400 Subject: [PATCH 4/4] fix quick-start examples that could not run as written the examples registered a single command but documented invocations as python cli.py . typer collapses a single-command app, so the name is rejected with 'got unexpected extra argument(s)'. each example now registers two commands, and a note explains the collapse. Co-Authored-By: Claude Opus 5 (1M context) --- CHANGELOG.md | 5 +++++ README.md | 7 +++++++ docs/getting-started.md | 8 ++++++++ docs/index.md | 5 +++++ 4 files changed, 25 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b6eb091..8bbce10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), ## [Unreleased] +### Fixed + +- `--set` overrides are now parsed as TOML, so `--set model__lr=0.01` yields the float `0.01` rather than the string `"0.01"`. Values that are not valid TOML (bare paths, unquoted text, values containing `=`) still fall back to strings. +- Corrected the quick-start examples, which registered a single command but were documented as `python cli.py `. Typer collapses single-command applications, so that invocation failed with `Got unexpected extra argument(s)`. The examples now register two commands. + ## [0.1.0] - 2026-08-22 Initial release. diff --git a/README.md b/README.md index 171cc19..ff4e9cd 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,11 @@ def analyze( """Run the analysis pipeline.""" ... +@cmd +def report(settings=None): + """Summarize the latest run.""" + ... + if __name__ == "__main__": app() ``` @@ -55,6 +60,8 @@ python cli.py analyze data.csv --config prod.yaml python cli.py analyze data.csv --set model__lr=0.01 --set db__host=remote ``` +> **Note:** Typer treats an application with exactly one registered command as a single-command CLI, and the command name is then left off the command line. These examples register two commands, so every invocation names the one to run. + Every run produces: ``` diff --git a/docs/getting-started.md b/docs/getting-started.md index fdb66ea..8a7258d 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -53,6 +53,11 @@ def train(settings=None, run_dir=None): print(f"Learning rate: {settings.model.lr}") print(f"Run artifacts in: {run_dir}") +@cmd +def evaluate(settings=None): + """Evaluate the trained model.""" + print(f"Epochs: {settings.model.epochs}") + if __name__ == "__main__": app() ``` @@ -63,6 +68,9 @@ if __name__ == "__main__": python cli.py train ``` +!!! note + Typer treats an application with exactly one registered command as a single-command CLI, and the command name is then left off the command line (`python cli.py --set model__lr=0.01`). These examples register two commands, so every invocation names the one to run. + This creates a timestamped directory under `outputs/train/` containing: - `run.log` — log output from the run diff --git a/docs/index.md b/docs/index.md index 2857d5d..09e136a 100644 --- a/docs/index.md +++ b/docs/index.md @@ -32,6 +32,11 @@ def analyze( """Run the analysis pipeline.""" ... +@cmd +def report(settings=None): + """Summarize the latest run.""" + ... + if __name__ == "__main__": app() ```