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

Side by Side Diff: Lib/_collections_abc.py

Issue 25958: Implicit ABCs have no means of "anti-registration"
Patch Set: Created 3 years, 6 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
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
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 def __aiter__(self): 156 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 def __aiter__(self): 175 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, '__iter__', '__next__')
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)
236 Iterator.register(range_iterator) 227 Iterator.register(range_iterator)
237 Iterator.register(set_iterator) 228 Iterator.register(set_iterator)
238 Iterator.register(str_iterator) 229 Iterator.register(str_iterator)
239 Iterator.register(tuple_iterator) 230 Iterator.register(tuple_iterator)
240 Iterator.register(zip_iterator) 231 Iterator.register(zip_iterator)
241 232
242 233
243 class Reversible(Iterable): 234 class Reversible(Iterable):
244 235
245 __slots__ = () 236 __slots__ = ()
246 237
247 @abstractmethod 238 @abstractmethod
248 def __reversed__(self): 239 def __reversed__(self):
249 return NotImplemented 240 while False:
241 yield None
250 242
251 @classmethod 243 @classmethod
252 def __subclasshook__(cls, C): 244 def __subclasshook__(cls, C):
253 if cls is Reversible: 245 if cls is Reversible:
254 for B in C.__mro__: 246 return _check_methods(C, "__reversed__", "__iter__")
255 if "__reversed__" in B.__dict__:
256 if B.__dict__["__reversed__"] is not None:
257 return True
258 break
259 return NotImplemented 247 return NotImplemented
260 248
261 249
262 class Generator(Iterator): 250 class Generator(Iterator):
263 251
264 __slots__ = () 252 __slots__ = ()
265 253
266 def __next__(self): 254 def __next__(self):
267 """Return the next item from the generator. 255 """Return the next item from the generator.
268 When exhausted, raise StopIteration. 256 When exhausted, raise StopIteration.
(...skipping 26 matching lines...) Expand all
295 try: 283 try:
296 self.throw(GeneratorExit) 284 self.throw(GeneratorExit)
297 except (GeneratorExit, StopIteration): 285 except (GeneratorExit, StopIteration):
298 pass 286 pass
299 else: 287 else:
300 raise RuntimeError("generator ignored GeneratorExit") 288 raise RuntimeError("generator ignored GeneratorExit")
301 289
302 @classmethod 290 @classmethod
303 def __subclasshook__(cls, C): 291 def __subclasshook__(cls, C):
304 if cls is Generator: 292 if cls is Generator:
305 mro = C.__mro__ 293 return _check_methods(C, '__iter__', '__next__',
306 for method in ('__iter__', '__next__', 'send', 'throw', 'close'): 294 'send', 'throw', 'close')
307 for base in mro:
308 if method in base.__dict__:
309 break
310 else:
311 return NotImplemented
312 return True
313 return NotImplemented 295 return NotImplemented
314
315 296
316 Generator.register(generator) 297 Generator.register(generator)
317 298
318 299
319 class Sized(metaclass=ABCMeta): 300 class Sized(metaclass=ABCMeta):
320 301
321 __slots__ = () 302 __slots__ = ()
322 303
323 @abstractmethod 304 @abstractmethod
324 def __len__(self): 305 def __len__(self):
325 return 0 306 return 0
326 307
327 @classmethod 308 @classmethod
328 def __subclasshook__(cls, C): 309 def __subclasshook__(cls, C):
329 if cls is Sized: 310 if cls is Sized:
330 if any("__len__" in B.__dict__ for B in C.__mro__): 311 return _check_methods(C, "__len__")
331 return True
332 return NotImplemented 312 return NotImplemented
333 313
334 314
335 class Container(metaclass=ABCMeta): 315 class Container(metaclass=ABCMeta):
336 316
337 __slots__ = () 317 __slots__ = ()
338 318
339 @abstractmethod 319 @abstractmethod
340 def __contains__(self, x): 320 def __contains__(self, x):
341 return False 321 return False
342 322
343 @classmethod 323 @classmethod
344 def __subclasshook__(cls, C): 324 def __subclasshook__(cls, C):
345 if cls is Container: 325 if cls is Container:
346 if any("__contains__" in B.__dict__ for B in C.__mro__): 326 return _check_methods(C, "__contains__")
347 return True
348 return NotImplemented 327 return NotImplemented
349 328
350 329
351 class Callable(metaclass=ABCMeta): 330 class Callable(metaclass=ABCMeta):
352 331
353 __slots__ = () 332 __slots__ = ()
354 333
355 @abstractmethod 334 @abstractmethod
356 def __call__(self, *args, **kwds): 335 def __call__(self, *args, **kwds):
357 return False 336 return False
358 337
359 @classmethod 338 @classmethod
360 def __subclasshook__(cls, C): 339 def __subclasshook__(cls, C):
361 if cls is Callable: 340 if cls is Callable:
362 if any("__call__" in B.__dict__ for B in C.__mro__): 341 return _check_methods(C, "__call__")
363 return True
364 return NotImplemented 342 return NotImplemented
365 343
366 344
367 ### SETS ### 345 ### SETS ###
368 346
369 347
370 class Set(Sized, Iterable, Container): 348 class Set(Sized, Iterable, Container):
371 349
372 """A set is a finite, iterable container. 350 """A set is a finite, iterable container.
373 351
(...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after
632 return ItemsView(self) 610 return ItemsView(self)
633 611
634 def values(self): 612 def values(self):
635 "D.values() -> an object providing a view on D's values" 613 "D.values() -> an object providing a view on D's values"
636 return ValuesView(self) 614 return ValuesView(self)
637 615
638 def __eq__(self, other): 616 def __eq__(self, other):
639 if not isinstance(other, Mapping): 617 if not isinstance(other, Mapping):
640 return NotImplemented 618 return NotImplemented
641 return dict(self.items()) == dict(other.items()) 619 return dict(self.items()) == dict(other.items())
620
621 __reversed__ = None
642 622
643 Mapping.register(mappingproxy) 623 Mapping.register(mappingproxy)
644 624
645 625
646 class MappingView(Sized): 626 class MappingView(Sized):
647 627
648 __slots__ = '_mapping', 628 __slots__ = '_mapping',
649 629
650 def __init__(self, mapping): 630 def __init__(self, mapping):
651 self._mapping = mapping 631 self._mapping = mapping
(...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after
950 Raise ValueError if the value is not present. 930 Raise ValueError if the value is not present.
951 ''' 931 '''
952 del self[self.index(value)] 932 del self[self.index(value)]
953 933
954 def __iadd__(self, values): 934 def __iadd__(self, values):
955 self.extend(values) 935 self.extend(values)
956 return self 936 return self
957 937
958 MutableSequence.register(list) 938 MutableSequence.register(list)
959 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+