From 16f31d8a622990d2de242c5ca8215b925d764d5a Mon Sep 17 00:00:00 2001 From: Bonu Krishna Chaitanya Date: Mon, 3 Nov 2025 16:59:31 +0530 Subject: [PATCH 1/5] fix --- Lib/collections/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py index 25ac4d1d524bc2..55ffc36ea5b0c7 100644 --- a/Lib/collections/__init__.py +++ b/Lib/collections/__init__.py @@ -1542,6 +1542,8 @@ def format_map(self, mapping): return self.data.format_map(mapping) def index(self, sub, start=0, end=_sys.maxsize): + if isinstance(sub, UserString): + sub = sub.data return self.data.index(sub, start, end) def isalpha(self): @@ -1610,6 +1612,8 @@ def rfind(self, sub, start=0, end=_sys.maxsize): return self.data.rfind(sub, start, end) def rindex(self, sub, start=0, end=_sys.maxsize): + if isinstance(sub, UserString): + sub = sub.data return self.data.rindex(sub, start, end) def rjust(self, width, *args): From 0210f95baa78f11b8e606815c07b6b61b798e41a Mon Sep 17 00:00:00 2001 From: Bonu Krishna Chaitanya Date: Mon, 3 Nov 2025 17:19:00 +0530 Subject: [PATCH 2/5] blurb --- .../Library/2025-11-03-17-13-00.gh-issue-140911.7KFvSQ.rst | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2025-11-03-17-13-00.gh-issue-140911.7KFvSQ.rst diff --git a/Misc/NEWS.d/next/Library/2025-11-03-17-13-00.gh-issue-140911.7KFvSQ.rst b/Misc/NEWS.d/next/Library/2025-11-03-17-13-00.gh-issue-140911.7KFvSQ.rst new file mode 100644 index 00000000000000..b0b6e4611924c2 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-11-03-17-13-00.gh-issue-140911.7KFvSQ.rst @@ -0,0 +1,3 @@ +:mod:`collections`: Ensure that the methods ``UserString.rindex()`` and +``UserString.index()`` accept :class:`collections.UserString` instances as the +sub argument. From e6fabcd7848434c273961cbd391912532278bbc1 Mon Sep 17 00:00:00 2001 From: Bonu Krishna Chaitanya Date: Mon, 24 Nov 2025 16:21:41 +0530 Subject: [PATCH 3/5] tests --- Lib/test/string_tests.py | 52 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/Lib/test/string_tests.py b/Lib/test/string_tests.py index 1814a55b74ea0c..a876c68be235e3 100644 --- a/Lib/test/string_tests.py +++ b/Lib/test/string_tests.py @@ -295,6 +295,32 @@ def test_index(self): else: self.checkraises(TypeError, 'hello', 'index', 42) + # For a variety of combinations, + # verify that str.index() matches __contains__ + # and that the found substring is really at that location + charset = ['', 'a', 'b', 'c'] + digits = 5 + base = len(charset) + teststrings = set() + for i in range(base ** digits): + entry = [] + for j in range(digits): + i, m = divmod(i, base) + entry.append(charset[m]) + teststrings.add(''.join(entry)) + teststrings = [self.fixtype(ts) for ts in teststrings] + for i in teststrings: + for j in teststrings: + try: + loc = i.index(j) + except ValueError: + loc = -1 + r1 = (loc != -1) + r2 = j in i + self.assertEqual(r1, r2) + if loc != -1: + self.assertEqual(i[loc:loc+len(j)], j) + def test_rindex(self): self.checkequal(12, 'abcdefghiabc', 'rindex', '') self.checkequal(3, 'abcdefghiabc', 'rindex', 'def') @@ -321,6 +347,32 @@ def test_rindex(self): else: self.checkraises(TypeError, 'hello', 'rindex', 42) + # For a variety of combinations, + # verify that str.rindex() matches __contains__ + # and that the found substring is really at that location + charset = ['', 'a', 'b', 'c'] + digits = 5 + base = len(charset) + teststrings = set() + for i in range(base ** digits): + entry = [] + for j in range(digits): + i, m = divmod(i, base) + entry.append(charset[m]) + teststrings.add(''.join(entry)) + teststrings = [self.fixtype(ts) for ts in teststrings] + for i in teststrings: + for j in teststrings: + try: + loc = i.rindex(j) + except ValueError: + loc = -1 + r1 = (loc != -1) + r2 = j in i + self.assertEqual(r1, r2) + if loc != -1: + self.assertEqual(i[loc:loc+len(j)], j) + def test_find_periodic_pattern(self): """Cover the special path for periodic patterns.""" def reference_find(p, s): From 4f47367a0801b18cb92a6a214899e3a3fc39cba0 Mon Sep 17 00:00:00 2001 From: Bonu Krishna Chaitanya Date: Tue, 25 Nov 2025 10:09:11 +0530 Subject: [PATCH 4/5] fix --- Lib/test/string_tests.py | 72 +++++++++++++--------------------------- 1 file changed, 23 insertions(+), 49 deletions(-) diff --git a/Lib/test/string_tests.py b/Lib/test/string_tests.py index a876c68be235e3..b5881509609b16 100644 --- a/Lib/test/string_tests.py +++ b/Lib/test/string_tests.py @@ -90,6 +90,18 @@ def checkcall(self, obj, methodname, *args): args = self.fixtype(args) getattr(obj, methodname)(*args) + def _get_teststrings(self, charset, digits): + base = len(charset) + teststrings = set() + for i in range(base ** digits): + entry = [] + for j in range(digits): + i, m = divmod(i, base) + entry.append(charset[m]) + teststrings.add(''.join(entry)) + teststrings = [self.fixtype(ts) for ts in teststrings] + return teststrings + def test_count(self): self.checkequal(3, 'aaa', 'count', 'a') self.checkequal(0, 'aaa', 'count', 'b') @@ -132,15 +144,7 @@ def test_count(self): # replacing all occurrences and then differencing the string lengths charset = ['', 'a', 'b'] digits = 7 - base = len(charset) - teststrings = set() - for i in range(base ** digits): - entry = [] - for j in range(digits): - i, m = divmod(i, base) - entry.append(charset[m]) - teststrings.add(''.join(entry)) - teststrings = [self.fixtype(ts) for ts in teststrings] + teststrings = self._get_teststrings(charset, digits) for i in teststrings: n = len(i) for j in teststrings: @@ -199,15 +203,7 @@ def test_find(self): # and that the found substring is really at that location charset = ['', 'a', 'b', 'c'] digits = 5 - base = len(charset) - teststrings = set() - for i in range(base ** digits): - entry = [] - for j in range(digits): - i, m = divmod(i, base) - entry.append(charset[m]) - teststrings.add(''.join(entry)) - teststrings = [self.fixtype(ts) for ts in teststrings] + teststrings = self._get_teststrings(charset, digits) for i in teststrings: for j in teststrings: loc = i.find(j) @@ -246,15 +242,7 @@ def test_rfind(self): # and that the found substring is really at that location charset = ['', 'a', 'b', 'c'] digits = 5 - base = len(charset) - teststrings = set() - for i in range(base ** digits): - entry = [] - for j in range(digits): - i, m = divmod(i, base) - entry.append(charset[m]) - teststrings.add(''.join(entry)) - teststrings = [self.fixtype(ts) for ts in teststrings] + teststrings = self._get_teststrings(charset, digits) for i in teststrings: for j in teststrings: loc = i.rfind(j) @@ -300,20 +288,13 @@ def test_index(self): # and that the found substring is really at that location charset = ['', 'a', 'b', 'c'] digits = 5 - base = len(charset) - teststrings = set() - for i in range(base ** digits): - entry = [] - for j in range(digits): - i, m = divmod(i, base) - entry.append(charset[m]) - teststrings.add(''.join(entry)) - teststrings = [self.fixtype(ts) for ts in teststrings] + teststrings = self._get_teststrings(charset, digits) for i in teststrings: for j in teststrings: - try: + if j in i: loc = i.index(j) - except ValueError: + else: + self.assertRaises(ValueError, i.index, j) loc = -1 r1 = (loc != -1) r2 = j in i @@ -352,20 +333,13 @@ def test_rindex(self): # and that the found substring is really at that location charset = ['', 'a', 'b', 'c'] digits = 5 - base = len(charset) - teststrings = set() - for i in range(base ** digits): - entry = [] - for j in range(digits): - i, m = divmod(i, base) - entry.append(charset[m]) - teststrings.add(''.join(entry)) - teststrings = [self.fixtype(ts) for ts in teststrings] + teststrings = self._get_teststrings(charset, digits) for i in teststrings: for j in teststrings: - try: + if j in i: loc = i.rindex(j) - except ValueError: + else: + self.assertRaises(ValueError, i.rindex, j) loc = -1 r1 = (loc != -1) r2 = j in i From 0c1440fff1fd421045a4ffab2bf0fdbc2bba6cb8 Mon Sep 17 00:00:00 2001 From: Bonu Krishna Chaitanya Date: Tue, 25 Nov 2025 17:48:42 +0530 Subject: [PATCH 5/5] more fixes --- Lib/test/string_tests.py | 36 +++++++++--------------------------- 1 file changed, 9 insertions(+), 27 deletions(-) diff --git a/Lib/test/string_tests.py b/Lib/test/string_tests.py index b5881509609b16..185aa3fce39149 100644 --- a/Lib/test/string_tests.py +++ b/Lib/test/string_tests.py @@ -142,9 +142,7 @@ def test_count(self): # For a variety of combinations, # verify that str.count() matches an equivalent function # replacing all occurrences and then differencing the string lengths - charset = ['', 'a', 'b'] - digits = 7 - teststrings = self._get_teststrings(charset, digits) + teststrings = self._get_teststrings(['', 'a', 'b'], 7) for i in teststrings: n = len(i) for j in teststrings: @@ -201,9 +199,7 @@ def test_find(self): # For a variety of combinations, # verify that str.find() matches __contains__ # and that the found substring is really at that location - charset = ['', 'a', 'b', 'c'] - digits = 5 - teststrings = self._get_teststrings(charset, digits) + teststrings = self._get_teststrings(['', 'a', 'b', 'c'], 5) for i in teststrings: for j in teststrings: loc = i.find(j) @@ -240,9 +236,7 @@ def test_rfind(self): # For a variety of combinations, # verify that str.rfind() matches __contains__ # and that the found substring is really at that location - charset = ['', 'a', 'b', 'c'] - digits = 5 - teststrings = self._get_teststrings(charset, digits) + teststrings = self._get_teststrings(['', 'a', 'b', 'c'], 5) for i in teststrings: for j in teststrings: loc = i.rfind(j) @@ -286,21 +280,15 @@ def test_index(self): # For a variety of combinations, # verify that str.index() matches __contains__ # and that the found substring is really at that location - charset = ['', 'a', 'b', 'c'] - digits = 5 - teststrings = self._get_teststrings(charset, digits) + teststrings = self._get_teststrings(['', 'a', 'b', 'c'], 5) for i in teststrings: for j in teststrings: if j in i: loc = i.index(j) + self.assertGreaterEqual(loc, 0) + self.assertEqual(i[loc:loc+len(j)], j) else: self.assertRaises(ValueError, i.index, j) - loc = -1 - r1 = (loc != -1) - r2 = j in i - self.assertEqual(r1, r2) - if loc != -1: - self.assertEqual(i[loc:loc+len(j)], j) def test_rindex(self): self.checkequal(12, 'abcdefghiabc', 'rindex', '') @@ -331,21 +319,15 @@ def test_rindex(self): # For a variety of combinations, # verify that str.rindex() matches __contains__ # and that the found substring is really at that location - charset = ['', 'a', 'b', 'c'] - digits = 5 - teststrings = self._get_teststrings(charset, digits) + teststrings = self._get_teststrings(['', 'a', 'b', 'c'], 5) for i in teststrings: for j in teststrings: if j in i: loc = i.rindex(j) + self.assertGreaterEqual(loc, 0) + self.assertEqual(i[loc:loc+len(j)], j) else: self.assertRaises(ValueError, i.rindex, j) - loc = -1 - r1 = (loc != -1) - r2 = j in i - self.assertEqual(r1, r2) - if loc != -1: - self.assertEqual(i[loc:loc+len(j)], j) def test_find_periodic_pattern(self): """Cover the special path for periodic patterns."""