Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions .github/workflows/ci-pydantic-latest.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: ci-pydantic-latest

on:
push:
branches:
- main
pull_request:
branches:
- main
workflow_dispatch:

defaults:
run:
shell: pixi run -e py312amber bash -e {0}

jobs:
test:
name: Test with latest pydantic on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- macos-latest

steps:
- uses: actions/checkout@v6

- name: Set up virtual environment
uses: prefix-dev/setup-pixi@v0.9.5
with:
pixi-version: v0.41.4
environments: py312amber
frozen: true

- name: Upgrade pydantic to latest
run: pip install "pydantic>=2.12"

- name: Run mypy
run: pixi run -e py312amber run_mypy

- name: Run tests
run: pixi run -e py312amber run_tests
2 changes: 1 addition & 1 deletion devtools/conda-envs/docs_env.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ dependencies:
- setuptools !=76.0.0
- pip
- numpy =2
- pydantic >=2,<2.12
- pydantic >=2
- openff-toolkit-base =0.17
- openmm
- mbuild-base =1
Expand Down
13 changes: 13 additions & 0 deletions openff/interchange/components/potentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,20 @@ def validate_collections(
raise ValueError(f"Validation mode {info.mode} not implemented.")


def serialize_collections(v: Any, handler: Any, info: Any) -> dict:
"""Serialize collections using each collection's actual type schema.

Without this, pydantic uses the declared Collection base class schema and
drops subclass-specific fields (e.g. scale_14, cutoff, periodic_potential).
"""
if info.mode == "json":
return {name: json.loads(collection.model_dump_json()) for name, collection in v.items()}
else:
raise NotImplementedError(f"Serialization mode {info.mode} not implemented.")


_AnnotatedCollections = Annotated[
dict[str, Collection],
WrapValidator(validate_collections),
WrapSerializer(serialize_collections),
]
5 changes: 4 additions & 1 deletion openff/interchange/pydantic.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,7 @@ def model_dump(self, **kwargs) -> dict[str, Any]:
return super().model_dump(serialize_as_any=True, **kwargs)

def model_dump_json(self, **kwargs) -> str:
return super().model_dump_json(serialize_as_any=True, **kwargs)
# serialize_as_any=True breaks pint.Quantity serialization in pydantic >=2.12
# (pydantic/pydantic#12348); the Annotated WrapSerializer on _Quantity handles
# JSON serialization correctly without it
return super().model_dump_json(**kwargs)