move sections
[python/dscho.git] / Lib / abc.py
blob515ba08f23cadab56bf009953eb9f7ace3f6ebdb
1 # Copyright 2007 Google, Inc. All Rights Reserved.
2 # Licensed to PSF under a Contributor Agreement.
4 """Abstract Base Classes (ABCs) according to PEP 3119."""
6 import types
9 # Instance of old-style class
10 class _C: pass
11 _InstanceType = type(_C())
14 def abstractmethod(funcobj):
15 """A decorator indicating abstract methods.
17 Requires that the metaclass is ABCMeta or derived from it. A
18 class that has a metaclass derived from ABCMeta cannot be
19 instantiated unless all of its abstract methods are overridden.
20 The abstract methods can be called using any of the normal
21 'super' call mechanisms.
23 Usage:
25 class C:
26 __metaclass__ = ABCMeta
27 @abstractmethod
28 def my_abstract_method(self, ...):
29 ...
30 """
31 funcobj.__isabstractmethod__ = True
32 return funcobj
35 class abstractproperty(property):
36 """A decorator indicating abstract properties.
38 Requires that the metaclass is ABCMeta or derived from it. A
39 class that has a metaclass derived from ABCMeta cannot be
40 instantiated unless all of its abstract properties are overridden.
41 The abstract properties can be called using any of the normal
42 'super' call mechanisms.
44 Usage:
46 class C:
47 __metaclass__ = ABCMeta
48 @abstractproperty
49 def my_abstract_property(self):
50 ...
52 This defines a read-only property; you can also define a read-write
53 abstract property using the 'long' form of property declaration:
55 class C:
56 __metaclass__ = ABCMeta
57 def getx(self): ...
58 def setx(self, value): ...
59 x = abstractproperty(getx, setx)
60 """
61 __isabstractmethod__ = True
64 class ABCMeta(type):
66 """Metaclass for defining Abstract Base Classes (ABCs).
68 Use this metaclass to create an ABC. An ABC can be subclassed
69 directly, and then acts as a mix-in class. You can also register
70 unrelated concrete classes (even built-in classes) and unrelated
71 ABCs as 'virtual subclasses' -- these and their descendants will
72 be considered subclasses of the registering ABC by the built-in
73 issubclass() function, but the registering ABC won't show up in
74 their MRO (Method Resolution Order) nor will method
75 implementations defined by the registering ABC be callable (not
76 even via super()).
78 """
80 # A global counter that is incremented each time a class is
81 # registered as a virtual subclass of anything. It forces the
82 # negative cache to be cleared before its next use.
83 _abc_invalidation_counter = 0
85 def __new__(mcls, name, bases, namespace):
86 cls = super(ABCMeta, mcls).__new__(mcls, name, bases, namespace)
87 # Compute set of abstract method names
88 abstracts = set(name
89 for name, value in namespace.items()
90 if getattr(value, "__isabstractmethod__", False))
91 for base in bases:
92 for name in getattr(base, "__abstractmethods__", set()):
93 value = getattr(cls, name, None)
94 if getattr(value, "__isabstractmethod__", False):
95 abstracts.add(name)
96 cls.__abstractmethods__ = frozenset(abstracts)
97 # Set up inheritance registry
98 cls._abc_registry = set()
99 cls._abc_cache = set()
100 cls._abc_negative_cache = set()
101 cls._abc_negative_cache_version = ABCMeta._abc_invalidation_counter
102 return cls
104 def register(cls, subclass):
105 """Register a virtual subclass of an ABC."""
106 if not isinstance(subclass, (type, types.ClassType)):
107 raise TypeError("Can only register classes")
108 if issubclass(subclass, cls):
109 return # Already a subclass
110 # Subtle: test for cycles *after* testing for "already a subclass";
111 # this means we allow X.register(X) and interpret it as a no-op.
112 if issubclass(cls, subclass):
113 # This would create a cycle, which is bad for the algorithm below
114 raise RuntimeError("Refusing to create an inheritance cycle")
115 cls._abc_registry.add(subclass)
116 ABCMeta._abc_invalidation_counter += 1 # Invalidate negative cache
118 def _dump_registry(cls, file=None):
119 """Debug helper to print the ABC registry."""
120 print >> file, "Class: %s.%s" % (cls.__module__, cls.__name__)
121 print >> file, "Inv.counter: %s" % ABCMeta._abc_invalidation_counter
122 for name in sorted(cls.__dict__.keys()):
123 if name.startswith("_abc_"):
124 value = getattr(cls, name)
125 print >> file, "%s: %r" % (name, value)
127 def __instancecheck__(cls, instance):
128 """Override for isinstance(instance, cls)."""
129 # Inline the cache checking when it's simple.
130 subclass = getattr(instance, '__class__', None)
131 if subclass in cls._abc_cache:
132 return True
133 subtype = type(instance)
134 # Old-style instances
135 if subtype is _InstanceType:
136 subtype = subclass
137 if subtype is subclass or subclass is None:
138 if (cls._abc_negative_cache_version ==
139 ABCMeta._abc_invalidation_counter and
140 subtype in cls._abc_negative_cache):
141 return False
142 # Fall back to the subclass check.
143 return cls.__subclasscheck__(subtype)
144 return (cls.__subclasscheck__(subclass) or
145 cls.__subclasscheck__(subtype))
147 def __subclasscheck__(cls, subclass):
148 """Override for issubclass(subclass, cls)."""
149 # Check cache
150 if subclass in cls._abc_cache:
151 return True
152 # Check negative cache; may have to invalidate
153 if cls._abc_negative_cache_version < ABCMeta._abc_invalidation_counter:
154 # Invalidate the negative cache
155 cls._abc_negative_cache = set()
156 cls._abc_negative_cache_version = ABCMeta._abc_invalidation_counter
157 elif subclass in cls._abc_negative_cache:
158 return False
159 # Check the subclass hook
160 ok = cls.__subclasshook__(subclass)
161 if ok is not NotImplemented:
162 assert isinstance(ok, bool)
163 if ok:
164 cls._abc_cache.add(subclass)
165 else:
166 cls._abc_negative_cache.add(subclass)
167 return ok
168 # Check if it's a direct subclass
169 if cls in getattr(subclass, '__mro__', ()):
170 cls._abc_cache.add(subclass)
171 return True
172 # Check if it's a subclass of a registered class (recursive)
173 for rcls in cls._abc_registry:
174 if issubclass(subclass, rcls):
175 cls._abc_cache.add(subclass)
176 return True
177 # Check if it's a subclass of a subclass (recursive)
178 for scls in cls.__subclasses__():
179 if issubclass(subclass, scls):
180 cls._abc_cache.add(subclass)
181 return True
182 # No dice; update negative cache
183 cls._abc_negative_cache.add(subclass)
184 return False