валидатор схемы cerberus для кортежей

У меня есть объявление переменной следующим образом

my_var = typing.List[typing.Tuple[int, int]]

и я хочу написать валидатор следующим образом

schema_validator = "my_var": {
    "type": "list",
    "empty": False,
    "items": [
        {"type": "tuple"},
        {"items": [
            {"type": "int"}, {"type": "int"}
        ]}
    ]
}

В документации Cerberus не указан пример валидатора для tuples.

Как это сделать?


person co2f2e    schedule 21.08.2018    source источник
comment
Вы можете создать пользовательский тип данных.   -  person Sohaib Farooqi    schedule 21.08.2018


Ответы (2)


Учитывая ваш typevar typing.List[typing.Tuple[int, int]], вы ожидаете список произвольной длины кортежей с двумя значениями, где каждое значение является целым числом.

class MyValidator(Validator):
    # add a type definition to a validator subclass
    types_mapping = Validator.types_mapping.copy()
    types_mapping['tuple'] = TypeDefinition((tuple,), ())


schema = {
    'type': 'list',
    'empty': False,
    'schema': {  # the number of items is undefined
        'type': 'tuple',
        'items': 2 * ({'type': 'int'},)
    }
}

validator = MyValidator(schema)

Важно понимать разницу между элементами и правило схемы.

Имейте в виду, что тип list по умолчанию фактически соответствует более абстрактному типу Sequence и вы можете добавить для этого другой, более строгий тип.

person funky-future    schedule 26.08.2018

Хотя это не самое чистое решение, оно, безусловно, сделает то, что вы хотите.

from cerberus import Validator, TypeDefinition

class MyValidator(Validator):
    def __init__(self, *args, **kwargs):
        # Add the tuple type
        tuple_type = TypeDefinition("tuple", (tuple,), ())
        Validator.types_mapping["tuple"] = tuple_type
        # Call the Validator constructor
        super(MyValidator, self).__init__(*args, **kwargs)

    def _validate_is_int_two_tuple(self, is_int_two_tuple, field, value):
        ''' Test that the value is a 2-tuple of ints

        The rule's arguments are validated against this schema:
        {'type': 'boolean'}
        '''
        if is_int_two_tuple:
            # Check the type
            if type(value) != tuple:
                self._error(field, "Must be of type 'tuple'")
            # Check the length
            if len(value) != 2:
                self._error(field, "Tuple must have two elements")
            # Check the element types
            if type(value[0]) != int or type(value[1]) != int:
                self._error(field, "Both tuple values must be of type 'int'")

data = {"mylist": [(1,1), (2,2), (3,3)]}

schema = {
    "mylist": {
        "type": "list",
        "schema": {
            "type": "tuple",
            "is_int_two_tuple": True
        }
    }
}

v = MyValidator(schema)
print("Validated: {}".format(v.validate(data)))
print("Validation errors: {}".format(v.errors))
print("Normalized result: {}".format(v.normalized(data)))

Итак, как указал бро-граммер, пользовательские типы данных дадут вам проверку типов, но это все. Судя по предоставленной вами схеме, вы также хотите проверить другие функции, такие как длина кортежа и типы элементов в кортеже. Для этого требуется больше, чем просто TypeDefinition для кортежей.

Расширение Validator для включения правила для этого конкретного варианта использования не идеально, но оно будет делать то, что вы хотите. Более комплексным решением было бы создание подкласса TupleValidator с правилами проверки длины, типов элементов, порядка и т. д. кортежей.

person Flargebla    schedule 25.08.2018