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

OneOfSchema can't use pre/post_dump/load decorators

Open lafrech opened this issue 7 years ago • 5 comments

class MyUberSchema(OneOfSchema):
    type_schemas = {
        'foo': FooSchema,
        'bar': BarSchema,
    }

    @post_load
    def whatever(self, data):
        print("post load")

AFAIU, post_load decorated method is never called. It may be intended, or it may not be an issue, but while trying to do that it failed and I didn't see this documented so I don't know if this is known.

To get this to work, the post_load method needs to be defined in FooSchema and BarSchema (or a common parent).

lafrech avatar Oct 19 '16 15:10 lafrech

I will look into this. Meantime, you can implement everything you need in your subschemas (like FooSchema and BarSchema)

maximkulkin avatar Oct 20 '16 05:10 maximkulkin

I rechecked source code and I really do not want to dive into all crazy logic that original Schema class has related to pre/post processing, validation and collecting errors. I couldn't find an elegant way to plug into original Schema data dumping/loading pipeline, so I had to replace it's implementation completely thus loosing all pre/post processing.

If somebody wants to do pre/post processing regardless of particular payload type, I suggest 1) think twice; 2) implement processing in subtypes:

import marshmallow as m
import marshmallow.fields as mf

class FooSchema(m.Schema):
    foo = mf.String(required=True)

class BarSchema(m.Schema):
    bar = mf.Integer(required=True)

def my_schema_pre_load(schema, data):
    # pre process data on load
    return data

class MySchema(OneOfSchema):
    class MyFooSchema(FooSchema):
        pre_load = m.pre_load(my_schema_pre_load)

    class MyBarSchema(BarSchema):
        pre_load = m.pre_load(my_schema_pre_load)

    type_schemas = {
        'foo': MyFooSchema,
        'bar': MyBarSchema,
    }

maximkulkin avatar Oct 31 '16 23:10 maximkulkin

Hello,

What would you advise in case I want to do preprocessing on type field? For instance I would like to .lower() type field value (in order to be able to get the schema whatever case the type is).

Thanks in advance!

hjonin avatar Nov 16 '18 10:11 hjonin

I was just looking at this because I wanted to add a post_dump method to remove the type field. I ended up overloading _dump as in

    def _dump(self, obj, **kwargs):
        data = super()._dump(obj, **kwargs)
        data.pop("type")
        return data

I bet a similar approach would work for the above case, overriding load or _load.

I looked a bit and I think at this point in time -- with the current codebase and marshmallow3-only support -- we could add these. I probably don't have time to work on this soon, but if it sits for a while I might come back with a PR.

sirosen avatar Nov 02 '20 17:11 sirosen

I was just looking at this because I wanted to add a post_dump method to remove the type field. I ended up overloading _dump as in

    def _dump(self, obj, **kwargs):
        data = super()._dump(obj, **kwargs)
        data.pop("type")
        return data

I bet a similar approach would work for the above case, overriding load or _load.

I looked a bit and I think at this point in time -- with the current codebase and marshmallow3-only support -- we could add these. I probably don't have time to work on this soon, but if it sits for a while I might come back with a PR.

Solid workaround, thank you

@maximkulkin it would be helpful to explain in the README file that these decorators are not supported

antoine-chopin avatar Apr 26 '23 16:04 antoine-chopin