pydantic: 1.10.2 is broken on some frozen dataclasses

Initial Checks

  • I have searched GitHub for a duplicate issue and I’m sure this is something new
  • I have searched Google & StackOverflow for a solution and couldn’t find anything
  • I have read and followed the docs and still think this is a bug
  • I am confident that the issue is with pydantic (not my code, or another library in the ecosystem like FastAPI or mypy)

Description

After upgrading to pydantic==1.10.2, my code which uses both frozen dataclasses and pydantic models started throwing exceptions:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "pydantic/main.py", line 198, in pydantic.main.ModelMetaclass.__new__
  File "pydantic/fields.py", line 506, in pydantic.fields.ModelField.infer
  File "pydantic/fields.py", line 436, in pydantic.fields.ModelField.__init__
  File "pydantic/fields.py", line 557, in pydantic.fields.ModelField.prepare
  File "pydantic/fields.py", line 831, in pydantic.fields.ModelField.populate_validators
  File "pydantic/validators.py", line 725, in find_validators
  File "pydantic/dataclasses.py", line 479, in make_dataclass_validator
    # Make sure we don't have fields without defaults following fields
  File "pydantic/dataclasses.py", line 231, in pydantic.dataclasses.dataclass
    )
  File "pydantic/dataclasses.py", line 218, in pydantic.dataclasses.dataclass.wrap
    # When cls._FIELDS is filled in with a list of Field objects, the name
  File "/usr/local/lib/python3.7/dataclasses.py", line 1010, in dataclass
    return wrap(_cls)
  File "/usr/local/lib/python3.7/dataclasses.py", line 1002, in wrap
    return _process_class(cls, init, repr, eq, order, unsafe_hash, frozen)
  File "/usr/local/lib/python3.7/dataclasses.py", line 879, in _process_class
    raise TypeError('cannot inherit non-frozen dataclass from a '
TypeError: cannot inherit non-frozen dataclass from a frozen one

See example below.

This is caused by https://github.com/pydantic/pydantic/pull/4484 and https://github.com/pydantic/pydantic/issues/4477

Example Code

from dataclasses import dataclass
from pydantic import BaseModel

@dataclass(frozen=True)
class First:
    a: int


@dataclass(frozen=True)
class Second(First):
    @property
    def b(self):
        return self.a

class My(BaseModel):
    my: Second

Python, Pydantic & OS Version

pydantic version: 1.10.2
            pydantic compiled: True
                 install path: /usr/local/lib/python3.7/site-packages/pydantic
               python version: 3.7.7 (default, Oct 21 2021, 12:06:26)  [GCC 4.8.5 20150623 (Red Hat 4.8.5-44.0.3)]
                     platform: Linux-5.19.4-1-MANJARO-x86_64-with-redhat-7.9-Maipo
     optional deps. installed: ['dotenv', 'typing-extensions']

Affected Components

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 4
  • Comments: 17 (15 by maintainers)

Most upvoted comments

this is not a reason?

In my opinion yanking is only for mistaken releases (immediately), malicious releases (if someone got your access keys), or very serious security threats e.g. SQL injection or remote code execution.

Yanking a release would break many peoples builds who have pinned to that version, it’s reserved for the most serious scenarios.

Also, V1.10.2 contains a number of fixes including partial mitigation of a dos risk, so I’m even less willing to yank it.

Removing _extra_dc_args(_cls) == _extra_dc_args(_cls.__bases__[0]) fixes the issue, but fails on this test with an error DataclassProxy.__init__() takes 2 positional argument but 4 were given.

This is caused by wrapping dataclass with DataclassProxy, which should perform validation over a dataclass, but bypass all the attributes access and method calls to the dataclass. Wrapping this proxy with another @pydantic.dataclasses.dataclass causes calling the wrong method, and test is failing.

I’ve tried to replace this proxy object just dataclass itsel with more complex logic in wrappers for __init__ and __post_init__ methods, but other tests were failing, in particular this one and some others, which are checking that builtin dataclass is not changed by adding a decorator over it.

So I stuck with this lump of magic and wrappers over wrappers inside pydantic’s dataclass decorator

I see here 2 options:

  1. Revert https://github.com/pydantic/pydantic/pull/4484. That is not good because this PR resolved other issue which affects other users
  2. Create PR which will solve current issue, and will not affect solution of https://github.com/pydantic/pydantic/issues/4477. But I’m not aware of pydantic code base, and this could take a lot of time, which is incompatible with urgent status. That’s why I asked about yanking release.