Skip to content

Commit ebbec41

Browse files
authored
Add support for ArviZ <1.0, on top of existing >1.0 support (#22)
* Support both xr.DataTree and arviz.InferenceData via duck-typing Add _get_group() and _has_group() private helpers that dispatch on hasattr(dt, 'children') to support both arviz >=1.0 DataTree and arviz <1.0 InferenceData with zero public API changes. - Rename _datatree_group_to_df → _group_to_df (no longer datatree-specific) - Route all group access through the two helpers - Loosen arviz pin from >=1.0 to any version - Update docstrings and error messages for dual-type support Closes #21 * Add backend dispatch tests covering both DataTree and InferenceData paths Parametrized tests verify parameter_draws, compare_draws, and prediction_draws work identically with xr.DataTree and a duck-type InferenceData mock (attribute-access groups, no .children). 42 new tests, 100% pass rate against both backends. * Add arviz<1.0 CI matrix and real-InferenceData fixture The legacy az.InferenceData dispatch branch was only exercised by the _InferenceDataMock duck-type; on arviz>=1.0 az.InferenceData aliases to DataTree so the getattr(dt, group) path was unreachable in CI. - ci.yml: matrix.arviz=[locked, legacy]; legacy job pins arviz<1.0 and runs tests with --no-sync so the downgrade is not reverted. - test_backend_compat.py: add real_inferencedata variant to parameter, compare, and prediction fixtures. Skips on arviz>=1.0 (DetectionWarning path), runs same assertions against real az.InferenceData on arviz<1.0. Verified: 92 passed/21 skipped on arviz 1.2.0; 63 passed/0 skipped on arviz 0.23.4 (real legacy branch exercised). * docs: add GitHub install instructions for pre-release testing Lets users test main-branch functionality before a PyPI release: pip install git+https://github.com/drbenvincent/tidydraws.git uv add git+https://github.com/drbenvincent/tidydraws.git Added to both README.md and index.qmd install sections. * Address review non-blocking items: type annotations, pin, error msg, docs - _extract.py: widen dt annotations from xr.DataTree to a PEP 695 ArviZData = xr.DataTree | az.InferenceData union alias. az is imported only under TYPE_CHECKING; the alias rhs is lazy so no runtime arviz import is needed (matches the PR's no-import design). Applied to all three public functions and the _get_group/_has_group/_group_to_df helpers. - pyproject.toml: pin arviz>=0.12 (was bare 'arviz'), matching the PR's stated out-of-scope (arviz<0.12 not supported). - _extract.py: restore 'constant_data_group' parameter name in the prediction_draws missing-data error message (AGENTS.md Hard Rule 3). - 04-showcase.qmd: fix stale _datatree_group_to_df -> _group_to_df ref. Verified: 92 passed/21 skipped; pre-commit (ruff, mypy v1.15.0, format) passes; arviz not imported at runtime; ArviZData is a lazy TypeAliasType.
1 parent 42fd6b6 commit ebbec41

10 files changed

Lines changed: 481 additions & 41 deletions

File tree

.github/workflows/ci.yml

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,16 @@ concurrency:
1414

1515
jobs:
1616
test:
17+
name: test (arviz ${{ matrix.arviz }})
1718
runs-on: ubuntu-latest
19+
strategy:
20+
fail-fast: false
21+
matrix:
22+
# "locked" uses the arviz version pinned in uv.lock (>=1.0).
23+
# "legacy" downgrades to arviz<1.0 to exercise the real
24+
# az.InferenceData dispatch branch (skipped on >=1.0 where
25+
# az.InferenceData is aliased to xarray.DataTree).
26+
arviz: [locked, legacy]
1827
permissions:
1928
contents: read
2029
steps:
@@ -25,8 +34,15 @@ jobs:
2534
uses: astral-sh/setup-uv@v8.2.0
2635
- name: Install dependencies
2736
run: uv sync --all-extras
37+
- name: Pin legacy arviz (<1.0)
38+
if: matrix.arviz == 'legacy'
39+
# Override the lock's arviz>=1.0 with a legacy release so the
40+
# real-InferenceData test variants activate instead of skipping.
41+
run: uv pip install 'arviz<1.0'
2842
- name: Run tests
29-
run: uv run pytest -v
43+
# --no-sync so the legacy-arviz downgrade from the previous step
44+
# is not reverted by `uv run` reconciling back to uv.lock.
45+
run: uv run --no-sync pytest -v
3046

3147
prek:
3248
runs-on: ubuntu-latest

AGENTS.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ Key point: prefix Python/pytest commands with `uv run` so they use the project's
5151
- **Fail loudly** on missing data to avoid silent misalignment bugs; give the user explicit guidance.
5252
- **Cross-dim joins auto-join with a logged warning** (e.g. scalar `sigma` broadcast across `beta[groups]`) — common case "just works", transparently.
5353
- **`compare_draws()` ships in v0.1** because prior vs. posterior comparison is fundamental.
54-
- **ArviZ 1.0 DataTree only**greenfield, no legacy `InferenceData` debt. Access groups via `.children[group].to_dataset()`.
54+
- **Supports both `xr.DataTree` and `arviz.InferenceData`**dispatch via `_get_group()` / `_has_group()` helpers using duck-typing.
5555
- **Polars over pandas** for faster joins and a consistent tidy-frame type across the API surface.
5656

5757
---
@@ -81,7 +81,7 @@ def compare_draws(
8181

8282
### Core helpers (in `_extract.py`)
8383

84-
- `_datatree_group_to_df(dt, group)``pl.DataFrame` with chain, draw, and all coord columns.
84+
- `_group_to_df(dt, group)``pl.DataFrame` with chain, draw, and all coord columns.
8585
- `_align_dims(frames)` → inner-join same-dim frames; cross-join different-dim frames with a logged warning.
8686
- `_coerce_to_dataframe(newdata)``pl.DataFrame` from `pl.DataFrame` / `pd.DataFrame`.
8787

@@ -91,7 +91,7 @@ def compare_draws(
9191

9292
- Returning `pl.LazyFrame` or leaving a `.lazy()` / `.collect()` round-trip in the extraction path — the data layer is eager by design.
9393
- Confusing dimension names with coordinate names in xarray — the DataArray already knows its dims, so auto-detection gets this right.
94-
- Forgetting groups are accessed via `.children[group].to_dataset()`.
94+
- Accessing groups directly instead of through `_get_group()` / `_has_group()` — use the helpers for compat with both DataTree and InferenceData.
9595
- Running `pytest`/`python` without `uv run` (wrong environment).
9696

9797
---

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,18 @@ With pip:
2626
pip install tidydraws
2727
```
2828

29+
If you want the latest functionality merged into main but not yet released, install directly from GitHub:
30+
31+
```bash
32+
pip install git+https://github.com/drbenvincent/tidydraws.git
33+
```
34+
35+
Or with uv:
36+
37+
```bash
38+
uv add git+https://github.com/drbenvincent/tidydraws.git
39+
```
40+
2941
## Why tidydraws?
3042

3143
Plotting MCMC output in Python means manually slicing xarray dimensions, iterating groups, and aligning coordinates — imperative, verbose, error-prone. R's [`tidybayes`](https://github.com/mjskay/tidybayes) solved this with a data layer that respects parameter space vs prediction space. `tidydraws` brings that to Python on Polars.

docs/examples/04-showcase.qmd

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ pred_summary = td.point_interval(
123123

124124
## 2. Varying intercepts
125125

126-
One-dimensional `alpha[group]` with string coordinate labels. Exercises `_datatree_group_to_df` with non-numeric coords and tests that forest-plot sorting/filtering works on string dims.
126+
One-dimensional `alpha[group]` with string coordinate labels. Exercises `_group_to_df` with non-numeric coords and tests that forest-plot sorting/filtering works on string dims.
127127

128128
### Use tidydraws
129129

index.qmd

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -305,21 +305,33 @@ alt_pred = (
305305

306306
## Install
307307

308-
:::: {.panel-tabset}
308+
::::: {.panel-tabset}
309309

310310
#### uv
311311

312312
```bash
313313
uv add tidydraws
314314
```
315315

316+
If you want the latest functionality merged into main but not yet released, install directly from GitHub:
317+
318+
```bash
319+
uv add git+https://github.com/drbenvincent/tidydraws.git
320+
```
321+
316322
#### pip
317323

318324
```bash
319325
pip install tidydraws
320326
```
321327

322-
::::
328+
If you want the latest functionality merged into main but not yet released, install directly from GitHub:
329+
330+
```bash
331+
pip install git+https://github.com/drbenvincent/tidydraws.git
332+
```
333+
334+
:::::
323335

324336
## Why tidydraws?
325337

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ classifiers = [
2929
requires-python = ">=3.12"
3030
dependencies = [
3131
"polars >=0.20",
32-
"arviz >=1.0",
32+
"arviz>=0.12",
3333
"xarray",
3434
"numpy",
3535
"pyarrow>=24.0.0",

0 commit comments

Comments
 (0)