Instantiate attrs class from dict with superfluous key/value pairs

226 Views Asked by At

I decorated a class using attrs.define and added all important attributes/fields.

import attrs

@attrs.define
class MyAttrsClass:
    important1 = attrs.field(type = int)
    important2 = attrs.field(type = str)
    [...]

Now I would like to initialize instances of that class from a dict. So what I do is calling the contructor with a dict-unpacking.

test_dict = {'important1': 100, 'important2': 'foo'}
ci = MyAttrsClass(**test_dict)

This works in that simple example case, because I specify the same fields in the dict as well as in the MyAttrsClass class.

However, in the real scenario the dict is a deserialized response from a web-api (using json.loads) and it returns many key-value-pairs I'm not interested in, despite the important ones. Then, I get the following error TypeError: MyAttrsClass.__init__() got an unexpected keyword argument 'XYZ'.

Is is possible to initialize an instance of MyAttrsClass, though? I would like to discard the superfluous elements. Do I need to manually remove entries from the input dict or is there a better way using attrs.

2

There are 2 best solutions below

0
user2390182 On

You can use the documented attrs.fields function:

big_dic = {"important1": 3, "important2": "abc", "spuriouskey": "dontcare"}
fields = {a.name for a in attrs.fields(MyAttrsClass)}
init_kwargs = {k: v for k, v in big_dic.items() if k in fields}

MyAttrsClass(**init_kwargs)
# MyAttrsClass(important1=3, important2='abc')
2
Tin Tvrtković On

I'm an attrs maintainer and the author of cattrs. You should probably just use cattrs since it was designed for cases like this.

from cattrs import structure

structure(big_dict, MyAttrsClass)

Otherwise, you'll have to do a little preprocessing yourself, as others have mentioned.