marshmallow icon indicating copy to clipboard operation
marshmallow copied to clipboard

Doubly Nested Schemas instantiated via lambdas cannot be referenced with multiple dot notation with onlys/excludes

Open somethingnew2-0 opened this issue 2 years ago • 3 comments

Related to https://github.com/marshmallow-code/marshmallow/pull/2164

The following works as intended

from marshmallow import Schema, fields

class ASchema(Schema):
    a = fields.String()
    a2 = fields.String()

class BSchema(Schema):
    b = fields.Nested(lambda: ASchema)

class CSchema(Schema):
    c = fields.Nested(lambda: BSchema)

class DSchema(Schema):
    d = fields.Nested(lambda: CSchema, only=("c.b.a2",))

class A:
    def __init__(self):
        self.a = 'Hello from a'
        self.a2 = 'Hello from a2'

class B:
    def __init__(self, a):
        self.b = a

class C:
    def __init__(self, b):
        self.c = b

class D:
    def __init__(self, c):
        self.d = c

print(DSchema().dump(D(C(B(A())))))

Outputting

{'d': {'c': {'b': {'a2': 'Hello from a2'}}}}

However when changing the CSchema nested field c lambda to return an instantiated BSchema(), the output is different and incorrect

class CSchema(Schema):
    c = fields.Nested(lambda: BSchema())

Outputs

{'d': {'c': {}}}

I've narrowed this issue down to https://github.com/marshmallow-code/marshmallow/blob/dev/src/marshmallow/fields.py#L601 where the self.only values in the instantiated BSchema() will be "b.a2" whereas original = self._schema.fields.keys() will be the top-level parent "b". This results in an empty set intersection meaning the serialized value will have no fields.

somethingnew2-0 avatar Aug 11 '23 01:08 somethingnew2-0

Thanks for the research and the comprehensive bug report.

A fix proposal would be very welcome, anyone.

lafrech avatar Aug 11 '23 20:08 lafrech