Repository navigation
copy fails on collections.OrderedDict dataclass with required args #105736
Copy link
Copy link
Open
Labels
3.11only security fixesonly security fixes3.12only security fixesonly security fixes3.13only security fixesonly security fixesstdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytopic-dataclassestype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
Description
Bug report
Related: huggingface/transformers#8978
import collections
import copy
import dataclasses
@dataclasses.dataclass
class ModelOutputDictBase(dict):
a: int
b: int = 2
# works
copy.deepcopy(
ModelOutputDictBase(
a=1,
b=2,
)
)
@dataclasses.dataclass
class ModelOutputAllDefaults(collections.OrderedDict):
a: int = 1
b: int = 2
# works
copy.deepcopy(
ModelOutputAllDefaults(
a=1,
b=2,
)
)
@dataclasses.dataclass
class ModelOutput(collections.OrderedDict):
a: int
b: int = 2
# fails
copy.deepcopy(
ModelOutput(
a=1,
b=2,
)
)---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[4], line 39
35 a: int
36 b: int = 2
---> 39 copy.deepcopy(
40 ModelOutput(
41 a=1,
42 b=2,
43 )
44 )
File [...lib/python3.8/copy.py:172), in deepcopy(x, memo, _nil)
170 y = x
171 else:
--> 172 y = _reconstruct(x, memo, *rv)
174 # If is its own copy, don't memoize.
175 if y is not x:
File [.../lib/python3.8/copy.py:264), in _reconstruct(x, memo, func, args, state, listiter, dictiter, deepcopy)
262 if deep and args:
263 args = (deepcopy(arg, memo) for arg in args)
--> 264 y = func(*args)
265 if deep:
266 memo[id(x)] = y
TypeError: __init__() missing 1 required positional argument: 'a'Your environment
- CPython versions tested on: Python 3.8.16 (default, Jan 17 2023, 23:13:24) [GCC 11.2.0] :: Anaconda, Inc. on linux
- Operating system and architecture: Ubuntu 20.04.6 LTS x86_64
Linked PRs
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
3.11only security fixesonly security fixes3.12only security fixesonly security fixes3.13only security fixesonly security fixesstdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytopic-dataclassestype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
Activity
eendebakpt commentedon Jun 14, 2023
@ringohoffman I can confirm the
deepcopy(orcopy.copy) fails on python 3.11 with the example above. What is the reason for mixing thedataclassdecorator and thedictorOrderedDictsubclassing?For the
OrderedDictsubclassing the__reduce__on theModelOutputbecomes<method '__reduce__' of 'collections.OrderedDict' objects>which is not handling the copy of the dataclass correctly (in combination with thecopy._reconstruct). I do not know whether this combination is supposed to workringohoffman commentedon Jun 14, 2023
transformersuses this pattern as part of theirModelOutputbase class so you can access elements both by attribute and by item: https://github.com/huggingface/transformers/blob/0c3fdccf2f271fb7c44f6ea6e9f4ee234795f2c5/src/transformers/utils/generic.py#L315-L332dictand its subclasses have special handling bytorchin terms of how it handles splitting tensors that are nested elements ofdictacross threads and processes: https://github.com/pytorch/pytorch/blob/d0ff640ec865dd8c2898b59f1dab689992ed4621/torch/nn/parallel/scatter_gather.py#L50-L51sobolevn commentedon Jun 20, 2023
CC @rhettinger
rhettinger commentedon Jul 9, 2023
Here's a smaller reproducer:
rhettinger commentedon Jul 10, 2023
For copying to work in this case, the
__reduce__method must return a callable that creates an instance but does not run the class's__init__method since we can't know its signature in advance.Also, even before copying, the example class isn't functional for the pure python
OrderedDictimplementation because it overrides__init__which is needed to set up the underlying data structures. That setup work needs to be moved from__init__to__new__.rhettinger commentedon Jul 11, 2023
@ericsnowcurrently Eric, do you have any thoughts on how we can (and/or whether we should) modify
OrderedDict.__reduce__(in both the Python and C versions) to survive a subclass that overrides__init__, doesn't call the parent__init__, and that has some required arguments?ericsnowcurrently commentedon Jul 25, 2023
I don't have much stake in this, but that situation certainly gives me pause. We're already dealing with a dict subclass, which makes things dicey. Furthermore, subclassing is necessarily cooperative, particularly when
__init__()is involved. I'd hesitate to accommodate subclasses that don't cooperate. (FWIW, I would have expected dataclasses to do the right thing in the original post. Maybe it can't and the use must supply the proper__init__()?)pythongh-105736: Sync pure python version of OrderedDict with the C v…
gh-105736: Sync pure python version of OrderedDict with the C version (…
pythongh-105736: Sync pure python version of OrderedDict with the C v…
[3.11] gh-105736: Sync pure python version of OrderedDict with the C …
[3.12] gh-105736: Sync pure python version of OrderedDict with the C …
hugovk commentedon Nov 10, 2023
Is there anything left to do here, or can we close this issue?
ZeroIntensity commentedon Jan 11, 2025
The downstream issue (huggingface/transformers#8978) is closed, but the reproducer still fails on main. I think there's still more to do.