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

How to create a schema that has no #516

Closed
sivabudh opened this Issue Aug 23, 2016 · 8 comments

Comments

Projects
None yet
6 participants
@sivabudh

sivabudh commented Aug 23, 2016

Given the following schema:

class CalendarSchema(Schema):
    days_of_month = fields.List(fields.Integer(), default=[], validate=validate.ContainsOnly(range(1, 31 + 1)))

The above schema works fine as long as the array passed contains the value between [1, 31]. However, if the array was an empty array ([]), the validation fails. How can I tweak fields.List such that it accepts an empty array?

@maximkulkin

This comment has been minimized.

Contributor

maximkulkin commented Aug 23, 2016

Looks like it's a bug in ContainsOnly validator which I guess treats None values and empty arrays the same (see these lines ). Also, I just found out that this validator is a bit tricky, because values can not be mentioned twice (which is not obvious from docstring).

@maximkulkin

This comment has been minimized.

Contributor

maximkulkin commented Aug 23, 2016

Solution for you would be either to write your own custom validator or to wait till bug in ContainsOnly is fixed.

class CalendarSchema(Schema):
    days_of_month = fields.List(fields.Integer(), default=[])

    @validates('days_of_month')
    def validate_days_of_month(self, data):
        for item in data:
            if item not in range(1, 31 + 1):
                raise ValidationError('Contains invalid value %s' % item)
@alexpantyukhin

This comment has been minimized.

alexpantyukhin commented Aug 31, 2016

It seems that not allow empty values is put-up behavior. See test:
https://github.com/marshmallow-code/marshmallow/blob/dev/tests/test_validate.py#L607-L608

@YuriHeupa

This comment has been minimized.

Contributor

YuriHeupa commented Nov 16, 2016

Would be nice to have ContainsOnly accepting a param like allow_empty to make empty lists allowed

@sloria sloria added the needs review label Mar 18, 2017

@sloria

This comment has been minimized.

Member

sloria commented Mar 18, 2017

I'm going to hold off on moving forward with this. You can use a custom validator if you want to accept empty collections as valid input.

from marshmallow import validate, Schema, fields
from marshmallow.utils import is_iterable_but_not_string


class LenientContainsOnly(validate.ContainsOnly):

    def __call__(self, value):
        if is_iterable_but_not_string(value) and not len(value):
            return True
        return super().__call__(value)

class MySchema(Schema):
    foo = fields.List(fields.Int(), validate=[LenientContainsOnly([1, 2])])

    class Meta:
        strict = True

sch = MySchema()
assert sch.load({'foo': []}).data == {'foo': []}

@sloria sloria closed this Mar 18, 2017

@lafrech

This comment has been minimized.

Member

lafrech commented Mar 18, 2017

As pointed out by @maximkulkin

validate.ContainsOnly([1, 2, 3])([1, 2, 3, 3])

raises ValidationError.

It seems intended (explicit del choices[index] in the code) but is not explicit in the docs, and in fact, I don't get the rationale.

The docs says

succeeds if value is a sequence and each element in the sequence is also in the sequence passed as choices

@sloria

This comment has been minimized.

Member

sloria commented Mar 18, 2017

Good point, @lafrech and @maximkulkin . That specific behavior seems incorrect; I'll open a new issue.

@sloria

This comment has been minimized.

Member

sloria commented Mar 19, 2017

After giving this some thought, I think ContainsOnly should accept empty values as valid inputs. Validating against empty vs. non-empty is outside the responsibility of ContainsOnly. If you need to validate that input is non-empty, use Length(min=1).

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

ContainsOnly accepts empty values
Length(min=1) should be used to disallow empty values

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