|
21 | 21 | from collections import deque |
22 | 22 | from collections.abc import Awaitable, Coroutine, AsyncIterator, AsyncIterable |
23 | 23 | from collections.abc import Hashable, Iterable, Iterator, Generator, Reversible |
24 | | -from collections.abc import Sized, Container, Callable |
| 24 | +from collections.abc import Sized, Container, Callable, Collection |
25 | 25 | from collections.abc import Set, MutableSet |
26 | 26 | from collections.abc import Mapping, MutableMapping, KeysView, ItemsView, ValuesView |
27 | 27 | from collections.abc import Sequence, MutableSequence |
@@ -771,6 +771,94 @@ class RevRevBlocked(Rev): |
771 | 771 | self.assertFalse(issubclass(RevRevBlocked, Reversible)) |
772 | 772 | self.assertFalse(isinstance(RevRevBlocked(), Reversible)) |
773 | 773 |
|
| 774 | + def test_Collection(self): |
| 775 | + # Check some non-collections |
| 776 | + non_collections = [None, 42, 3.14, 1j, lambda x: 2*x] |
| 777 | + for x in non_collections: |
| 778 | + self.assertNotIsInstance(x, Collection) |
| 779 | + self.assertFalse(issubclass(type(x), Collection), repr(type(x))) |
| 780 | + # Check some non-collection iterables |
| 781 | + non_col_iterables = [_test_gen(), iter(b''), iter(bytearray()), |
| 782 | + (x for x in []), dict().values()] |
| 783 | + for x in non_col_iterables: |
| 784 | + self.assertNotIsInstance(x, Collection) |
| 785 | + self.assertFalse(issubclass(type(x), Collection), repr(type(x))) |
| 786 | + # Check some collections |
| 787 | + samples = [set(), frozenset(), dict(), bytes(), str(), tuple(), |
| 788 | + list(), dict().keys(), dict().items()] |
| 789 | + for x in samples: |
| 790 | + self.assertIsInstance(x, Collection) |
| 791 | + self.assertTrue(issubclass(type(x), Collection), repr(type(x))) |
| 792 | + # Check also Mapping, MutableMapping, etc. |
| 793 | + self.assertTrue(issubclass(Sequence, Collection), repr(Sequence)) |
| 794 | + self.assertTrue(issubclass(Mapping, Collection), repr(Mapping)) |
| 795 | + self.assertTrue(issubclass(MutableMapping, Collection), |
| 796 | + repr(MutableMapping)) |
| 797 | + self.assertTrue(issubclass(Set, Collection), repr(Set)) |
| 798 | + self.assertTrue(issubclass(MutableSet, Collection), repr(MutableSet)) |
| 799 | + self.assertTrue(issubclass(Sequence, Collection), repr(MutableSet)) |
| 800 | + # Check direct subclassing |
| 801 | + class Col(Collection): |
| 802 | + def __iter__(self): |
| 803 | + return iter(list()) |
| 804 | + def __len__(self): |
| 805 | + return 0 |
| 806 | + def __contains__(self, item): |
| 807 | + return False |
| 808 | + class DerCol(Col): pass |
| 809 | + self.assertEqual(list(iter(Col())), []) |
| 810 | + self.assertFalse(issubclass(list, Col)) |
| 811 | + self.assertFalse(issubclass(set, Col)) |
| 812 | + self.assertFalse(issubclass(float, Col)) |
| 813 | + self.assertEqual(list(iter(DerCol())), []) |
| 814 | + self.assertFalse(issubclass(list, DerCol)) |
| 815 | + self.assertFalse(issubclass(set, DerCol)) |
| 816 | + self.assertFalse(issubclass(float, DerCol)) |
| 817 | + self.validate_abstract_methods(Collection, '__len__', '__iter__', |
| 818 | + '__contains__') |
| 819 | + # Check sized container non-iterable (which is not Collection) etc. |
| 820 | + class ColNoIter: |
| 821 | + def __len__(self): return 0 |
| 822 | + def __contains__(self, item): return False |
| 823 | + class ColNoSize: |
| 824 | + def __iter__(self): return iter([]) |
| 825 | + def __contains__(self, item): return False |
| 826 | + class ColNoCont: |
| 827 | + def __iter__(self): return iter([]) |
| 828 | + def __len__(self): return 0 |
| 829 | + self.assertFalse(issubclass(ColNoIter, Collection)) |
| 830 | + self.assertFalse(isinstance(ColNoIter(), Collection)) |
| 831 | + self.assertFalse(issubclass(ColNoSize, Collection)) |
| 832 | + self.assertFalse(isinstance(ColNoSize(), Collection)) |
| 833 | + self.assertFalse(issubclass(ColNoCont, Collection)) |
| 834 | + self.assertFalse(isinstance(ColNoCont(), Collection)) |
| 835 | + # Check None blocking |
| 836 | + class SizeBlock: |
| 837 | + def __iter__(self): return iter([]) |
| 838 | + def __contains__(self): return False |
| 839 | + __len__ = None |
| 840 | + class IterBlock: |
| 841 | + def __len__(self): return 0 |
| 842 | + def __contains__(self): return True |
| 843 | + __iter__ = None |
| 844 | + self.assertFalse(issubclass(SizeBlock, Collection)) |
| 845 | + self.assertFalse(isinstance(SizeBlock(), Collection)) |
| 846 | + self.assertFalse(issubclass(IterBlock, Collection)) |
| 847 | + self.assertFalse(isinstance(IterBlock(), Collection)) |
| 848 | + # Check None blocking in subclass |
| 849 | + class ColImpl: |
| 850 | + def __iter__(self): |
| 851 | + return iter(list()) |
| 852 | + def __len__(self): |
| 853 | + return 0 |
| 854 | + def __contains__(self, item): |
| 855 | + return False |
| 856 | + class NonCol(ColImpl): |
| 857 | + __contains__ = None |
| 858 | + self.assertFalse(issubclass(NonCol, Collection)) |
| 859 | + self.assertFalse(isinstance(NonCol(), Collection)) |
| 860 | + |
| 861 | + |
774 | 862 | def test_Iterator(self): |
775 | 863 | non_samples = [None, 42, 3.14, 1j, b"", "", (), [], {}, set()] |
776 | 864 | for x in non_samples: |
|
0 commit comments