From 81aa933d7c0a55c455d03112578fb5f67bbdda7c Mon Sep 17 00:00:00 2001 From: Laurent Peuch Date: Wed, 22 Apr 2020 21:20:09 +0200 Subject: [deprecation/refactoring] start simplifying module and simplify class_deprecated --- logilab/common/deprecation.py | 59 ++++++++++++++++++++++++++++++++++++++++++- test/unittest_deprecation.py | 2 +- 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/logilab/common/deprecation.py b/logilab/common/deprecation.py index 4aaeba3..4a14aac 100644 --- a/logilab/common/deprecation.py +++ b/logilab/common/deprecation.py @@ -19,6 +19,7 @@ __docformat__ = "restructuredtext en" +import os import sys from warnings import warn from functools import wraps @@ -178,15 +179,71 @@ class DeprecationManager(object): reason = '[%s] %s' % (version, reason) warn(reason, DeprecationWarning, stacklevel=stacklevel) + _defaultdeprecator = DeprecationManager() + +def _get_package_name(number=2): + """ + automagically try to determine the package name from which the warning has + been triggered by loop other calling frames. + + If it fails to do so, return an empty string. + """ + + frame = sys._getframe() + + for i in range(number): + if frame.f_back is None: + break + + frame = frame.f_back + + if frame.f_globals["__package__"] is not None: + return frame.f_globals["__package__"] + + file_name = os.path.split(frame.f_globals["__file__"])[1] + + if file_name.endswith(".py"): + file_name = file_name[:-len(".py")] + + return file_name + + +def send_warning(reason, version=None, stacklevel=2): + """Display a deprecation message only if the version is older than the + compatible version. + """ + module_name = _get_package_name(stacklevel + 1) + + if module_name and version: + reason = '[%s %s] %s' % (module_name, version, reason) + elif module_name: + reason = '[%s] %s' % (module_name, reason) + elif version: + reason = '[%s] %s' % (version, reason) + + warn(reason, DeprecationWarning, stacklevel=stacklevel) + + def deprecated(reason=None, stacklevel=2, name=None, doc=None): return _defaultdeprecator.deprecated(None, reason, stacklevel, name, doc) -class_deprecated = _defaultdeprecator.class_deprecated() + +class class_deprecated(type): + """metaclass to print a warning on instantiation of a deprecated class""" + + def __call__(cls, *args, **kwargs): + msg = getattr(cls, "__deprecation_warning__", + "%(cls)s is deprecated") % {'cls': cls.__name__} + send_warning(msg, stacklevel=4) + return type.__call__(cls, *args, **kwargs) + def moved(modpath, objname): return _defaultdeprecator.moved(None, modpath, objname) + + moved.__doc__ = _defaultdeprecator.moved.__doc__ diff --git a/test/unittest_deprecation.py b/test/unittest_deprecation.py index 60b10f4..a348d67 100644 --- a/test/unittest_deprecation.py +++ b/test/unittest_deprecation.py @@ -49,7 +49,7 @@ class RawInputTC(TestCase): pass AnyClass() self.assertEqual(self.messages, - ['AnyClass is deprecated']) + ['[logilab.common] AnyClass is deprecated']) def test_deprecated_func(self): any_func = deprecation.deprecated()(self.mk_func()) -- cgit v1.2.1