Пример #1
0
def returns(return_type):
    """
    Assert that function returns value of specific type

    Example:

        @returns(int)
        def get_random_number():
            return 4  # http://xckd.com/221/

    See module documentation for more information about type signatures.

    """
    _check_constraint_validity(return_type)

    def deco(fn):
        if not conf._decorator_enabled:
            return fn

        if not hasattr(fn, '__def__site__'):
            if hasattr(fn, '__code__'):
                fc = fn.__code__
            else:
                fc = fn.func_code
            fn.__def_site__ = (fc.co_filename, fc.co_firstlineno, fn.__name__,
                               '')

        def wrapper(*args, **kwargs):
            retval = fn(*args, **kwargs)
            if conf._enabled:
                if retval is None and return_type is not type(None):
                    _type_error("non-void function didn't return a value",
                                stack=fn.__def_site__)
                elif retval is not None and return_type is type(None):
                    _type_error("void function returned a value",
                                stack=fn.__def_site__)
                elif not _verify_type_constraint(retval, return_type):
                    _type_error("function returned value %s not matching "
                                "signature %s" % (repr(retval),
                                                  _constraint_to_string(return_type)),
                                stack=fn.__def_site__)
            return retval

        wrapper.__name__ = fn.__name__
        wrapper.__doc__ = fn.__doc__
        wrapper.__return_type__ = return_type
        return wrapper

    return deco
Пример #2
0
def params(**types):
    """
    Assert that function is called with arguments of correct types

    Example:

        @params(a=int)
        def double(a):
            return a * 2

    See module documentation for more information about type signatures.

    Note: this decorator must be used directly on the function being annotated
    (ie. there should be no other decorators "between" this one and the
    function), because it inspects the function argument declarations.

    This means that, if using both @returns and @params, @returns must go
    first, as in this example:

        @returns(int)
        @params(a=int, b=int)
        def add(a, b):
            return a + b

    """

    for arg_name, arg_type in types.items():
        _check_constraint_validity(arg_type)

    def deco(fn):
        if not conf._decorator_enabled:
            return fn

        if hasattr(fn, "__return_type__"):
            raise TypeError("You must use @returns before @params")

        if hasattr(fn, "__code__"):
            fc = fn.__code__
        else:
            fc = fn.func_code

        if not hasattr(fn, "__def__site__"):
            fn.__def_site__ = (fc.co_filename, fc.co_firstlineno, fn.__name__, "")

        arg_names = fc.co_varnames[: fc.co_argcount]
        if any(arg not in arg_names for arg in types.keys()) or any(arg not in types for arg in arg_names):
            raise TypeError("Annotation doesn't match function signature")

        def wrapper(*args, **kwargs):
            if conf._enabled:
                for arg, name in zip(args, arg_names):
                    if not _verify_type_constraint(arg, types[name]):
                        _type_error(
                            "argument %s = %s doesn't match "
                            "signature %s" % (name, repr(arg), _constraint_to_string(types[name]))
                        )

                for k, v in kwargs.items():
                    if k not in types:
                        _type_error("unknown keyword argument %s " "(positional specified as keyword?)" % k)
                    if not _verify_type_constraint(v, types[k]):
                        _type_error(
                            "keyword argument %s = %s "
                            "doesn't match signature %s" % (k, repr(v), _constraint_to_string(types[k]))
                        )
            return fn(*args, **kwargs)

        wrapper.__name__ = fn.__name__
        wrapper.__doc__ = fn.__doc__
        return wrapper

    return deco