classABCMeta(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.
#Note: this counter is private. Use `abc.get_cache_token()` for
#external code.
_abc_invalidation_counter =0def __new__(mcls, name, bases, namespace):
cls= super().__new__(mcls, name, bases, namespace)#Compute set of abstract method names
abstracts ={namefor name, value innamespace.items()if getattr(value, "__isabstractmethod__", False)}for base inbases: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_counterreturnclsdefregister(cls, subclass):"""Register a virtual subclass of an ABC.
Returns the subclass, to allow usage as a class decorator."""
if notisinstance(subclass, type):raise TypeError("Can only register classes")ifissubclass(subclass, cls):return subclass #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.
ifissubclass(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
returnsubclassdef _dump_registry(cls, file=None):"""Debug helper to print the ABC registry."""
print("Class: %s.%s" % (cls.__module__, cls.__qualname__), file=file)print("Inv.counter: %s" % ABCMeta._abc_invalidation_counter, file=file)for name in sorted(cls.__dict__.keys()):if name.startswith("_abc_"):
value=getattr(cls, name)print("%s: %r" % (name, value), file=file)def __instancecheck__(cls, instance):"""Override for isinstance(instance, cls)."""
#Inline the cache checking
subclass = instance.__class__
if subclass incls._abc_cache:returnTrue
subtype=type(instance)if subtype issubclass:if (cls._abc_negative_cache_version ==ABCMeta._abc_invalidation_counterandsubclassincls._abc_negative_cache):returnFalse#Fall back to the subclass check.
return cls.__subclasscheck__(subclass)return any(cls.__subclasscheck__(c) for c in{subclass, subtype})def __subclasscheck__(cls, subclass):"""Override for issubclass(subclass, cls)."""
#Check cache
if subclass incls._abc_cache:returnTrue#Check negative cache; may have to invalidate
if cls._abc_negative_cache_version
cls._abc_negative_cache =WeakSet()
cls._abc_negative_cache_version=ABCMeta._abc_invalidation_counterelif subclass incls._abc_negative_cache:returnFalse#Check the subclass hook
ok = cls.__subclasshook__(subclass)if ok is notNotImplemented:assertisinstance(ok, bool)ifok:
cls._abc_cache.add(subclass)else:
cls._abc_negative_cache.add(subclass)returnok#Check if it's a direct subclass
if cls in getattr(subclass, '__mro__', ()):
cls._abc_cache.add(subclass)returnTrue#Check if it's a subclass of a registered class (recursive)
for rcls incls._abc_registry:ifissubclass(subclass, rcls):
cls._abc_cache.add(subclass)returnTrue#Check if it's a subclass of a subclass (recursive)
for scls in cls.__subclasses__():ifissubclass(subclass, scls):
cls._abc_cache.add(subclass)returnTrue#No dice; update negative cache
cls._abc_negative_cache.add(subclass)returnFalseclass ABC(metaclass=ABCMeta):"""Helper class that provides a standard way to create an ABC using
inheritance."""
pass