dataclasses
dataclasses copied to clipboard
dataclasses.astuple breaks NamedTuple attribute of dataclass instance
It seems the fix of https://bugs.python.org/issue34363 is missing in dataclasses
version 0.7
backported to python 3.6
# 3.6.8 (default, Feb 28 2019, 22:12:13)
# [GCC 8.2.1 20181127](6, 0, 1)
# dataclasses 0.7
from dataclasses import InitVar, astuple, dataclass, field
from typing import NamedTuple, Tuple
import numpy as np
class A(NamedTuple):
x: float = np.nan
y: float = np.nan
@dataclass
class B:
tuple_a: InitVar[Tuple] = None
named_tuple_a: A = field(init=False, default=A())
def __post_init__(self, tuple_a):
if tuple_a is not None:
self.named_tuple_a = A(*tuple_a)
b = B()
astuple(b)
>> (A(x=<generator object _astuple_inner.<locals>.<genexpr> at 0x7f7dec0902b0>, y=nan),)
While the same code in Python 3.7.4 gives:
# 3.7.4 (default, Oct 4 2019, 06:57:26)
# [GCC 9.2.0] (6, 0, 1)
from dataclasses import InitVar, astuple, dataclass, field
from typing import NamedTuple, Tuple
import numpy as np
class A(NamedTuple):
x: float = np.nan
y: float = np.nan
@dataclass
class B:
tuple_a: InitVar[Tuple] = None
named_tuple_a: A = field(init=False, default=A())
def __post_init__(self, tuple_a):
if tuple_a is not None:
self.named_tuple_a = A(*tuple_a)
b = B()
astuple(b)
>> (A(x=nan, y=nan),)
This is the monkey patch I am using to resolve this issue while we wait for a fix here
orig_asdict_inner = dataclasses._asdict_inner
def _asdict_inner(obj, dict_factory):
if isinstance(obj, tuple) and hasattr(obj, '_fields'):
return type(obj)(*[_asdict_inner(v, dict_factory) for v in obj])
else:
return orig_asdict_inner(obj, dict_factory)
dataclasses._asdict_inner = _asdict_inner
orig_astuple_inner = dataclasses._astuple_inner
def _astuple_inner(obj, tuple_factory):
if isinstance(obj, tuple) and hasattr(obj, '_fields'):
return type(obj)(*[_astuple_inner(v, tuple_factory) for v in obj])
else:
return orig_astuple_inner(obj, tuple_factory)
dataclasses._astuple_inner = _astuple_inner