diff --git a/scrapy/tests/test_utils_deprecate.py b/scrapy/tests/test_utils_deprecate.py index aea27bf05..f1f0d77d8 100644 --- a/scrapy/tests/test_utils_deprecate.py +++ b/scrapy/tests/test_utils_deprecate.py @@ -36,9 +36,9 @@ class WarnWhenSubclassedTest(unittest.TestCase): assert issubclass(msg.category, MyWarning) self.assertEqual( str(msg.message), - "Base class scrapy.tests.test_utils_deprecate.Deprecated of " - "scrapy.tests.test_utils_deprecate.UserClass was deprecated. " - "Please inherit from scrapy.tests.test_utils_deprecate.NewName." + "scrapy.tests.test_utils_deprecate.UserClass inherits from " + "deprecated class scrapy.tests.test_utils_deprecate.Deprecated, " + "please inherit from scrapy.tests.test_utils_deprecate.NewName." ) self.assertEqual(msg.lineno, inspect.getsourcelines(UserClass)[1]) diff --git a/scrapy/utils/deprecate.py b/scrapy/utils/deprecate.py index 2506357f6..40df25e26 100644 --- a/scrapy/utils/deprecate.py +++ b/scrapy/utils/deprecate.py @@ -14,7 +14,8 @@ def attribute(obj, oldattr, newattr, version='0.12'): def create_deprecated_class(name, new_class, clsdict=None, warn_category=ScrapyDeprecationWarning, - warn_message=None): + warn_message="{cls} inherits from deprecated class {old}, "\ + "please inherit from {new}."): """ Return a "deprecated" class that causes its subclasses to issue a warning. Subclasses of ``new_class`` are considered subclasses of this class. @@ -38,16 +39,21 @@ def create_deprecated_class(name, new_class, clsdict=None, OldName. """ - deprecated = {} class DeprecatedClass(type): + deprecated_class = None + + def __new__(metacls, name, bases, clsdict_): + cls = super(DeprecatedClass, metacls).__new__(metacls, name, bases, clsdict_) + if metacls.deprecated_class is None: + metacls.deprecated_class = cls + return cls + def __init__(cls, name, bases, clsdict_): - if 'cls' in deprecated: - if warn_message is not None: - msg = warn_message - else: - msg = "Base class {0} of {1} was deprecated. Please inherit from {2}."\ - .format(_clspath(deprecated['cls']), _clspath(cls), _clspath(new_class)) + if cls is not cls.__class__.deprecated_class: + msg = warn_message.format(cls=_clspath(cls), + old=_clspath(cls.__class__.deprecated_class), + new=_clspath(new_class)) warnings.warn(msg, warn_category, stacklevel=2) super(DeprecatedClass, cls).__init__(name, bases, clsdict_) @@ -66,10 +72,7 @@ def create_deprecated_class(name, new_class, clsdict=None, candidates = {cls, new_class} return any(c in candidates for c in mro) - clsdict = clsdict if clsdict is not None else {} - deprecated_cls = DeprecatedClass(name, (new_class,), clsdict) - deprecated['cls'] = deprecated_cls - + deprecated_cls = DeprecatedClass(name, (new_class,), clsdict or {}) frm = inspect.stack()[1] parent_module = inspect.getmodule(frm[0]) if parent_module is not None: