diff -r 9c68831ff153 Lib/_collections_abc.py --- a/Lib/_collections_abc.py Wed Jan 07 11:33:51 2015 -0600 +++ b/Lib/_collections_abc.py Wed Jan 07 11:40:44 2015 -0600 @@ -661,13 +661,23 @@ for i in reversed(range(len(self))): yield self[i] - def index(self, value): - '''S.index(value) -> integer -- return first index of value. + def index(self, value, start=0, stop=None): + '''S.index(value, [start, [stop]]) -> integer -- return first index of value. Raises ValueError if the value is not present. ''' - for i, v in enumerate(self): - if v == value: - return i + if start is not None and start < 0: + start = max(len(self) + start, 0) + if stop is not None and stop < 0: + stop += len(self) + + i = start + while stop is None or i < stop: + try: + if self[i] == value: + return i + except IndexError: + break + i += 1 raise ValueError def count(self, value): diff -r 9c68831ff153 Lib/test/test_collections.py --- a/Lib/test/test_collections.py Wed Jan 07 11:33:51 2015 -0600 +++ b/Lib/test/test_collections.py Wed Jan 07 11:40:44 2015 -0600 @@ -614,9 +614,9 @@ class TestCollectionABCs(ABCTestCase): - # XXX For now, we only test some virtual inheritance properties. - # We should also test the proper behavior of the collection ABCs - # as real base classes or mix-in classes. + # XXX The virtual inheritance properties are tested here, but we need more + # tests for proper behavior of the collection ABCs as real base classes or + # mix-in classes. def test_Set(self): for sample in [set, frozenset]: @@ -1000,6 +1000,43 @@ self.validate_abstract_methods(Sequence, '__contains__', '__iter__', '__len__', '__getitem__') + def test_Sequence_mixins(self): + class SequenceSubclass(Sequence): + def __init__(self, seq=()): + self.seq = seq + + def __getitem__(self, index): + return self.seq[index] + + def __len__(self): + return len(self.seq) + + # Compare Sequence.index() behavior to (list|str).index() behavior + def assert_index_same(seq1, seq2, index_args): + try: + expected = seq1.index(*index_args) + except ValueError: + with self.assertRaises(ValueError): + seq2.index(*index_args) + else: + actual = seq2.index(*index_args) + self.assertEqual( + actual, expected, '%r.index%s' % (seq1, index_args)) + + for ty in list, str: + nativeseq = ty('abracadabra') + indexes = [-10000, -9999] + list(range(-3, len(nativeseq) + 3)) + seqseq = SequenceSubclass(nativeseq) + for letter in set(nativeseq) | {'z'}: + assert_index_same(nativeseq, seqseq, (letter,)) + for start in range(-3, len(nativeseq) + 3): + assert_index_same(nativeseq, seqseq, (letter, start)) + for stop in range(-3, len(nativeseq) + 3): + assert_index_same( + nativeseq, seqseq, (letter, start, stop)) + + # XXX We should test the other mixin methods too. + def test_ByteString(self): for sample in [bytes, bytearray]: self.assertIsInstance(sample(), ByteString)