New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Load Nested field with only=str gives error when sent flat data structure instead of dictionary #307

Closed
erlingbo opened this Issue Oct 23, 2015 · 7 comments

Comments

Projects
None yet
3 participants
@erlingbo
Contributor

erlingbo commented Oct 23, 2015

When using a schema with the only attribute set to a string, the load method returns UnmarshalResult without errors nor data.

class MySchema(Schema):
    class Meta:
        fields = ('pk',)

    pk = fields.String()

MySchema(only='pk').load('an_id1234')
MySchema(only='pk').load({'pk': 'an_id1234'})

Both return the same UnmarshalResult
UnmarshalResult(data={}, errors={})

Preferably the first should work, but the second could be used with a pre load method on the schema class.

Is there anything I have done wrong or is this a bug?

Note: I use the same schema for dumping data an thus use only='pk' and not only=('pk',) for getting the correct dump output

@franciscod

This comment has been minimized.

Contributor

franciscod commented Oct 23, 2015

Since 'pk' may be interpreted as ('p', 'k'), you should use ('pk',), right?

When using only=('pk',) it gives a more interesting result:

>>> MySchema(only=('pk',)).load('an_id1234')
UnmarshalResult(data={}, errors={'_schema': ['Invalid input type.']})
>>> MySchema(only=('pk',)).load({'pk': 'an_id1234'})
UnmarshalResult(data={'pk': 'an_id1234'}, errors={})

https://marshmallow.readthedocs.org/en/latest/api_reference.html#schema
The only attribute expects a tuple or a list, if you give it a string it will interpret it as an iterable of chars:

>>> class CharSchema(Schema):
...     class Meta:
...             fields = ('a', 'b', 'c', 'd')
...     a = fields.String()
...     b = fields.String()
...     c = fields.String()
...     d = fields.String()
... 
>>> CharSchema(only='ab').load({'a': 'asd', 'b': 'qwe'})
UnmarshalResult(data={'b': 'qwe', 'a': 'asd'}, errors={})
@erlingbo

This comment has been minimized.

Contributor

erlingbo commented Oct 27, 2015

My bad. I went to far when I tried to dumb down my problem.

The real scenario is like this:

        class MyNestedSchema(Schema):
        class Meta:
            fields = ('pk',)

        pk = fields.String()

    class MySchema(Schema):
        class Meta:
            fields = ('pk', 'child')
        child = fields.Nested(MyNestedSchema, only='pk')

    class Obj(object):
        def __init__(self, pk, child):
            self.pk = pk
            self.child = child

    result = MySchema().dump(Obj(123, Obj(456, None)))
    print result
    print MySchema().load(result.data)
    print MySchema().load({'pk': 'an_id1234', 'child': 'child123'})
    print MySchema().load({'pk': 'an_id1234', 'child': {'pk': 'child123'}})

I use nested fields with only parameter as described in the docs.

This gives me the following results:

MarshalResult(data={'pk': 123, 'child': u'456'}, errors={})
UnmarshalResult(data={'pk': 123}, errors={'child': {u'_schema': [u'Invalid input type.']}})
UnmarshalResult(data={'pk': 'an_id1234'}, errors={'child': {u'_schema': [u'Invalid input type.']}})
UnmarshalResult(data={'pk': 'an_id1234', 'child': {'pk': u'child123'}}, errors={})

Shouldn't the Nested field be able to handle this?

@erlingbo erlingbo changed the title from Load schema with only=str gives empty UnmarshalResult to Load Nested field with only=str gives error when sent flat data structure instead of dictionary Oct 27, 2015

@franciscod

This comment has been minimized.

Contributor

franciscod commented Oct 27, 2015

    class MySchema(Schema):
        class Meta:
            fields = ('pk', 'child')
        child = fields.Nested(MyNestedSchema, only='pk')

Have you tried using

only=('pk',)

as opposed to

only='pk'

?

@erlingbo

This comment has been minimized.

Contributor

erlingbo commented Oct 28, 2015

Yes, that gives me a dump with a dictionary instead of a flat object, as expected

{'pk': '456'}
'456'
@franciscod

This comment has been minimized.

Contributor

franciscod commented Oct 29, 2015

I don't get what's the issue 😞

@erlingbo

This comment has been minimized.

Contributor

erlingbo commented Oct 29, 2015

Okei. I'll try to explain. I'll want a dump that gives me a file (json or yaml) and then be able to load the file again later.

I want the relations to be flat, just using the primary key of the object it links to. This feature is documented here as only='pk'

When I try to load the file using the same schema I get an error UnmarshalResult(data={'pk': 123}, errors={'child': {u'_schema': [u'Invalid input type.']}})

If I use only=('pk',) the dumped relations will not be flat and include an object with the pk as attribute. E.g. {'pk': 123, 'child': {'pk': u'456'}} vs what I want: ``{'pk': 123, 'child': u'456'}`

I need to integrate with other teams, and the files need to be as human readable as possible, thus I want the flat structure. When this is a documented feature of the Nested field, I also expect it to be able to load the corresponding data.

@sloria

This comment has been minimized.

Member

sloria commented Jan 8, 2017

This is the same issue addressed in #316. Further discussion should happen there.

@sloria sloria closed this Jan 8, 2017

sloria added a commit that referenced this issue Mar 4, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment