Skip to content

Commit 8669894

Browse files
[3.13] gh-140911: Ensure that UserString.index() and UserString.rindex() accept UserString as argument (GH-140945) (GH-141945)
(cherry picked from commit e6174ee) Co-authored-by: Krishna Chaitanya <141550576+XChaitanyaX@users.noreply.github.com>
1 parent 1d16256 commit 8669894

File tree

3 files changed

+48
-33
lines changed

3 files changed

+48
-33
lines changed

Lib/collections/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1486,6 +1486,8 @@ def format_map(self, mapping):
14861486
return self.data.format_map(mapping)
14871487

14881488
def index(self, sub, start=0, end=_sys.maxsize):
1489+
if isinstance(sub, UserString):
1490+
sub = sub.data
14891491
return self.data.index(sub, start, end)
14901492

14911493
def isalpha(self):
@@ -1554,6 +1556,8 @@ def rfind(self, sub, start=0, end=_sys.maxsize):
15541556
return self.data.rfind(sub, start, end)
15551557

15561558
def rindex(self, sub, start=0, end=_sys.maxsize):
1559+
if isinstance(sub, UserString):
1560+
sub = sub.data
15571561
return self.data.rindex(sub, start, end)
15581562

15591563
def rjust(self, width, *args):

Lib/test/string_tests.py

Lines changed: 41 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,18 @@ def checkcall(self, obj, methodname, *args):
9090
args = self.fixtype(args)
9191
getattr(obj, methodname)(*args)
9292

93+
def _get_teststrings(self, charset, digits):
94+
base = len(charset)
95+
teststrings = set()
96+
for i in range(base ** digits):
97+
entry = []
98+
for j in range(digits):
99+
i, m = divmod(i, base)
100+
entry.append(charset[m])
101+
teststrings.add(''.join(entry))
102+
teststrings = [self.fixtype(ts) for ts in teststrings]
103+
return teststrings
104+
93105
def test_count(self):
94106
self.checkequal(3, 'aaa', 'count', 'a')
95107
self.checkequal(0, 'aaa', 'count', 'b')
@@ -130,17 +142,7 @@ def test_count(self):
130142
# For a variety of combinations,
131143
# verify that str.count() matches an equivalent function
132144
# replacing all occurrences and then differencing the string lengths
133-
charset = ['', 'a', 'b']
134-
digits = 7
135-
base = len(charset)
136-
teststrings = set()
137-
for i in range(base ** digits):
138-
entry = []
139-
for j in range(digits):
140-
i, m = divmod(i, base)
141-
entry.append(charset[m])
142-
teststrings.add(''.join(entry))
143-
teststrings = [self.fixtype(ts) for ts in teststrings]
145+
teststrings = self._get_teststrings(['', 'a', 'b'], 7)
144146
for i in teststrings:
145147
n = len(i)
146148
for j in teststrings:
@@ -197,17 +199,7 @@ def test_find(self):
197199
# For a variety of combinations,
198200
# verify that str.find() matches __contains__
199201
# and that the found substring is really at that location
200-
charset = ['', 'a', 'b', 'c']
201-
digits = 5
202-
base = len(charset)
203-
teststrings = set()
204-
for i in range(base ** digits):
205-
entry = []
206-
for j in range(digits):
207-
i, m = divmod(i, base)
208-
entry.append(charset[m])
209-
teststrings.add(''.join(entry))
210-
teststrings = [self.fixtype(ts) for ts in teststrings]
202+
teststrings = self._get_teststrings(['', 'a', 'b', 'c'], 5)
211203
for i in teststrings:
212204
for j in teststrings:
213205
loc = i.find(j)
@@ -244,17 +236,7 @@ def test_rfind(self):
244236
# For a variety of combinations,
245237
# verify that str.rfind() matches __contains__
246238
# and that the found substring is really at that location
247-
charset = ['', 'a', 'b', 'c']
248-
digits = 5
249-
base = len(charset)
250-
teststrings = set()
251-
for i in range(base ** digits):
252-
entry = []
253-
for j in range(digits):
254-
i, m = divmod(i, base)
255-
entry.append(charset[m])
256-
teststrings.add(''.join(entry))
257-
teststrings = [self.fixtype(ts) for ts in teststrings]
239+
teststrings = self._get_teststrings(['', 'a', 'b', 'c'], 5)
258240
for i in teststrings:
259241
for j in teststrings:
260242
loc = i.rfind(j)
@@ -295,6 +277,19 @@ def test_index(self):
295277
else:
296278
self.checkraises(TypeError, 'hello', 'index', 42)
297279

280+
# For a variety of combinations,
281+
# verify that str.index() matches __contains__
282+
# and that the found substring is really at that location
283+
teststrings = self._get_teststrings(['', 'a', 'b', 'c'], 5)
284+
for i in teststrings:
285+
for j in teststrings:
286+
if j in i:
287+
loc = i.index(j)
288+
self.assertGreaterEqual(loc, 0)
289+
self.assertEqual(i[loc:loc+len(j)], j)
290+
else:
291+
self.assertRaises(ValueError, i.index, j)
292+
298293
def test_rindex(self):
299294
self.checkequal(12, 'abcdefghiabc', 'rindex', '')
300295
self.checkequal(3, 'abcdefghiabc', 'rindex', 'def')
@@ -321,6 +316,19 @@ def test_rindex(self):
321316
else:
322317
self.checkraises(TypeError, 'hello', 'rindex', 42)
323318

319+
# For a variety of combinations,
320+
# verify that str.rindex() matches __contains__
321+
# and that the found substring is really at that location
322+
teststrings = self._get_teststrings(['', 'a', 'b', 'c'], 5)
323+
for i in teststrings:
324+
for j in teststrings:
325+
if j in i:
326+
loc = i.rindex(j)
327+
self.assertGreaterEqual(loc, 0)
328+
self.assertEqual(i[loc:loc+len(j)], j)
329+
else:
330+
self.assertRaises(ValueError, i.rindex, j)
331+
324332
def test_find_periodic_pattern(self):
325333
"""Cover the special path for periodic patterns."""
326334
def reference_find(p, s):
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
:mod:`collections`: Ensure that the methods ``UserString.rindex()`` and
2+
``UserString.index()`` accept :class:`collections.UserString` instances as the
3+
sub argument.

0 commit comments

Comments
 (0)