diff options
Diffstat (limited to 'logilab')
-rw-r--r-- | logilab/common/deprecation.py | 50 |
1 files changed, 44 insertions, 6 deletions
diff --git a/logilab/common/deprecation.py b/logilab/common/deprecation.py index 5dc23f7..ff6dc7c 100644 --- a/logilab/common/deprecation.py +++ b/logilab/common/deprecation.py @@ -22,7 +22,45 @@ __docformat__ = "restructuredtext en" import os import sys from warnings import warn -from functools import wraps +from functools import WRAPPER_ASSIGNMENTS, WRAPPER_UPDATES, wraps + + +def lazy_wraps(wrapped): + """ + This is the equivalent of the @wraps decorator of functools except it won't + try to grabs attributes of the targeted function on decoration but on access. + + This is needed because of logilab.common.modutils.LazyObject. + + Indeed: if you try to decorate a LazyObject with @wraps, wraps will try to + access attributes of LazyObject and this will trigger the attempt to import + the module decorated by LazyObject which you don't want to do when you just + want to mark this LazyObject has been a deprecated objet that you only + wants to trigger if the user try to use it. + + Usage: like @wraps() + + >>> @lazy_wraps(function) + >>> def wrapper(*args, **kwargs): ... + """ + + def update_wrapper_attributes(wrapper): + def __getattribute__(self, attribute): + if attribute in WRAPPER_ASSIGNMENTS: + return getattr(wrapped, attribute) + + return super(self.__class__, self).__getattribute__(attribute) + + wrapper.__getattribute__ = __getattribute__ + + for attribute in WRAPPER_UPDATES: + getattr(wrapper, attribute).update(getattr(wrapped, attribute, {})) + + wrapper.__wrapped__ = wrapped + + return wrapper + + return update_wrapper_attributes class DeprecationWrapper(object): @@ -160,12 +198,12 @@ def callable_deprecated(reason=None, version=None, stacklevel=2): """ def decorator(func): - message = reason or 'The function "%s" is deprecated' - if "%s" in message: - message %= func.__name__ - - @wraps(func) + @lazy_wraps(func) def wrapped(*args, **kwargs): + message = reason or 'The function "%s" is deprecated' + if "%s" in message: + message %= func.__name__ + send_warning(message, version, stacklevel + 1, module_name=func.__module__) return func(*args, **kwargs) |