Source code for decoutils

# -*- coding: utf-8 -*-

__version__ = '0.0.4'

import functools
import inspect
import sys

[docs]def decorator_with_args(func, return_original=False, target_pos=0): """Enable a function to work with a decorator with arguments Args: func (callable): The input function. return_original (bool): Whether the resultant decorator returns the decorating target unchanged. If True, will return the target unchanged. Otherwise, return the returned value from *func*. Default to False. This is useful for converting a non-decorator function to a decorator. See examples below. Return: callable: a decorator with arguments. Examples: >>> @decorator_with_args ... def register_plugin(plugin, arg1=1): ... print('Registering '+plugin.__name__+' with arg1='+str(arg1)) ... return plugin # note register_plugin is an ordinary decorator >>> @register_plugin(arg1=10) ... def plugin1(): pass Registering plugin1 with arg1=10 >>> @decorator_with_args(return_original=True) ... def register_plugin_xx(plugin, arg1=1): ... print('Registering '+plugin.__name__+' with arg1='+str(arg1)) ... # Note register_plugin_xxx does not return plugin, so it cannot ... # be used as a decorator directly before applying ... # decorator_with_args. >>> @register_plugin_xx(arg1=10) ... def plugin1(): pass Registering plugin1 with arg1=10 >>> plugin1() >>> @decorator_with_args(return_original=True) ... def register_plugin_xxx(plugin, arg1=1): pass >>> # use result decorator as a function >>> register_plugin_xxx(plugin=plugin1, arg1=10) <function plugin1...> >>> @decorator_with_args(return_original=True, target_pos=1) ... def register_plugin_xxxx(arg1, plugin, arg2=10): ... print('Registering '+plugin.__name__+' with arg1='+str(arg1)) >>> @register_plugin_xxxx(100) ... def plugin2(): pass Registering plugin2 with arg1=100 """ if sys.version_info[0] >= 3: target_name = inspect.getfullargspec(func).args[target_pos] else: target_name = inspect.getargspec(func).args[target_pos] @functools.wraps(func) def wrapper(*args, **kwargs): if len(args) > target_pos: res = func(*args, **kwargs) return args[target_pos] if return_original else res elif len(args) <= 0 and target_name in kwargs: res = func(*args, **kwargs) return kwargs[target_name] if return_original else res else: return wrap_with_args(*args, **kwargs) def wrap_with_args(*args, **kwargs): def wrapped_with_args(target): kwargs2 = dict() kwargs2[target_name] = target kwargs2.update(kwargs) res = func(*args, **kwargs2) return target if return_original else res return wrapped_with_args return wrapper
# make decorator_with_argument itself a decorator with arguments decorator_with_args = decorator_with_args(decorator_with_args)