Source code for verify.containers

"""Assertions related to containers/iterables.
"""

import operator

import pydash

from .base import Assertion, Comparator, Negate
from .numbers import Between


__all__ = (
    'In',
    'NotIn',
    'Contains',
    'NotContains',
    'ContainsOnly',
    'NotContainsOnly',
    'Subset',
    'NotSubset',
    'Superset',
    'NotSuperset',
    'Unique',
    'NotUnique',
    'Length',
    'NotLength',
)


[docs]class In(Comparator): """Asserts that `value` is in `comparable`. Aliases: - ``to_be_in`` - ``is_in`` .. versionadded:: 0.0.1 """ #: reason = '{0} is not in {comparable}' @staticmethod def op(value, comparable): """Return whether `value` is contained in `comparable`.""" try: return value in comparable except (TypeError, ValueError): return False
to_be_in = In is_in = In
[docs]class NotIn(Negate, In): """Asserts that `value` is not in `comparable`. Aliases: - ``to_not_be_in`` - ``is_not_in`` .. versionadded:: 0.5.0 """ #: reason = '{0} is in {comparable}'
to_not_be_in = NotIn is_not_in = NotIn
[docs]class Contains(Comparator): """Asserts that `value` is an iterable and contains `comparable`. Aliases: - ``to_contain`` - ``contains`` .. versionadded:: 0.2.0 """ #: reason = '{0} does not contain {comparable}' @staticmethod def op(value, comparable): """Return whether `value` contains `comparable`.""" try: return comparable in value except (TypeError, ValueError): return False
to_contain = Contains contains = Contains
[docs]class NotContains(Negate, Contains): """Asserts that `value` does not contain `comparable`. Aliases: - ``to_not_contain`` - ``does_not_contain`` .. versionadded:: 0.5.0 """ #: reason = '{0} contains {comparable}'
to_not_contain = NotContains does_not_contain = NotContains
[docs]class ContainsOnly(Comparator): """Asserts that `value` is an iterable and only contains `comparable`. Aliases: - ``to_contain_only`` - ``contains_only`` .. versionadded:: 0.2.0 """ #: reason = '{0} does not only contain values in {comparable}' @staticmethod def op(value, comparable): """Return whether `value` contains only values in `comparable`.""" try: return all(val in comparable for val in value) except (TypeError, ValueError): return False
to_contain_only = ContainsOnly contains_only = ContainsOnly
[docs]class NotContainsOnly(Negate, ContainsOnly): """Asserts that `value` does not contain only `comparable`. Aliases: - ``to_not_contain_only`` - ``does_not_contain_only`` .. versionadded:: 0.5.0 """ #: reason = '{0} contains only {comparable}'
to_not_contain_only = NotContainsOnly does_not_contain_only = NotContainsOnly
[docs]class Subset(Comparator): """Asserts that `value` is a subset of `comparable`. Comparison supports nested ``dict``, ``list``, and ``tuple`` objects. Aliases: - ``to_be_subset`` - ``is_subset`` .. versionadded:: 0.3.0 """ #: reason = '{0} is not a subset of {comparable}' op = pydash.rearg(pydash.is_match, 1, 0)
to_be_subset = Subset is_subset = Subset
[docs]class NotSubset(Negate, Subset): """Asserts that `value` is a not a subset of `comparable`. Aliases: - ``to_not_be_subset`` - ``is_not_subset`` .. versionadded:: 0.5.0 """ #: reason = '{0} is a subset of {comparable}'
to_not_be_subset = NotSubset is_not_subset = NotSubset
[docs]class Superset(Comparator): """Asserts that `value` is a superset of `comparable`. Comparison supports nested ``dict``, ``list``, and ``tuple`` objects. Aliases: - ``to_be_superset`` - ``is_superset`` .. versionadded:: 0.3.0 """ #: reason = '{0} is not a supserset of {comparable}' op = staticmethod(pydash.is_match)
to_be_superset = Superset is_superset = Superset
[docs]class NotSuperset(Negate, Superset): """Asserts that `value` is a not a superset of `comparable`. Aliases: - ``to_not_be_superset`` - ``is_not_superset`` .. versionadded:: 0.5.0 """ #: reason = '{0} is a superset of {comparable}'
to_not_be_superset = NotSuperset is_not_superset = NotSuperset
[docs]class Unique(Assertion): """Asserts that `value` contains only unique values. If `value` is a ``dict``, then its ``values()`` will be compared. Aliases: - ``to_be_unique`` - ``is_unique`` .. versionadded:: 0.3.0 """ #: reason = '{0} contains duplicate items' @staticmethod def op(value): if isinstance(value, dict): value = value.values() is_unique = True seen = [] for item in value: if item in seen: is_unique = False break seen.append(item) return is_unique
to_be_unique = Unique is_unique = Unique
[docs]class NotUnique(Negate, Unique): """Asserts that `value` is a not a unique. Aliases: - ``to_not_be_unique`` - ``is_not_unique`` .. versionadded:: 0.5.0 """ #: reason = '{0} is unique'
to_not_be_unique = NotUnique is_not_unique = NotUnique
[docs]class Length(Between): """Asserts that `value` is an iterable with length between `min` and `max` inclusively. Examples: These will pass: >>> assert Length([1, 2, 3], min=3, max=3) # 3 <= len(a) <= 3 >>> assert Length([1, 2, 3, 4, 5], min=5, max=6) # 5 <= len(a) <= 6 >>> assert Length([1, 2, 3], max=6) # len(a) <= 6 >>> assert Length([1, 2, 3, 4], min=4) # len(a) >= 4 This will fail: >>> Length([1, 2, 4], max=2) # len(a) <= 2 Traceback (most recent call last): ... AssertionError... Args: value (mixed, optional): Value to compare. Keyword Args: min (int, optional): Minimum value that `value` must be greater than or equal to. max (int, optional): Maximum value that `value` must be less than or equal to. Aliases: - ``to_have_length`` - ``has_length`` .. versionadded:: 0.2.0 .. versionchanged:: 0.4.0 - Change comparison to function like :class:`Between` meaning length is compared to min and max values. - Allow keyword arguments ``min`` and ``max`` to be used in place of positional tuple .. versionchanged:: 1.0.0 Removed positional tuple argument and only support ``min`` and ``max`` keyword arguments. """ #: reason = '{0} does not have length between {min} and {max}' @staticmethod def op(value, min=None, max=None): try: return Between.op(len(value), min=min, max=max) except (TypeError, ValueError): return False
to_have_length = Length has_length = Length
[docs]class NotLength(Negate, Length): """Asserts that `value` is an iterable with length not between `min` and `max` inclusively. Aliases: - ``to_not_have_length`` - ``does_not_have_length`` .. versionadded:: 1.0.0 """ #: reason = '{0} has length between {min} and {max}'
to_not_have_length = NotLength does_not_have_length = NotLength