Source code for drytools.annotation.functions


'''
=====================================================
annotation.functions - Coerce and validate parameters
=====================================================

When the :func:`drytools.annotation.composition.compose_annotations` decorator
is used, these functions can he used as annotations to coerce and/or
validate parameters.

'''
from collections.abc import Iterable

'''
Validation
----------
'''
[docs]def check(predicate, *args, raises=ValueError, **kwargs): ''' Factory for univariate validation functions Args: predicate (*callable*): Function returning True if the input value is valid, False otherwise. The value to be checked is used as the first argument. Additional (constant) arguments can be supplied in *args* and *kwargs* (see example). raises (*callable*): Constructor for :class:`Exception` to raise if *predicate* returns False args, kwargs: additional arguments for predicate Returns: func: Identity function (ie: returns the value passed to it) except that it raises *exception_type* if *predicate* returns False when applied to its input value. Example: >>> from operator import gt >>> check_positive = check(gt, 0) >>> check_positive(5) 5 >>> check_positive(-3) Traceback (most recent call last): ... ValueError: -3 ''' def checked_passthrough(x): if not predicate(x, *args, **kwargs): raise raises(x) return x return checked_passthrough
''' Coercion -------- In addition to the functions below, types (eg: :class:`int`, :class:`str`, :class:`pathlib.Path`) are useful for coercion. '''
[docs]def iterify(x, excluded_types=str): ''' Coerce to an iterable Args: x: Object to coerce excluded_types (:class:`type` or iterable): one or more types to treat as elements even if they are iterable Returns: *iterable*: Either *x* (if it's iterable and not one of *excluded_types*) or a single-element list containing *x* Example: >>> list(iterify('foo')) ['foo'] >>> list(iterify('foo', excluded_types={})) ['f', 'o', 'o'] >>> iterify(['foo', 'bar', 'baz']) ['foo', 'bar', 'baz'] ''' if not isinstance(excluded_types, Iterable): excluded_types = [excluded_types] ok = isinstance(x, Iterable) and (not any(isinstance(x, t) for t in excluded_types)) return x if ok else [x]
if __name__ == '__main__': import doctest doctest.testmod()