Уведомления

Группа в Telegram: @pythonsu

#1 Май 4, 2020 12:55:42

EvgIq
От:
Зарегистрирован: 2009-11-14
Сообщения: 57
Репутация: +  0  -
Профиль   Отправить e-mail  

ValidatedDC - датаклассы с валидацией данных

Понадобилось валидировать данные получаемые и отправляемые по api.
Сделал небольшую “надстройку” над датаклассом - датакласс ValidatedDC.

Валидируются аннотации:
1. Стандартные типы python и пользовательские классы
2. Некоторый алиасы из typing: Any, List, Literal, Optional, Union (можно добавить и другие, но для json-api пока без надобности). Эти алиасы могут быть вложены друг в друга, то есть можно описывать сложные структуры данных.
3. При инициализации экземпляра, если его поле имеет в аннотации потомка ValidatedDC, то в такое поле можно подставить словарь (или список словарей, если поле List), и если он будет валидный, то значение поля станет экземпляром потомка ValidatedDC из аннотации.

Пример:

   
from dataclasses import dataclass
from typing import List, Union
  
from validated_dc import ValidatedDC
  
  
# Some combinations of List and Union
  
@dataclass
class Foo(ValidatedDC):
    value: Union[int, List[int]]
  
  
@dataclass
class Bar(ValidatedDC):
    foo: Union[Foo, List[Foo]]
  
  
# --- Valid input ---
  
foo = {'value': 1}
instance = Bar(foo=foo)
assert instance.get_errors() is None
assert instance == Bar(foo=Foo(value=1))
  
foo = {'value': [1, 2]}
instance = Bar(foo=foo)
assert instance.get_errors() is None
assert instance == Bar(foo=Foo(value=[1, 2]))
  
foo = [{'value': 1}, {'value': 2}]
instance = Bar(foo=foo)
assert instance.get_errors() is None
assert instance == Bar(foo=[Foo(value=1), Foo(value=2)])
  
foo = [{'value': [1, 2]}, {'value': [3, 4]}]
instance = Bar(foo=foo)
assert instance.get_errors() is None
assert instance == Bar(foo=[Foo(value=[1, 2]), Foo(value=[3, 4])])
  
  
# --- Invalid input ---
  
foo = {'value': 'S'}
instance = Bar(foo=foo)
assert instance.get_errors()
assert instance == Bar(foo={'value': 'S'})
# fix
instance.foo['value'] = 1
assert instance.is_valid()
assert instance.get_errors() is None
assert instance == Bar(foo=Foo(value=1))
  
foo = [{'value': [1, 2]}, {'value': ['S', 4]}]
instance = Bar(foo=foo)
assert instance.get_errors()
assert instance == Bar(foo=[{'value': [1, 2]}, {'value': ['S', 4]}])
# fix
instance.foo[1]['value'][0] = 3
assert instance.is_valid()
assert instance.get_errors() is None
assert instance == Bar(foo=[Foo(value=[1, 2]), Foo(value=[3, 4])])
  
  
# --- get_errors() ---
  
foo = {'value': 'S'}
instance = Bar(foo=foo)
print(instance.get_errors())
# {
#   'foo': [
#       # An unsuccessful attempt to use the dictionary to create a Foo instance
#       InstanceValidationError(
#           value_repr="{'value': 'S'}",
#           value_type=<class 'dict'>,
#           annotation=<class '__main__.Foo'>,
#           exception=None,
#           errors={
#               'value': [
#                   BasicValidationError(  # because the str isn't an int
#                       value_repr='S', value_type=<class 'str'>,
#                       annotation=<class 'int'>, exception=None
#                   ),
#                   BasicValidationError(  # and the str is not a list of int
#                       value_repr='S', value_type=<class 'str'>,
#                       annotation=typing.List[int], exception=None
#                   )
#               ]
#           }
#       ),
#       BasicValidationError(  # the dict is not a list of Foo
#           value_repr="{'value': 'S'}",
#           value_type=<class 'dict'>,
#           annotation=typing.List[__main__.Foo],
#           exception=None
#       )
#   ]
# }

Подробнее тут:
https://github.com/EvgeniyBurdin/validated_dc



Отредактировано EvgIq (Май 7, 2020 12:03:13)

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version