diff --git a/scrapy/tests/test_utils_deprecate.py b/scrapy/tests/test_utils_deprecate.py index 07b9a3dd5..fd6bc90c3 100644 --- a/scrapy/tests/test_utils_deprecate.py +++ b/scrapy/tests/test_utils_deprecate.py @@ -145,6 +145,9 @@ class WarnWhenSubclassedTest(unittest.TestCase): class OutdatedUserClass1(DeprecatedName): pass + class OutdatedUserClass1a(DeprecatedName): + pass + class UnrelatedClass(object): pass @@ -159,6 +162,8 @@ class WarnWhenSubclassedTest(unittest.TestCase): assert not issubclass(UnrelatedClass, DeprecatedName) assert not issubclass(OldStyleClass, DeprecatedName) assert not issubclass(OldStyleClass, DeprecatedName) + assert not issubclass(OutdatedUserClass1, OutdatedUserClass1a) + assert not issubclass(OutdatedUserClass1a, OutdatedUserClass1) self.assertRaises(TypeError, issubclass, object(), DeprecatedName) @@ -175,6 +180,9 @@ class WarnWhenSubclassedTest(unittest.TestCase): class OutdatedUserClass2(DeprecatedName): pass + class OutdatedUserClass2a(DeprecatedName): + pass + class UnrelatedClass(object): pass @@ -186,6 +194,9 @@ class WarnWhenSubclassedTest(unittest.TestCase): assert isinstance(UpdatedUserClass2(), DeprecatedName) assert isinstance(UpdatedUserClass2a(), DeprecatedName) assert isinstance(OutdatedUserClass2(), DeprecatedName) + assert isinstance(OutdatedUserClass2a(), DeprecatedName) + assert not isinstance(OutdatedUserClass2a(), OutdatedUserClass2) + assert not isinstance(OutdatedUserClass2(), OutdatedUserClass2a) assert not isinstance(UnrelatedClass(), DeprecatedName) assert not isinstance(OldStyleClass(), DeprecatedName) diff --git a/scrapy/utils/deprecate.py b/scrapy/utils/deprecate.py index edaecc3d3..66f0217a0 100644 --- a/scrapy/utils/deprecate.py +++ b/scrapy/utils/deprecate.py @@ -79,12 +79,18 @@ def create_deprecated_class(name, new_class, clsdict=None, for c in {type(inst), inst.__class__}) def __subclasscheck__(cls, sub): + if cls is not DeprecatedClass.deprecated_class: + # we should do the magic only if second `issubclass` argument + # is the deprecated class itself - subclasses of the + # deprecated class should not use custom `__subclasscheck__` + # method. + return super(DeprecatedClass, cls).__subclasscheck__(sub) + if not inspect.isclass(sub): raise TypeError("issubclass() arg 1 must be a class") mro = getattr(sub, '__mro__', ()) - candidates = {cls, new_class} - return any(c in candidates for c in mro) + return any(c in {cls, new_class} for c in mro) def __call__(cls, *args, **kwargs): old = DeprecatedClass.deprecated_class