Skip to content

Commit 0558af4

Browse files
authored
Dataclass deepcopy 1.10 (#4963)
* add test to reproduce #4949 * fix infinitely recursive deepcopy * add test for shallow copy of wrapped dataclass * fix infinitely recursive copy of wrapped dataclass --------- Co-authored-by: Martin Billinger-Finke <[email protected]>
1 parent a699707 commit 0558af4

File tree

3 files changed

+31
-0
lines changed

3 files changed

+31
-0
lines changed

changes/4949-mbillingr.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix `RecursionError` when deep-copying dataclass types wrapped by pydantic.

pydantic/dataclasses.py

+7
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class M:
3131
The trick is to create a wrapper around `M` that will act as a proxy to trigger
3232
validation without altering default `M` behaviour.
3333
"""
34+
import copy
3435
import sys
3536
from contextlib import contextmanager
3637
from functools import wraps
@@ -260,6 +261,12 @@ def __setattr__(self, __name: str, __value: Any) -> None:
260261
def __instancecheck__(self, instance: Any) -> bool:
261262
return isinstance(instance, self.__dataclass__)
262263

264+
def __copy__(self) -> 'DataclassProxy':
265+
return DataclassProxy(copy.copy(self.__dataclass__))
266+
267+
def __deepcopy__(self, memo: Any) -> 'DataclassProxy':
268+
return DataclassProxy(copy.deepcopy(self.__dataclass__, memo))
269+
263270

264271
def _add_pydantic_validation_attributes( # noqa: C901 (ignore complexity)
265272
dc_cls: Type['Dataclass'],

tests/test_dataclasses.py

+23
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import copy
12
import dataclasses
23
import pickle
34
import re
@@ -1608,3 +1609,25 @@ def check_b(cls, v):
16081609
assert m1.a == m2.a == 3
16091610
assert m1.b == m2.b == 'b'
16101611
assert m1.c == m2.c == 3.0
1612+
1613+
1614+
def test_can_copy_wrapped_dataclass_type():
1615+
@pydantic.dataclasses.dataclass
1616+
@dataclasses.dataclass
1617+
class A:
1618+
name: int
1619+
1620+
B = copy.copy(A)
1621+
assert B is not A
1622+
assert B(1) == A(1)
1623+
1624+
1625+
def test_can_deepcopy_wrapped_dataclass_type():
1626+
@pydantic.dataclasses.dataclass
1627+
@dataclasses.dataclass
1628+
class A:
1629+
name: int
1630+
1631+
B = copy.deepcopy(A)
1632+
assert B is not A
1633+
assert B(1) == A(1)

0 commit comments

Comments
 (0)