Source code for hbutils.design.decorator

"""
Overview:
    Some useful utilities for decorator pattern and python decorators \
    for function or class.
"""
__all__ = ['decolize']

from functools import wraps, partial
from typing import Callable, Optional

from .singleton import SingletonMark

_NO_FUNC = SingletonMark('NO_FUNC_FOR_DECORATOR')


[docs]def decolize(deco: Callable[..., Callable]): """ Overview: Decorator for decorator, make a decorator function with keyword-arguments \ usable as the real python decorator. Arguments: - deco (:obj:`Callable[..., Callable]`): Decorator function to be decorated. Examples:: >>> from functools import wraps >>> @decolize # decorate the decorator ... def deco(func, a=1, b=2): ... @wraps(func) ... def _new_func(*args, **kwargs): ... return func(*args, **kwargs) * a + b ... ... return _new_func >>> @deco # used as simple decorator, same as deco(_func_1) >>> def _func_1(a, b, c): ... return (a + b * 2) * c >>> @deco(a=2) # used as parameterized decorator, same as deco(_func_2, a=2) >>> def _func_2(a, b, c): ... return (a + b * 2) * c >>> _func_1(1, 2, 3) 17 # ((1 + 2 * 2) * 3) * 1 + 2 == 17 >>> _func_2(1, 2, 3) 32 # ((1 + 2 * 2) * 3) * 2 + 2 == 32 .. tip:: This decorator can be useful when build a decorator with parameters. .. note:: In the decorated decorator, **only keyword arguments are supported**. \ So make sure the original decorator function's parameter (except ``func``) are \ all keyword supported, and do not try to use positional arguments when use it to \ decorator another function. """ @wraps(deco) def _new_deco(func: Optional[Callable] = _NO_FUNC, **kwargs): if func is _NO_FUNC: # used as parameterized decorator return partial(deco, **kwargs) else: # functional use return deco(func, **kwargs) return _new_deco