From ad579d1be1ac5fa9d5c02fab3b6d598da3ae1dc4 Mon Sep 17 00:00:00 2001 From: Matthias Schabel Date: Sat, 17 Oct 2026 12:06:22 -0700 Subject: [PATCH 1/2] test: run test_model_fields in CI again tests/test_model_fields.py imports BaseModel from pydantic_compat, which was never a declared test dependency. It arrived through napari's app-model until app-model 0.5.0 dropped it, and since then the module-level except ImportError has skipped the whole file in every CI job, reporting "pydantic not installed" while pydantic was installed. Declare pydantic-compat in the test_thirdparty group, and skip only when pydantic itself is missing, so a missing pydantic_compat fails collection instead of skipping silently. Reviewed-By: Codex (gpt-6-astra, reasoning effort medium) Co-Authored-By: Claude Opus 5.5 --- pyproject.toml | 1 + tests/test_model_fields.py | 9 +++------ 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 5f13dfa11..42a6957d6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,6 +42,7 @@ test_thirdparty = [ "plotly", "pydantic-extra-types>=2,!=2.10.1", "pydantic", + "pydantic-compat", "pygfx", "pyqtgraph", "pytest-qt", diff --git a/tests/test_model_fields.py b/tests/test_model_fields.py index 43c42add1..3bcf7d2b1 100644 --- a/tests/test_model_fields.py +++ b/tests/test_model_fields.py @@ -7,13 +7,10 @@ from cmap import Color, Colormap from cmap._colormap import ColorStops -try: - import pydantic - from pydantic_compat import BaseModel +pydantic = pytest.importorskip("pydantic") +from pydantic_compat import BaseModel # noqa: E402 - V2 = int(pydantic.__version__.split(".")[0]) >= 2 -except ImportError: - pytest.skip("pydantic not installed", allow_module_level=True) +V2 = int(pydantic.__version__.split(".")[0]) >= 2 try: import pydantic_extra_types.color as pydantic_color From 4033230b73cca01c14b12e0a3f957b52e0dbabed Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Mon, 19 Oct 2026 15:49:50 +0200 Subject: [PATCH 2/2] fix: update pydantic usage and remove pydantic-compat dependency --- pyproject.toml | 2 +- tests/test_model_fields.py | 58 +++++++++++--------------------------- 2 files changed, 18 insertions(+), 42 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 42a6957d6..69a6f9006 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,9 +40,9 @@ test_thirdparty = [ "PyQt6==6.8.1", "numba>=0.60", "plotly", + "psygnal", "pydantic-extra-types>=2,!=2.10.1", "pydantic", - "pydantic-compat", "pygfx", "pyqtgraph", "pytest-qt", diff --git a/tests/test_model_fields.py b/tests/test_model_fields.py index 3bcf7d2b1..8d0f5dcc5 100644 --- a/tests/test_model_fields.py +++ b/tests/test_model_fields.py @@ -1,16 +1,10 @@ -import os -from typing import ClassVar - import numpy as np import pytest from cmap import Color, Colormap from cmap._colormap import ColorStops -pydantic = pytest.importorskip("pydantic") -from pydantic_compat import BaseModel # noqa: E402 - -V2 = int(pydantic.__version__.split(".")[0]) >= 2 +pydantic = pytest.importorskip("pydantic", minversion="2") try: import pydantic_extra_types.color as pydantic_color @@ -22,44 +16,30 @@ def test_pydantic_casting() -> None: assert Color(pydantic_color.Color("red")) is Color("red") -# we're interested in testing serializeability... -# Color can serialized with `str`, and Colormap can be serialized with `as_dict` -@pytest.mark.filterwarnings("ignore:`json_encoders` is deprecated") def test_pydantic_validate() -> None: - class MyModel(BaseModel): + class MyModel(pydantic.BaseModel): color: Color colormap: Colormap - if V2: - - class Config: - # since json.dump is not extendable, this just needs to be documented. - json_encoders: ClassVar[dict] = {Color: str, Colormap: Colormap.as_dict} - obj = MyModel(color=np.array([1.0, 0, 0]), colormap=["r", (0.7, "b"), "w"]) assert obj.color is Color("red") assert obj.colormap == Colormap(["r", (0.7, "b"), "w"]) - serialized = obj.json() - if os.getenv("CI"): - # not sure why this is different in CI - assert serialized == ( - '{"color":"red",' - '"colormap":{"name":"custom colormap","identifier":"custom_colormap",' - '"category":null,' - '"value":[' - "[0.0,[1.0,0.0,0.0,1]]," - "[0.7,[0.0,0.0,1.0,1]]," - "[1.0,[1.0,1.0,1.0,1]]]}" - "}" - ) - if hasattr(MyModel, "model_validate_json"): - assert MyModel.model_validate_json(serialized) == obj - else: - assert MyModel.parse_raw(serialized) == obj + serialized = obj.model_dump_json() + assert serialized == ( + '{"color":"red",' + '"colormap":{"name":"custom colormap","identifier":"custom_colormap",' + '"category":null,' + '"value":[' + "[0.0,[1.0,0.0,0.0,1]]," + "[0.7,[0.0,0.0,1.0,1]]," + "[1.0,[1.0,1.0,1.0,1]]]}" + "}" + ) + assert MyModel.model_validate_json(serialized) == obj # with category colormaps, we only use the qualified name obj2 = MyModel(color="red", colormap=Colormap("viridis")) - serialized2 = obj2.json() + serialized2 = obj2.model_dump_json() assert '"colormap":"bids:viridis"' in serialized2 @@ -76,9 +56,5 @@ class MyModel(psygnal.EventedModel): # type: ignore color=np.array([1, 0, 0]), colormap=["r", (0.7, "b"), "w"], stops="green_r" ) - data = obj.model_dump_json() if V2 else obj.json() - - if hasattr(MyModel, "model_validate_json"): - assert MyModel.model_validate_json(data) == obj - else: - assert MyModel.parse_raw(data) == obj + data = obj.model_dump_json() + assert MyModel.model_validate_json(data) == obj