Source code for validx.contracts

# coding: utf-8

from .compat.colabc import Container, Sequence, Mapping, Callable
from .compat.frozendict import frozendict
from .compat.types import chars, basestr


[docs]def expect( obj, attr, value, nullable=False, types=None, not_types=None, convert_to=None ): """ Check, whether the value satisfies expectations :param obj: an object, which will set the value to its attribute. It is used to make error messages more specific. :param str attr: name of an attribute of the object. It is used to make error messages more specific. :param value: checked value itself. :param bool nullable: accept ``None`` as a valid value. Default: ``False`` — does not accept ``None``. :param types: define acceptable types of the value. Default: ``None`` — accept any type. :type types: None, type or tuple :param not_types: define implicitly unacceptable types of the value. Default: ``None`` — accept any type. :type types: None, type or tuple :param type convert_to: convert the value to specified type. Default: ``None`` — does not convert the value. :raises TypeError: * if ``types is not None`` and ``not isinstance(value, types)``; * if ``not_types is not None`` and ``isinstance(value, not_types)``. """ if nullable and value is None: return value if types is not None and not isinstance(value, types): raise TypeError( "%s.%s.%s should be of type %r" % (obj.__class__.__module__, obj.__class__.__name__, attr, types) ) if not_types is not None and isinstance(value, not_types): raise TypeError( "%s.%s.%s should not be of type %r" % (obj.__class__.__module__, obj.__class__.__name__, attr, not_types) ) if convert_to is not None and not isinstance(value, convert_to): value = convert_to(value) return value
[docs]def expect_flag(obj, attr, value): """ Check, whether the value satisfies expectations of boolean flag :param obj: an object, which will set the value to its attribute. It is used to make error messages more specific. :param str attr: name of an attribute of the object. It is used to make error messages more specific. :param value: checked value itself. :param bool nullable: accept ``None`` as a valid value. Default: ``False`` — does not accept ``None``. :raises TypeError: if ``not isinstance(value, (bool, int, type(None)))``. """ return expect(obj, attr, value, types=(bool, int, type(None)), convert_to=bool)
[docs]def expect_length(obj, attr, value, nullable=False): """ Check, whether the value satisfies expectations of integer length :param obj: an object, which will set the value to its attribute. It is used to make error messages more specific. :param str attr: name of an attribute of the object. It is used to make error messages more specific. :param value: checked value itself. :param bool nullable: accept ``None`` as a valid value. Default: ``False`` — does not accept ``None``. :raises TypeError: if ``not isinstance(value, int)``. :raises ValueError: if ``value < 0``. """ value = expect(obj, attr, value, nullable=nullable, types=int) if value is not None: if value < 0: raise ValueError( "%s.%s.%s should not be negative number" % (obj.__class__.__module__, obj.__class__.__name__, attr) ) return value
[docs]def expect_basestr(obj, attr, value, nullable=False): """ Check, whether the value satisfies expectations of base string :param obj: an object, which will set the value to its attribute. It is used to make error messages more specific. :param str attr: name of an attribute of the object. It is used to make error messages more specific. :param value: checked value itself. :param bool nullable: accept ``None`` as a valid value. Default: ``False`` — does not accept ``None``. :raises TypeError: * if ``not isinstance(value, str)`` (Python 3.x); * if ``not isinstance(value, basestring)`` (Python 2.x). """ return expect(obj, attr, value, nullable=nullable, types=basestr)
[docs]def expect_callable(obj, attr, value, nullable=False): """ Check, whether the value satisfies expectations of callable :param obj: an object, which will set the value to its attribute. It is used to make error messages more specific. :param str attr: name of an attribute of the object. It is used to make error messages more specific. :param value: checked value itself. :param bool nullable: accept ``None`` as a valid value. Default: ``False`` — does not accept ``None``. :raises TypeError: if ``not isinstance(value, collections.abc.Callable)``. """ return expect(obj, attr, value, nullable=nullable, types=Callable)
[docs]def expect_container(obj, attr, value, nullable=False, empty=False, item_type=None): """ Check, whether the value satisfies expectations of container :param obj: an object, which will set the value to its attribute. It is used to make error messages more specific. :param str attr: name of an attribute of the object. It is used to make error messages more specific. :param value: checked value itself. :param bool nullable: accept ``None`` as a valid value. Default: ``False`` — does not accept ``None``. :param bool empty: accept empty container as a valid value. Default: ``False`` — does not accept empty container. :param type item_type: check, whether each item of the container has specified type. Default: ``None`` — does not check items. :raises TypeError: * if ``not isinstance(value, collections.abc.Container)``; * if ``isinstance(value, (str, bytes))`` (Python 3.x); * if ``isinstance(value, (unicode, bytes))`` (Python 2.x); * if ``item_type is not None`` and ``isinstance(item, item_type)``, ``for item in value``. :raises ValueError: if ``not empty`` and ``not value``. :returns: passed container converted to ``frozenset``, if items are hashable, otherwise to ``tuple``. """ value = expect( obj, attr, value, nullable=nullable, types=Container, not_types=chars ) if value is not None: if not isinstance(value, frozenset): try: value = frozenset(value) except TypeError: # Unhashable type, fallback to tuple value = tuple(value) if not value and not empty: raise ValueError( "%s.%s.%s should not be empty" % (obj.__class__.__module__, obj.__class__.__name__, attr) ) if item_type is not None: for item in value: if not isinstance(item, item_type): raise TypeError( "%s.%s.%s items should be of type %r, got %r" % ( obj.__class__.__module__, obj.__class__.__name__, attr, item_type, type(item), ) ) return value
[docs]def expect_sequence(obj, attr, value, nullable=False, empty=False, item_type=None): """ Check, whether the value satisfies expectations of sequence :param obj: an object, which will set the value to its attribute. It is used to make error messages more specific. :param str attr: name of an attribute of the object. It is used to make error messages more specific. :param value: checked value itself. :param bool nullable: accept ``None`` as a valid value. Default: ``False`` — does not accept ``None``. :param bool empty: accept empty sequence as a valid value. Default: ``False`` — does not accept empty sequence. :param type item_type: check, whether each item of the sequence has specified type. Default: ``None`` — does not check items. :raises TypeError: * if ``not isinstance(value, collections.abc.Sequence)``; * if ``isinstance(value, (str, bytes))`` (Python 3.x); * if ``isinstance(value, (unicode, bytes))`` (Python 2.x); * if ``item_type is not None`` and ``isinstance(item, item_type)``, ``for item in value``. :raises ValueError: if ``not empty`` and ``not value``. :returns: passed sequence converted to ``tuple``. """ value = expect( obj, attr, value, nullable=nullable, types=Sequence, not_types=chars, convert_to=tuple, ) if value is not None: if not value and not empty: raise ValueError( "%s.%s.%s should not be empty" % (obj.__class__.__module__, obj.__class__.__name__, attr) ) if item_type is not None: for n, item in enumerate(value): if not isinstance(item, item_type): raise TypeError( "%s.%s.%s[%s] value should be of type %r" % ( obj.__class__.__module__, obj.__class__.__name__, attr, n, item_type, ) ) return value
[docs]def expect_mapping(obj, attr, value, nullable=False, empty=False, value_type=None): """ Check, whether the value satisfies expectations of mapping :param obj: an object, which will set the value to its attribute. It is used to make error messages more specific. :param str attr: name of an attribute of the object. It is used to make error messages more specific. :param value: checked value itself. :param bool nullable: accept ``None`` as a valid value. Default: ``False`` — does not accept ``None``. :param bool empty: accept empty mapping as a valid value. Default: ``False`` — does not accept empty mapping. :param type value_type: check, whether each value of the mapping has specified type. Default: ``None`` — does not check items. :raises TypeError: * if ``not isinstance(value, collections.abc.Sequence)``; * if ``isinstance(value, (str, bytes))`` (Python 3.x); * if ``isinstance(value, (unicode, bytes))`` (Python 2.x); * if ``value_type is not None`` and ``isinstance(val, value_type)``, ``for key, val in value.items()``. :raises ValueError: if ``not empty`` and ``not value``. :returns: passed mapping converted to ``frozendict``. """ value = expect( obj, attr, value, nullable=nullable, types=Mapping, convert_to=frozendict ) if value is not None: if not value and not empty: raise ValueError( "%s.%s.%s should not be empty" % (obj.__class__.__module__, obj.__class__.__name__, attr) ) if value_type is not None: for key, val in value.items(): if not isinstance(val, value_type): raise TypeError( "%s.%s.%s[%r] value should be of type %r" % ( obj.__class__.__module__, obj.__class__.__name__, attr, key, value_type, ) ) return value
[docs]def expect_tuple(obj, attr, value, struct, nullable=False): """ Check, whether the value satisfies expectations of tuple of specific structure :param obj: an object, which will set the value to its attribute. It is used to make error messages more specific. :param str attr: name of an attribute of the object. It is used to make error messages more specific. :param value: checked value itself. :param tuple struct: tuple of types. :param bool nullable: accept ``None`` as a valid value. Default: ``False`` — does not accept ``None``. :raises TypeError: * if ``not isinstance(value, collections.abc.Sequence)``; * if ``isinstance(value, (str, bytes))`` (Python 3.x); * if ``isinstance(value, (unicode, bytes))`` (Python 2.x); * if ``not isinstance(item, item_type)``, ``for item_type, item in zip(struct, value)``. :raises ValueError: if ``len(value) != len(struct)``. :returns: passed sequence converted to ``tuple``. """ value = expect( obj, attr, value, nullable=nullable, types=Sequence, not_types=chars, convert_to=tuple, ) if value is not None: if len(value) != len(struct): raise ValueError( "%s.%s.%s should be a tuple of %r" % (obj.__class__.__module__, obj.__class__.__name__, attr, struct) ) for n, (item_type, item) in enumerate(zip(struct, value)): if not isinstance(item, item_type): raise TypeError( "%s.%s.%s[%s] value should be of type %r" % ( obj.__class__.__module__, obj.__class__.__name__, attr, n, item_type, ) ) return value