"""
This module contains some generally useful function and method decorators.
"""
[docs]def sig(params, ret):
"""
Decorator for functions: decorates a function with parameter and return types.
Type checking is performed dynamically.
Typical use::
@sig([type_1, ..., type_n], type_ret)
def func(param_1, ..., param_n):
...
return ...
When invoking `func(arg_1, ..., arg_n)`, this decorator checks that `arg_i` is
an instance of `type_i`, and that the returned value is an instance of
`type_ret`.
:param params: list of parameter's types
:type params: type list
:param type ret: return type
:returns: A "typecheck" function which accepts as parameter a function f
and returns the decorated function.
:rtype: function decorator (function -> function)
"""
def typecheck(f):
def new_f(*args):
assert len(args) == len(params), "Wrong number of arguments in function %s: it has %d parameters, but %d arguments were passed." % (f.__name__, len(params), len(args))
i = 1
for arg, param in zip(args, params):
postfix = 'th' if i > 2 else 'nd' if i == 2 else 'st'
assert isinstance(arg, param), "Bad argument type in function %s: the %d-%s argument is of type %s, but the corresponding parameter must be of type %s." % (f.__name__, i, postfix, type(arg).__name__, param.__name__)
i += 1
result = f(*args)
assert isinstance(result, ret), "Bad return type in function %s: it returned a value of type %s but it should return a value of type %s" % (f.__name__, type(result).__name__, ret.__name__)
return result
return new_f
return typecheck
[docs]def msig(params, ret):
"""
Decorator for methods: decorates a method with parameter and return types.
Type checking is performed dynamically.
This is just like the sig decorator, but ignores the first argument.
Typical use::
@msig([type_1, ..., type_n], type_ret)
def meth(self, param_1, ..., param_n):
...
return ...
When invoking `func(arg_1, ..., arg_n)`, this decorator checks that `arg_i` is
an instance of `type_i`, and that the returned value is an instance of
`type_ret`.
:param params: list of parameter's types
:type params: type list
:param type ret: return type
:returns: A "typecheck" function which accepts as parameter a function f
and returns the decorated function.
:rtype: method decorator (method -> method)
"""
def typecheck(f):
def new_f(*args):
assert len(args) > 0, "Instance method %s called without an instance." % f.__name__
self = args[0]
assert len(args) - 1 == len(params), "Wrong number of arguments in method %s of class %s: it has %d parameters (excluding 'self'), but %d arguments were passed." % (f.__name__, self.__class__.__name__, len(params), len(args) - 1)
i = 1
for arg, param in zip(args[1:], params):
postfix = 'th' if i > 2 else 'nd' if i == 2 else 'st'
assert isinstance(arg, param), "Bad argument type in method %s of class %s: the %d-%s argument is of type %s, but the corresponding parameter must be of type %s." % (f.__name__, self.__class__.__name__, i, postfix, type(arg).__name__, param.__name__)
i += 1
result = f(*args)
assert isinstance(result, ret), "Bad return type in method %s of class %s: it returned a value of type %s but it should return a value of type %s" % (f.__name__, self.__class__.__name__, type(result).__name__, ret.__name__)
return result
return new_f
return typecheck