Example #1
0
    def test_instance_in_list_in_dict(self):
        spec = translate({})

        assert spec.get_default_for({"a": [1]}) == {"a": [1]}

        spec = translate({"a": [0]})

        assert spec.get_default_for({"a": [0]}) == {"a": [0]}
        assert spec.get_default_for({"a": [0, 1]}) == {"a": [0, 1]}
Example #2
0
    def test_list(self):
        assert translate(list) == IsA(list)

        assert translate([]) == IsA(list)

        with pytest.raises(errors.StructureSpecificationError) as excinfo:
            translate([1,2])
        assert ("StructureSpecificationError: Expected a list "
                "containing exactly 1 item; got 2: [1, 2]") in excinfo.exconly()
Example #3
0
    def test_validate_optional_one_of_in_a_list(self):
        # unset "optional" should work exactly as in a Rule
        schema = translate([IsA(str) | IsA(int)])
        with raises(ValidationError):
            schema([])

        schema = translate([optional(IsA(str) | IsA(int))])

        schema([])
        schema([123])
        schema([123, 'sss'])
        with raises(ValidationError):
            schema([123, 'sss', 999.999])
Example #4
0
    def test_validate_optional_one_of_in_a_list(self):
        # unset "optional" should work exactly as in a Rule
        schema = translate([IsA(str) | IsA(int)])
        with raises(ValidationError):
            schema([])

        schema = translate([optional(IsA(str) | IsA(int))])

        schema([])
        schema([123])
        schema([123, 'sss'])
        with raises(ValidationError):
            schema([123, 'sss', 999.999])
Example #5
0
    def test_custom_validators_in_dict_keys(self):
        # FIXME this is one of those cases where "human-readable" errors
        #       are much less readable than "mechanical" ones (as before).
        #       Can we do anything?

        day_note_schema = translate({
            InRange(2000, 2020): {
                InRange(1, 12): {
                    InRange(1, 31): str,
                },
            },
        })
        good_note = {2013: {12: {9:  'it is a good day today'}}}
        bad_note1 = {1999: {12: {9:  'wrong year: below min'}}}
        bad_note2 = {2013: {13: {9:  'wrong month: above max'}}}
        bad_note3 = {2013: {12: {40: 'wrong day of month: above max'}}}

        day_note_schema(good_note)

        #with raises_regexp(InvalidKeys, '^1999$'):
        with raises_regexp(ValidationError,
                           "^must not have keys like 1999$"):
            day_note_schema(bad_note1)

        #with raises_regexp(InvalidKeys, '^2013: 13$'):
        with raises_regexp(ValidationError,
                           "^2013 value must not have keys like 13$"):
            day_note_schema(bad_note2)

        #with raises_regexp(InvalidKeys, '^2013: 12: 40$'):
        with raises_regexp(ValidationError,
                           "^in 2013 \(12 value must not have keys like 40\)$"):
            day_note_schema(bad_note3)
Example #6
0
    def test_int_in_list_in_dict_in_list_in_dict(self):
        spec = translate({'foo': [{'bar': [int]}]})

        with raises_regexp(ValidationError,
            "'foo' value must be list"):
            spec({'foo': None})

        with raises_regexp(ValidationError,
            "'foo' value item #0: 'bar' value must be list"):
            spec({'foo': [{'bar': None}]})

        with raises_regexp(ValidationError,
            "'foo' value lacks item: must be dict"):
            spec({'foo': []})

        with raises_regexp(ValidationError,
           "'foo' value item #0: 'bar' value lacks item: must be int"):
            spec({'foo': [{'bar': []}]})

        spec({'foo': [{'bar': [1]}]})
        spec({'foo': [{'bar': [1, 2]}]})

        with raises_regexp(ValidationError,
            "'foo' value item #0: 'bar' value item #1: must be int"):
            spec({'foo': [{'bar': [1, 'bogus']}]})
Example #7
0
    def test_required_inside_optional_dict_in_dict(self):
        spec = translate({"foo": optional({"a": 1, "b": optional(2)})})

        data = {}
        expected = {"foo": None}
        assert merge_defaults(spec, data) == expected

        data = {"foo": None}
        expected = {"foo": None}
        assert merge_defaults(spec, data) == expected

        data = {"foo": {}}
        # XXX CHANGED:
        # expected = {'foo': {'a': 1, 'b': 2}}
        expected = {"foo": {"a": 1, "b": None}}
        assert merge_defaults(spec, data) == expected

        data = {"foo": {"a": 3}}
        # XXX CHANGED:
        # expected = {'foo': {'a': 3, 'b': 2}}
        expected = {"foo": {"a": 3, "b": None}}
        assert merge_defaults(spec, data) == expected

        data = {"foo": {"b": 3}}
        expected = {"foo": {"a": 1, "b": 3}}
        assert merge_defaults(spec, data) == expected
Example #8
0
 def test_unexpected_dict_in_dict(self):
     """ Non-dictionary in spec, dict in data.
     Data is preserved though won't validate.
     """
     spec = translate({"a": t})
     data = {"a": {"b": 123}}
     assert spec.get_default_for(data) == data
Example #9
0
    def test_custom_validators_in_dict_keys(self):
        # FIXME this is one of those cases where "human-readable" errors
        #       are much less readable than "mechanical" ones (as before).
        #       Can we do anything?

        day_note_schema = translate({
            InRange(2000, 2020): {
                InRange(1, 12): {
                    InRange(1, 31): str,
                },
            },
        })
        good_note = {2013: {12: {9: 'it is a good day today'}}}
        bad_note1 = {1999: {12: {9: 'wrong year: below min'}}}
        bad_note2 = {2013: {13: {9: 'wrong month: above max'}}}
        bad_note3 = {2013: {12: {40: 'wrong day of month: above max'}}}

        day_note_schema(good_note)

        #with raises_regexp(InvalidKeys, '^1999$'):
        with raises_regexp(ValidationError, "^must not have keys like 1999$"):
            day_note_schema(bad_note1)

        #with raises_regexp(InvalidKeys, '^2013: 13$'):
        with raises_regexp(ValidationError,
                           "^2013 value must not have keys like 13$"):
            day_note_schema(bad_note2)

        #with raises_regexp(InvalidKeys, '^2013: 12: 40$'):
        with raises_regexp(
                ValidationError,
                "^in 2013 \(12 value must not have keys like 40\)$"):
            day_note_schema(bad_note3)
Example #10
0
    def test_instance_in_list_of_dicts_in_dict(self):
        spec = translate({"a": [{"b": 1}]})

        assert spec.get_default_for({}) == {"a": []}
        assert spec.get_default_for({"a": []}) == {"a": []}
        assert spec.get_default_for({"a": [{}]}) == {"a": [{"b": 1}]}
        assert spec.get_default_for({"a": [{"b": 0}]}) == {"a": [{"b": 0}]}
Example #11
0
    def test_int_in_list_in_dict_in_list_in_dict(self):
        spec = translate({'foo': [{'bar': [int]}]})

        with raises_regexp(ValidationError, "'foo' value must be list"):
            spec({'foo': None})

        with raises_regexp(ValidationError,
                           "'foo' value item #0: 'bar' value must be list"):
            spec({'foo': [{'bar': None}]})

        with raises_regexp(ValidationError,
                           "'foo' value lacks item: must be dict"):
            spec({'foo': []})

        with raises_regexp(
                ValidationError,
                "'foo' value item #0: 'bar' value lacks item: must be int"):
            spec({'foo': [{'bar': []}]})

        spec({'foo': [{'bar': [1]}]})
        spec({'foo': [{'bar': [1, 2]}]})

        with raises_regexp(
                ValidationError,
                "'foo' value item #0: 'bar' value item #1: must be int"):
            spec({'foo': [{'bar': [1, 'bogus']}]})
Example #12
0
 def test_callable_nested_in_dict(self):
     """ Nested callable defaults.
     """
     spec = translate({"content": {"text": lambda: t("hello")}})
     data = {}
     expected = {"content": {"text": t("hello")}}
     assert merge_defaults(spec, data) == expected
Example #13
0
 def test_unexpected_list_in_dict(self):
     """ Non-list in spec, list in data.
     Data is preserved though won't validate.
     """
     spec = translate({"a": t})
     data = {"a": [123]}
     assert spec.get_default_for(data) == data
Example #14
0
 def test_opt_key__py2_unicode(self):
     raw = {
         opt_key(unicode('foo')): int,
     }
     assert translate(raw) == DictOf([
         (Equals(unicode('foo')) | ~Exists(), IsA(int)),
     ])
Example #15
0
 def test_opt_key__str(self):
     # this also means Unicode for Py3 but it's OK
     raw = {
         opt_key('foo'): int,
     }
     assert translate(raw) == DictOf([
         (Equals('foo') | ~Exists(), IsA(int)),
     ])
Example #16
0
def test_translate_dict():
    assert translate(dict) == IsA(dict)
    assert translate({}) == IsA(dict)

    # literal as a key
    assert translate({'foo': 123}) == DictOf([
        (Equals('foo'), IsA(int, default=123)),
    ])
    assert translate({123: str}) == DictOf([
        (Equals(123), IsA(str)),
    ])

    # validator as a key
    assert translate({Equals('foo') | Equals('bar'): str}) == DictOf([
        (Equals('foo') | Equals('bar'), IsA(str)),
    ])

    # type as a key
    assert translate({str: int}) == DictOf([
        (IsA(str), IsA(int)),
    ])

    # function as a key
    func = lambda: 'foo'
    assert translate({func: int}) == DictOf([
        (Equals('foo'), IsA(int)),
    ])
Example #17
0
    def test_missing(self):

        # MISSING KEY

        dict_with_opt_key = translate({IsA(text_type) | ~Exists(): text_type})
        dict_with_opt_key({})

        dict_with_req_key_opt_value = translate({'a': IsA(text_type) | Equals(None)})
        with raises(MissingKeys):
            dict_with_req_key_opt_value({})

        dict_with_req_key_req_value = translate({'a': IsA(text_type)})
        with raises(MissingKeys):
            dict_with_req_key_req_value({})

        dict_with_req_keys_req_values = translate({'a': text_type, 'b': int})
        with raises(MissingKeys):
            dict_with_req_keys_req_values({'b': 1})
Example #18
0
    def test_list_type(self):

        v = translate(list)

        with raises_regexp(ValidationError, 'must be list'):
            v(None)
        v([])
        v(['hi'])
        v([1234])
Example #19
0
    def test_list_type(self):

        v = translate(list)

        with raises_regexp(ValidationError, 'must be list'):
            v(None)
        v([])
        v(['hi'])
        v([1234])
Example #20
0
    def test_list_obj_empty(self):

        v = translate([])

        with raises_regexp(ValidationError, 'must be list'):
            v(None)
        v([])
        v([None])
        v(['hi'])
        v([1234])
Example #21
0
    def test_list_obj_empty(self):

        v = translate([])

        with raises_regexp(ValidationError, 'must be list'):
            v(None)
        v([])
        v([None])
        v(['hi'])
        v([1234])
Example #22
0
    def test_list_with_opt_elem(self):

        v = translate([optional(str)])

        with raises_regexp(ValidationError, 'must be list'):
            v(None)
        v([])
        with raises_regexp(ValidationError, 'must be str or must not exist'):
            v([None])
        v(['hi'])
        with raises_regexp(ValidationError, 'must be str'):
            v([1234])
Example #23
0
    def test_list_with_req_elem(self):

        v = translate([str])

        with raises_regexp(ValidationError, 'must be list'):
            v(None)
        with raises_regexp(ValidationError, 'lacks item: must be str'):
            v([])
        with raises_regexp(ValidationError, '#0: must be str'):
            v([None])
        v(['hi'])
        with raises_regexp(ValidationError, '#0: must be str'):
            v([1234])
Example #24
0
    def test_merge_dictof_dictof_isa(self):
        raw_spec = {"content": {"text": t("hello")}}

        spec = translate(raw_spec)

        # make sure translation went as expected
        assert spec == DictOf([(Equals("content"), DictOf([(Equals("text"), IsA(t, default=t("hello")))]))])

        # make sure merging works as expected for nested dict
        assert raw_spec == spec.get_default_for({"content": {}})

        # make sure merging works as expected for nested *and* root dicts
        assert raw_spec == spec.get_default_for({})
Example #25
0
    def test_list_with_req_elem(self):

        v = translate([str])

        with raises_regexp(ValidationError, 'must be list'):
            v(None)
        with raises_regexp(ValidationError, 'lacks item: must be str'):
            v([])
        with raises_regexp(ValidationError, '#0: must be str'):
            v([None])
        v(['hi'])
        with raises_regexp(ValidationError, '#0: must be str'):
            v([1234])
Example #26
0
def test_translate_list():
    assert translate(list) == IsA(list)
    assert translate([]) == IsA(list)
    assert translate([int]) == ListOf(IsA(int))
    assert translate([1]) == ListOf(IsA(int, default=1))
    with raises_regexp(StructureSpecificationError,
                       'Expected a list containing exactly 1 item; '
                       'got 3: \[1, 2, 3\]'):
        translate([1, 2, 3])
Example #27
0
    def test_int_in_dict_in_dict(self):
        "A required int nested in a required dict nested in another required dict"

        spec = translate({'foo': {'bar': int}})

        # inner key is missing

        with raises_regexp(ValidationError, "^'foo' value must have keys: 'bar'$"):
            spec({'foo': {}})

        # inner key is present, inner value is missing

        with raises_regexp(ValidationError, "^in 'foo' \('bar' value must be int\)$"):
            spec({'foo': {'bar': None}})

        # inner value is present

        spec({'foo': {'bar': 123}})
Example #28
0
    def test_int_in_dict(self):
        "A required int nested in a required dict"

        spec = translate({'foo': int})

        # key is missing

        with raises_regexp(MissingKeys, "must have keys: 'foo'"):
            spec({})

        # key is present, value is missing

        with raises_regexp(ValidationError, "'foo' value must be int"):
            spec({'foo': None})

        # key is present, value is present

        spec({'foo': 1})
Example #29
0
    def test_dict_in_dict(self):
        "A required dict nested in another required dict"

        spec = translate({'foo': dict})

        # key is missing

        with raises_regexp(MissingKeys, "must have keys: 'foo'"):
            spec({})

        # key is present, value is missing

        with raises_regexp(ValidationError, "'foo' value must be dict"):
            spec({'foo': None})

        # value is present

        validate(spec, {'foo': {}})
Example #30
0
    def test_dict_in_dict(self):
        "A required dict nested in another required dict"

        spec = translate({'foo': dict})

        # key is missing

        with raises_regexp(MissingKeys, "must have keys: 'foo'"):
            spec({})

        # key is present, value is missing

        with raises_regexp(ValidationError, "'foo' value must be dict"):
            spec({'foo': None})

        # value is present

        validate(spec, {'foo': {}})
Example #31
0
    def test_int_in_dict(self):
        "A required int nested in a required dict"

        spec = translate({'foo': int})

        # key is missing

        with raises_regexp(MissingKeys, "must have keys: 'foo'"):
            spec({})

        # key is present, value is missing

        with raises_regexp(ValidationError, "'foo' value must be int"):
            spec({'foo': None})

        # key is present, value is present

        spec({'foo': 1})
Example #32
0
    def test_int_in_dict_in_dict(self):
        "A required int nested in a required dict nested in another required dict"

        spec = translate({'foo': {'bar': int}})

        # inner key is missing

        with raises_regexp(ValidationError,
                           "^'foo' value must have keys: 'bar'$"):
            spec({'foo': {}})

        # inner key is present, inner value is missing

        with raises_regexp(ValidationError,
                           "^in 'foo' \('bar' value must be int\)$"):
            spec({'foo': {'bar': None}})

        # inner value is present

        spec({'foo': {'bar': 123}})
Example #33
0
    def test_type_in_dict_in_dict(self):
        spec = translate({"a": {"b": int}})

        # key is absent; should be inserted
        assert spec.get_default_for({}) == {"a": {"b": None}}
        # same with nested key
        assert spec.get_default_for({"a": {}}) == {"a": {"b": None}}

        # key is present but value is None; should be overridden with defaults
        #
        #   XXX do we really need to override *present* values in data
        #       even if they are None?
        #
        assert spec.get_default_for({"a": None}) == {"a": {"b": None}}
        assert spec.get_default_for({"a": {"b": None}}) == {"a": {"b": None}}

        # key is present, value is not None; leave as is
        # (even if it won't pass validation)
        assert spec.get_default_for({"a": {"b": 1234}}) == {"a": {"b": 1234}}
        assert spec.get_default_for({"a": t("bogus string")}) == {"a": t("bogus string")}
Example #34
0
    def test_int_in_optional_dict(self):
        "A required int nested in an optional dict"

        spec = translate({'foo': int}) | Equals(None)

        # outer optional value is missing

        spec(None)

        # outer optional value is present, inner key is missing

        with raises_regexp(AllFailed, "must have keys: 'foo' or must equal None"):
            spec({})

        # inner key is present, inner value is missing

        with raises_regexp(AllFailed, "'foo' value must be int or must equal None"):
            spec({'foo': None})

        # inner value is present

        spec({'foo': 123})
Example #35
0
    def test_int_in_optional_dict(self):
        "A required int nested in an optional dict"

        spec = translate({'foo': int}) | Equals(None)

        # outer optional value is missing

        spec(None)

        # outer optional value is present, inner key is missing

        with raises_regexp(AllFailed,
                           "must have keys: 'foo' or must equal None"):
            spec({})

        # inner key is present, inner value is missing

        with raises_regexp(AllFailed,
                           "'foo' value must be int or must equal None"):
            spec({'foo': None})

        # inner value is present

        spec({'foo': 123})
Example #36
0
 def test_validator_in_dict(self):
     spec = translate({"foo": IsA(str, default="bar")})
     data = {}
     expected = {"foo": "bar"}
     assert merge_defaults(spec, data) == expected
Example #37
0
    def test_type_in_list_in_dict(self):
        spec = translate({"a": [int]})

        assert spec.get_default_for({"a": []}) == {"a": []}
        assert spec.get_default_for({"a": [123]}) == {"a": [123]}
        assert spec.get_default_for({"a": [123, 456]}) == {"a": [123, 456]}
Example #38
0
 def test_custom_structures(self):
     "custom keys should not be lost even if they are not in spec"
     spec = translate({})
     data = {"a": [{"b": {"c": 123}}]}
     assert spec.get_default_for(data) == data
Example #39
0
    def test_rule_in_list(self):
        spec = translate({"a": [IsA(int)]})

        assert spec.get_default_for({"a": []}) == {"a": []}
        assert spec.get_default_for({"a": None}) == {"a": []}
        assert spec.get_default_for({}) == {"a": []}
Example #40
0
    def test_instance_in_dict(self):
        spec = translate({"a": {"b": 1}})

        assert spec.get_default_for({}) == {"a": {"b": 1}}