Skip to content

Commit

Permalink
super-ugly hack to get isinstance working (FIXME)
Browse files Browse the repository at this point in the history
  • Loading branch information
pbauer committed Jan 31, 2017
1 parent b555781 commit da4fffe
Showing 1 changed file with 68 additions and 0 deletions.
68 changes: 68 additions & 0 deletions src/Persistence/mapping.py
Expand Up @@ -12,7 +12,9 @@
#
##############################################################################

from _weakrefset import WeakSet
from abc import ABCMeta
from abc import _InstanceType

from ExtensionClass import ExtensionClass
from persistent.mapping import PersistentMapping as _BasePersistentMapping
Expand All @@ -26,10 +28,76 @@ class _Meta(ExtensionClass, ABCMeta):
# which has an ABCMeta class. Reconcile this with the
# ExtensionClass meta class, by ignoring the ABCMeta registration.

_abc_invalidation_counter = 0

def __new__(cls, *args, **kw):
# Ignore ABCMeta.
cls._abc_registry = WeakSet()
cls._abc_cache = WeakSet()
cls._abc_negative_cache = WeakSet()
cls._abc_negative_cache_version = _Meta._abc_invalidation_counter

return ExtensionClass.__new__(cls, *args, **kw)

def __instancecheck__(cls, instance):
"""Override for isinstance(instance, cls)."""
# Inline the cache checking when it's simple.
subclass = getattr(instance, '__class__', None)
if subclass is not None and subclass in cls._abc_cache:
return True
subtype = type(instance)
# Old-style instances
if subtype is _InstanceType:
subtype = subclass
if subtype is subclass or subclass is None:
if (cls._abc_negative_cache_version ==
_Meta._abc_invalidation_counter and
subtype in cls._abc_negative_cache):
return False
# Fall back to the subclass check.
return cls.__subclasscheck__(subtype)
return (cls.__subclasscheck__(subclass) or
cls.__subclasscheck__(subtype))

def __subclasscheck__(cls, subclass):
"""Override for issubclass(subclass, cls)."""
# Check cache
if subclass in cls._abc_cache:
return True
# Check negative cache; may have to invalidate
if cls._abc_negative_cache_version < _Meta._abc_invalidation_counter:
# Invalidate the negative cache
cls._abc_negative_cache = WeakSet()
cls._abc_negative_cache_version = _Meta._abc_invalidation_counter
elif subclass in cls._abc_negative_cache:
return False
# Check the subclass hook
ok = cls.__subclasshook__(subclass)
if ok is not NotImplemented:
assert isinstance(ok, bool)
if ok:
cls._abc_cache.add(subclass)
else:
cls._abc_negative_cache.add(subclass)
return ok
# Check if it's a direct subclass
if cls in getattr(subclass, '__mro__', ()):
cls._abc_cache.add(subclass)
return True
# Check if it's a subclass of a registered class (recursive)
for rcls in cls._abc_registry:
if issubclass(subclass, rcls):
cls._abc_cache.add(subclass)
return True
# Check if it's a subclass of a subclass (recursive)
for scls in cls.__subclasses__():
if issubclass(subclass, scls):
cls._abc_cache.add(subclass)
return True
# No dice; update negative cache
cls._abc_negative_cache.add(subclass)
return False


if six.PY2:
# Neither six.with_metaclass nor six.add_metaclass work under
Expand Down

0 comments on commit da4fffe

Please sign in to comment.