Voluptuous库笔记

特别好用的python数据校验库

参考文档:http://alecthomas.github.io/voluptuous/

一、Scheme类 基本Python数据模式校验

Scheme类初始化方法
接受需要校验的数据作为参数,required为True参数表示模式中定义的数据结构必须包含在scheme,extra表示如果数据包含校验模式定义中没有的结构时如何处理

options for extra keys
PREVENT_EXTRA = 0  # any extra key not in schema will raise an error
ALLOW_EXTRA = 1  # extra keys not in schema will be included in output
REMOVE_EXTRA = 2  # extra keys not in schema will be excluded from output

def __init__(self, schema, required=False, extra=PREVENT_EXTRA):
    """Create a new Schema.

    :param schema: Validation schema. See :module:`voluptuous` for details.
    :param required: Keys defined in the schema must be in the data.
    :param extra: Specify how extra keys in the data are treated:
        - :const:`~voluptuous.PREVENT_EXTRA`: to disallow any undefined
          extra keys (raise ``Invalid``).
        - :const:`~voluptuous.ALLOW_EXTRA`: to include undefined extra
          keys in the output.
        - :const:`~voluptuous.REMOVE_EXTRA`: to exclude undefined extra keys
          from the output.
        - Any value other than the above defaults to
          :const:`~voluptuous.PREVENT_EXTRA`
    """
    self.schema = schema
    self.required = required
    self.extra = int(extra)  # ensure the value is an integer
    self._compiled = self._compile(schema)

可调用校验对象
实现call方法,使得类实例对象变成可调用对象,接受需要校验的数据作为参数,返回校验通过后的数据或抛出异常

def __call__(self, data):
    """Validate data against this schema."""
    try:
        return self._compiled([], data)
    except er.MultipleInvalid:
        raise
    except er.Invalid as e:
        raise er.MultipleInvalid([e])
        # return self.validate([], self.schema, data)
scheme可以校验哪些数据模式
def _compile(self, schema):
        if schema is Extra:
            return lambda _, v: v
        if isinstance(schema, Object):
            return self._compile_object(schema)
        if isinstance(schema, collections.Mapping) and len(schema):
            return self._compile_dict(schema)
        elif isinstance(schema, list) and len(schema):
            return self._compile_list(schema)
        elif isinstance(schema, tuple):
            return self._compile_tuple(schema)
        type_ = type(schema)
        if type_ is type:
            type_ = schema
        if type_ in (bool, int, long, str, unicode, float, complex, object,
                     list, dict, type(None)) or callable(schema):
            return _compile_scalar(schema)
        raise er.SchemaError('unsupported schema data type %r' %
                             type(schema).__name__)

Extra
Object
collections.Mapping(长度大于0)
list(长度大于0)
tuple
bool, int, long, str, unicode, float, complex, object,list(长度为0), dict(长度为0), type(None), callable

二、Mark类 高级数据模式校验

Mark类 定义
组合Scheme类对象,扩展类功能

class Marker(object):
    """Mark nodes for special treatment."""

    def __init__(self, schema_, msg=None):
        try:
            from util import to_utf8_py2
        except ImportError:
            from .util import to_utf8_py2
        schema_ = to_utf8_py2(schema_)
        self.schema = schema_
        self._schema = Schema(schema_)
        self.msg = msg

    def __call__(self, v):
        try:
            return self._schema(v)
        except er.Invalid as e:
            if not self.msg or len(e.path) > 1:
                raise
            raise er.Invalid(self.msg)

    def __str__(self):
        return str(self.schema)

    def __repr__(self):
        return repr(self.schema)

    def __lt__(self, other):
        return self.schema < other.schema

Optional类
定义某个字段为可选模式,或者提供默认值

class Optional(Marker):
    """Mark a node in the schema as optional, and optionally provide a default

    >>> schema = Schema({Optional('key'): str})
    >>> schema({})
    {}
    >>> schema = Schema({Optional('key', default='value'): str})
    >>> schema({})
    {'key': 'value'}
    >>> schema = Schema({Optional('key', default=list): list})
    >>> schema({})
    {'key': []}

    If 'required' flag is set for an entire schema, optional keys aren't required

    >>> schema = Schema({
    ...    Optional('key'): str,
    ...    'key2': str
    ... }, required=True)
    >>> schema({'key2':'value'})
    {'key2': 'value'}
    """

    def __init__(self, schema, msg=None, default=UNDEFINED):
        super(Optional, self).__init__(schema, msg=msg)
        self.default = default_factory(default)

Exclusive类
定义某组字段如果有,则有且只能有一个

class Exclusive(Optional):
    """Mark a node in the schema as exclusive.

    Exclusive keys inherited from Optional:

    >>> schema = Schema({Exclusive('alpha', 'angles'): int, Exclusive('beta', 'angles'): int})
    >>> schema({'alpha': 30})
    {'alpha': 30}

    Keys inside a same group of exclusion cannot be together, it only makes sense for dictionaries:

    >>> with raises(er.MultipleInvalid, "two or more values in the same group of exclusion 'angles' @ data[<angles>]"):
    ...   schema({'alpha': 30, 'beta': 45})

    For example, API can provides multiple types of authentication, but only one works in the same time:

    >>> msg = 'Please, use only one type of authentication at the same time.'
    >>> schema = Schema({
    ... Exclusive('classic', 'auth', msg=msg):{
    ...     Required('email'): basestring,
    ...     Required('password'): basestring
    ...     },
    ... Exclusive('internal', 'auth', msg=msg):{
    ...     Required('secret_key'): basestring
    ...     },
    ... Exclusive('social', 'auth', msg=msg):{
    ...     Required('social_network'): basestring,
    ...     Required('token'): basestring
    ...     }
    ... })

    >>> with raises(er.MultipleInvalid, "Please, use only one type of authentication at the same time. @ data[<auth>]"):
    ...     schema({'classic': {'email': 'foo@example.com', 'password': 'bar'},
    ...             'social': {'social_network': 'barfoo', 'token': 'tEMp'}})
    """

    def __init__(self, schema, group_of_exclusion, msg=None):
        super(Exclusive, self).__init__(schema, msg=msg)
        self.group_of_exclusion = group_of_exclusion

Inclusive类
定义某组字段如果有,则必须同时有

class Inclusive(Optional):
    """ Mark a node in the schema as inclusive.

    Inclusive keys inherited from Optional:

    >>> schema = Schema({
    ...     Inclusive('filename', 'file'): str,
    ...     Inclusive('mimetype', 'file'): str
    ... })
    >>> data = {'filename': 'dog.jpg', 'mimetype': 'image/jpeg'}
    >>> data == schema(data)
    True

    Keys inside a same group of inclusive must exist together, it only makes sense for dictionaries:

    >>> with raises(er.MultipleInvalid, "some but not all values in the same group of inclusion 'file' @ data[<file>]"):
    ...     schema({'filename': 'dog.jpg'})

    If none of the keys in the group are present, it is accepted:

    >>> schema({})
    {}

    For example, API can return 'height' and 'width' together, but not separately.

    >>> msg = "Height and width must exist together"
    >>> schema = Schema({
    ...     Inclusive('height', 'size', msg=msg): int,
    ...     Inclusive('width', 'size', msg=msg): int
    ... })

    >>> with raises(er.MultipleInvalid, msg + " @ data[<size>]"):
    ...     schema({'height': 100})

    >>> with raises(er.MultipleInvalid, msg + " @ data[<size>]"):
    ...     schema({'width': 100})

    >>> data = {'height': 100, 'width': 100}
    >>> data == schema(data)
    True
    """

    def __init__(self, schema, group_of_inclusion, msg=None):
        super(Inclusive, self).__init__(schema, msg=msg)
        self.group_of_inclusion = group_of_inclusion

Required类
定义某个字段必须有

class Required(Marker):
    """Mark a node in the schema as being required, and optionally provide a default value.

    >>> schema = Schema({Required('key'): str})
    >>> with raises(er.MultipleInvalid, "required key not provided @ data['key']"):
    ...   schema({})

    >>> schema = Schema({Required('key', default='value'): str})
    >>> schema({})
    {'key': 'value'}
    >>> schema = Schema({Required('key', default=list): list})
    >>> schema({})
    {'key': []}
    """

    def __init__(self, schema, msg=None, default=UNDEFINED):
        super(Required, self).__init__(schema, msg=msg)
        self.default = default_factory(default)

Remove类
移除指定的字段

class Remove(Marker):
    """Mark a node in the schema to be removed and excluded from the validated
    output. Keys that fail validation will not raise ``Invalid``. Instead, these
    keys will be treated as extras.

    >>> schema = Schema({str: int, Remove(int): str})
    >>> with raises(er.MultipleInvalid, "extra keys not allowed @ data[1]"):
    ...    schema({'keep': 1, 1: 1.0})
    >>> schema({1: 'red', 'red': 1, 2: 'green'})
    {'red': 1}
    >>> schema = Schema([int, Remove(float), Extra])
    >>> schema([1, 2, 3, 4.0, 5, 6.0, '7'])
    [1, 2, 3, 5, '7']
    """

    def __call__(self, v):
        super(Remove, self).__call__(v)
        return self.__class__

    def __repr__(self):
        return "Remove(%r)" % (self.schema,)

三、validate装饰器

函数参数和返回值校验

def validate(*a, **kw):
    """Decorator for validating arguments of a function against a given schema.

    Set restrictions for arguments:

        >>> @validate(arg1=int, arg2=int)
        ... def foo(arg1, arg2):
        ...   return arg1 * arg2

    Set restriction for returned value:

        >>> @validate(arg=int, __return__=int)
        ... def bar(arg1):
        ...   return arg1 * 2

    """
    RETURNS_KEY = '__return__'

    def validate_schema_decorator(func):

        returns_defined = False
        returns = None

        schema_args_dict = _args_to_dict(func, a)
        schema_arguments = _merge_args_with_kwargs(schema_args_dict, kw)

        if RETURNS_KEY in schema_arguments:
            returns_defined = True
            returns = schema_arguments[RETURNS_KEY]
            del schema_arguments[RETURNS_KEY]

        input_schema = Schema(schema_arguments) if len(schema_arguments) != 0 else lambda x: x
        output_schema = Schema(returns) if returns_defined else lambda x: x

        @wraps(func)
        def func_wrapper(*args, **kwargs):
            args_dict = _args_to_dict(func, args)
            arguments = _merge_args_with_kwargs(args_dict, kwargs)
            validated_arguments = input_schema(arguments)
            output = func(**validated_arguments)
            return output_schema(output)

        return func_wrapper

    return validate_schema_decorator

四、常用数据转换和校验

常用数据转换函数
voluptuous.util
Lower
Upper
Capitalize
Strip
DefaultTo
SetTo
Set
常用校验函数,校验不通过抛出异常
voluptuous.validators
Url
IsFile
IsDir
PathExists
Range
Clamp
Datetime
Date
In
NotIn
Number

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值