Factory for making preprocessing functions that check a predicate on the
    input value.

    Parameters
    ----------
    exc_type : Exception
        The exception type to raise if the predicate fails.
    template : str
        A template string to use to create error messages.
        Should have %-style named template parameters for 'funcname',
        'argname', and 'actual'.
    pred : function[object -> bool]
        A function to call on the argument being preprocessed.  If the
        predicate returns `True`, we raise an instance of `exc_type`.
    actual : function[object -> object]
        A function to call on bad values to produce the value to display in the
        error message.
    funcname : str or callable
        Name to use in error messages, or function to call on decorated
        functions to produce a name.  Passing an explicit name is useful when
        creating checks for __init__ or __new__ methods when you want the error
        to refer to the class name instead of the method name.

def make_check(exc_type, template, pred, actual, funcname):
    """
    Factory for making preprocessing functions that check a predicate on the
    input value.

    Parameters
    ----------
    exc_type : Exception
        The exception type to raise if the predicate fails.
    template : str
        A template string to use to create error messages.
        Should have %-style named template parameters for 'funcname',
        'argname', and 'actual'.
    pred : function[object -> bool]
        A function to call on the argument being preprocessed.  If the
        predicate returns `True`, we raise an instance of `exc_type`.
    actual : function[object -> object]
        A function to call on bad values to produce the value to display in the
        error message.
    funcname : str or callable
        Name to use in error messages, or function to call on decorated
        functions to produce a name.  Passing an explicit name is useful when
        creating checks for __init__ or __new__ methods when you want the error
        to refer to the class name instead of the method name.
    """
    if isinstance(funcname, str):
        def get_funcname(_):
            return funcname
    else:
        get_funcname = funcname

    def _check(func, argname, argvalue):
        if pred(argvalue):
            raise exc_type(
                template % {
                    'funcname': get_funcname(func),
                    'argname': argname,
                    'actual': actual(argvalue),
                },
            )
        return argvalue
    return _check