Higi M.
Higi M.

Reputation: 65

How to deserialize json with optional fields using attrs and cattrs

I want to deserialize MongoDB documents using attr and cattrs. Since noSQL has no fixed schema, I need to point somehow to the attr.ib-s that they could be missed, and not add them to the dict's object in this case.

I used colander before to do this kind of things and it provides a 'missing' parameter in colander.SchemaNode constructor that do exactly this by passing 'colander.drop' as an argument. I'm wondering how to do the same with these libraries, I didn't find anything in the documentation. So:

import attr
from cattr import structure

@attr.s
class ABC:
    A: float = attr.ib()
    B: float = attr.ib()
    C: float = attr.ib()

d = {'A': 1, 'B': 2}
obj = structure(d, ABC)

Should return an object with only A and B attributes. I've been trying with some parameters (init, default...) and even with Optional class from typing lib, but all of the methods I tried returned the attribute in some way.

Thanks for your help.

Upvotes: 0

Views: 3597

Answers (1)

Tin Tvrtković
Tin Tvrtković

Reputation: 701

(I'm the author of cattrs and a core contributor to attrs.)

Hello,

an attrs Python class will, by definition, have all of its fields in the instance __dict__. When you say the structuring "should return an object with only A and B attributes", I'm assuming you want the instance returned to throw AttributeError when you try accessing obj.C.

To my knowledge this isn't possible with attrs, and neither is it in the spirit of attrs. You've defined your class to have three attributes, so it should have values in those attributes.

What you can do is use None as a value marker for a missing value; this is the usual way of representing missing values in Python generally. The code snippet becomes:

from typing import Optional

import attr
from cattr import structure

@attr.s
class ABC:
    A: float = attr.ib()
    B: float = attr.ib()
    C: Optional[float] = attr.ib(default=None)

d = {'A': 1, 'B': 2}
obj = structure(d, ABC)

You wouldn't want code that expects an instance of ABC to have to deal with mysteriously missing attributes, right?

Upvotes: 8

Related Questions