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
- Compatibility between releases
- Data validation/parsing
- Data serialization -
.dict()and.json() - JSON Schema
- Dataclasses
- Model Config
- Field Types - adding or changing a particular data type
- Function validation decorator
- Generic Models
- Other Model behaviour -
construct(), pickling, private attributes, ORM mode - Settings Management
- Plugins and integration with other tools - mypy, FastAPI, python-devtools, Hypothesis, VS Code, PyCharm, etc.
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Reactions: 4
- Comments: 17 (15 by maintainers)
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 errorDataclassProxy.__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.dataclasscauses 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: