Issue 27598: Add Collections to collections.abc.
Patch by Ivan Levkivskyi, docs by Neil Girdhar.
This commit is contained in:
parent
9ff4fb3619
commit
f0666949fd
@ -45,10 +45,12 @@ ABC Inherits from Abstract Methods Mixin
|
|||||||
:class:`Generator` :class:`Iterator` ``send``, ``throw`` ``close``, ``__iter__``, ``__next__``
|
:class:`Generator` :class:`Iterator` ``send``, ``throw`` ``close``, ``__iter__``, ``__next__``
|
||||||
:class:`Sized` ``__len__``
|
:class:`Sized` ``__len__``
|
||||||
:class:`Callable` ``__call__``
|
:class:`Callable` ``__call__``
|
||||||
|
:class:`Collection` :class:`Sized`, ``__contains__``,
|
||||||
|
:class:`Iterable`, ``__iter__``,
|
||||||
|
:class:`Container` ``__len__``
|
||||||
|
|
||||||
:class:`Sequence` :class:`Sized`, ``__getitem__``, ``__contains__``, ``__iter__``, ``__reversed__``,
|
:class:`Sequence` :class:`Reversible`, ``__getitem__``, ``__contains__``, ``__iter__``, ``__reversed__``,
|
||||||
:class:`Reversible`, ``__len__`` ``index``, and ``count``
|
:class:`Collection` ``__len__`` ``index``, and ``count``
|
||||||
:class:`Container`
|
|
||||||
|
|
||||||
:class:`MutableSequence` :class:`Sequence` ``__getitem__``, Inherited :class:`Sequence` methods and
|
:class:`MutableSequence` :class:`Sequence` ``__getitem__``, Inherited :class:`Sequence` methods and
|
||||||
``__setitem__``, ``append``, ``reverse``, ``extend``, ``pop``,
|
``__setitem__``, ``append``, ``reverse``, ``extend``, ``pop``,
|
||||||
@ -59,9 +61,9 @@ ABC Inherits from Abstract Methods Mixin
|
|||||||
:class:`ByteString` :class:`Sequence` ``__getitem__``, Inherited :class:`Sequence` methods
|
:class:`ByteString` :class:`Sequence` ``__getitem__``, Inherited :class:`Sequence` methods
|
||||||
``__len__``
|
``__len__``
|
||||||
|
|
||||||
:class:`Set` :class:`Sized`, ``__contains__``, ``__le__``, ``__lt__``, ``__eq__``, ``__ne__``,
|
:class:`Set` :class:`Collection` ``__contains__``, ``__le__``, ``__lt__``, ``__eq__``, ``__ne__``,
|
||||||
:class:`Iterable`, ``__iter__``, ``__gt__``, ``__ge__``, ``__and__``, ``__or__``,
|
``__iter__``, ``__gt__``, ``__ge__``, ``__and__``, ``__or__``,
|
||||||
:class:`Container` ``__len__`` ``__sub__``, ``__xor__``, and ``isdisjoint``
|
``__len__`` ``__sub__``, ``__xor__``, and ``isdisjoint``
|
||||||
|
|
||||||
:class:`MutableSet` :class:`Set` ``__contains__``, Inherited :class:`Set` methods and
|
:class:`MutableSet` :class:`Set` ``__contains__``, Inherited :class:`Set` methods and
|
||||||
``__iter__``, ``clear``, ``pop``, ``remove``, ``__ior__``,
|
``__iter__``, ``clear``, ``pop``, ``remove``, ``__ior__``,
|
||||||
@ -69,9 +71,9 @@ ABC Inherits from Abstract Methods Mixin
|
|||||||
``add``,
|
``add``,
|
||||||
``discard``
|
``discard``
|
||||||
|
|
||||||
:class:`Mapping` :class:`Sized`, ``__getitem__``, ``__contains__``, ``keys``, ``items``, ``values``,
|
:class:`Mapping` :class:`Collection` ``__getitem__``, ``__contains__``, ``keys``, ``items``, ``values``,
|
||||||
:class:`Iterable`, ``__iter__``, ``get``, ``__eq__``, and ``__ne__``
|
``__iter__``, ``get``, ``__eq__``, and ``__ne__``
|
||||||
:class:`Container` ``__len__``
|
``__len__``
|
||||||
|
|
||||||
:class:`MutableMapping` :class:`Mapping` ``__getitem__``, Inherited :class:`Mapping` methods and
|
:class:`MutableMapping` :class:`Mapping` ``__getitem__``, Inherited :class:`Mapping` methods and
|
||||||
``__setitem__``, ``pop``, ``popitem``, ``clear``, ``update``,
|
``__setitem__``, ``pop``, ``popitem``, ``clear``, ``update``,
|
||||||
@ -106,6 +108,12 @@ ABC Inherits from Abstract Methods Mixin
|
|||||||
ABC for classes that provide the :meth:`__iter__` method.
|
ABC for classes that provide the :meth:`__iter__` method.
|
||||||
See also the definition of :term:`iterable`.
|
See also the definition of :term:`iterable`.
|
||||||
|
|
||||||
|
.. class:: Collection
|
||||||
|
|
||||||
|
ABC for sized iterable container classes.
|
||||||
|
|
||||||
|
.. versionadded:: 3.6
|
||||||
|
|
||||||
.. class:: Iterator
|
.. class:: Iterator
|
||||||
|
|
||||||
ABC for classes that provide the :meth:`~iterator.__iter__` and
|
ABC for classes that provide the :meth:`~iterator.__iter__` and
|
||||||
|
@ -11,7 +11,7 @@ import sys
|
|||||||
|
|
||||||
__all__ = ["Awaitable", "Coroutine", "AsyncIterable", "AsyncIterator",
|
__all__ = ["Awaitable", "Coroutine", "AsyncIterable", "AsyncIterator",
|
||||||
"Hashable", "Iterable", "Iterator", "Generator", "Reversible",
|
"Hashable", "Iterable", "Iterator", "Generator", "Reversible",
|
||||||
"Sized", "Container", "Callable",
|
"Sized", "Container", "Callable", "Collection",
|
||||||
"Set", "MutableSet",
|
"Set", "MutableSet",
|
||||||
"Mapping", "MutableMapping",
|
"Mapping", "MutableMapping",
|
||||||
"MappingView", "KeysView", "ItemsView", "ValuesView",
|
"MappingView", "KeysView", "ItemsView", "ValuesView",
|
||||||
@ -326,6 +326,15 @@ class Container(metaclass=ABCMeta):
|
|||||||
return _check_methods(C, "__contains__")
|
return _check_methods(C, "__contains__")
|
||||||
return NotImplemented
|
return NotImplemented
|
||||||
|
|
||||||
|
class Collection(Sized, Iterable, Container):
|
||||||
|
|
||||||
|
__slots__ = ()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def __subclasshook__(cls, C):
|
||||||
|
if cls is Collection:
|
||||||
|
return _check_methods(C, "__len__", "__iter__", "__contains__")
|
||||||
|
return NotImplemented
|
||||||
|
|
||||||
class Callable(metaclass=ABCMeta):
|
class Callable(metaclass=ABCMeta):
|
||||||
|
|
||||||
@ -345,7 +354,7 @@ class Callable(metaclass=ABCMeta):
|
|||||||
### SETS ###
|
### SETS ###
|
||||||
|
|
||||||
|
|
||||||
class Set(Sized, Iterable, Container):
|
class Set(Collection):
|
||||||
|
|
||||||
"""A set is a finite, iterable container.
|
"""A set is a finite, iterable container.
|
||||||
|
|
||||||
@ -570,7 +579,7 @@ MutableSet.register(set)
|
|||||||
### MAPPINGS ###
|
### MAPPINGS ###
|
||||||
|
|
||||||
|
|
||||||
class Mapping(Sized, Iterable, Container):
|
class Mapping(Collection):
|
||||||
|
|
||||||
__slots__ = ()
|
__slots__ = ()
|
||||||
|
|
||||||
@ -794,7 +803,7 @@ MutableMapping.register(dict)
|
|||||||
### SEQUENCES ###
|
### SEQUENCES ###
|
||||||
|
|
||||||
|
|
||||||
class Sequence(Sized, Reversible, Container):
|
class Sequence(Reversible, Collection):
|
||||||
|
|
||||||
"""All the operations on a read-only sequence.
|
"""All the operations on a read-only sequence.
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ from collections import ChainMap
|
|||||||
from collections import deque
|
from collections import deque
|
||||||
from collections.abc import Awaitable, Coroutine, AsyncIterator, AsyncIterable
|
from collections.abc import Awaitable, Coroutine, AsyncIterator, AsyncIterable
|
||||||
from collections.abc import Hashable, Iterable, Iterator, Generator, Reversible
|
from collections.abc import Hashable, Iterable, Iterator, Generator, Reversible
|
||||||
from collections.abc import Sized, Container, Callable
|
from collections.abc import Sized, Container, Callable, Collection
|
||||||
from collections.abc import Set, MutableSet
|
from collections.abc import Set, MutableSet
|
||||||
from collections.abc import Mapping, MutableMapping, KeysView, ItemsView, ValuesView
|
from collections.abc import Mapping, MutableMapping, KeysView, ItemsView, ValuesView
|
||||||
from collections.abc import Sequence, MutableSequence
|
from collections.abc import Sequence, MutableSequence
|
||||||
@ -771,6 +771,94 @@ class TestOneTrickPonyABCs(ABCTestCase):
|
|||||||
self.assertFalse(issubclass(RevRevBlocked, Reversible))
|
self.assertFalse(issubclass(RevRevBlocked, Reversible))
|
||||||
self.assertFalse(isinstance(RevRevBlocked(), Reversible))
|
self.assertFalse(isinstance(RevRevBlocked(), Reversible))
|
||||||
|
|
||||||
|
def test_Collection(self):
|
||||||
|
# Check some non-collections
|
||||||
|
non_collections = [None, 42, 3.14, 1j, lambda x: 2*x]
|
||||||
|
for x in non_collections:
|
||||||
|
self.assertNotIsInstance(x, Collection)
|
||||||
|
self.assertFalse(issubclass(type(x), Collection), repr(type(x)))
|
||||||
|
# Check some non-collection iterables
|
||||||
|
non_col_iterables = [_test_gen(), iter(b''), iter(bytearray()),
|
||||||
|
(x for x in []), dict().values()]
|
||||||
|
for x in non_col_iterables:
|
||||||
|
self.assertNotIsInstance(x, Collection)
|
||||||
|
self.assertFalse(issubclass(type(x), Collection), repr(type(x)))
|
||||||
|
# Check some collections
|
||||||
|
samples = [set(), frozenset(), dict(), bytes(), str(), tuple(),
|
||||||
|
list(), dict().keys(), dict().items()]
|
||||||
|
for x in samples:
|
||||||
|
self.assertIsInstance(x, Collection)
|
||||||
|
self.assertTrue(issubclass(type(x), Collection), repr(type(x)))
|
||||||
|
# Check also Mapping, MutableMapping, etc.
|
||||||
|
self.assertTrue(issubclass(Sequence, Collection), repr(Sequence))
|
||||||
|
self.assertTrue(issubclass(Mapping, Collection), repr(Mapping))
|
||||||
|
self.assertTrue(issubclass(MutableMapping, Collection),
|
||||||
|
repr(MutableMapping))
|
||||||
|
self.assertTrue(issubclass(Set, Collection), repr(Set))
|
||||||
|
self.assertTrue(issubclass(MutableSet, Collection), repr(MutableSet))
|
||||||
|
self.assertTrue(issubclass(Sequence, Collection), repr(MutableSet))
|
||||||
|
# Check direct subclassing
|
||||||
|
class Col(Collection):
|
||||||
|
def __iter__(self):
|
||||||
|
return iter(list())
|
||||||
|
def __len__(self):
|
||||||
|
return 0
|
||||||
|
def __contains__(self, item):
|
||||||
|
return False
|
||||||
|
class DerCol(Col): pass
|
||||||
|
self.assertEqual(list(iter(Col())), [])
|
||||||
|
self.assertFalse(issubclass(list, Col))
|
||||||
|
self.assertFalse(issubclass(set, Col))
|
||||||
|
self.assertFalse(issubclass(float, Col))
|
||||||
|
self.assertEqual(list(iter(DerCol())), [])
|
||||||
|
self.assertFalse(issubclass(list, DerCol))
|
||||||
|
self.assertFalse(issubclass(set, DerCol))
|
||||||
|
self.assertFalse(issubclass(float, DerCol))
|
||||||
|
self.validate_abstract_methods(Collection, '__len__', '__iter__',
|
||||||
|
'__contains__')
|
||||||
|
# Check sized container non-iterable (which is not Collection) etc.
|
||||||
|
class ColNoIter:
|
||||||
|
def __len__(self): return 0
|
||||||
|
def __contains__(self, item): return False
|
||||||
|
class ColNoSize:
|
||||||
|
def __iter__(self): return iter([])
|
||||||
|
def __contains__(self, item): return False
|
||||||
|
class ColNoCont:
|
||||||
|
def __iter__(self): return iter([])
|
||||||
|
def __len__(self): return 0
|
||||||
|
self.assertFalse(issubclass(ColNoIter, Collection))
|
||||||
|
self.assertFalse(isinstance(ColNoIter(), Collection))
|
||||||
|
self.assertFalse(issubclass(ColNoSize, Collection))
|
||||||
|
self.assertFalse(isinstance(ColNoSize(), Collection))
|
||||||
|
self.assertFalse(issubclass(ColNoCont, Collection))
|
||||||
|
self.assertFalse(isinstance(ColNoCont(), Collection))
|
||||||
|
# Check None blocking
|
||||||
|
class SizeBlock:
|
||||||
|
def __iter__(self): return iter([])
|
||||||
|
def __contains__(self): return False
|
||||||
|
__len__ = None
|
||||||
|
class IterBlock:
|
||||||
|
def __len__(self): return 0
|
||||||
|
def __contains__(self): return True
|
||||||
|
__iter__ = None
|
||||||
|
self.assertFalse(issubclass(SizeBlock, Collection))
|
||||||
|
self.assertFalse(isinstance(SizeBlock(), Collection))
|
||||||
|
self.assertFalse(issubclass(IterBlock, Collection))
|
||||||
|
self.assertFalse(isinstance(IterBlock(), Collection))
|
||||||
|
# Check None blocking in subclass
|
||||||
|
class ColImpl:
|
||||||
|
def __iter__(self):
|
||||||
|
return iter(list())
|
||||||
|
def __len__(self):
|
||||||
|
return 0
|
||||||
|
def __contains__(self, item):
|
||||||
|
return False
|
||||||
|
class NonCol(ColImpl):
|
||||||
|
__contains__ = None
|
||||||
|
self.assertFalse(issubclass(NonCol, Collection))
|
||||||
|
self.assertFalse(isinstance(NonCol(), Collection))
|
||||||
|
|
||||||
|
|
||||||
def test_Iterator(self):
|
def test_Iterator(self):
|
||||||
non_samples = [None, 42, 3.14, 1j, b"", "", (), [], {}, set()]
|
non_samples = [None, 42, 3.14, 1j, b"", "", (), [], {}, set()]
|
||||||
for x in non_samples:
|
for x in non_samples:
|
||||||
|
@ -1548,13 +1548,15 @@ class TestSingleDispatch(unittest.TestCase):
|
|||||||
bases = [c.Sequence, c.MutableMapping, c.Mapping, c.Set]
|
bases = [c.Sequence, c.MutableMapping, c.Mapping, c.Set]
|
||||||
for haystack in permutations(bases):
|
for haystack in permutations(bases):
|
||||||
m = mro(dict, haystack)
|
m = mro(dict, haystack)
|
||||||
self.assertEqual(m, [dict, c.MutableMapping, c.Mapping, c.Sized,
|
self.assertEqual(m, [dict, c.MutableMapping, c.Mapping,
|
||||||
c.Iterable, c.Container, object])
|
c.Collection, c.Sized, c.Iterable,
|
||||||
|
c.Container, object])
|
||||||
bases = [c.Container, c.Mapping, c.MutableMapping, c.OrderedDict]
|
bases = [c.Container, c.Mapping, c.MutableMapping, c.OrderedDict]
|
||||||
for haystack in permutations(bases):
|
for haystack in permutations(bases):
|
||||||
m = mro(c.ChainMap, haystack)
|
m = mro(c.ChainMap, haystack)
|
||||||
self.assertEqual(m, [c.ChainMap, c.MutableMapping, c.Mapping,
|
self.assertEqual(m, [c.ChainMap, c.MutableMapping, c.Mapping,
|
||||||
c.Sized, c.Iterable, c.Container, object])
|
c.Collection, c.Sized, c.Iterable,
|
||||||
|
c.Container, object])
|
||||||
|
|
||||||
# If there's a generic function with implementations registered for
|
# If there's a generic function with implementations registered for
|
||||||
# both Sized and Container, passing a defaultdict to it results in an
|
# both Sized and Container, passing a defaultdict to it results in an
|
||||||
@ -1575,9 +1577,9 @@ class TestSingleDispatch(unittest.TestCase):
|
|||||||
bases = [c.MutableSequence, c.MutableMapping]
|
bases = [c.MutableSequence, c.MutableMapping]
|
||||||
for haystack in permutations(bases):
|
for haystack in permutations(bases):
|
||||||
m = mro(D, bases)
|
m = mro(D, bases)
|
||||||
self.assertEqual(m, [D, c.MutableSequence, c.Sequence,
|
self.assertEqual(m, [D, c.MutableSequence, c.Sequence, c.Reversible,
|
||||||
c.defaultdict, dict, c.MutableMapping,
|
c.defaultdict, dict, c.MutableMapping, c.Mapping,
|
||||||
c.Mapping, c.Sized, c.Reversible, c.Iterable, c.Container,
|
c.Collection, c.Sized, c.Iterable, c.Container,
|
||||||
object])
|
object])
|
||||||
|
|
||||||
# Container and Callable are registered on different base classes and
|
# Container and Callable are registered on different base classes and
|
||||||
@ -1590,7 +1592,8 @@ class TestSingleDispatch(unittest.TestCase):
|
|||||||
for haystack in permutations(bases):
|
for haystack in permutations(bases):
|
||||||
m = mro(C, haystack)
|
m = mro(C, haystack)
|
||||||
self.assertEqual(m, [C, c.Callable, c.defaultdict, dict, c.Mapping,
|
self.assertEqual(m, [C, c.Callable, c.defaultdict, dict, c.Mapping,
|
||||||
c.Sized, c.Iterable, c.Container, object])
|
c.Collection, c.Sized, c.Iterable,
|
||||||
|
c.Container, object])
|
||||||
|
|
||||||
def test_register_abc(self):
|
def test_register_abc(self):
|
||||||
c = collections
|
c = collections
|
||||||
|
@ -126,6 +126,9 @@ Core and Builtins
|
|||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue 27598: Add Collections to collections.abc.
|
||||||
|
Patch by Ivan Levkivskyi, docs by Neil Girdhar.
|
||||||
|
|
||||||
- Issue #25958: Support "anti-registration" of special methods from
|
- Issue #25958: Support "anti-registration" of special methods from
|
||||||
various ABCs, like __hash__, __iter__ or __len__. All these (and
|
various ABCs, like __hash__, __iter__ or __len__. All these (and
|
||||||
several more) can be set to None in an implementation class and the
|
several more) can be set to None in an implementation class and the
|
||||||
|
Loading…
x
Reference in New Issue
Block a user