From a0001b4d4400ba59bb3b0b629bbece1559061921 Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Thu, 17 Sep 2026 14:45:11 +0200 Subject: [PATCH] Support pandas 3 The pandas3 leg of the test matrix has never run pandas 3: `uv run pip install` is followed by `uv run`, which re-syncs the environment from the lockfile and puts pandas 2 back. The last main run installed pandas 3.0.5 and then reported `pandas 2.3.3`. Install with `uv pip install`, set UV_NO_SYNC for the job, and assert the major version so the leg fails loudly instead of silently testing the wrong thing. With the leg fixed, two tests fail under pandas 3. `_parse_dataset` tags untagged data vars with kind="auxiliary" and `Comparer.__init__` read those attrs back off the caller's dataset, relying on `_normalize_time_to_ns` having returned the same object. pandas 3 defaults datetime64 to microseconds, so that call now genuinely converts and returns a copy, and the mutation stops leaking. Read from the parsed dataset instead. The pandas floor was `>= 1.4, < 3.0`, which is not what is supported: with requires-python >= 3.12, pandas 2.1.1 is the first release with wheels, and xarray already requires pandas >= 2.2. Drop the upper bound, state the real floor. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/full_test.yml | 14 ++++++++++---- pyproject.toml | 2 +- src/modelskill/comparison/_comparison.py | 2 +- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/.github/workflows/full_test.yml b/.github/workflows/full_test.yml index 341923a71..84c575db5 100644 --- a/.github/workflows/full_test.yml +++ b/.github/workflows/full_test.yml @@ -21,6 +21,10 @@ jobs: build: runs-on: ubuntu-latest + # Without this, `uv run` re-syncs the environment from the lockfile and + # silently undoes the pandas version installed below. + env: + UV_NO_SYNC: "1" strategy: matrix: python-version: ["3.12", "3.14"] @@ -42,14 +46,16 @@ jobs: - name: Install pandas 2.x if: matrix.pandas-version == 'pandas2' - run: uv run pip install "pandas>=2.0,<3.0" + run: uv pip install "pandas>=2.0,<3.0" - name: Install pandas 3.x if: matrix.pandas-version == 'pandas3' - run: uv run pip install "pandas>=3.0,<4.0" + run: uv pip install "pandas>=3.0,<4.0" - - name: Show pandas version - run: uv run python -c "import pandas; print(f'pandas {pandas.__version__}')" + - name: Check pandas version + env: + EXPECTED_MAJOR: ${{ matrix.pandas-version == 'pandas3' && '3' || '2' }} + run: uv run python -c "import os, pandas; v = pandas.__version__; print('pandas', v); assert v.split('.')[0] == os.environ['EXPECTED_MAJOR'], v" - name: Type check run: just typecheck diff --git a/pyproject.toml b/pyproject.toml index 890fc7574..bb2322f0e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ name = "modelskill" version = "1.4.0a3" dependencies = [ "numpy > 1.24.4", - "pandas >= 1.4, < 3.0", # TODO remove upper limit + "pandas >= 2.2", "mikeio >= 1.2", "matplotlib", "xarray", diff --git a/src/modelskill/comparison/_comparison.py b/src/modelskill/comparison/_comparison.py index 8838184e5..03f6832d1 100644 --- a/src/modelskill/comparison/_comparison.py +++ b/src/modelskill/comparison/_comparison.py @@ -495,7 +495,7 @@ def __init__( else { # key: ModelResult(value, gtype=self.data.gtype, name=key, x=self.x, y=self.y) str(key): PointModelResult(self.data[[str(key)]], name=str(key)) - for key, value in matched_data.data_vars.items() + for key, value in self.data.data_vars.items() if value.attrs["kind"] == "model" } )