Reputation: 121608
I would like to recreate my object from a dictionary using cattr
but it looks that this does not work with nested field set to None
.
Here a code example that explains the problem:
import attr
import cattr
@attr.s(auto_attribs=True)
class B(object):
b :int = 0
@attr.s(auto_attribs=True)
class A(object):
a :int = 0
b: B = None
x = A(1)
x_dict = attr.asdict(x)
Now if Iry to structure my object using:
cattr.structure(x_dict,A)
I get the following error:
if 'b' in o:
TypeError: argument of type 'NoneType' is not iterable
One workaround is to remove None fields from the dict before call to structure :
del x_dict["b"]
cattr.structure(x_dict,A)
Do I need to do this? or there is a simpler solution
Any help is much appreciated.
Upvotes: 2
Views: 1503
Reputation: 23825
Below is a dataclass based solution
from dataclasses import dataclass
from typing import List
from dacite import from_dict
@dataclass
class Dog:
name:str
age:int
@dataclass
class Person:
name: str
dogs: List[Dog] = None
data1 = [{'name':'jack','dogs':[{'name':'bark','age':12},{'name':'jumpy','age':3}]}]
persons1: List[Person] = [from_dict(Person,entry) for entry in data1]
print(persons1)
data2 = [{'name':'jack'}]
persons2: List[Person] = [from_dict(Person,entry) for entry in data2]
print(persons2)
output
[Person(name='jack', dogs=[Dog(name='bark', age=12), Dog(name='jumpy', age=3)])]
[Person(name='jack', dogs=None)]
Upvotes: 1
Reputation: 31354
None
is not a valid B
. You should define b
to be of type Optional[B]
:
from typing import Optional
import attr
import cattr
@attr.s(auto_attribs=True)
class B(object):
b: int = 0
@attr.s(auto_attribs=True)
class A(object):
a: int = 0
b: Optional[B] = None
x = A(1)
x_dict = attr.asdict(x)
cattr.structure(x_dict, A)
Upvotes: 2