Skip to content

Commit

Permalink
Fix wrong checks on subclassing of deprecated classes. closes #581
Browse files Browse the repository at this point in the history
  • Loading branch information
dangra committed Feb 5, 2014
1 parent 13846de commit 46d98d6
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 2 deletions.
11 changes: 11 additions & 0 deletions scrapy/tests/test_utils_deprecate.py
Expand Up @@ -145,6 +145,9 @@ class UpdatedUserClass1a(NewName):
class OutdatedUserClass1(DeprecatedName):
pass

class OutdatedUserClass1a(DeprecatedName):
pass

class UnrelatedClass(object):
pass

Expand All @@ -159,6 +162,8 @@ class OldStyleClass:
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)

Expand All @@ -175,6 +180,9 @@ class UpdatedUserClass2a(NewName):
class OutdatedUserClass2(DeprecatedName):
pass

class OutdatedUserClass2a(DeprecatedName):
pass

class UnrelatedClass(object):
pass

Expand All @@ -186,6 +194,9 @@ class OldStyleClass:
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)

Expand Down
10 changes: 8 additions & 2 deletions scrapy/utils/deprecate.py
Expand Up @@ -79,12 +79,18 @@ def __instancecheck__(cls, inst):
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
Expand Down

0 comments on commit 46d98d6

Please sign in to comment.