From a7ee6b258a949a2c83a94d23dad0d67b0fd0d655 Mon Sep 17 00:00:00 2001 From: wpbonelli Date: Wed, 15 May 2024 18:47:55 -0400 Subject: [PATCH] test(snapshots): use devtools snapshot fixtures (#2189) * import snapshot fixtures from modflow-devtools and remove them from conftest.py * switch to dev version of devtools in environment.yml, use micromamba in rtd.yml ci --- .github/workflows/rtd.yml | 26 ++++++---- DEVELOPER.md | 6 +-- autotest/conftest.py | 103 +------------------------------------- etc/environment.yml | 3 +- 4 files changed, 19 insertions(+), 119 deletions(-) diff --git a/.github/workflows/rtd.yml b/.github/workflows/rtd.yml index 965e548608..4192123a9a 100644 --- a/.github/workflows/rtd.yml +++ b/.github/workflows/rtd.yml @@ -19,7 +19,7 @@ jobs: defaults: run: - shell: bash + shell: bash -l {0} steps: - name: Checkout flopy repo @@ -32,18 +32,22 @@ jobs: echo $GITHUB_REF echo $GITHUB_EVENT_NAME - - name: Setup Python - uses: actions/setup-python@v5 + - name: Setup Micromamba + uses: mamba-org/setup-micromamba@v1 with: - python-version: 3.9 - cache: 'pip' - cache-dependency-path: pyproject.toml + environment-file: etc/environment.yml + cache-environment: true + cache-downloads: true + create-args: >- + python=3.12 + init-shell: >- + bash + powershell - - name: Upgrade pip - run: python -m pip install --upgrade pip - - - name: Install flopy and dependencies - run: pip install ".[test, doc, optional]" + - name: Install Python dependencies + run: | + pip install --upgrade pip + pip install . - name: Workaround OpenGL issue on Linux if: runner.os == 'Linux' diff --git a/DEVELOPER.md b/DEVELOPER.md index fbf10257f4..dcb2f9a113 100644 --- a/DEVELOPER.md +++ b/DEVELOPER.md @@ -350,11 +350,7 @@ By default, `pytest-benchmark` will only print profiling results to `stdout`. If ### Snapshot testing -Snapshot testing is a form of regression testing in which a "snapshot" of the results of some computation is verified and captured by the developer to be compared against when tests are subsequently run. This is accomplished with [`syrupy`](https://github.com/tophat/syrupy), which provides a `snapshot` fixture overriding the equality operator to allow comparison with e.g. `snapshot == result`. A few custom fixtures for snapshots of NumPy arrays are provided in `autotest/conftest.py`: - -- `array_snapshot`: saves an array in a binary file for compact storage, can be inspected programmatically with `np.load()` -- `text_array_snapshot`: flattens an array and stores it in a text file, compromise between readability and disk usage -- `readable_array_snapshot`: stores an array in a text file in its original shape, easy to inspect but largest on disk +Snapshot testing is a form of regression testing in which a "snapshot" of the results of some computation is verified and captured by the developer to be compared against when tests are subsequently run. This is accomplished with [`syrupy`](https://github.com/tophat/syrupy) via [fixtures defined in `modflow-devtools`](https://modflow-devtools.readthedocs.io/en/latest/md/snapshots.html). By default, tests run in comparison mode. This means a newly written test using any of the snapshot fixtures will fail until a snapshot is created. Snapshots can be created/updated by running pytest with the `--snapshot-update` flag. diff --git a/autotest/conftest.py b/autotest/conftest.py index c96c0384f5..6f770ef54d 100644 --- a/autotest/conftest.py +++ b/autotest/conftest.py @@ -12,7 +12,7 @@ # import modflow-devtools fixtures -pytest_plugins = ["modflow_devtools.fixtures"] +pytest_plugins = ["modflow_devtools.fixtures", "modflow_devtools.snapshots"] # constants @@ -163,104 +163,3 @@ def pytest_report_header(config): f"{optional} packages not found: {', '.join(not_found)}" ) return "\n".join(lines) - - -# snapshot classes and fixtures - -from syrupy.extensions.single_file import ( - SingleFileSnapshotExtension, - WriteMode, -) -from syrupy.types import ( - PropertyFilter, - PropertyMatcher, - SerializableData, - SerializedData, -) - - -def _serialize_bytes(data): - buffer = BytesIO() - np.save(buffer, data) - return buffer.getvalue() - - -class BinaryArrayExtension(SingleFileSnapshotExtension): - """ - Binary snapshot of a NumPy array. Can be read back into NumPy with - .load(), preserving dtype and shape. This is the recommended array - snapshot approach if human-readability is not a necessity, as disk - space is minimized. - """ - - _write_mode = WriteMode.BINARY - _file_extension = "npy" - - def serialize( - self, - data, - *, - exclude=None, - include=None, - matcher=None, - ): - return _serialize_bytes(data) - - -class TextArrayExtension(SingleFileSnapshotExtension): - """ - Text snapshot of a NumPy array. Flattens the array before writing. - Can be read back into NumPy with .loadtxt() assuming you know the - shape of the expected data and subsequently reshape it if needed. - """ - - _write_mode = WriteMode.TEXT - _file_extension = "txt" - - def serialize( - self, - data: "SerializableData", - *, - exclude: Optional["PropertyFilter"] = None, - include: Optional["PropertyFilter"] = None, - matcher: Optional["PropertyMatcher"] = None, - ) -> "SerializedData": - buffer = StringIO() - np.savetxt(buffer, data.ravel()) - return buffer.getvalue() - - -class ReadableArrayExtension(SingleFileSnapshotExtension): - """ - Human-readable snapshot of a NumPy array. Preserves array shape - at the expense of possible loss of precision (default 8 places) - and more difficulty loading into NumPy than TextArrayExtension. - """ - - _write_mode = WriteMode.TEXT - _file_extension = "txt" - - def serialize( - self, - data: "SerializableData", - *, - exclude: Optional["PropertyFilter"] = None, - include: Optional["PropertyFilter"] = None, - matcher: Optional["PropertyMatcher"] = None, - ) -> "SerializedData": - return np.array2string(data, threshold=np.inf) - - -@pytest.fixture -def array_snapshot(snapshot): - return snapshot.use_extension(BinaryArrayExtension) - - -@pytest.fixture -def text_array_snapshot(snapshot): - return snapshot.use_extension(TextArrayExtension) - - -@pytest.fixture -def readable_array_snapshot(snapshot): - return snapshot.use_extension(ReadableArrayExtension) diff --git a/etc/environment.yml b/etc/environment.yml index 50be8d792e..c16a75b5bc 100644 --- a/etc/environment.yml +++ b/etc/environment.yml @@ -19,7 +19,8 @@ dependencies: - filelock - jupyter - jupytext - - modflow-devtools + - pip: + - git+https://github.com/MODFLOW-USGS/modflow-devtools.git - pytest!=8.1.0 - pytest-benchmark - pytest-cov