|  | # Copyright 2007 Google, Inc. All Rights Reserved. | 
|  | # Licensed to PSF under a Contributor Agreement. | 
|  |  | 
|  | """Abstract Base Classes (ABCs) according to PEP 3119.""" | 
|  |  | 
|  | import types | 
|  |  | 
|  | from _weakrefset import WeakSet | 
|  |  | 
|  | # Instance of old-style class | 
|  | class _C: pass | 
|  | _InstanceType = type(_C()) | 
|  |  | 
|  |  | 
|  | def abstractmethod(funcobj): | 
|  | """A decorator indicating abstract methods. | 
|  |  | 
|  | Requires that the metaclass is ABCMeta or derived from it.  A | 
|  | class that has a metaclass derived from ABCMeta cannot be | 
|  | instantiated unless all of its abstract methods are overridden. | 
|  | The abstract methods can be called using any of the normal | 
|  | 'super' call mechanisms. | 
|  |  | 
|  | Usage: | 
|  |  | 
|  | class C: | 
|  | __metaclass__ = ABCMeta | 
|  | @abstractmethod | 
|  | def my_abstract_method(self, ...): | 
|  | ... | 
|  | """ | 
|  | funcobj.__isabstractmethod__ = True | 
|  | return funcobj | 
|  |  | 
|  |  | 
|  | class abstractproperty(property): | 
|  | """A decorator indicating abstract properties. | 
|  |  | 
|  | Requires that the metaclass is ABCMeta or derived from it.  A | 
|  | class that has a metaclass derived from ABCMeta cannot be | 
|  | instantiated unless all of its abstract properties are overridden. | 
|  | The abstract properties can be called using any of the normal | 
|  | 'super' call mechanisms. | 
|  |  | 
|  | Usage: | 
|  |  | 
|  | class C: | 
|  | __metaclass__ = ABCMeta | 
|  | @abstractproperty | 
|  | def my_abstract_property(self): | 
|  | ... | 
|  |  | 
|  | This defines a read-only property; you can also define a read-write | 
|  | abstract property using the 'long' form of property declaration: | 
|  |  | 
|  | class C: | 
|  | __metaclass__ = ABCMeta | 
|  | def getx(self): ... | 
|  | def setx(self, value): ... | 
|  | x = abstractproperty(getx, setx) | 
|  | """ | 
|  | __isabstractmethod__ = True | 
|  |  | 
|  |  | 
|  | class ABCMeta(type): | 
|  |  | 
|  | """Metaclass for defining Abstract Base Classes (ABCs). | 
|  |  | 
|  | Use this metaclass to create an ABC.  An ABC can be subclassed | 
|  | directly, and then acts as a mix-in class.  You can also register | 
|  | unrelated concrete classes (even built-in classes) and unrelated | 
|  | ABCs as 'virtual subclasses' -- these and their descendants will | 
|  | be considered subclasses of the registering ABC by the built-in | 
|  | issubclass() function, but the registering ABC won't show up in | 
|  | their MRO (Method Resolution Order) nor will method | 
|  | implementations defined by the registering ABC be callable (not | 
|  | even via super()). | 
|  |  | 
|  | """ | 
|  |  | 
|  | # A global counter that is incremented each time a class is | 
|  | # registered as a virtual subclass of anything.  It forces the | 
|  | # negative cache to be cleared before its next use. | 
|  | _abc_invalidation_counter = 0 | 
|  |  | 
|  | def __new__(mcls, name, bases, namespace): | 
|  | cls = super(ABCMeta, mcls).__new__(mcls, name, bases, namespace) | 
|  | # Compute set of abstract method names | 
|  | abstracts = set(name | 
|  | for name, value in namespace.items() | 
|  | if getattr(value, "__isabstractmethod__", False)) | 
|  | for base in bases: | 
|  | for name in getattr(base, "__abstractmethods__", set()): | 
|  | value = getattr(cls, name, None) | 
|  | if getattr(value, "__isabstractmethod__", False): | 
|  | abstracts.add(name) | 
|  | cls.__abstractmethods__ = frozenset(abstracts) | 
|  | # Set up inheritance registry | 
|  | cls._abc_registry = WeakSet() | 
|  | cls._abc_cache = WeakSet() | 
|  | cls._abc_negative_cache = WeakSet() | 
|  | cls._abc_negative_cache_version = ABCMeta._abc_invalidation_counter | 
|  | return cls | 
|  |  | 
|  | def register(cls, subclass): | 
|  | """Register a virtual subclass of an ABC.""" | 
|  | if not isinstance(subclass, (type, types.ClassType)): | 
|  | raise TypeError("Can only register classes") | 
|  | if issubclass(subclass, cls): | 
|  | return  # Already a subclass | 
|  | # Subtle: test for cycles *after* testing for "already a subclass"; | 
|  | # this means we allow X.register(X) and interpret it as a no-op. | 
|  | if issubclass(cls, subclass): | 
|  | # This would create a cycle, which is bad for the algorithm below | 
|  | raise RuntimeError("Refusing to create an inheritance cycle") | 
|  | cls._abc_registry.add(subclass) | 
|  | ABCMeta._abc_invalidation_counter += 1  # Invalidate negative cache | 
|  |  | 
|  | def _dump_registry(cls, file=None): | 
|  | """Debug helper to print the ABC registry.""" | 
|  | print >> file, "Class: %s.%s" % (cls.__module__, cls.__name__) | 
|  | print >> file, "Inv.counter: %s" % ABCMeta._abc_invalidation_counter | 
|  | for name in sorted(cls.__dict__.keys()): | 
|  | if name.startswith("_abc_"): | 
|  | value = getattr(cls, name) | 
|  | print >> file, "%s: %r" % (name, value) | 
|  |  | 
|  | 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 == | 
|  | ABCMeta._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 < ABCMeta._abc_invalidation_counter: | 
|  | # Invalidate the negative cache | 
|  | cls._abc_negative_cache = WeakSet() | 
|  | cls._abc_negative_cache_version = ABCMeta._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 |