1# Copyright 2007 Google, Inc. All Rights Reserved. 2# Licensed to PSF under a Contributor Agreement. 3 4"""Abstract Base Classes (ABCs) according to PEP 3119.""" 5 6from _weakrefset import WeakSet 7 8 9def abstractmethod(funcobj): 10 """A decorator indicating abstract methods. 11 12 Requires that the metaclass is ABCMeta or derived from it. A 13 class that has a metaclass derived from ABCMeta cannot be 14 instantiated unless all of its abstract methods are overridden. 15 The abstract methods can be called using any of the normal 16 'super' call mechanisms. 17 18 Usage: 19 20 class C(metaclass=ABCMeta): 21 @abstractmethod 22 def my_abstract_method(self, ...): 23 ... 24 """ 25 funcobj.__isabstractmethod__ = True 26 return funcobj 27 28 29class abstractclassmethod(classmethod): 30 """ 31 A decorator indicating abstract classmethods. 32 33 Similar to abstractmethod. 34 35 Usage: 36 37 class C(metaclass=ABCMeta): 38 @abstractclassmethod 39 def my_abstract_classmethod(cls, ...): 40 ... 41 42 'abstractclassmethod' is deprecated. Use 'classmethod' with 43 'abstractmethod' instead. 44 """ 45 46 __isabstractmethod__ = True 47 48 def __init__(self, callable): 49 callable.__isabstractmethod__ = True 50 super().__init__(callable) 51 52 53class abstractstaticmethod(staticmethod): 54 """ 55 A decorator indicating abstract staticmethods. 56 57 Similar to abstractmethod. 58 59 Usage: 60 61 class C(metaclass=ABCMeta): 62 @abstractstaticmethod 63 def my_abstract_staticmethod(...): 64 ... 65 66 'abstractstaticmethod' is deprecated. Use 'staticmethod' with 67 'abstractmethod' instead. 68 """ 69 70 __isabstractmethod__ = True 71 72 def __init__(self, callable): 73 callable.__isabstractmethod__ = True 74 super().__init__(callable) 75 76 77class abstractproperty(property): 78 """ 79 A decorator indicating abstract properties. 80 81 Requires that the metaclass is ABCMeta or derived from it. A 82 class that has a metaclass derived from ABCMeta cannot be 83 instantiated unless all of its abstract properties are overridden. 84 The abstract properties can be called using any of the normal 85 'super' call mechanisms. 86 87 Usage: 88 89 class C(metaclass=ABCMeta): 90 @abstractproperty 91 def my_abstract_property(self): 92 ... 93 94 This defines a read-only property; you can also define a read-write 95 abstract property using the 'long' form of property declaration: 96 97 class C(metaclass=ABCMeta): 98 def getx(self): ... 99 def setx(self, value): ... 100 x = abstractproperty(getx, setx) 101 102 'abstractproperty' is deprecated. Use 'property' with 'abstractmethod' 103 instead. 104 """ 105 106 __isabstractmethod__ = True 107 108 109class ABCMeta(type): 110 111 """Metaclass for defining Abstract Base Classes (ABCs). 112 113 Use this metaclass to create an ABC. An ABC can be subclassed 114 directly, and then acts as a mix-in class. You can also register 115 unrelated concrete classes (even built-in classes) and unrelated 116 ABCs as 'virtual subclasses' -- these and their descendants will 117 be considered subclasses of the registering ABC by the built-in 118 issubclass() function, but the registering ABC won't show up in 119 their MRO (Method Resolution Order) nor will method 120 implementations defined by the registering ABC be callable (not 121 even via super()). 122 123 """ 124 125 # A global counter that is incremented each time a class is 126 # registered as a virtual subclass of anything. It forces the 127 # negative cache to be cleared before its next use. 128 # Note: this counter is private. Use `abc.get_cache_token()` for 129 # external code. 130 _abc_invalidation_counter = 0 131 132 def __new__(mcls, name, bases, namespace): 133 cls = super().__new__(mcls, name, bases, namespace) 134 # Compute set of abstract method names 135 abstracts = {name 136 for name, value in namespace.items() 137 if getattr(value, "__isabstractmethod__", False)} 138 for base in bases: 139 for name in getattr(base, "__abstractmethods__", set()): 140 value = getattr(cls, name, None) 141 if getattr(value, "__isabstractmethod__", False): 142 abstracts.add(name) 143 cls.__abstractmethods__ = frozenset(abstracts) 144 # Set up inheritance registry 145 cls._abc_registry = WeakSet() 146 cls._abc_cache = WeakSet() 147 cls._abc_negative_cache = WeakSet() 148 cls._abc_negative_cache_version = ABCMeta._abc_invalidation_counter 149 return cls 150 151 def register(cls, subclass): 152 """Register a virtual subclass of an ABC. 153 154 Returns the subclass, to allow usage as a class decorator. 155 """ 156 if not isinstance(subclass, type): 157 raise TypeError("Can only register classes") 158 if issubclass(subclass, cls): 159 return subclass # Already a subclass 160 # Subtle: test for cycles *after* testing for "already a subclass"; 161 # this means we allow X.register(X) and interpret it as a no-op. 162 if issubclass(cls, subclass): 163 # This would create a cycle, which is bad for the algorithm below 164 raise RuntimeError("Refusing to create an inheritance cycle") 165 cls._abc_registry.add(subclass) 166 ABCMeta._abc_invalidation_counter += 1 # Invalidate negative cache 167 return subclass 168 169 def _dump_registry(cls, file=None): 170 """Debug helper to print the ABC registry.""" 171 print("Class: %s.%s" % (cls.__module__, cls.__qualname__), file=file) 172 print("Inv.counter: %s" % ABCMeta._abc_invalidation_counter, file=file) 173 for name in sorted(cls.__dict__.keys()): 174 if name.startswith("_abc_"): 175 value = getattr(cls, name) 176 print("%s: %r" % (name, value), file=file) 177 178 def __instancecheck__(cls, instance): 179 """Override for isinstance(instance, cls).""" 180 # Inline the cache checking 181 subclass = instance.__class__ 182 if subclass in cls._abc_cache: 183 return True 184 subtype = type(instance) 185 if subtype is subclass: 186 if (cls._abc_negative_cache_version == 187 ABCMeta._abc_invalidation_counter and 188 subclass in cls._abc_negative_cache): 189 return False 190 # Fall back to the subclass check. 191 return cls.__subclasscheck__(subclass) 192 return any(cls.__subclasscheck__(c) for c in {subclass, subtype}) 193 194 def __subclasscheck__(cls, subclass): 195 """Override for issubclass(subclass, cls).""" 196 # Check cache 197 if subclass in cls._abc_cache: 198 return True 199 # Check negative cache; may have to invalidate 200 if cls._abc_negative_cache_version < ABCMeta._abc_invalidation_counter: 201 # Invalidate the negative cache 202 cls._abc_negative_cache = WeakSet() 203 cls._abc_negative_cache_version = ABCMeta._abc_invalidation_counter 204 elif subclass in cls._abc_negative_cache: 205 return False 206 # Check the subclass hook 207 ok = cls.__subclasshook__(subclass) 208 if ok is not NotImplemented: 209 assert isinstance(ok, bool) 210 if ok: 211 cls._abc_cache.add(subclass) 212 else: 213 cls._abc_negative_cache.add(subclass) 214 return ok 215 # Check if it's a direct subclass 216 if cls in getattr(subclass, '__mro__', ()): 217 cls._abc_cache.add(subclass) 218 return True 219 # Check if it's a subclass of a registered class (recursive) 220 for rcls in cls._abc_registry: 221 if issubclass(subclass, rcls): 222 cls._abc_cache.add(subclass) 223 return True 224 # Check if it's a subclass of a subclass (recursive) 225 for scls in cls.__subclasses__(): 226 if issubclass(subclass, scls): 227 cls._abc_cache.add(subclass) 228 return True 229 # No dice; update negative cache 230 cls._abc_negative_cache.add(subclass) 231 return False 232 233 234class ABC(metaclass=ABCMeta): 235 """Helper class that provides a standard way to create an ABC using 236 inheritance. 237 """ 238 pass 239 240 241def get_cache_token(): 242 """Returns the current ABC cache token. 243 244 The token is an opaque object (supporting equality testing) identifying the 245 current version of the ABC cache for virtual subclasses. The token changes 246 with every call to ``register()`` on any ABC. 247 """ 248 return ABCMeta._abc_invalidation_counter 249