diff -r 23d986228c6b Doc/library/collections.abc.rst --- a/Doc/library/collections.abc.rst Sat Apr 02 04:48:46 2016 +0300 +++ b/Doc/library/collections.abc.rst Sat Apr 02 22:50:46 2016 +0200 @@ -40,12 +40,13 @@ :class:`Hashable` ``__hash__`` :class:`Iterable` ``__iter__`` :class:`Iterator` :class:`Iterable` ``__next__`` ``__iter__`` +:class:`Reversible` :class:`Iterable` ``__reversed__`` :class:`Generator` :class:`Iterator` ``send``, ``throw`` ``close``, ``__iter__``, ``__next__`` :class:`Sized` ``__len__`` :class:`Callable` ``__call__`` :class:`Sequence` :class:`Sized`, ``__getitem__``, ``__contains__``, ``__iter__``, ``__reversed__``, - :class:`Iterable`, ``__len__`` ``index``, and ``count`` + :class:`Reversible`, ``__len__`` ``index``, and ``count`` :class:`Container` :class:`MutableSequence` :class:`Sequence` ``__getitem__``, Inherited :class:`Sequence` methods and @@ -107,6 +108,10 @@ :meth:`~iterator.__next__` methods. See also the definition of :term:`iterator`. +.. class:: Reversible + + ABC for classes that provide the :meth:`__reversed__` method. + .. class:: Generator ABC for generator classes that implement the protocol defined in diff -r 23d986228c6b Doc/library/typing.rst --- a/Doc/library/typing.rst Sat Apr 02 04:48:46 2016 +0300 +++ b/Doc/library/typing.rst Sat Apr 02 22:50:46 2016 +0200 @@ -351,6 +351,10 @@ A generic version of the :class:`collections.abc.Iterator`. +.. class:: Reversible(Iterable[T_co]) + + A generic version of the :class:`collections.abc.Reversible`. + .. class:: SupportsInt An ABC with one abstract method ``__int__``. @@ -369,11 +373,6 @@ An ABC with one abstract method ``__round__`` that is covariant in its return type. -.. class:: Reversible - - An ABC with one abstract method ``__reversed__`` returning - an ``Iterator[T_co]``. - .. class:: Container(Generic[T_co]) A generic version of :class:`collections.abc.Container`. @@ -394,7 +393,7 @@ A generic version of :class:`collections.abc.MutableMapping`. -.. class:: Sequence(Sized, Iterable[T_co], Container[T_co]) +.. class:: Sequence(Sized, Reversible[T_co], Container[T_co]) A generic version of :class:`collections.abc.Sequence`. diff -r 23d986228c6b Lib/_collections_abc.py --- a/Lib/_collections_abc.py Sat Apr 02 04:48:46 2016 +0300 +++ b/Lib/_collections_abc.py Sat Apr 02 22:50:46 2016 +0200 @@ -10,7 +10,7 @@ import sys __all__ = ["Awaitable", "Coroutine", "AsyncIterable", "AsyncIterator", - "Hashable", "Iterable", "Iterator", "Generator", + "Hashable", "Iterable", "Iterator", "Generator", "Reversible", "Sized", "Container", "Callable", "Set", "MutableSet", "Mapping", "MutableMapping", @@ -240,6 +240,25 @@ Iterator.register(zip_iterator) +class Reversible(Iterable): + + __slots__ = () + + @abstractmethod + def __reversed__(self): + return NotImplemented + + @classmethod + def __subclasshook__(cls, C): + if cls is Reversible: + for B in C.__mro__: + if "__reversed__" in B.__dict__: + if B.__dict__["__reversed__"] is not None: + return True + break + return NotImplemented + + class Generator(Iterator): __slots__ = () @@ -794,7 +813,7 @@ ### SEQUENCES ### -class Sequence(Sized, Iterable, Container): +class Sequence(Sized, Reversible, Container): """All the operations on a read-only sequence. diff -r 23d986228c6b Lib/test/test_collections.py --- a/Lib/test/test_collections.py Sat Apr 02 04:48:46 2016 +0300 +++ b/Lib/test/test_collections.py Sat Apr 02 22:50:46 2016 +0200 @@ -20,7 +20,7 @@ from collections import ChainMap from collections import deque from collections.abc import Awaitable, Coroutine, AsyncIterator, AsyncIterable -from collections.abc import Hashable, Iterable, Iterator, Generator +from collections.abc import Hashable, Iterable, Iterator, Generator, Reversible from collections.abc import Sized, Container, Callable from collections.abc import Set, MutableSet from collections.abc import Mapping, MutableMapping, KeysView, ItemsView @@ -689,6 +689,31 @@ self.validate_abstract_methods(Iterable, '__iter__') self.validate_isinstance(Iterable, '__iter__') + def test_Reversible(self): + # Check some non-reversibles + non_samples = [None, 42, 3.14, 1j, dict(), set(), frozenset()] + for x in non_samples: + self.assertNotIsInstance(x, Reversible) + self.assertFalse(issubclass(type(x), Reversible), repr(type(x))) + # Check some reversibles + samples = [tuple(), list()] + for x in samples: + self.assertIsInstance(x, Reversible) + self.assertTrue(issubclass(type(x), Reversible), repr(type(x))) + # Check also Mapping, MutableMapping, and Sequence + self.assertTrue(issubclass(Sequence, Reversible), repr(Sequence)) + self.assertFalse(issubclass(Mapping, Reversible), repr(Mapping)) + self.assertFalse(issubclass(MutableMapping, Reversible), repr(MutableMapping)) + # Check direct subclassing + class R(Reversible): + def __iter__(self): + return iter(list()) + def __reversed__(self): + return iter(list()) + self.assertEqual(list(reversed(R())), []) + self.assertFalse(issubclass(float, R)) + self.validate_abstract_methods(Reversible, '__reversed__', '__iter__') + def test_Iterator(self): non_samples = [None, 42, 3.14, 1j, b"", "", (), [], {}, set()] for x in non_samples: @@ -842,14 +867,14 @@ self.validate_isinstance(Callable, '__call__') def test_direct_subclassing(self): - for B in Hashable, Iterable, Iterator, Sized, Container, Callable: + for B in Hashable, Iterable, Iterator, Reversible, Sized, Container, Callable: class C(B): pass self.assertTrue(issubclass(C, B)) self.assertFalse(issubclass(int, C)) def test_registration(self): - for B in Hashable, Iterable, Iterator, Sized, Container, Callable: + for B in Hashable, Iterable, Iterator, Reversible, Sized, Container, Callable: class C: __hash__ = None # Make sure it isn't hashable by default self.assertFalse(issubclass(C, B), B.__name__) diff -r 23d986228c6b Lib/test/test_functools.py --- a/Lib/test/test_functools.py Sat Apr 02 04:48:46 2016 +0300 +++ b/Lib/test/test_functools.py Sat Apr 02 22:50:46 2016 +0200 @@ -1516,7 +1516,7 @@ m = mro(D, bases) self.assertEqual(m, [D, c.MutableSequence, c.Sequence, c.defaultdict, dict, c.MutableMapping, - c.Mapping, c.Sized, c.Iterable, c.Container, + c.Mapping, c.Sized, c.Reversible, c.Iterable, c.Container, object]) # Container and Callable are registered on different base classes and