marshmallow_dataclass icon indicating copy to clipboard operation
marshmallow_dataclass copied to clipboard

`unknown` does't take effect when nested

Open qin-nz opened this issue 6 years ago • 2 comments

main code:

from dataclasses import dataclass, field
from typing import List, Optional

import marshmallow
import marshmallow_dataclass


@dataclass
class Building:
    # field metadata is used to instantiate the marshmallow field
    height: float = field(metadata={"validate": marshmallow.validate.Range(min=0)})
    name: str = field(default="anonymous")


@dataclass
class City:
    name: Optional[str]
    buildings: List[Building] = field(default_factory=list)


CitySchema = marshmallow_dataclass.class_schema(City)

city = CitySchema().load(
    {"name": "Paris", "aaa": "bbb", "buildings": [{"name": "Eiffel Tower", "height": 324, "ccc": "ddd"}]},
    unknown=marshmallow.EXCLUDE
)

print(city)

If I use {"name": "Paris", "aaa": "bbb", "buildings": [{"name": "Eiffel Tower", "height": 324}]}, unknown works well.

errer:

Traceback (most recent call last):
  File "clos/Untitled-2.py", line 25, in <module>
    unknown=marshmallow.EXCLUDE
  File "/home/hudingyuan/.local/lib/python3.6/site-packages/marshmallow/schema.py", line 714, in load
    data, many=many, partial=partial, unknown=unknown, postprocess=True
  File "/home/hudingyuan/.local/lib/python3.6/site-packages/marshmallow/schema.py", line 892, in _do_load
    raise exc
marshmallow.exceptions.ValidationError: {'buildings': {0: {'ccc': ['Unknown field.']}}}

qin-nz avatar Oct 21 '19 05:10 qin-nz

@sloria Do you know why that it ?

lovasoa avatar Oct 29 '19 09:10 lovasoa

It seems there is a WIP feature to overcome this issue: https://github.com/marshmallow-code/marshmallow/pull/1634.

Currently i found solution overriding base schema during loading:

from dataclasses import dataclass
import marshmallow
from marshmallow_dataclass import class_schema


@dataclass
class A:
    name: str
   
  
@dataclass    
class B:
    nested: A
    surname: str
 

class BaseSchema(marshmallow.Schema):
    class Meta:
        unknown = marshmallow.EXCLUDE
 

B_schema = class_schema(B, base_schema=BaseSchema)
loaded = B_schema().load(
    {
        "surname": "Smith", 
        "top_level_unknown": "value", 
        "nested": {
            "name": "John", 
            "low_level_unknown": "value"
        }
    }
)
print(loaded)  # B(nested=A(name='John'), surname='Smith')

SlonSky avatar Jul 23 '20 16:07 SlonSky