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)) == []
Example #2
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(),
    }
Example #3
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)
    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}) == []
Example #5
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'
                },
            })
        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]
    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'}) == []
Example #8
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']
                    },
                ]
            })
    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))) == []
    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)) == []
Example #11
0
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,
)

JobRequestSchema = Dictionary(
    {
        'control': ControlHeaderSchema,
        'context': ContextHeaderSchema,
        'actions': List(ActionRequestSchema),
    }, )
Example #12
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')
    def test_validate_method(self):  # type: () -> None
        schema = Dictionary({
            'name': UnicodeString(max_length=20),
            'greeting': UnicodeString(),
        }, optional_keys=('greeting', ))

        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]

        assert getattr(Helper.greeter, '__validated__') is True
        assert getattr(Helper.greeter, '__validated_schema_args__') is None
        assert getattr(Helper.greeter, '__validated_schema_kwargs__') is schema
        assert getattr(Helper.greeter, '__validated_schema_returns__') == UnicodeString()

        assert getattr(Helper.args_method, '__validated__') is True
        assert getattr(Helper.args_method, '__validated_schema_args__') == Tuple(Integer(), Integer())
        assert getattr(Helper.args_method, '__validated_schema_kwargs__') is None
        assert getattr(Helper.args_method, '__validated_schema_returns__') == Integer()

        assert getattr(Helper.args_and_kwargs_method, '__validated__') is True
        assert getattr(Helper.args_and_kwargs_method, '__validated_schema_args__') == List(UnicodeString())
        assert (
            getattr(Helper.args_and_kwargs_method, '__validated_schema_kwargs__') ==
            SchemalessDictionary(value_type=UnicodeString())
        )
        assert getattr(Helper.args_and_kwargs_method, '__validated_schema_returns__') == List(UnicodeString())

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

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

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

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

        with self.assertRaises(PositionalError):
            Helper.greeter('Andrew')

        assert Helper.args_method(1, 2) == 3
        assert Helper.args_method(75, 23) == 98
        with pytest.raises(ValidationError):
            Helper.args_method(1.0, 2)
        with pytest.raises(ValidationError):
            Helper.args_method(1, 2.0)
        with pytest.raises(KeywordError):
            Helper.args_method(1, 2, extra='Forbidden')

        assert Helper().args_and_kwargs_method('hello', 'cool {planet}', 'hot {star}', planet='Earth', star='Sun') == [
            'hello',
            'cool Earth',
            'hot Sun',
        ]
        with pytest.raises(ValidationError):
            Helper().args_and_kwargs_method(1, 'sweet', planet='Earth', star='Sun')
        with pytest.raises(ValidationError):
            Helper().args_and_kwargs_method('hello', 'cool {planet}', 'hot {star}', planet=1, star=2)
Example #14
0
    def test_integers(self):  # type: () -> None
        schema = Integer(gt=0, lt=10)
        self.assertEqual([], schema.errors(1))
        self.assertEqual([Error('Not an integer')], schema.errors('one'))
        self.assertEqual([Error('Not an integer')], schema.errors(True))
        self.assertEqual([Error('Value not > 0')], schema.errors(0))
        self.assertEqual([Error('Value not < 10')], schema.errors(10))

        schema = Integer(gte=0, lte=10)
        self.assertEqual([Error('Value not >= 0')], schema.errors(-1))
        self.assertEqual([Error('Value not <= 10')], schema.errors(11))
Example #15
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'),
        ]
Example #16
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()
Example #17
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'],
        )
Example #18
0
            'when those requests are made with `request.client.call_**(...)` or '
            '`request.client.send_request(...)`. For example, if Foo Service calls Bar Service, the '
            'request context that Bar Service receives will include `"calling_service": "foo"`. May be '
            'useful for logging or metrics.'),
        'correlation_id':
        UnicodeString(
            description=
            'Correlation IDs can be used at your own discretion, but are generally shared across multiple '
            'service requests, even across multiple services, to correlate requests that are logically '
            'linked together (example: such as all PySOA requests that occur within the scope of a single '
            'HTTP request in a client application). The PySOA client automatically adds a UUID correlation '
            'ID to all outgoing requests if the client is not already configured with an inherited '
            'correlation ID, and the client available in `request.client` automatically inherits the '
            'correlation ID from the request.', ),
        'switches':
        List(Integer(),
             description='See: :ref:`api-versioning-using-switches`.'),
    },
    allow_extra_keys=True,
    optional_keys=('caller', 'calling_service'),
)

JobRequestSchema = Dictionary(
    {
        'control':
        ControlHeaderSchema,
        'context':
        ContextHeaderSchema,
        'actions':
        List(
            ActionRequestSchema,
    def test_validate_call(self):  # type: () -> None
        schema = Dictionary({
            'name': UnicodeString(max_length=20),
            'greeting': UnicodeString(),
        }, optional_keys=('greeting', ))

        @validate_call(schema, UnicodeString())
        def greeter(name, greeting='Hello'):
            # Special case to check return value stuff
            if name == 'error':
                return 5
            return '{}, {}!'.format(greeting, name)

        assert getattr(greeter, '__validated__') is True
        assert getattr(greeter, '__validated_schema_args__') is None
        assert getattr(greeter, '__validated_schema_kwargs__') is schema
        assert getattr(greeter, '__validated_schema_returns__') == UnicodeString()

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

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

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

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

        with self.assertRaises(PositionalError):
            greeter('Andrew')

        @validate_call(
            args=Tuple(Integer(), UnicodeString()),
            kwargs=None,
            returns=Null(),
        )
        def args_function(foo, bar):
            if foo:
                return bar.format(bar)

        assert getattr(args_function, '__validated__') is True
        assert getattr(args_function, '__validated_schema_args__') == Tuple(Integer(), UnicodeString())
        assert getattr(args_function, '__validated_schema_kwargs__') is None
        assert getattr(args_function, '__validated_schema_returns__') == Null()

        assert args_function(0, 'John {}') is None
        with pytest.raises(ValidationError):
            args_function(1, 'Jeff {}')
        with pytest.raises(ValidationError):
            args_function(0, b'Nope {}')
        with pytest.raises(ValidationError):
            args_function(0, bar='John {}')
        with pytest.raises(KeywordError):
            args_function(0, 'John {}', extra='Unsupported')

        @validate_call(
            args=Tuple(Integer(), UnicodeString()),
            kwargs=Dictionary({'extra': UnicodeString()}, optional_keys=('extra', )),
            returns=UnicodeString(),
        )
        def args_and_kwargs_function(foo, bar, extra='baz'):
            return bar.format(foo, extra)

        assert getattr(args_and_kwargs_function, '__validated__') is True
        assert getattr(args_and_kwargs_function, '__validated_schema_args__') == Tuple(Integer(), UnicodeString())
        assert (
            getattr(args_and_kwargs_function, '__validated_schema_kwargs__') ==
            Dictionary({'extra': UnicodeString()}, optional_keys=('extra', ))
        )
        assert getattr(args_and_kwargs_function, '__validated_schema_returns__') == UnicodeString()

        assert args_and_kwargs_function(0, 'John {}: {}') == 'John 0: baz'
        assert args_and_kwargs_function(1, 'Jeff {}: {}', extra='cool') == 'Jeff 1: cool'
        with pytest.raises(ValidationError):
            args_and_kwargs_function(1, 'Jeff {}: {}', 'cool')
        with pytest.raises(ValidationError):
            args_and_kwargs_function('nope', 'Jeff {}: {}')
        with pytest.raises(ValidationError):
            args_and_kwargs_function(1, b'nope')
        with pytest.raises(ValidationError):
            args_and_kwargs_function(0, bar='John {}: {}')
Example #20
0
 def test_warnings_returns_field_deprecation_warning(self):
     field = Deprecated(Integer(), 'This field has been deprecated')
     warnings = field.warnings(1)
     assert len(warnings) == 1
     assert warnings[0].code == WARNING_CODE_FIELD_DEPRECATED
     assert warnings[0].message == field.message
Example #21
0
 def test_introspect_adds_deprecated_field(self):
     field = Deprecated(Integer(), 'This field has been deprecated')
     introspection = field.introspect()
     assert 'deprecated' in introspection
     assert introspection['deprecated'] is True