1

I am using dataclasses + dataclasses_json to implement my web api.

My application will decode the request from dict to object, I hope that the object can still be generated without every field is fill, and fill the empty filed with default value.

This is my likely code:

from dataclasses import dataclass
from dataclasses_json import dataclass_json

@dataclass
class Glasses:
    color: str
    size: str
    prize: int

@dataclass
class Tshirt:
    color: str
    size: str
    prize: int

@dataclass_json
@dataclass
class People:
    Name : str = 'James'
    Age : int = 25
    Glasses: Glasses = Glasses('black', 'M', 2500)
    Tshirt: Tshirt = Tshirt('black', 'XL', 500)

p = {
    'Name': 'Gino',
    'Age': 20,
    'Glasses': {
        'color' : 'red',
        'size' : 'M',
        'prize' : 4000
    },
    'Tshirt': {
        'color' : 'red',
        'size' : 'M',
        'prize' : 4000
    }
}

a = People.from_dict(p)
print(a)

and I will get the error

Traceback (most recent call last):
  File ".\People.py", line 39, in <module>
    a = People.from_dict(p)
  File "C:\Python3.7\lib\site-packages\dataclasses_json\api.py", line 83, in from_dict
    return _decode_dataclass(cls, kvs, infer_missing)
  File "C:\Python3.7\lib\site-packages\dataclasses_json\core.py", line 133, in _decode_dataclass
    overrides = _user_overrides_or_exts(cls)
  File "C:\Python3.7\lib\site-packages\dataclasses_json\core.py", line 59, in _user_overrides_or_exts
    if field.type in encoders:
TypeError: unhashable type: 'Glasses'

I found that I can add (eq=True, frozen=True) So I change my code to

from dataclasses import dataclass
from dataclasses_json import dataclass_json

@dataclass(eq=True, frozen=True)
class Glasses:
    color: str
    size: str
    prize: int

@dataclass(eq=True, frozen=True)
class Tshirt:
    color: str
    size: str
    prize: int

@dataclass_json
@dataclass
class People:
    Name : str = 'James'
    Age : int = 25
    Glasses: Glasses = Glasses('black', 'M', 2500)
    Tshirt: Tshirt = Tshirt('black', 'XL', 500)

p = {
    'Name': 'Gino',
    'Age': 20,
    'Glasses': {
        'color' : 'red',
        'size' : 'M',
        'prize' : 4000
    },
    'Tshirt': {
        'color' : 'red',
        'size' : 'M',
        'prize' : 4000
    }
}

a = People.from_dict(p)
print(a)

And I got the other error

  File ".\People.py", line 39, in <module>
    a = People.from_dict(p)
  File "C:\Python3.7\lib\site-packages\dataclasses_json\api.py", line 83, in from_dict
    return _decode_dataclass(cls, kvs, infer_missing)
  File "C:\Python3.7\lib\site-packages\dataclasses_json\core.py", line 198, in _decode_dataclass
    infer_missing)
  File "C:\Python3.7\lib\site-packages\dataclasses_json\core.py", line 131, in _decode_dataclass
    if isinstance(kvs, cls):
TypeError: isinstance() arg 2 must be a type or tuple of types

Is there any possible way to fit my requirement using built-in functions without coding it myself?

1 Answer 1

1

You have field name and type name collision. In order for your code to work you must have JSON fields named differently from classes names, i.e. you can't have field "Glasses" and class Glasses, you must rename class to something like Glasses_ or rename your fields names.

Another option is to create alias for classes types, i.e. create alias GlassesT to Glasses.

Version of code with type aliases:

Try it online!

from dataclasses import dataclass
from dataclasses_json import dataclass_json

@dataclass
class Glasses:
    color: str
    size: str
    prize: int

GlassesT = Glasses

@dataclass
class Tshirt:
    color: str
    size: str
    prize: int
    
TshirtT = Tshirt
    
@dataclass_json
@dataclass
class People:
    Name : str = 'James'
    Age : int = 25
    Glasses: GlassesT = GlassesT('black', 'M', 2500)
    Tshirt: TshirtT = TshirtT('black', 'XL', 500)

p = {
    'Name': 'Gino',
    'Age': 20,
    'Glasses': {
        'color' : 'red',
        'size' : 'M',
        'prize' : 4000
    },
    'Tshirt': {
        'color' : 'red',
        'size' : 'M',
        'prize' : 4000
    }
}

a = People.from_dict(p)
print(a)

Output:

People(Name='Gino', Age=20, Glasses=Glasses(color='red', size='M', prize=4000), Tshirt=Tshirt(color='red', size='M', prize=4000))

Version of code with renamed classes:

Try it online!

from dataclasses import dataclass
from dataclasses_json import dataclass_json

@dataclass
class Glasses_:
    color: str
    size: str
    prize: int

@dataclass
class Tshirt_:
    color: str
    size: str
    prize: int

@dataclass_json
@dataclass
class People:
    Name : str = 'James'
    Age : int = 25
    Glasses: Glasses_ = Glasses_('black', 'M', 2500)
    Tshirt: Tshirt_ = Tshirt_('black', 'XL', 500)

p = {
    'Name': 'Gino',
    'Age': 20,
    'Glasses': {
        'color' : 'red',
        'size' : 'M',
        'prize' : 4000
    },
    'Tshirt': {
        'color' : 'red',
        'size' : 'M',
        'prize' : 4000
    }
}

a = People.from_dict(p)
print(a)

Output:

People(Name='Gino', Age=20, Glasses=Glasses_(color='red', size='M', prize=4000), Tshirt=Tshirt_(color='red', size='M', prize=4000))
Sign up to request clarification or add additional context in comments.

1 Comment

Oh, this is awesome ! this really helps me ! thanks

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.