Source code for ewoksxas.resources.data.regenerate_reference
"""Regenerate the reference snapshots used by the test suite.
The tests compare computed arrays against stored ``.npz`` snapshots (in the
``snapshots`` directory next to this module) with a tolerance, which is portable
across operating systems where byte-level hashing is not. Run this only after a
dependency change (e.g. a larch upgrade) has been reviewed and accepted, to
refresh those snapshots::
python -m ewoksxas.resources.data.regenerate_reference # all
python -m ewoksxas.resources.data.regenerate_reference autobk_chi # one
Adding a snapshot for a new test takes two steps:
1. Write a builder function returning a ``dict`` of arrays and register it in
``SNAPSHOTS`` under the snapshot name.
2. In the test, load it with
``np.load(resource_filename("ewoksxas:data/snapshots/<name>.npz"))`` and
compare with ``numpy.testing.assert_allclose``.
The data-loading helpers mirror the fixtures in ``tasks/tests/conftest.py``.
"""
from __future__ import annotations
import sys
from pathlib import Path
from typing import TYPE_CHECKING
import larch
import numpy as np
from ewoksorange.tests.utils import execute_task
from silx.resources import resource_filename
from ewoksxas.converters.orange import Converter
from ewoksxas.tasks.autobk import AutoBK
from ewoksxas.tasks.normalize import Normalize
from ewoksxas.tasks.read_scans import ReadScans
from ewoksxas.tasks.read_sources import ReadSources
if TYPE_CHECKING:
from collections.abc import Callable
SNAPSHOT_DIR = Path(__file__).parent / "snapshots"
# --- shared data loaders (mirror tasks/tests/conftest.py) ------------------
[docs]
def raw_fe_foil():
"""Return the raw Fe-foil scans, as the fe_foil_data fixture does."""
data_path = resource_filename("ewoksxas:data/Fe_foil_0001.h5")
sources = execute_task(
ReadSources, inputs={"file_paths": [data_path], "filters": []}
)
return execute_task(
ReadScans,
inputs={
"Data": sources["Data"],
"x": "instrument/energy_enc/data",
"counters": [{"name": "mu_trans", "path": "measurement/mu_trans"}],
"metadata": [],
},
)["Data"]
[docs]
def normalized_fe_foil_one():
"""Return a single normalized Fe-foil spectrum, as the fe_foil_one fixture."""
return execute_task(Normalize, inputs={"Data": raw_fe_foil()})["Data"][:1]
# --- snapshot builders: name -> dict of arrays to store --------------------
def _build_fe_foil_raw() -> dict:
energy, mu = Converter.from_table(raw_fe_foil()).features
return {"energy": energy, "mu": mu}
def _build_autobk_chi() -> dict:
outputs = execute_task(
AutoBK,
inputs={"Data": normalized_fe_foil_one(), "parameters": {"output": "chi"}},
)
k, chi = Converter.from_table(outputs["Data"]).features
return {
"k": k,
"chi": chi,
"larch_version": getattr(larch, "__version__", "unknown"),
}
# Registry of available snapshots. Add a builder here to support a new test.
SNAPSHOTS: dict[str, Callable[[], dict]] = {
"fe_foil_raw_reference": _build_fe_foil_raw,
"autobk_chi_reference": _build_autobk_chi,
}
[docs]
def regenerate(name: str) -> Path:
"""Rebuild one snapshot and write it into the snapshots directory."""
try:
builder = SNAPSHOTS[name]
except KeyError:
known = ", ".join(sorted(SNAPSHOTS))
raise KeyError(f"Unknown snapshot '{name}'. Known snapshots: {known}") from None
SNAPSHOT_DIR.mkdir(parents=True, exist_ok=True)
path = SNAPSHOT_DIR / f"{name}.npz"
np.savez(path, **builder())
print(f"Wrote {path}")
return path
[docs]
def main(argv: list[str] | None = None) -> None:
"""Regenerate the snapshots named on the command line, or all of them."""
names = argv if argv else list(SNAPSHOTS)
for name in names:
regenerate(name)
if __name__ == "__main__":
main(sys.argv[1:])