classification
Title: dataclasses.asdict breaks with defaultdict fields
Type: Stage: patch review
Components: Library (Lib) Versions: Python 3.7
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: eric.smith Nosy List: eric.smith, levkivskyi, remi.lapeyre, wrmsr
Priority: normal Keywords: patch, patch, patch

Created on 2018-12-19 22:06 by wrmsr, last changed 2018-12-30 01:25 by remi.lapeyre.

Pull Requests
URL Status Linked Edit
PR 11361 open remi.lapeyre, 2018-12-30 00:55
PR 11361 open remi.lapeyre, 2018-12-30 00:55
PR 11361 open remi.lapeyre, 2018-12-30 00:55
Messages (2)
msg332166 - (view) Author: Will T (wrmsr) Date: 2018-12-19 22:06
_asdict_inner attempts to manually recursively deepcopy dicts by calling type(obj) with a generator of transformed keyvalue tuples @ https://github.com/python/cpython/blob/b2f642ccd2f65d2f3bf77bbaa103dd2bc2733734/Lib/dataclasses.py#L1080 . defaultdicts are dicts so this runs but unlike other dicts their first arg has to be a callable or None:

    import collections
    import dataclasses as dc

    @dc.dataclass()
    class C:
        d: dict

    c = C(collections.defaultdict(lambda: 3, {}))
    d = dc.asdict(c)

    assert isinstance(d['d'], collections.defaultdict)
    assert d['d']['a'] == 3

=>

    Traceback (most recent call last):
      File "boom.py", line 9, in <module>
        d = dc.asdict(c)
      File "/Users/spinlock/.pyenv/versions/3.7.1/lib/python3.7/dataclasses.py", line 1019, in asdict
        return _asdict_inner(obj, dict_factory)
      File "/Users/spinlock/.pyenv/versions/3.7.1/lib/python3.7/dataclasses.py", line 1026, in _asdict_inner
        value = _asdict_inner(getattr(obj, f.name), dict_factory)
      File "/Users/spinlock/.pyenv/versions/3.7.1/lib/python3.7/dataclasses.py", line 1058, in _asdict_inner
        for k, v in obj.items())
    TypeError: first argument must be callable or None

I understand that it isn't this bit of code's job to support every dict (and list etc.) subclass under the sun but given defaultdict is stdlib it's imo worth supporting explicitly.
msg332741 - (view) Author: Rémi Lapeyre (remi.lapeyre) * Date: 2018-12-30 01:25
Hi @wrmsr, this happens because the constructor for `collections.defaultdict` differs from the one of `dict`.

I think the argument that collections.defaultdict is in the stdlib and should be supported is right, the changes in PR #11361 should do what you want.
History
Date User Action Args
2018-12-30 01:25:41remi.lapeyresetnosy: + remi.lapeyre
messages: + msg332741
2018-12-30 00:55:46remi.lapeyresetkeywords: + patch
stage: patch review
pull_requests: + pull_request10684
2018-12-30 00:55:38remi.lapeyresetkeywords: + patch
stage: (no value)
pull_requests: + pull_request10683
2018-12-30 00:55:30remi.lapeyresetkeywords: + patch
stage: (no value)
pull_requests: + pull_request10682
2018-12-21 17:56:37levkivskyisetnosy: + levkivskyi
2018-12-19 22:32:30eric.smithsetassignee: eric.smith

nosy: + eric.smith
2018-12-19 22:06:44wrmsrcreate