asdf-format / asdf

ASDF (Advanced Scientific Data Format) is a next generation interchange format for scientific data
http://asdf.readthedocs.io/
BSD 3-Clause "New" or "Revised" License
530 stars 58 forks source link

TaggedDict multiple inheritance is failing Pydantic validation #1869

Open ketozhang opened 6 days ago

ketozhang commented 6 days ago

Description of the problem

Using pydantic for deserialization, the ASDF serialized node of the YAML tree comes in as a asdf.tagged.TaggedDict. Pydantic is having trouble validating this as if it's a regular dictionary. I identified this being due to TaggedDict having multiple-inheritance to both UserDict and dict. I have not seen examples where this is the intended implementation for custom dicts.

Example of the problem

from collections import UserDict

from asdf.tagged import TaggedDict
from pydantic import BaseModel

class Bar(BaseModel):
    a: int

class Foo(BaseModel):
    bar: Bar

Foo.model_validate({"bar": {"a": 1}})
Foo.model_validate({"bar": TaggedDict({"a": 1})})
pydantic_core._pydantic_core.ValidationError: 1 validation error for Foo
bar.a
  Field required [type=missing, input_value={'a': 1}, input_type=TaggedDict]
    For further information visit https://errors.pydantic.dev/2.9/v/missing

Success on simplest single-inheritance.

class SimpleDict(UserDict): ...

Foo.model_validate({"bar": SimpleDict({"a": 1})})

Fails on simplest multi-inheritance

class MultiInheritanceDict(UserDict, dict): ...

Foo.model_validate({"bar": MultiInheritanceDict({"a": 1})})
pydantic_core._pydantic_core.ValidationError: 1 validation error for Foo
bar.a
  Field required [type=missing, input_value={'a': 1}, input_type=MultiInheritanceDict]
    For further information visit https://errors.pydantic.dev/2.9/v/missing

System information

asdf version: 3.5.0 python version: 3.12.7 operating system: OSX 14.6.1

ketozhang commented 6 days ago

I don't use TaggedDict directly with pydantic, so I don't suggest this needs to be fixed. This is likely relevant for pydantic to solve.

However, I do question the multiple inheritance here. A cursory glance, it's not typical to see UserDict inheriting dict.