Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(4)

Side by Side Diff: Lib/_collections_abc.py

Issue 25958: Implicit ABCs have no means of "anti-registration"
Patch Set: Created 4 years, 4 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « Doc/reference/datamodel.rst ('k') | Lib/test/test_augassign.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright 2007 Google, Inc. All Rights Reserved. 1 # Copyright 2007 Google, Inc. All Rights Reserved.
2 # Licensed to PSF under a Contributor Agreement. 2 # Licensed to PSF under a Contributor Agreement.
3 3
4 """Abstract Base Classes (ABCs) for collections, according to PEP 3119. 4 """Abstract Base Classes (ABCs) for collections, according to PEP 3119.
5 5
6 Unit tests are in test_collections. 6 Unit tests are in test_collections.
7 """ 7 """
8 8
9 from abc import ABCMeta, abstractmethod 9 from abc import ABCMeta, abstractmethod
10 import sys 10 import sys
11 11
12 __all__ = ["Awaitable", "Coroutine", "AsyncIterable", "AsyncIterator", 12 __all__ = ["Awaitable", "Coroutine", "AsyncIterable", "AsyncIterator",
13 "Hashable", "Iterable", "Iterator", "Generator", 13 "Hashable", "Iterable", "Iterator", "Generator",
14 "Sized", "Container", "Callable", 14 "Sized", "Container", "Reversible", "Callable",
15 "Set", "MutableSet", 15 "Set", "MutableSet",
16 "Mapping", "MutableMapping", 16 "Mapping", "MutableMapping",
17 "MappingView", "KeysView", "ItemsView", "ValuesView", 17 "MappingView", "KeysView", "ItemsView", "ValuesView",
18 "Sequence", "MutableSequence", 18 "Sequence", "MutableSequence",
19 "ByteString", 19 "ByteString",
20 ] 20 ]
21 21
22 # This module has been renamed from collections.abc to _collections_abc to 22 # This module has been renamed from collections.abc to _collections_abc to
23 # speed up interpreter startup. Some of the types such as MutableMapping are 23 # speed up interpreter startup. Some of the types such as MutableMapping are
24 # required early but collections module imports a lot of other modules. 24 # required early but collections module imports a lot of other modules.
(...skipping 29 matching lines...) Expand all
54 generator = type((lambda: (yield))()) 54 generator = type((lambda: (yield))())
55 ## coroutine ## 55 ## coroutine ##
56 async def _coro(): pass 56 async def _coro(): pass
57 _coro = _coro() 57 _coro = _coro()
58 coroutine = type(_coro) 58 coroutine = type(_coro)
59 _coro.close() # Prevent ResourceWarning 59 _coro.close() # Prevent ResourceWarning
60 del _coro 60 del _coro
61 61
62 62
63 ### ONE-TRICK PONIES ### 63 ### ONE-TRICK PONIES ###
64
65 def _check_methods(C, *methods):
66 mro = C.__mro__
67 for method in methods:
68 for B in mro:
69 if method in B.__dict__:
70 if B.__dict__[method] is None:
71 return NotImplemented
72 break
73 else:
74 return NotImplemented
75 return True
64 76
65 class Hashable(metaclass=ABCMeta): 77 class Hashable(metaclass=ABCMeta):
66 78
67 __slots__ = () 79 __slots__ = ()
68 80
69 @abstractmethod 81 @abstractmethod
70 def __hash__(self): 82 def __hash__(self):
71 return 0 83 return 0
72 84
73 @classmethod 85 @classmethod
74 def __subclasshook__(cls, C): 86 def __subclasshook__(cls, C):
75 if cls is Hashable: 87 if cls is Hashable:
76 for B in C.__mro__: 88 return _check_methods(C, "__hash__")
77 if "__hash__" in B.__dict__:
78 if B.__dict__["__hash__"]:
79 return True
80 break
81 return NotImplemented 89 return NotImplemented
82 90
83 91
84 class Awaitable(metaclass=ABCMeta): 92 class Awaitable(metaclass=ABCMeta):
85 93
86 __slots__ = () 94 __slots__ = ()
87 95
88 @abstractmethod 96 @abstractmethod
89 def __await__(self): 97 def __await__(self):
90 yield 98 yield
91 99
92 @classmethod 100 @classmethod
93 def __subclasshook__(cls, C): 101 def __subclasshook__(cls, C):
94 if cls is Awaitable: 102 if cls is Awaitable:
95 for B in C.__mro__: 103 return _check_methods(C, "__await__")
96 if "__await__" in B.__dict__:
97 if B.__dict__["__await__"]:
98 return True
99 break
100 return NotImplemented 104 return NotImplemented
101 105
102 106
103 class Coroutine(Awaitable): 107 class Coroutine(Awaitable):
104 108
105 __slots__ = () 109 __slots__ = ()
106 110
107 @abstractmethod 111 @abstractmethod
108 def send(self, value): 112 def send(self, value):
109 """Send a value into the coroutine. 113 """Send a value into the coroutine.
(...skipping 20 matching lines...) Expand all
130 try: 134 try:
131 self.throw(GeneratorExit) 135 self.throw(GeneratorExit)
132 except (GeneratorExit, StopIteration): 136 except (GeneratorExit, StopIteration):
133 pass 137 pass
134 else: 138 else:
135 raise RuntimeError("coroutine ignored GeneratorExit") 139 raise RuntimeError("coroutine ignored GeneratorExit")
136 140
137 @classmethod 141 @classmethod
138 def __subclasshook__(cls, C): 142 def __subclasshook__(cls, C):
139 if cls is Coroutine: 143 if cls is Coroutine:
140 mro = C.__mro__ 144 return _check_methods(C, '__await__', 'send', 'throw', 'close')
141 for method in ('__await__', 'send', 'throw', 'close'):
142 for base in mro:
143 if method in base.__dict__:
144 break
145 else:
146 return NotImplemented
147 return True
148 return NotImplemented 145 return NotImplemented
149 146
150 147
151 Coroutine.register(coroutine) 148 Coroutine.register(coroutine)
152 149
153 150
154 class AsyncIterable(metaclass=ABCMeta): 151 class AsyncIterable(metaclass=ABCMeta):
155 152
156 __slots__ = () 153 __slots__ = ()
157 154
158 @abstractmethod 155 @abstractmethod
159 async def __aiter__(self): 156 async def __aiter__(self):
160 return AsyncIterator() 157 return AsyncIterator()
161 158
162 @classmethod 159 @classmethod
163 def __subclasshook__(cls, C): 160 def __subclasshook__(cls, C):
164 if cls is AsyncIterable: 161 if cls is AsyncIterable:
165 if any("__aiter__" in B.__dict__ for B in C.__mro__): 162 return _check_methods(C, "__aiter__")
166 return True
167 return NotImplemented 163 return NotImplemented
168 164
169 165
170 class AsyncIterator(AsyncIterable): 166 class AsyncIterator(AsyncIterable):
171 167
172 __slots__ = () 168 __slots__ = ()
173 169
174 @abstractmethod 170 @abstractmethod
175 async def __anext__(self): 171 async def __anext__(self):
176 """Return the next item or raise StopAsyncIteration when exhausted.""" 172 """Return the next item or raise StopAsyncIteration when exhausted."""
177 raise StopAsyncIteration 173 raise StopAsyncIteration
178 174
179 async def __aiter__(self): 175 async def __aiter__(self):
180 return self 176 return self
181 177
182 @classmethod 178 @classmethod
183 def __subclasshook__(cls, C): 179 def __subclasshook__(cls, C):
184 if cls is AsyncIterator: 180 if cls is AsyncIterator:
185 if (any("__anext__" in B.__dict__ for B in C.__mro__) and 181 return _check_methods(C, "__anext__", "__aiter__")
186 any("__aiter__" in B.__dict__ for B in C.__mro__)):
187 return True
188 return NotImplemented 182 return NotImplemented
189 183
190 184
191 class Iterable(metaclass=ABCMeta): 185 class Iterable(metaclass=ABCMeta):
192 186
193 __slots__ = () 187 __slots__ = ()
194 188
195 @abstractmethod 189 @abstractmethod
196 def __iter__(self): 190 def __iter__(self):
197 while False: 191 while False:
198 yield None 192 yield None
199 193
200 @classmethod 194 @classmethod
201 def __subclasshook__(cls, C): 195 def __subclasshook__(cls, C):
202 if cls is Iterable: 196 if cls is Iterable:
203 if any("__iter__" in B.__dict__ for B in C.__mro__): 197 return _check_methods(C, "__iter__")
204 return True
205 return NotImplemented 198 return NotImplemented
206 199
207 200
208 class Iterator(Iterable): 201 class Iterator(Iterable):
209 202
210 __slots__ = () 203 __slots__ = ()
211 204
212 @abstractmethod 205 @abstractmethod
213 def __next__(self): 206 def __next__(self):
214 'Return the next item from the iterator. When exhausted, raise StopItera tion' 207 'Return the next item from the iterator. When exhausted, raise StopItera tion'
215 raise StopIteration 208 raise StopIteration
216 209
217 def __iter__(self): 210 def __iter__(self):
218 return self 211 return self
219 212
220 @classmethod 213 @classmethod
221 def __subclasshook__(cls, C): 214 def __subclasshook__(cls, C):
222 if cls is Iterator: 215 if cls is Iterator:
223 if (any("__next__" in B.__dict__ for B in C.__mro__) and 216 return _check_methods(C, "__next__", "__iter__")
224 any("__iter__" in B.__dict__ for B in C.__mro__)):
225 return True
226 return NotImplemented 217 return NotImplemented
227 218
228 Iterator.register(bytes_iterator) 219 Iterator.register(bytes_iterator)
229 Iterator.register(bytearray_iterator) 220 Iterator.register(bytearray_iterator)
230 #Iterator.register(callable_iterator) 221 #Iterator.register(callable_iterator)
231 Iterator.register(dict_keyiterator) 222 Iterator.register(dict_keyiterator)
232 Iterator.register(dict_valueiterator) 223 Iterator.register(dict_valueiterator)
233 Iterator.register(dict_itemiterator) 224 Iterator.register(dict_itemiterator)
234 Iterator.register(list_iterator) 225 Iterator.register(list_iterator)
235 Iterator.register(list_reverseiterator) 226 Iterator.register(list_reverseiterator)
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
276 try: 267 try:
277 self.throw(GeneratorExit) 268 self.throw(GeneratorExit)
278 except (GeneratorExit, StopIteration): 269 except (GeneratorExit, StopIteration):
279 pass 270 pass
280 else: 271 else:
281 raise RuntimeError("generator ignored GeneratorExit") 272 raise RuntimeError("generator ignored GeneratorExit")
282 273
283 @classmethod 274 @classmethod
284 def __subclasshook__(cls, C): 275 def __subclasshook__(cls, C):
285 if cls is Generator: 276 if cls is Generator:
286 mro = C.__mro__ 277 return _check_methods(C, '__iter__', '__next__',
287 for method in ('__iter__', '__next__', 'send', 'throw', 'close'): 278 'send', 'throw', 'close')
288 for base in mro:
289 if method in base.__dict__:
290 break
291 else:
292 return NotImplemented
293 return True
294 return NotImplemented 279 return NotImplemented
295 280
296 281
297 Generator.register(generator) 282 Generator.register(generator)
298 283
299 284
300 class Sized(metaclass=ABCMeta): 285 class Sized(metaclass=ABCMeta):
301 286
302 __slots__ = () 287 __slots__ = ()
303 288
304 @abstractmethod 289 @abstractmethod
305 def __len__(self): 290 def __len__(self):
306 return 0 291 return 0
307 292
308 @classmethod 293 @classmethod
309 def __subclasshook__(cls, C): 294 def __subclasshook__(cls, C):
310 if cls is Sized: 295 if cls is Sized:
311 if any("__len__" in B.__dict__ for B in C.__mro__): 296 return _check_methods(C, "__len__")
312 return True
313 return NotImplemented 297 return NotImplemented
314 298
315 299
316 class Container(metaclass=ABCMeta): 300 class Container(metaclass=ABCMeta):
317 301
318 __slots__ = () 302 __slots__ = ()
319 303
320 @abstractmethod 304 @abstractmethod
321 def __contains__(self, x): 305 def __contains__(self, x):
322 return False 306 return False
323 307
324 @classmethod 308 @classmethod
325 def __subclasshook__(cls, C): 309 def __subclasshook__(cls, C):
326 if cls is Container: 310 if cls is Container:
327 if any("__contains__" in B.__dict__ for B in C.__mro__): 311 return _check_methods(C, "__contains__")
328 return True
329 return NotImplemented 312 return NotImplemented
330 313
331 314
332 class Callable(metaclass=ABCMeta): 315 class Callable(metaclass=ABCMeta):
333 316
334 __slots__ = () 317 __slots__ = ()
335 318
336 @abstractmethod 319 @abstractmethod
337 def __call__(self, *args, **kwds): 320 def __call__(self, *args, **kwds):
338 return False 321 return False
339 322
340 @classmethod 323 @classmethod
341 def __subclasshook__(cls, C): 324 def __subclasshook__(cls, C):
342 if cls is Callable: 325 if cls is Callable:
343 if any("__call__" in B.__dict__ for B in C.__mro__): 326 return _check_methods(C, "__call__")
344 return True
345 return NotImplemented 327 return NotImplemented
346 328
347 329
330 class Reversible(Iterable):
331
332 __slots__ = ()
333
334 @abstractmethod
335 def __reversed__(self):
336 while False:
337 yield None
338
339 @classmethod
340 def __subclasshook__(cls, C):
341 if cls is Reversible:
342 return _check_methods(C, "__reversed__", "__iter__")
343 return NotImplemented
344
345
348 ### SETS ### 346 ### SETS ###
349 347
350 348
351 class Set(Sized, Iterable, Container): 349 class Set(Sized, Iterable, Container):
352 350
353 """A set is a finite, iterable container. 351 """A set is a finite, iterable container.
354 352
355 This class provides concrete generic implementations of all 353 This class provides concrete generic implementations of all
356 methods except for __contains__, __iter__ and __len__. 354 methods except for __contains__, __iter__ and __len__.
357 355
(...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after
613 return ItemsView(self) 611 return ItemsView(self)
614 612
615 def values(self): 613 def values(self):
616 "D.values() -> an object providing a view on D's values" 614 "D.values() -> an object providing a view on D's values"
617 return ValuesView(self) 615 return ValuesView(self)
618 616
619 def __eq__(self, other): 617 def __eq__(self, other):
620 if not isinstance(other, Mapping): 618 if not isinstance(other, Mapping):
621 return NotImplemented 619 return NotImplemented
622 return dict(self.items()) == dict(other.items()) 620 return dict(self.items()) == dict(other.items())
621
622 __reversed__ = None
623 623
624 Mapping.register(mappingproxy) 624 Mapping.register(mappingproxy)
625 625
626 626
627 class MappingView(Sized): 627 class MappingView(Sized):
628 628
629 __slots__ = '_mapping', 629 __slots__ = '_mapping',
630 630
631 def __init__(self, mapping): 631 def __init__(self, mapping):
632 self._mapping = mapping 632 self._mapping = mapping
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
787 except KeyError: 787 except KeyError:
788 self[key] = default 788 self[key] = default
789 return default 789 return default
790 790
791 MutableMapping.register(dict) 791 MutableMapping.register(dict)
792 792
793 793
794 ### SEQUENCES ### 794 ### SEQUENCES ###
795 795
796 796
797 class Sequence(Sized, Iterable, Container): 797 class Sequence(Sized, Reversible, Container):
798 798
799 """All the operations on a read-only sequence. 799 """All the operations on a read-only sequence.
800 800
801 Concrete subclasses must override __new__ or __init__, 801 Concrete subclasses must override __new__ or __init__,
802 __getitem__, and __len__. 802 __getitem__, and __len__.
803 """ 803 """
804 804
805 __slots__ = () 805 __slots__ = ()
806 806
807 @abstractmethod 807 @abstractmethod
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
930 Raise ValueError if the value is not present. 930 Raise ValueError if the value is not present.
931 ''' 931 '''
932 del self[self.index(value)] 932 del self[self.index(value)]
933 933
934 def __iadd__(self, values): 934 def __iadd__(self, values):
935 self.extend(values) 935 self.extend(values)
936 return self 936 return self
937 937
938 MutableSequence.register(list) 938 MutableSequence.register(list)
939 MutableSequence.register(bytearray) # Multiply inheriting, see ByteString 939 MutableSequence.register(bytearray) # Multiply inheriting, see ByteString
OLDNEW
« no previous file with comments | « Doc/reference/datamodel.rst ('k') | Lib/test/test_augassign.py » ('j') | no next file with comments »

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+