marshmallow-oneofschema icon indicating copy to clipboard operation
marshmallow-oneofschema copied to clipboard

_dump should raise errors instead of returning them

Open robbertvc opened this issue 5 years ago • 3 comments

The Error

If the default get_obj_type is used (i.e. when the subclass does not overwrite the get_obj_type method), then the dumping of the schema does not raise an error when encountering an unknown type. Instead, the error gets dumped into the serialization outputs.

It looks like _dump returns an error tuple on unexpected behaviour:

https://github.com/marshmallow-code/marshmallow-oneofschema/blob/master/marshmallow_oneofschema/one_of_schema.py#L99

... but dump expects Exceptions to be thrown: https://github.com/marshmallow-code/marshmallow-oneofschema/blob/master/marshmallow_oneofschema/one_of_schema.py#L77

Minimal example

# minimal_example.py

import marshmallow
import marshmallow.fields
from marshmallow_oneofschema import OneOfSchema


class Foo(object):
    def __init__(self, foo):
        self.foo = foo


class Bar(object):
    def __init__(self, bar):
        self.bar = bar


class FooSchema(marshmallow.Schema):
    foo = marshmallow.fields.String(required=True)

    @marshmallow.post_load
    def make_foo(self, data):
        return Foo(**data)


class BarSchema(marshmallow.Schema):
    bar = marshmallow.fields.Integer(required=True)

    @marshmallow.post_load
    def make_bar(self, data):
        return Bar(**data)


class MyUberSchema(OneOfSchema):
    type_schemas = {
        'Foo': FooSchema
    }


if __name__ == '__main__':
    serialized = MyUberSchema().dump([
                    Foo(foo='hello'),
                    Bar(bar=123)],
                    many=True)

    print(serialized)
~$ pip freeze | grep marshmallow
marshmallow==3.0.0b19
marshmallow-oneofschema==2.0.0b2

~$ python --version
Python 3.6.7 :: Anaconda, Inc.

~$ python minimal_example.py 
[{'foo': 'hello', 'type': 'Foo'}, (None, {'_schema': 'Unsupported object type: Bar'})]

robbertvc avatar Jan 08 '19 14:01 robbertvc

Feels like code written for marshmallow 2...

ThiefMaster avatar Apr 29 '21 18:04 ThiefMaster

If everything is fine, dump returns an ordered dict of the object, e.g. {"hello": "world"}. If handling object type fails, it returns (None, {"_schema": "Unsupported object type: something"}). How are we supposed to handle this? Why not just always raise ValidationError?

kamzil avatar Feb 09 '24 14:02 kamzil

I added a workaround for this to my subclass of OneOfSchema but it's very ugly:

class MySchema(OneOfSchema):
    def _dump(self, obj, *, update_fields=True, **kwargs):
        res = super()._dump(obj, update_fields=update_fields, **kwargs)
        if isinstance(res, tuple) and len(res) == 2 and res[0] is None and isinstance(res[1], dict):
            error_dict = res[1]
            field_name, message = list(error_dict.items())[0]
            raise ValidationError(message=message, field_name=field_name)
        return res

Any suggestions to make it better?

kamzil avatar Feb 09 '24 14:02 kamzil