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

Side by Side Diff: Lib/_collections_abc.py

Issue 25958: Implicit ABCs have no means of "anti-registration"
Patch Set: Created 4 years, 1 month 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
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):
storchaka 2016/01/05 21:48:04 FYI, there is a separate issue for introducing suc
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):
87 print(cls)
gvanrossum 2016/01/05 20:55:20 Delete this.
storchaka 2016/01/05 21:48:04 Forgotten debugging print.
75 if cls is Hashable: 88 if cls is Hashable:
76 for B in C.__mro__: 89 return _check_methods(C, "__hash__")
77 if "__hash__" in B.__dict__:
78 if B.__dict__["__hash__"]:
79 return True
80 break
81 return NotImplemented 90 return NotImplemented
82 91
83 92
84 class Awaitable(metaclass=ABCMeta): 93 class Awaitable(metaclass=ABCMeta):
85 94
86 __slots__ = () 95 __slots__ = ()
87 96
88 @abstractmethod 97 @abstractmethod
89 def __await__(self): 98 def __await__(self):
90 yield 99 yield
91 100
92 @classmethod 101 @classmethod
93 def __subclasshook__(cls, C): 102 def __subclasshook__(cls, C):
94 if cls is Awaitable: 103 if cls is Awaitable:
95 for B in C.__mro__: 104 return _check_methods(C, "__await__")
96 if "__await__" in B.__dict__:
97 if B.__dict__["__await__"]:
98 return True
99 break
100 return NotImplemented 105 return NotImplemented
101 106
102 107
103 class Coroutine(Awaitable): 108 class Coroutine(Awaitable):
104 109
105 __slots__ = () 110 __slots__ = ()
106 111
107 @abstractmethod 112 @abstractmethod
108 def send(self, value): 113 def send(self, value):
109 """Send a value into the coroutine. 114 """Send a value into the coroutine.
(...skipping 20 matching lines...) Expand all
130 try: 135 try:
131 self.throw(GeneratorExit) 136 self.throw(GeneratorExit)
132 except (GeneratorExit, StopIteration): 137 except (GeneratorExit, StopIteration):
133 pass 138 pass
134 else: 139 else:
135 raise RuntimeError("coroutine ignored GeneratorExit") 140 raise RuntimeError("coroutine ignored GeneratorExit")
136 141
137 @classmethod 142 @classmethod
138 def __subclasshook__(cls, C): 143 def __subclasshook__(cls, C):
139 if cls is Coroutine: 144 if cls is Coroutine:
140 mro = C.__mro__ 145 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 146 return NotImplemented
149 147
150 148
151 Coroutine.register(coroutine) 149 Coroutine.register(coroutine)
152 150
153 151
154 class AsyncIterable(metaclass=ABCMeta): 152 class AsyncIterable(metaclass=ABCMeta):
155 153
156 __slots__ = () 154 __slots__ = ()
157 155
158 @abstractmethod 156 @abstractmethod
159 async def __aiter__(self): 157 async def __aiter__(self):
160 return AsyncIterator() 158 return AsyncIterator()
161 159
162 @classmethod 160 @classmethod
163 def __subclasshook__(cls, C): 161 def __subclasshook__(cls, C):
164 if cls is AsyncIterable: 162 if cls is AsyncIterable:
165 if any("__aiter__" in B.__dict__ for B in C.__mro__): 163 return _check_methods(C, "__aiter__")
166 return True
167 return NotImplemented 164 return NotImplemented
168 165
169 166
170 class AsyncIterator(AsyncIterable): 167 class AsyncIterator(AsyncIterable):
171 168
172 __slots__ = () 169 __slots__ = ()
173 170
174 @abstractmethod 171 @abstractmethod
175 async def __anext__(self): 172 async def __anext__(self):
176 """Return the next item or raise StopAsyncIteration when exhausted.""" 173 """Return the next item or raise StopAsyncIteration when exhausted."""
177 raise StopAsyncIteration 174 raise StopAsyncIteration
178 175
179 async def __aiter__(self): 176 async def __aiter__(self):
180 return self 177 return self
181 178
182 @classmethod 179 @classmethod
183 def __subclasshook__(cls, C): 180 def __subclasshook__(cls, C):
184 if cls is AsyncIterator: 181 if cls is AsyncIterator:
185 if (any("__anext__" in B.__dict__ for B in C.__mro__) and 182 return _check_methods(C, "__anext__", "__aiter__")
186 any("__aiter__" in B.__dict__ for B in C.__mro__)):
187 return True
188 return NotImplemented 183 return NotImplemented
189 184
190 185
191 class Iterable(metaclass=ABCMeta): 186 class Iterable(metaclass=ABCMeta):
192 187
193 __slots__ = () 188 __slots__ = ()
194 189
195 @abstractmethod 190 @abstractmethod
196 def __iter__(self): 191 def __iter__(self):
197 while False: 192 while False:
198 yield None 193 yield None
199 194
200 @classmethod 195 @classmethod
201 def __subclasshook__(cls, C): 196 def __subclasshook__(cls, C):
202 if cls is Iterable: 197 if cls is Iterable:
203 if any("__iter__" in B.__dict__ for B in C.__mro__): 198 return _check_methods(C, "__iter__")
204 return True
205 return NotImplemented 199 return NotImplemented
206 200
207 201
208 class Iterator(Iterable): 202 class Iterator(Iterable):
209 203
210 __slots__ = () 204 __slots__ = ()
211 205
212 @abstractmethod 206 @abstractmethod
213 def __next__(self): 207 def __next__(self):
214 'Return the next item from the iterator. When exhausted, raise StopItera tion' 208 'Return the next item from the iterator. When exhausted, raise StopItera tion'
215 raise StopIteration 209 raise StopIteration
216 210
217 def __iter__(self): 211 def __iter__(self):
218 return self 212 return self
219 213
220 @classmethod 214 @classmethod
221 def __subclasshook__(cls, C): 215 def __subclasshook__(cls, C):
222 if cls is Iterator: 216 if cls is Iterator:
223 if (any("__next__" in B.__dict__ for B in C.__mro__) and 217 return _check_methods(C, "__next__", "__iter__")
224 any("__iter__" in B.__dict__ for B in C.__mro__)):
225 return True
226 return NotImplemented 218 return NotImplemented
227 219
228 Iterator.register(bytes_iterator) 220 Iterator.register(bytes_iterator)
229 Iterator.register(bytearray_iterator) 221 Iterator.register(bytearray_iterator)
230 #Iterator.register(callable_iterator) 222 #Iterator.register(callable_iterator)
231 Iterator.register(dict_keyiterator) 223 Iterator.register(dict_keyiterator)
232 Iterator.register(dict_valueiterator) 224 Iterator.register(dict_valueiterator)
233 Iterator.register(dict_itemiterator) 225 Iterator.register(dict_itemiterator)
234 Iterator.register(list_iterator) 226 Iterator.register(list_iterator)
235 Iterator.register(list_reverseiterator) 227 Iterator.register(list_reverseiterator)
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
276 try: 268 try:
277 self.throw(GeneratorExit) 269 self.throw(GeneratorExit)
278 except (GeneratorExit, StopIteration): 270 except (GeneratorExit, StopIteration):
279 pass 271 pass
280 else: 272 else:
281 raise RuntimeError("generator ignored GeneratorExit") 273 raise RuntimeError("generator ignored GeneratorExit")
282 274
283 @classmethod 275 @classmethod
284 def __subclasshook__(cls, C): 276 def __subclasshook__(cls, C):
285 if cls is Generator: 277 if cls is Generator:
286 mro = C.__mro__ 278 return _check_methods(C, '__iter__', '__next__',
287 for method in ('__iter__', '__next__', 'send', 'throw', 'close'): 279 '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 280 return NotImplemented
295 281
296 282
297 Generator.register(generator) 283 Generator.register(generator)
298 284
299 285
300 class Sized(metaclass=ABCMeta): 286 class Sized(metaclass=ABCMeta):
301 287
302 __slots__ = () 288 __slots__ = ()
303 289
304 @abstractmethod 290 @abstractmethod
305 def __len__(self): 291 def __len__(self):
306 return 0 292 return 0
307 293
308 @classmethod 294 @classmethod
309 def __subclasshook__(cls, C): 295 def __subclasshook__(cls, C):
310 if cls is Sized: 296 if cls is Sized:
311 if any("__len__" in B.__dict__ for B in C.__mro__): 297 return _check_methods(C, "__len__")
312 return True
313 return NotImplemented 298 return NotImplemented
314 299
315 300
316 class Container(metaclass=ABCMeta): 301 class Container(metaclass=ABCMeta):
317 302
318 __slots__ = () 303 __slots__ = ()
319 304
320 @abstractmethod 305 @abstractmethod
321 def __contains__(self, x): 306 def __contains__(self, x):
322 return False 307 return False
323 308
324 @classmethod 309 @classmethod
325 def __subclasshook__(cls, C): 310 def __subclasshook__(cls, C):
326 if cls is Container: 311 if cls is Container:
327 if any("__contains__" in B.__dict__ for B in C.__mro__): 312 return _check_methods(C, "__contains__")
328 return True
329 return NotImplemented 313 return NotImplemented
330 314
331 315
332 class Callable(metaclass=ABCMeta): 316 class Callable(metaclass=ABCMeta):
333 317
334 __slots__ = () 318 __slots__ = ()
335 319
336 @abstractmethod 320 @abstractmethod
337 def __call__(self, *args, **kwds): 321 def __call__(self, *args, **kwds):
338 return False 322 return False
339 323
340 @classmethod 324 @classmethod
341 def __subclasshook__(cls, C): 325 def __subclasshook__(cls, C):
342 if cls is Callable: 326 if cls is Callable:
343 if any("__call__" in B.__dict__ for B in C.__mro__): 327 return _check_methods(C, "__call__")
344 return True
345 return NotImplemented 328 return NotImplemented
346 329
347 330
331 class Reversible(Iterable):
332
333 __slots__ = ()
334
335 @abstractmethod
336 def __reversed__(self):
337 while False:
338 yield None
339
340 @classmethod
341 def __subclasshook__(cls, C):
storchaka 2016/01/05 21:48:04 Since Reversible is Iterable subclass, shouldn't R
342 if cls is Reversible:
343 return _check_methods(C, "__reversed__")
344 return NotImplemented
345
346
348 ### SETS ### 347 ### SETS ###
349 348
350 349
351 class Set(Sized, Iterable, Container): 350 class Set(Sized, Iterable, Container):
352 351
353 """A set is a finite, iterable container. 352 """A set is a finite, iterable container.
354 353
355 This class provides concrete generic implementations of all 354 This class provides concrete generic implementations of all
356 methods except for __contains__, __iter__ and __len__. 355 methods except for __contains__, __iter__ and __len__.
357 356
(...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after
613 return ItemsView(self) 612 return ItemsView(self)
614 613
615 def values(self): 614 def values(self):
616 "D.values() -> an object providing a view on D's values" 615 "D.values() -> an object providing a view on D's values"
617 return ValuesView(self) 616 return ValuesView(self)
618 617
619 def __eq__(self, other): 618 def __eq__(self, other):
620 if not isinstance(other, Mapping): 619 if not isinstance(other, Mapping):
621 return NotImplemented 620 return NotImplemented
622 return dict(self.items()) == dict(other.items()) 621 return dict(self.items()) == dict(other.items())
622
623 __reversed__ = None
623 624
624 Mapping.register(mappingproxy) 625 Mapping.register(mappingproxy)
625 626
626 627
627 class MappingView(Sized): 628 class MappingView(Sized):
628 629
629 __slots__ = '_mapping', 630 __slots__ = '_mapping',
630 631
631 def __init__(self, mapping): 632 def __init__(self, mapping):
632 self._mapping = mapping 633 self._mapping = mapping
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
787 except KeyError: 788 except KeyError:
788 self[key] = default 789 self[key] = default
789 return default 790 return default
790 791
791 MutableMapping.register(dict) 792 MutableMapping.register(dict)
792 793
793 794
794 ### SEQUENCES ### 795 ### SEQUENCES ###
795 796
796 797
797 class Sequence(Sized, Iterable, Container): 798 class Sequence(Sized, Reversible, Container):
798 799
799 """All the operations on a read-only sequence. 800 """All the operations on a read-only sequence.
800 801
801 Concrete subclasses must override __new__ or __init__, 802 Concrete subclasses must override __new__ or __init__,
802 __getitem__, and __len__. 803 __getitem__, and __len__.
803 """ 804 """
804 805
805 __slots__ = () 806 __slots__ = ()
806 807
807 @abstractmethod 808 @abstractmethod
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
930 Raise ValueError if the value is not present. 931 Raise ValueError if the value is not present.
931 ''' 932 '''
932 del self[self.index(value)] 933 del self[self.index(value)]
933 934
934 def __iadd__(self, values): 935 def __iadd__(self, values):
935 self.extend(values) 936 self.extend(values)
936 return self 937 return self
937 938
938 MutableSequence.register(list) 939 MutableSequence.register(list)
939 MutableSequence.register(bytearray) # Multiply inheriting, see ByteString 940 MutableSequence.register(bytearray) # Multiply inheriting, see ByteString
OLDNEW

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