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