Skip to content

Commit d4c0bb4

Browse files
committed
Remove 'string.commonprefix()' as an alternative
1 parent 1f2086b commit d4c0bb4

File tree

9 files changed

+37
-129
lines changed

9 files changed

+37
-129
lines changed

Doc/deprecations/pending-removal-in-future.rst

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,8 @@ although there is currently no date scheduled for their removal.
7878

7979
* :mod:`os`: Calling :func:`os.register_at_fork` in a multi-threaded process.
8080

81-
* :mod:`os.path`: :func:`os.path.commonprefix` is deprecated, use either
82-
:func:`os.path.commonpath` for path prefixes or
83-
:func:`string.commonprefix` for string prefixes.
81+
* :mod:`os.path`: :func:`os.path.commonprefix` is deprecated, use
82+
:func:`os.path.commonpath` for path prefixes.
8483

8584
* :class:`!pydoc.ErrorDuringImport`: A tuple value for *exc_info* parameter is
8685
deprecated, use an exception instance.

Doc/library/os.path.rst

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,7 @@ the :mod:`glob` module.)
121121
Accepts a :term:`path-like object`.
122122

123123
.. deprecated:: next
124-
Deprecated in favor of :func:`os.path.commonpath` for path prefixes and
125-
:func:`string.commonprefix` for string prefixes.
124+
Deprecated in favor of :func:`os.path.commonpath` for path prefixes.
126125

127126

128127
.. function:: dirname(path, /)

Lib/genericpath.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,26 @@ def commonprefix(m, /):
107107
"Given a list of pathnames, returns the longest common leading component"
108108
import warnings
109109
warnings.warn('os.path.commonprefix() is deprecated. Use '
110-
'os.path.commonpath() for longest path prefix, or '
111-
'string.commonprefix() for longest string prefix.',
110+
'os.path.commonpath() for longest path prefix.',
112111
category=DeprecationWarning,
113112
stacklevel=2)
114-
import string
115-
return string.commonprefix(m)
113+
return _commonprefix(m)
114+
115+
def _commonprefix(m, /):
116+
"Internal implementation of commonprefix()"
117+
if not m: return ''
118+
# Some people pass in a list of pathname parts to operate in an OS-agnostic
119+
# fashion; don't try to translate in that case as that's an abuse of the
120+
# API and they are already doing what they need to be OS-agnostic and so
121+
# they most likely won't be using an os.PathLike object in the sublists.
122+
if not isinstance(m[0], (list, tuple)):
123+
m = tuple(map(os.fspath, m))
124+
s1 = min(m)
125+
s2 = max(m)
126+
for i, c in enumerate(s1):
127+
if c != s2[i]:
128+
return s1[:i]
129+
return s1
116130

117131
# Are two stat buffers (obtained from stat, fstat or lstat)
118132
# describing the same file?

Lib/posixpath.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
import os
2727
import sys
2828
import stat
29-
import string
3029
import genericpath
3130
from genericpath import *
3231

@@ -543,7 +542,7 @@ def relpath(path, start=None):
543542
start_list = start_tail.split(sep) if start_tail else []
544543
path_list = path_tail.split(sep) if path_tail else []
545544
# Work out how much of the filepath is shared by start and path.
546-
i = len(string.commonprefix([start_list, path_list]))
545+
i = len(genericpath._commonprefix([start_list, path_list]))
547546

548547
rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
549548
if not rel_list:

Lib/string/__init__.py

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -48,27 +48,6 @@ def capwords(s, sep=None):
4848
return (sep or ' ').join(map(str.capitalize, s.split(sep)))
4949

5050

51-
def commonprefix(m, /):
52-
"""Given a list of strings, returns the longest common leading component."""
53-
if not m:
54-
return ''
55-
# Note that previously this function was in the 'os.path' module, hence the
56-
# handling for paths. Maintain compatibility so users have a 1-to-1 drop-in.
57-
# Some people pass in a list of pathname parts to operate in an OS-agnostic
58-
# fashion; don't try to translate in that case as that's an abuse of the
59-
# API and they are already doing what they need to be OS-agnostic and so
60-
# they most likely won't be using an os.PathLike object in the sublists.
61-
if not isinstance(m[0], (list, tuple)):
62-
import os
63-
m = tuple(map(os.fspath, m))
64-
s1 = min(m)
65-
s2 = max(m)
66-
for i, c in enumerate(s1):
67-
if c != s2[i]:
68-
return s1[:i]
69-
return s1
70-
71-
7251
####################################################################
7352
_sentinel_dict = {}
7453

Lib/test/test_string/test_string.py

Lines changed: 0 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -41,97 +41,6 @@ def test_capwords(self):
4141
self.assertEqual(string.capwords('\taBc\tDeF\t'), 'Abc Def')
4242
self.assertEqual(string.capwords('\taBc\tDeF\t', '\t'), '\tAbc\tDef\t')
4343

44-
def test_commonprefix(self):
45-
self.assertEqual(
46-
string.commonprefix([]),
47-
""
48-
)
49-
self.assertEqual(
50-
string.commonprefix(["a", "b"]),
51-
""
52-
)
53-
self.assertEqual(
54-
string.commonprefix(["/home/swenson/spam", "/home/swen/spam"]),
55-
"/home/swen"
56-
)
57-
self.assertEqual(
58-
string.commonprefix(["/home/swen/spam", "/home/swen/eggs"]),
59-
"/home/swen/"
60-
)
61-
self.assertEqual(
62-
string.commonprefix(["/home/swen/spam", "/home/swen/spam"]),
63-
"/home/swen/spam"
64-
)
65-
self.assertEqual(
66-
string.commonprefix(["home:swenson:spam", "home:swen:spam"]),
67-
"home:swen"
68-
)
69-
self.assertEqual(
70-
string.commonprefix([":home:swen:spam", ":home:swen:eggs"]),
71-
":home:swen:"
72-
)
73-
self.assertEqual(
74-
string.commonprefix([":home:swen:spam", ":home:swen:spam"]),
75-
":home:swen:spam"
76-
)
77-
78-
self.assertEqual(
79-
string.commonprefix([b"/home/swenson/spam", b"/home/swen/spam"]),
80-
b"/home/swen"
81-
)
82-
self.assertEqual(
83-
string.commonprefix([b"/home/swen/spam", b"/home/swen/eggs"]),
84-
b"/home/swen/"
85-
)
86-
self.assertEqual(
87-
string.commonprefix([b"/home/swen/spam", b"/home/swen/spam"]),
88-
b"/home/swen/spam"
89-
)
90-
self.assertEqual(
91-
string.commonprefix([b"home:swenson:spam", b"home:swen:spam"]),
92-
b"home:swen"
93-
)
94-
self.assertEqual(
95-
string.commonprefix([b":home:swen:spam", b":home:swen:eggs"]),
96-
b":home:swen:"
97-
)
98-
self.assertEqual(
99-
string.commonprefix([b":home:swen:spam", b":home:swen:spam"]),
100-
b":home:swen:spam"
101-
)
102-
103-
testlist = ['', 'abc', 'Xbcd', 'Xb', 'XY', 'abcd',
104-
'aXc', 'abd', 'ab', 'aX', 'abcX']
105-
for s1 in testlist:
106-
for s2 in testlist:
107-
p = string.commonprefix([s1, s2])
108-
self.assertStartsWith(s1, p)
109-
self.assertStartsWith(s2, p)
110-
if s1 != s2:
111-
n = len(p)
112-
self.assertNotEqual(s1[n:n+1], s2[n:n+1])
113-
114-
def test_commonprefix_paths(self):
115-
# Test backwards-compatibility with os.path.commonprefix()
116-
# This function must handle PathLike objects.
117-
file_name = os_helper.TESTFN
118-
file_path = os_helper.FakePath(file_name)
119-
self.assertEqual(string.commonprefix([file_path, file_name]),
120-
file_name)
121-
122-
def test_commonprefix_sequence_of_str(self):
123-
# Test backwards-compatibility with os.path.commonprefix()
124-
# This function must handle lists and tuples of strings.
125-
for type_ in (tuple, list):
126-
seq1 = type_(["abc", "de", "fgh"])
127-
seq2 = type_(["abc", "def", "gh"])
128-
self.assertEqual(string.commonprefix([seq1, seq2]),
129-
type_(["abc"]))
130-
131-
seq1 = type_(["ab"])
132-
seq2 = type_(["ac"])
133-
self.assertEqual(string.commonprefix([seq1, seq2]), type_([]))
134-
13544
def test_basic_formatter(self):
13645
fmt = string.Formatter()
13746
self.assertEqual(fmt.format("foo"), "foo")

Lib/textwrap.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,7 @@ def dedent(text):
432432
msg = f'expected str object, not {type(text).__qualname__!r}'
433433
raise TypeError(msg) from None
434434

435-
# Get length of leading whitespace, inspired by ``string.commonprefix()``.
435+
# Get length of leading whitespace, inspired by ``os.path.commonprefix()``.
436436
non_blank_lines = [l for l in lines if l and not l.isspace()]
437437
l1 = min(non_blank_lines, default='')
438438
l2 = max(non_blank_lines, default='')

Lib/unittest/util.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
"""Various utility functions."""
22

33
from collections import namedtuple, Counter
4-
from string import commonprefix
54

65
__unittest = True
76

@@ -21,13 +20,25 @@ def _shorten(s, prefixlen, suffixlen):
2120
s = '%s[%d chars]%s' % (s[:prefixlen], skip, s[len(s) - suffixlen:])
2221
return s
2322

23+
def _commonprefix(m, /):
24+
if not m:
25+
return ""
26+
m = sorted(m)
27+
prefix = m[0]
28+
for item in m[1:]:
29+
for i in range(len(prefix)):
30+
if item[i] != prefix[i]:
31+
prefix = prefix[:i]
32+
break
33+
return prefix
34+
2435
def _common_shorten_repr(*args):
2536
args = tuple(map(safe_repr, args))
2637
maxlen = max(map(len, args))
2738
if maxlen <= _MAX_LENGTH:
2839
return args
2940

30-
prefix = commonprefix(args)
41+
prefix = _commonprefix(args)
3142
prefixlen = len(prefix)
3243

3344
common_len = _MAX_LENGTH - \
Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,2 @@
11
Deprecate :func:`os.path.commonprefix` in favor of
2-
:func:`os.path.commonpath` for path segment prefixes
3-
and :func:`string.commonprefix` for character prefixes.
4-
2+
:func:`os.path.commonpath` for path segment prefixes.

0 commit comments

Comments
 (0)