示例#1
0
    def test_all(self):  # type: () -> None
        schema = All(Constant('one'), UnicodeString())
        self.assertEqual(
            schema.errors('one'),
            [],
        )
        self.assertEqual(
            len(schema.errors('two')),
            1,
        )

        assert schema.introspect() == {
            'type':
            'all',
            'requirements': [
                {
                    'type': 'constant',
                    'values': ['one']
                },
                {
                    'type': 'unicode'
                },
            ]
        }

        with pytest.raises(TypeError):
            # noinspection PyTypeChecker
            All('not a field')  # type: ignore

        with pytest.raises(TypeError):
            All(Constant('one'), UnicodeString(), description=b'Not unicode')

        with pytest.raises(TypeError):
            All(Constant('one'), UnicodeString(), unsupported='argument')
示例#2
0
    def test_nullable(self):
        constant = Constant('one', 'two')
        schema = Nullable(constant)
        self.assertEqual([], schema.errors(None))
        self.assertEqual([], schema.errors('one'))
        self.assertEqual([], schema.errors('two'))
        self.assertEqual(1, len(schema.errors('three')))
        self.assertEqual(
            {
                'type': 'nullable',
                'nullable': constant.introspect()
            }, schema.introspect())

        boolean = Boolean(description='This is a test description')
        schema = Nullable(boolean)
        self.assertEqual([], schema.errors(None))
        self.assertIsNone(schema.errors(True))
        self.assertIsNone(schema.errors(False))
        self.assertEqual(1, len(schema.errors('true')))
        self.assertEqual(1, len(schema.errors(1)))
        self.assertEqual({
            'type': 'nullable',
            'nullable': boolean.introspect()
        }, schema.introspect())

        string = UnicodeString()
        schema = Nullable(string)
        self.assertEqual([], schema.errors(None))
        self.assertIsNone(schema.errors('hello, world'))
        self.assertEqual(1, len(schema.errors(b'hello, world')))
        self.assertEqual({
            'type': 'nullable',
            'nullable': string.introspect()
        }, schema.introspect())
    def test_tuple(self):
        with pytest.raises(TypeError):
            Tuple(UnicodeString(),
                  Integer(),
                  Boolean(),
                  additional_validator='Not a validator')  # type: ignore

        field = Tuple(UnicodeString(), Integer(), Boolean())

        assert field.errors(['foo', 'bar',
                             'baz']) == [Error(message='Not a tuple')]
        assert field.errors({'foo': 'bar'}) == [Error(message='Not a tuple')]
        assert field.errors({'foo', 'bar',
                             'baz'}) == [Error(message='Not a tuple')]
        assert field.errors(
            ('foo', 'bar',
             True)) == [Error(message='Not an integer', pointer='1')]
        assert field.errors(('foo', 12, False)) == []
        assert field.errors(('foo', 12, True)) == []

        class V(AdditionalCollectionValidator[TupleType[AnyType]]):
            def errors(self, value):
                if value[2] is not True:
                    return [Error('The third value must be True', pointer='2')]
                return []

        field = Tuple(UnicodeString(),
                      Integer(),
                      Boolean(),
                      additional_validator=V())

        assert field.errors(('foo', 12, False)) == [
            Error(message='The third value must be True', pointer='2')
        ]
        assert field.errors(('foo', 12, True)) == []
    def test_validate_method(self):

        schema = Dictionary(
            {
                'name': UnicodeString(max_length=20),
                'greeting': UnicodeString(),
            },
            optional_keys=['greeting'])

        class Greeter(object):
            @classmethod
            @validate_method(schema, UnicodeString())
            def greeter(cls, name, greeting='Hello'):
                # Special case to check return value stuff
                if name == 'error':
                    return 5
                return '%s, %s!' % (greeting, name)

        self.assertEqual(Greeter.greeter(name='Andrew'), 'Hello, Andrew!')
        self.assertEqual(Greeter.greeter(name='Andrew', greeting='Ahoy'),
                         'Ahoy, Andrew!')

        with self.assertRaises(ValidationError):
            Greeter.greeter(name='Andrewverylongnameperson')

        with self.assertRaises(ValidationError):
            Greeter.greeter(name='Andrew', greeeeeeting='Boo')

        with self.assertRaises(ValidationError):
            Greeter.greeter(name='error')

        with self.assertRaises(PositionalError):
            Greeter.greeter('Andrew')
    def test_validator_arguments_validation(self):  # type: () -> None
        with pytest.raises(ValueError):
            @validate_call(List(UnicodeString()), UnicodeString())  # type: ignore
            def something(_foo):
                pass

        with pytest.raises(ValueError):
            @validate_call(args=SchemalessDictionary(), kwargs=None, returns=UnicodeString())  # type: ignore
            def something_else(_foo):
                pass
示例#6
0
class RequestSchemaPrediction(Dictionary):
    contents = {
        'currency': UnicodeString(),
        'country_code': UnicodeString(),
        'address_postal_code': UnicodeString(),
        'category': UnicodeString(),
    }
    optional_keys = [
        'currency',
        'address_postal_code',
    ]
示例#7
0
class ResponseSchemaPurchase(Dictionary):
    contents = {
        'id': UnicodeString(),
        'currency': UnicodeString(),
        'address_postal_code': UnicodeString(),
        'country_code': UnicodeString(),
        'category': UnicodeString(),
        'ticket_price_amount': Integer(),
        'purchased_at': DateTime(),
        'quantity_sold': Integer(),
    }
示例#8
0
    def test_list(self):  # type: () -> None
        schema = List(UnicodeString(), min_length=4, max_length=8)

        assert schema.errors(['foo', 'bar', 'baz', 'qux']) == []
        assert schema.errors(['foo', 'bar',
                              'baz']) == [Error('List is shorter than 4')]
        assert schema.errors(
            ['foo', 'bar', 'baz', 'qux', 'foo', 'bar', 'baz', 'qux', 'foo'
             ], ) == [Error('List is longer than 8')]

        with pytest.raises(ValueError):
            List(UnicodeString(), min_length=21, max_length=20)
    def test_dictionary(self):
        with pytest.raises(TypeError):
            # noinspection PyTypeChecker
            Dictionary({'foo': UnicodeString()},
                       additional_validator='Not a validator')  # type: ignore

        field = Dictionary({
            'foo': UnicodeString(),
            'bar': Integer(),
            'baz': UnicodeString(),
        })

        assert field.errors(['foo', 'bar',
                             'baz']) == [Error(message='Not a dict')]
        assert field.errors(
            ('foo', 'bar', 'baz')) == [Error(message='Not a dict')]
        assert field.errors({'foo', 'bar',
                             'baz'}) == [Error(message='Not a dict')]
        assert field.errors({
            'foo': 'Hello',
            'bar': 12,
            'baz': True
        }) == [
            Error(message='Not a unicode string', pointer='baz'),
        ]
        assert field.errors({
            'foo': 'Hello',
            'bar': 12,
            'baz': 'Goodbye'
        }) == []

        class V(AdditionalCollectionValidator[Mapping[HashableType, AnyType]]):
            def errors(self, value):
                if value['foo'] != value['baz']:
                    return [
                        Error('Value foo does not match value baz',
                              pointer='foo')
                    ]
                return []

        field = field.extend(additional_validator=V())

        assert field.errors({
            'foo': 'Hello',
            'bar': 12,
            'baz': 'Goodbye'
        }) == [
            Error(message='Value foo does not match value baz', pointer='foo'),
        ]
        assert field.errors({'foo': 'Hello', 'bar': 12, 'baz': 'Hello'}) == []
    def test_validate(self):  # type: () -> None
        schema = Dictionary({
            'name': UnicodeString(max_length=20),
            'greeting': UnicodeString(),
        }, optional_keys=('greeting', ))

        validate(schema, {'name': 'Andrew'})
        validate(schema, {'name': 'Andrew', 'greeting': 'Ahoy-hoy'})

        with self.assertRaises(ValidationError):
            validate(schema, {'name': 'Andrewverylongnameperson'})

        with self.assertRaises(ValidationError):
            validate(schema, {'name': 'Andrew', 'greeeeeeting': 'Ahoy-hoy'})
示例#11
0
    def test_schemaless_dictionary(self):
        with pytest.raises(TypeError):
            # noinspection PyTypeChecker
            SchemalessDictionary(
                key_type=UnicodeString(),
                value_type=Integer(),
                additional_validator='Not a validator',  # type: ignore
            )

        field = SchemalessDictionary(key_type=UnicodeString(),
                                     value_type=Integer())

        assert field.errors(['foo', 'bar',
                             'baz']) == [Error(message='Not a dict')]
        assert field.errors(
            ('foo', 'bar', 'baz')) == [Error(message='Not a dict')]
        assert field.errors({'foo', 'bar',
                             'baz'}) == [Error(message='Not a dict')]
        assert field.errors({
            'foo': 42,
            'bar': 11,
            'baz': 'Goodbye'
        }) == [
            Error(message='Not an integer', pointer='baz'),
        ]
        assert field.errors({'foo': 42, 'bar': 11, 'baz': 91}) == []

        class V(AdditionalCollectionValidator[Mapping[HashableType, AnyType]]):
            def errors(self, value):
                if value['foo'] != value['baz']:
                    return [
                        Error('Value foo does not match value baz',
                              pointer='foo')
                    ]
                return []

        field = SchemalessDictionary(key_type=UnicodeString(),
                                     value_type=Integer(),
                                     additional_validator=V())

        assert field.errors({
            'foo': 42,
            'bar': 11,
            'baz': 91
        }) == [
            Error(message='Value foo does not match value baz', pointer='foo'),
        ]
        assert field.errors({'foo': 42, 'bar': 11, 'baz': 42}) == []
示例#12
0
    def test_schemaless_dict(self):  # type: () -> None
        """
        Tests the schemaless dict with some schema
        """
        schema = SchemalessDictionary(Integer(),
                                      UnicodeString(),
                                      min_length=1,
                                      max_length=5)

        self.assertEqual(schema.errors({1: 'value'}), [])

        assert schema.errors(
            {}) == [Error('Dict contains fewer than 1 value(s)')]

        self.assertEqual(
            schema.errors({
                'x': 123,
                2: 'foo',
                3: 'bar',
                4: 'baz',
                5: 'qux',
                6: 'too many'
            }),
            [
                Error('Dict contains more than 5 value(s)'),
                Error('Not an integer', pointer='x'),
                Error('Not a unicode string', pointer='x'),
            ],
        )

        self.assertEqual(
            schema.introspect(), {
                'type': 'schemaless_dictionary',
                'key_type': {
                    'type': 'integer'
                },
                'value_type': {
                    'type': 'unicode'
                },
                'max_length': 5,
                'min_length': 1,
            })

        with pytest.raises(ValueError):
            SchemalessDictionary(Integer(),
                                 UnicodeString(),
                                 min_length=12,
                                 max_length=11)
示例#13
0
    def test_python_path(self):  # type: () -> None
        schema = PythonPath()
        assert schema.errors('tests.test_fields_meta.MY_FOO') == []
        assert schema.errors('tests.test_fields_meta.MY_BAR') == []
        assert schema.errors('tests.test_fields_meta:MY_QUX') == []
        assert schema.errors('tests.test_fields_meta.MY_DICT') == []
        assert schema.errors('tests.test_fields_meta:Qux.INNER_CONSTANT') == []

        schema = PythonPath(ObjectInstance(Foo))
        assert schema.errors('tests.test_fields_meta.MY_FOO') == []
        assert schema.errors('tests.test_fields_meta.MY_BAR') == []
        assert schema.errors('tests.test_fields_meta:MY_QUX') == [
            Error('Not an instance of Foo')
        ]
        assert schema.errors('tests.test_fields_meta.MY_DICT') == [
            Error('Not an instance of Foo')
        ]
        assert schema.errors('tests.test_fields_meta:Qux.INNER_CONSTANT') == [
            Error('Not an instance of Foo')
        ]

        schema = PythonPath(SchemalessDictionary())
        assert schema.errors('tests.test_fields_meta.MY_DICT') == []
        assert schema.errors('tests.test_fields_meta:MY_QUX') == [
            Error('Not a dict')
        ]

        schema = PythonPath(UnicodeString())
        assert schema.errors('tests.test_fields_meta:Qux.INNER_CONSTANT') == []
        assert schema.errors('tests.test_fields_meta.MY_DICT') == [
            Error('Not a unicode string')
        ]
示例#14
0
    def test_schemaless_dict(self):
        """
        Tests the schemaless dict with some schema
        """
        schema = SchemalessDictionary(Integer(), UnicodeString())

        self.assertEqual(schema.errors({1: u'value'}), [])

        self.assertEqual(
            schema.errors({'x': 123}),
            [
                Error('Not an integer', pointer='x'),
                Error('Not a unicode string', pointer='x'),
            ],
        )

        self.assertEqual(
            schema.introspect(), {
                'type': 'schemaless_dictionary',
                'key_type': {
                    'type': 'integer'
                },
                'value_type': {
                    'type': 'unicode'
                },
            })
示例#15
0
 class Greeter(object):
     @classmethod
     @validate_method(schema, UnicodeString())
     def greeter(cls, name, greeting='Hello'):
         # Special case to check return value stuff
         if name == 'error':
             return 5
         return '%s, %s!' % (greeting, name)
示例#16
0
    def test_set(self):  # type: () -> None
        with pytest.raises(TypeError):
            # noinspection PyTypeChecker
            Set(UnicodeString(),
                additional_validator='Not a validator')  # type: ignore

        field = Set(UnicodeString())

        assert field.errors(
            ('hello', 'goodbye')) == [Error(message='Not a set or frozenset')]
        assert field.errors({'hello': 'goodbye'
                             }) == [Error(message='Not a set or frozenset')]
        assert field.errors(['hello', 'goodbye'
                             ]) == [Error(message='Not a set or frozenset')]
        assert field.errors(
            {'hello',
             2}) == [Error(message='Not a unicode string', pointer='[2]')]
        assert field.errors(frozenset(
            ('hello',
             2))) == [Error(message='Not a unicode string', pointer='[2]')]
        assert field.errors({'hello', 'goodbye'}) == []
        assert field.errors(frozenset(('hello', 'goodbye'))) == []

        class V(AdditionalCollectionValidator[AbstractSet]):
            def errors(self, value):
                errors = []
                for v in value:
                    if v > 500:
                        errors.append(
                            Error('Whoop custom error',
                                  pointer='{}'.format(v)))
                return errors

        field = Set(Integer(), additional_validator=V())

        assert field.errors({501, 'Not a number'}) == [
            Error(message='Not an integer', pointer='[Not a number]')
        ]
        assert field.errors(
            {501,
             499}) == [Error(message='Whoop custom error', pointer='501')]
        assert field.errors(frozenset(
            (501,
             499))) == [Error(message='Whoop custom error', pointer='501')]
        assert field.errors({500, 499}) == []
        assert field.errors(frozenset((500, 499))) == []
示例#17
0
 def test_all(self):
     schema = All(Constant('one'), UnicodeString())
     self.assertEqual(
         schema.errors('one'),
         [],
     )
     self.assertEqual(
         len(schema.errors('two')),
         1,
     )
示例#18
0
    def test_sequence(self):  # type: () -> None
        with pytest.raises(TypeError):
            # noinspection PyTypeChecker
            Sequence(UnicodeString(),
                     additional_validator='Not a validator')  # type: ignore

        field = Sequence(UnicodeString())

        assert field.errors({'hello':
                             'goodbye'}) == [Error(message='Not a sequence')]
        assert field.errors({'hello',
                             'goodbye'}) == [Error(message='Not a sequence')]
        assert field.errors(
            ['hello',
             2]) == [Error(message='Not a unicode string', pointer='1')]
        assert field.errors(
            (1,
             'world')) == [Error(message='Not a unicode string', pointer='0')]
        assert field.errors(['hello', 'goodbye']) == []
        assert field.errors(('hello', 'goodbye')) == []

        class V(AdditionalCollectionValidator[SequenceType]):
            def errors(self, value):
                errors = []
                for i, v in enumerate(value):
                    if v > 500:
                        errors.append(
                            Error('Whoop another error',
                                  pointer='{}'.format(i)))
                return errors

        field = Sequence(Integer(), additional_validator=V())

        assert field.errors([501, 'Not a number dude']) == [
            Error(message='Not an integer', pointer='1')
        ]
        assert field.errors(
            [501, 499]) == [Error(message='Whoop another error', pointer='0')]
        assert field.errors(
            (501, 499)) == [Error(message='Whoop another error', pointer='0')]
        assert field.errors([500, 499]) == []
        assert field.errors((500, 499)) == []
        class Helper(object):
            @classmethod
            @validate_method(schema, UnicodeString())
            def greeter(cls, name, greeting='Hello'):
                # Special case to check return value stuff
                if name == 'error':
                    return 5
                return '{}, {}!'.format(greeting, name)

            @staticmethod
            @validate_call(args=Tuple(Integer(), Integer()), kwargs=None, returns=Integer())
            def args_method(one, two):
                return one + two

            # noinspection PyMethodMayBeStatic
            @validate_method(
                args=List(UnicodeString()),
                kwargs=SchemalessDictionary(value_type=UnicodeString()),
                returns=List(UnicodeString()),
            )
            def args_and_kwargs_method(self, *args, **kwargs):
                return [s.format(**kwargs) for s in args]
示例#20
0
    def test_tuple(self):
        schema = Tuple(Integer(gt=0), UnicodeString(),
                       Constant('I love tuples'))

        self.assertEqual(schema.errors((1, 'test', 'I love tuples')), [])

        # too short
        self.assertEqual(
            schema.errors((1, 'test')),
            [Error('Number of elements 2 does not match expected 3')])

        # too long
        self.assertEqual(
            schema.errors((1, 'test', 'I love tuples', '... and coffee')),
            [Error('Number of elements 4 does not match expected 3')])

        self.assertEqual(schema.errors((
            -1,
            None,
            'I hate tuples',
        )), [
            Error('Value not > 0', pointer='0'),
            Error('Not a unicode string', pointer='1'),
            Error(
                'Value is not "I love tuples"',
                code=ERROR_CODE_UNKNOWN,
                pointer='2',
            ),
        ])

        self.assertEqual(
            schema.introspect(), {
                'type':
                'tuple',
                'contents': [
                    {
                        'type': 'integer',
                        'gt': 0
                    },
                    {
                        'type': 'unicode'
                    },
                    {
                        'type': 'constant',
                        'values': ['I love tuples']
                    },
                ]
            })
示例#21
0
文件: schemas.py 项目: guoyu07/pysoa
from conformity.fields import (
    Boolean,
    Dictionary,
    Integer,
    List,
    SchemalessDictionary,
    UnicodeString,
)

ActionRequestSchema = Dictionary(
    {
        'action': UnicodeString(),
        'body': SchemalessDictionary(key_type=UnicodeString()),
    },
    optional_keys=['body'],
)

ControlHeaderSchema = Dictionary(
    {
        'continue_on_error': Boolean(),
    },
    allow_extra_keys=True,
)

ContextHeaderSchema = Dictionary(
    {
        'switches': List(Integer()),
        'correlation_id': UnicodeString(),
    },
    allow_extra_keys=True,
)
示例#22
0
    def test_polymorph(self):

        card = Dictionary({
            'payment_type':
            Constant('card'),
            'number':
            UnicodeString(),
            'cvc':
            UnicodeString(description='Card Verification Code'),
        })

        bankacc = Dictionary({
            'payment_type':
            Constant('bankacc'),
            'routing':
            UnicodeString(description='US RTN or foreign equivalent'),
            'account':
            UnicodeString(),
        })

        schema = Polymorph(
            'payment_type',
            {
                'card': card,
                'bankacc': bankacc,
            },
        )

        self.assertEqual(
            schema.errors({
                'payment_type': 'card',
                'number': '1234567890123456',
                'cvc': '000',
            }),
            [],
        )

        self.assertEqual(
            schema.errors({
                'payment_type': 'bankacc',
                'routing': '13456790',
                'account': '13910399',
            }),
            [],
        )

        self.assertEqual(
            schema.introspect(),
            {
                'type': 'polymorph',
                'contents_map': {
                    'bankacc': {
                        'type': 'dictionary',
                        'allow_extra_keys': False,
                        'contents': {
                            'account': {
                                'type': 'unicode'
                            },
                            'payment_type': {
                                'type': 'constant',
                                'values': ['bankacc'],
                            },
                            'routing': {
                                'type': 'unicode',
                                'description': 'US RTN or foreign equivalent',
                            },
                        },
                        'optional_keys': [],
                    },
                    'card': {
                        'type': 'dictionary',
                        'allow_extra_keys': False,
                        'contents': {
                            'cvc': {
                                'type': 'unicode',
                                'description': 'Card Verification Code',
                            },
                            'number': {
                                'type': 'unicode'
                            },
                            'payment_type': {
                                'type': 'constant',
                                'values': ['card'],
                            },
                        },
                        'optional_keys': [],
                    },
                },
                'switch_field': 'payment_type',
            },
        )
示例#23
0
    def test_dictionary_subclass(self):  # type: () -> None
        """
        Tests that subclassing a Dictionary allows you to provide the
        same options as instantiating it.
        """
        class Coordinate(Dictionary):
            contents = {
                'x': Float(),
                'y': Float(),
                'z': Float(),
            }
            optional_keys = ('z', )

        schema = Coordinate(description='Where the treasure is')  # type: Base

        # Test the options work right
        self.assertEqual(
            schema.errors({
                'x': 4.4,
                'y': 65.21
            }),
            [],
        )
        self.assertEqual(
            schema.errors({
                'x': 4.4,
                'y': 65.21,
                'z': 5542
            }),
            [],
        )
        self.assertEqual(
            len(schema.errors({
                'x': 'HERRING',
                'z': 5542
            })),
            2,
        )

        # Test you can't make a dict without contents
        with self.assertRaises(ValueError):
            Dictionary()

        # Test not overriding one field
        class TwoDeeCoordinate(Dictionary):
            contents = {
                'x': Float(),
                'y': Float(),
            }

        schema2d = TwoDeeCoordinate(description='Where the treasure is')
        self.assertEqual(
            len(schema2d.errors({
                'x': 3.14,
                'z': 5542
            })),
            2,
        )

        class Another(Dictionary):
            allow_extra_keys = True
            description = 'Yep'

        schema = Another({'foo': UnicodeString()})
        assert schema.introspect() == {
            'type': 'dictionary',
            'contents': {
                'foo': {
                    'type': 'unicode',
                }
            },
            'description': 'Yep',
            'allow_extra_keys': True,
            'optional_keys': [],
        }

        with pytest.raises(TypeError):
            # noinspection PyTypeChecker
            Another({'foo': UnicodeString()},
                    optional_keys=1234)  # type: ignore

        class BadDict1(Dictionary):
            allow_extra_keys = 'not a bool'  # type: ignore

        with pytest.raises(TypeError):
            BadDict1(contents={})

        class BadDict2(Dictionary):
            description = b'not a unicode'  # type: ignore

        with pytest.raises(TypeError):
            BadDict2(contents={})

        class BadDict3(Dictionary):
            contents = 'not a dict'  # type: ignore

        with pytest.raises(TypeError):
            BadDict3()

        class ExtraDict(Dictionary):
            contents = {}  # type: ignore
            optional_keys = ('one', 'two'
                             )  # type: TupleType[HashableType, ...]

        d = ExtraDict()
        assert d.optional_keys == frozenset({'one', 'two'})

        class ExtraExtraDict(ExtraDict):
            optional_keys = ()  # type: TupleType[HashableType, ...]

        d = ExtraExtraDict()
        assert d.optional_keys == frozenset({})
示例#24
0
    def test_strings(self):  # type: () -> None
        schema = UnicodeString()
        self.assertEqual([], schema.errors(''))
        self.assertEqual(
            [],
            schema.errors(
                'Foo bar baz qux foo bar baz qux foo bar baz qux foo bar baz qux foo bar'
            ))
        self.assertEqual([Error('Not a unicode string')],
                         schema.errors(b'Test'))

        schema = UnicodeString(min_length=5, max_length=10)
        self.assertEqual([Error('String must have a length of at least 5')],
                         schema.errors(''))
        self.assertEqual([Error('String must have a length of at least 5')],
                         schema.errors('1234'))
        self.assertEqual([], schema.errors('12345'))
        self.assertEqual([], schema.errors('1234567890'))
        self.assertEqual([Error('String must have a length no more than 10')],
                         schema.errors('12345678901'))

        schema = UnicodeString(allow_blank=False)
        self.assertEqual([Error('String cannot be blank')], schema.errors(''))
        self.assertEqual([Error('String cannot be blank')], schema.errors(' '))
        self.assertEqual([Error('String cannot be blank')],
                         schema.errors(' \n '))
        self.assertEqual([], schema.errors('foo'))

        schema = ByteString()
        self.assertEqual([], schema.errors(b''))
        self.assertEqual(
            [],
            schema.errors(
                b'Foo bar baz qux foo bar baz qux foo bar baz qux foo bar baz qux foo'
            ))
        self.assertEqual([Error('Not a byte string')], schema.errors('Test'))

        schema = ByteString(min_length=5, max_length=10)
        self.assertEqual([Error('String must have a length of at least 5')],
                         schema.errors(b''))
        self.assertEqual([Error('String must have a length of at least 5')],
                         schema.errors(b'1234'))
        self.assertEqual([], schema.errors(b'12345'))
        self.assertEqual([], schema.errors(b'1234567890'))
        self.assertEqual([Error('String must have a length no more than 10')],
                         schema.errors(b'12345678901'))

        with pytest.raises(ValueError):
            UnicodeString(min_length=6, max_length=5)
示例#25
0
    def test_tuple(self):  # type: () -> None
        schema = Tuple(Integer(gt=0), UnicodeString(),
                       Constant('I love tuples'))

        self.assertEqual(schema.errors((1, 'test', 'I love tuples')), [])

        # too short
        self.assertEqual(
            schema.errors((1, 'test')),
            [Error('Number of elements 2 does not match expected 3')])

        # too long
        self.assertEqual(
            schema.errors((1, 'test', 'I love tuples', '... and coffee')),
            [Error('Number of elements 4 does not match expected 3')])

        self.assertEqual(schema.errors((
            -1,
            None,
            'I hate tuples',
        )), [
            Error('Value not > 0', pointer='0'),
            Error('Not a unicode string', pointer='1'),
            Error(
                'Value is not "I love tuples"',
                code=ERROR_CODE_UNKNOWN,
                pointer='2',
            ),
        ])

        self.assertEqual(
            schema.introspect(), {
                'type':
                'tuple',
                'contents': [
                    {
                        'type': 'integer',
                        'gt': 0
                    },
                    {
                        'type': 'unicode'
                    },
                    {
                        'type': 'constant',
                        'values': ['I love tuples']
                    },
                ]
            })

        with pytest.raises(TypeError):
            # noinspection PyTypeChecker
            Tuple('not a field')  # type: ignore

        with pytest.raises(TypeError):
            Tuple(Integer(gt=0),
                  UnicodeString(),
                  Constant('I love tuples'),
                  description=b'Not a unicode string')

        with pytest.raises(TypeError):
            Tuple(Integer(gt=0),
                  UnicodeString(),
                  Constant('I love tuples'),
                  unsupported='argument')
示例#26
0
    def test_dictionary_ordering(self):  # type: () -> None
        schema1 = Dictionary(
            OrderedDict((
                ('foo', UnicodeString()),
                ('bar', Boolean()),
                ('baz', List(Integer())),
            )),
            optional_keys=('foo', ),
            description='Hello, world',
        )

        assert schema1.introspect()['contents'] == {
            'baz': List(Integer()).introspect(),
            'foo': UnicodeString().introspect(),
            'bar': Boolean().introspect(),
        }

        assert schema1.introspect()['display_order'] == ['foo', 'bar', 'baz']

        schema2 = schema1.extend(
            OrderedDict((
                ('bar', Integer()),
                ('qux', Set(UnicodeString())),
                ('moon', Tuple(Decimal(), UnicodeString())),
            )))

        assert schema2.introspect()['contents'] == {
            'baz': List(Integer()).introspect(),
            'foo': UnicodeString().introspect(),
            'moon': Tuple(Decimal(), UnicodeString()).introspect(),
            'bar': Integer().introspect(),
            'qux': Set(UnicodeString()).introspect(),
        }

        assert schema2.introspect()['display_order'] == [
            'foo', 'bar', 'baz', 'qux', 'moon'
        ]

        assert not schema1.errors({'bar': True, 'foo': 'Hello', 'baz': [15]})

        errors = schema1.errors({
            'baz': 'Nope',
            'foo': False,
            'bar': ['Heck nope']
        })

        assert errors == [
            Error(code='INVALID',
                  pointer='foo',
                  message='Not a unicode string'),
            Error(code='INVALID', pointer='bar', message='Not a boolean'),
            Error(code='INVALID', pointer='baz', message='Not a list'),
        ]

        assert not schema2.errors(
            {
                'bar': 91,
                'foo': 'Hello',
                'qux': {'Yes'},
                'baz': [15],
                'moon': (decimal.Decimal('15.25'), 'USD')
            }, )

        errors = schema2.errors({
            'baz': 'Nope',
            'foo': False,
            'bar': ['Heck nope'],
            'qux': 'Denied',
            'moon': 72
        })

        assert errors == [
            Error(code='INVALID',
                  pointer='foo',
                  message='Not a unicode string'),
            Error(code='INVALID', pointer='bar', message='Not an integer'),
            Error(code='INVALID', pointer='baz', message='Not a list'),
            Error(code='INVALID',
                  pointer='qux',
                  message='Not a set or frozenset'),
            Error(code='INVALID', pointer='moon', message='Not a tuple'),
        ]
示例#27
0
    def test_dictionary_extension(self):  # type: () -> None
        schema1 = Dictionary(
            {
                'foo': UnicodeString(),
                'bar': Boolean(),
            },
            optional_keys=('foo', ),
            description='Hello, world',
        )

        schema2 = schema1.extend(
            {
                'bar': Integer(),
                'baz': List(Integer()),
            },
            optional_keys=('baz', ),
        )

        schema3 = schema1.extend(
            {
                'bar': Integer(),
                'baz': List(Integer()),
            },
            optional_keys=('baz', ),
            allow_extra_keys=True,
            description='Goodbye, universe',
            replace_optional_keys=True,
        )

        self.assertEqual(
            Dictionary(
                {
                    'foo': UnicodeString(),
                    'bar': Integer(),
                    'baz': List(Integer()),
                },
                optional_keys=(
                    'foo',
                    'baz',
                ),
                allow_extra_keys=False,
                description='Hello, world',
            ).introspect(),
            schema2.introspect(),
        )

        self.assertEqual(
            Dictionary(
                {
                    'foo': UnicodeString(),
                    'bar': Integer(),
                    'baz': List(Integer()),
                },
                optional_keys=('baz', ),
                allow_extra_keys=True,
                description='Goodbye, universe',
            ).introspect(),
            schema3.introspect(),
        )

        assert 'display_order' not in schema1.introspect()
        assert 'display_order' not in schema2.introspect()
        assert 'display_order' not in schema3.introspect()
示例#28
0
    def test_complex(self):  # type: () -> None

        schema = Dictionary({
            'child_ids':
            List(Integer(gt=0)),
            'address':
            Dictionary(
                {
                    'line1': UnicodeString(),
                    'line2': UnicodeString(),
                    'city': UnicodeString(),
                    'postcode': UnicodeString(),
                    'state': UnicodeString(),
                    'country': UnicodeString(),
                },
                optional_keys=('line2', 'state'),
            ),
            'unique_things':
            Set(UnicodeString()),
        })

        self.assertEqual(
            schema.errors(None),
            [Error('Not a dict')],
        )

        self.assertEqual(
            sorted(
                schema.errors(
                    {
                        'child_ids': [1, 2, 'ten'],
                        'unsolicited_item': 'Should not be here',
                        'another_bad': 'Also extra',
                        'unique_things': ['hello', 'world'],
                    }, )),
            sorted([
                Error('Not an integer', pointer='child_ids.2'),
                Error('Missing key: address',
                      code=ERROR_CODE_MISSING,
                      pointer='address'),
                Error('Extra keys present: another_bad, unsolicited_item',
                      code=ERROR_CODE_UNKNOWN),
                Error('Not a set or frozenset', pointer='unique_things'),
            ]),
        )

        self.assertEqual(
            schema.errors({
                'child_ids': [1, 2, 3, 4],
                'address': {
                    'line1': '115 5th Street',
                    'city': 'San Francisco',
                    'state': 'CA',
                    'country': 'USA',
                    'postcode': '94103',
                },
                'unique_things': {'hello', b'world'},
            }),
            [
                Error('Not a unicode string',
                      pointer='unique_things.[{}]'.format(str(b'world')))
            ],
        )

        self.assertEqual(
            schema.errors({
                'child_ids': [1, 2, 3, 4],
                'address': {
                    'line1': '115 5th Street',
                    'city': 'San Francisco',
                    'state': 'CA',
                    'country': 'USA',
                    'postcode': '94103',
                },
                'unique_things': {'hello', 'world'},
            }),
            [],
        )

        introspection = schema.introspect()
        self.assertEqual('dictionary', introspection['type'])
        self.assertFalse(introspection['allow_extra_keys'])
        self.assertEqual([], introspection['optional_keys'])
        self.assertEqual(3, len(introspection['contents']))
        self.assertIn('child_ids', introspection['contents'])
        self.assertEqual(
            {
                'type': 'list',
                'contents': {
                    'gt': 0,
                    'type': 'integer'
                },
            },
            introspection['contents']['child_ids'],
        )
        self.assertIn('address', introspection['contents'])
        self.assertEqual('dictionary',
                         introspection['contents']['address']['type'])
        self.assertFalse(
            introspection['contents']['address']['allow_extra_keys'])
        self.assertEqual(
            {'line2', 'state'},
            set(introspection['contents']['address']['optional_keys']))
        self.assertEqual(
            {
                'city': {
                    'type': 'unicode'
                },
                'country': {
                    'type': 'unicode'
                },
                'line1': {
                    'type': 'unicode'
                },
                'line2': {
                    'type': 'unicode'
                },
                'postcode': {
                    'type': 'unicode'
                },
                'state': {
                    'type': 'unicode'
                },
            },
            introspection['contents']['address']['contents'],
        )
        self.assertEqual(
            {
                'type': 'set',
                'contents': {
                    'type': 'unicode'
                },
            },
            introspection['contents']['unique_things'],
        )
示例#29
0
    def test_subclass_definition(self):  # type: () -> None
        class ImmutableDict(Mapping):
            def __init__(self, underlying):
                self.underlying = underlying

            def __contains__(self, item):
                return item in self.underlying

            def __getitem__(self, k):
                return self.underlying[k]

            def get(self, k, default=None):
                return self.underlying.get(k, default)

            def __iter__(self):
                return iter(self.underlying)

            def __len__(self):
                return len(self.underlying)

            def keys(self):
                return self.underlying.keys()

            def items(self):
                return self.underlying.items()

            def values(self):
                return self.underlying.values()

        class ExtendedSchema(ClassConfigurationSchema):
            base_class = BaseSomething
            default_path = 'tests.test_fields_meta.AnotherSomething'
            description = 'Neat-o schema thing'

        schema = ExtendedSchema()

        config = {}  # type: dict
        with pytest.raises(ValidationError) as error_context:
            schema.instantiate_from(config)
        assert error_context.value.args[0] == [
            Error('Missing key: baz', code='MISSING', pointer='kwargs.baz'),
        ]
        assert config['object'] == AnotherSomething

        config = {'kwargs': {'baz': None}}
        value = schema.instantiate_from(config)
        assert isinstance(value, AnotherSomething)
        assert value.baz is None
        assert value.qux == 'unset'
        assert config['object'] == AnotherSomething

        config2 = ImmutableDict({'kwargs': {'baz': None}})
        assert schema.errors(config2) == []
        assert 'object' not in config2

        assert schema.introspect() == {
            'type':
            'class_config_dictionary',
            'description':
            'Neat-o schema thing',
            'default_path':
            'tests.test_fields_meta.AnotherSomething',
            'base_class':
            'BaseSomething',
            'switch_field':
            'path',
            'switch_field_schema':
            TypePath(base_classes=BaseSomething).introspect(),
            'kwargs_field':
            'kwargs',
            'kwargs_contents_map': {
                'tests.test_fields_meta.AnotherSomething':
                Dictionary(
                    {
                        'baz': Nullable(UnicodeString()),
                        'qux': Boolean()
                    },
                    optional_keys=('qux', ),
                ).introspect(),
            },
        }
示例#30
0
    def test_inline_definition_no_default_or_base_class(
            self):  # type: () -> None
        schema = ClassConfigurationSchema()

        assert schema.errors('Not a dict') == [
            Error('Not a mapping (dictionary)')
        ]
        assert schema.errors({
            'foo': 'bar',
            'baz': 'qux',
            'path': 'unprocessed',
            'kwargs': {},
            'object': Foo
        }) == [Error('Extra keys present: baz, foo', code='UNKNOWN')]
        assert schema.errors({}) == [
            Error('Missing key (and no default specified): path',
                  code='MISSING',
                  pointer='path'),
        ]
        assert schema.errors({'path': 'foo.bar:Hello'}) == [
            Error(
                'ImportError: No module named foo.bar'
                if six.PY2 else "ImportError: No module named 'foo'",
                pointer='path',
            )
        ]
        assert schema.errors({'path': 'tests.test_fields_meta.Foo'}) == [
            Error(
                "Neither class 'tests.test_fields_meta.Foo' nor one of its superclasses was decorated with "
                "@ClassConfigurationSchema.provider",
                pointer='path',
            )
        ]
        assert schema.errors({
            'path': 'tests.test_fields_meta:InvalidProvider'
        }) == [
            Error(
                "Class 'tests.test_fields_meta:InvalidProvider' attribute '_conformity_initialization_schema' should be a "
                "Dictionary or SchemalessDictionary Conformity field or one of their subclasses",
                pointer='path',
            )
        ]

        config = {
            'path': 'tests.test_fields_meta:BasicProvider'
        }  # type: Dict[HashableType, AnyType]
        assert sorted(schema.errors(config)) == [
            Error('Missing key: bar', code='MISSING', pointer='kwargs.bar'),
            Error('Missing key: foo', code='MISSING', pointer='kwargs.foo'),
        ]
        assert config['object'] == BasicProvider

        with pytest.raises(ValidationError) as error_context:
            # noinspection PyTypeChecker
            schema.instantiate_from('Not a dict')  # type: ignore
        assert error_context.value.args[0] == [
            Error('Not a mutable mapping (dictionary)')
        ]

        config = {'path': 'tests.test_fields_meta:BasicProvider'}
        with pytest.raises(ValidationError) as error_context:
            schema.instantiate_from(config)
        assert sorted(error_context.value.args[0]) == [
            Error('Missing key: bar', code='MISSING', pointer='kwargs.bar'),
            Error('Missing key: foo', code='MISSING', pointer='kwargs.foo'),
        ]
        assert config['object'] == BasicProvider

        config = {
            'path': 'tests.test_fields_meta:BasicProvider',
            'kwargs': {
                'foo': 'Fine',
                'bar': 'Bad'
            }
        }
        assert schema.errors(config) == [
            Error('Not a boolean', pointer='kwargs.bar')
        ]
        assert config['object'] == BasicProvider

        config = {
            'path': 'tests.test_fields_meta:BasicProvider',
            'kwargs': {
                'foo': 'Fine',
                'bar': 'Bad'
            }
        }
        with pytest.raises(ValidationError) as error_context:
            schema.instantiate_from(config)
        assert error_context.value.args[0] == [
            Error('Not a boolean', pointer='kwargs.bar')
        ]
        assert config['object'] == BasicProvider

        config = {
            'path': 'tests.test_fields_meta:BasicProvider',
            'kwargs': {
                'foo': 'Fine',
                'bar': True
            }
        }
        assert schema.errors(config) == []
        assert config['object'] == BasicProvider

        config = {
            'path': 'tests.test_fields_meta:BasicProvider',
            'kwargs': {
                'foo': 'Fine',
                'bar': True
            }
        }
        value = schema.instantiate_from(config)
        assert isinstance(value, BasicProvider)
        assert value.foo == 'Fine'
        assert value.bar is True
        assert config['object'] == BasicProvider

        schema = ClassConfigurationSchema()
        with pytest.raises(ValidationError):
            schema.initiate_cache_for('foo.bar:Hello')
        schema.initiate_cache_for('tests.test_fields_meta.BasicProvider')
        schema.initiate_cache_for('tests.test_fields_meta:BasicProvider')
        assert schema.introspect() == {
            'type': 'class_config_dictionary',
            'base_class': 'object',
            'switch_field': 'path',
            'switch_field_schema': TypePath(base_classes=object).introspect(),
            'kwargs_field': 'kwargs',
            'kwargs_contents_map': {
                'tests.test_fields_meta.BasicProvider':
                Dictionary({
                    'foo': UnicodeString(),
                    'bar': Boolean()
                }, ).introspect(),
                'tests.test_fields_meta:BasicProvider':
                Dictionary({
                    'foo': UnicodeString(),
                    'bar': Boolean()
                }, ).introspect(),
            },
        }

        schema = ClassConfigurationSchema(add_class_object_to_dict=False)
        config = {
            'path': 'tests.test_fields_meta:BasicProvider',
            'kwargs': {
                'foo': 'Fine',
                'bar': True
            }
        }
        value = schema.instantiate_from(config)
        assert isinstance(value, BasicProvider)
        assert value.foo == 'Fine'
        assert value.bar is True
        assert 'object' not in config