Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Doc/deprecations/pending-removal-in-future.rst
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ although there is currently no date scheduled for their removal.

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

* :mod:`os.path`: :func:`os.path.commonprefix` is deprecated, use
:func:`os.path.commonpath` for path prefixes.

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

Expand Down
3 changes: 3 additions & 0 deletions Doc/library/os.path.rst
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ the :mod:`glob` module.)
.. versionchanged:: 3.6
Accepts a :term:`path-like object`.

.. deprecated:: next
Deprecated in favor of :func:`os.path.commonpath` for path prefixes.


.. function:: dirname(path, /)

Expand Down
9 changes: 9 additions & 0 deletions Lib/genericpath.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,15 @@ def getctime(filename, /):
# Return the longest prefix of all list elements.
def commonprefix(m, /):
"Given a list of pathnames, returns the longest common leading component"
import warnings
warnings.warn('os.path.commonprefix() is deprecated. Use '
'os.path.commonpath() for longest path prefix.',
category=DeprecationWarning,
stacklevel=2)
return _commonprefix(m)

def _commonprefix(m, /):
"Internal implementation of commonprefix()"
if not m: return ''
# Some people pass in a list of pathname parts to operate in an OS-agnostic
# fashion; don't try to translate in that case as that's an abuse of the
Expand Down
2 changes: 1 addition & 1 deletion Lib/posixpath.py
Original file line number Diff line number Diff line change
Expand Up @@ -542,7 +542,7 @@ def relpath(path, start=None):
start_list = start_tail.split(sep) if start_tail else []
path_list = path_tail.split(sep) if path_tail else []
# Work out how much of the filepath is shared by start and path.
i = len(commonprefix([start_list, path_list]))
i = len(genericpath._commonprefix([start_list, path_list]))

rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
if not rel_list:
Expand Down
136 changes: 69 additions & 67 deletions Lib/test/test_genericpath.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,71 +34,72 @@ def test_no_argument(self):
.format(self.pathmodule.__name__, attr))

def test_commonprefix(self):
commonprefix = self.pathmodule.commonprefix
self.assertEqual(
commonprefix([]),
""
)
self.assertEqual(
commonprefix(["/home/swenson/spam", "/home/swen/spam"]),
"/home/swen"
)
self.assertEqual(
commonprefix(["/home/swen/spam", "/home/swen/eggs"]),
"/home/swen/"
)
self.assertEqual(
commonprefix(["/home/swen/spam", "/home/swen/spam"]),
"/home/swen/spam"
)
self.assertEqual(
commonprefix(["home:swenson:spam", "home:swen:spam"]),
"home:swen"
)
self.assertEqual(
commonprefix([":home:swen:spam", ":home:swen:eggs"]),
":home:swen:"
)
self.assertEqual(
commonprefix([":home:swen:spam", ":home:swen:spam"]),
":home:swen:spam"
)

self.assertEqual(
commonprefix([b"/home/swenson/spam", b"/home/swen/spam"]),
b"/home/swen"
)
self.assertEqual(
commonprefix([b"/home/swen/spam", b"/home/swen/eggs"]),
b"/home/swen/"
)
self.assertEqual(
commonprefix([b"/home/swen/spam", b"/home/swen/spam"]),
b"/home/swen/spam"
)
self.assertEqual(
commonprefix([b"home:swenson:spam", b"home:swen:spam"]),
b"home:swen"
)
self.assertEqual(
commonprefix([b":home:swen:spam", b":home:swen:eggs"]),
b":home:swen:"
)
self.assertEqual(
commonprefix([b":home:swen:spam", b":home:swen:spam"]),
b":home:swen:spam"
)

testlist = ['', 'abc', 'Xbcd', 'Xb', 'XY', 'abcd',
'aXc', 'abd', 'ab', 'aX', 'abcX']
for s1 in testlist:
for s2 in testlist:
p = commonprefix([s1, s2])
self.assertStartsWith(s1, p)
self.assertStartsWith(s2, p)
if s1 != s2:
n = len(p)
self.assertNotEqual(s1[n:n+1], s2[n:n+1])
with warnings_helper.check_warnings((".*commonpath().*", DeprecationWarning)):
commonprefix = self.pathmodule.commonprefix
Comment on lines 36 to +38
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May I suggest that you have:

def test_commonprefix(self):
    with warnings_helper...:
        self.do_test_commonprefix()

def do_test_commonprefix(self):
    # the original test

That way, the diff will be smaller

self.assertEqual(
commonprefix([]),
""
)
self.assertEqual(
commonprefix(["/home/swenson/spam", "/home/swen/spam"]),
"/home/swen"
)
self.assertEqual(
commonprefix(["/home/swen/spam", "/home/swen/eggs"]),
"/home/swen/"
)
self.assertEqual(
commonprefix(["/home/swen/spam", "/home/swen/spam"]),
"/home/swen/spam"
)
self.assertEqual(
commonprefix(["home:swenson:spam", "home:swen:spam"]),
"home:swen"
)
self.assertEqual(
commonprefix([":home:swen:spam", ":home:swen:eggs"]),
":home:swen:"
)
self.assertEqual(
commonprefix([":home:swen:spam", ":home:swen:spam"]),
":home:swen:spam"
)

self.assertEqual(
commonprefix([b"/home/swenson/spam", b"/home/swen/spam"]),
b"/home/swen"
)
self.assertEqual(
commonprefix([b"/home/swen/spam", b"/home/swen/eggs"]),
b"/home/swen/"
)
self.assertEqual(
commonprefix([b"/home/swen/spam", b"/home/swen/spam"]),
b"/home/swen/spam"
)
self.assertEqual(
commonprefix([b"home:swenson:spam", b"home:swen:spam"]),
b"home:swen"
)
self.assertEqual(
commonprefix([b":home:swen:spam", b":home:swen:eggs"]),
b":home:swen:"
)
self.assertEqual(
commonprefix([b":home:swen:spam", b":home:swen:spam"]),
b":home:swen:spam"
)

testlist = ['', 'abc', 'Xbcd', 'Xb', 'XY', 'abcd',
'aXc', 'abd', 'ab', 'aX', 'abcX']
for s1 in testlist:
for s2 in testlist:
p = commonprefix([s1, s2])
self.assertStartsWith(s1, p)
self.assertStartsWith(s2, p)
if s1 != s2:
n = len(p)
self.assertNotEqual(s1[n:n+1], s2[n:n+1])

def test_getsize(self):
filename = os_helper.TESTFN
Expand Down Expand Up @@ -606,8 +607,9 @@ def test_path_isdir(self):
self.assertPathEqual(os.path.isdir)

def test_path_commonprefix(self):
self.assertEqual(os.path.commonprefix([self.file_path, self.file_name]),
self.file_name)
with warnings_helper.check_warnings((".*commonpath().*", DeprecationWarning)):
self.assertEqual(os.path.commonprefix([self.file_path, self.file_name]),
self.file_name)

def test_path_getsize(self):
self.assertPathEqual(os.path.getsize)
Expand Down
14 changes: 8 additions & 6 deletions Lib/test/test_ntpath.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from ntpath import ALL_BUT_LAST, ALLOW_MISSING
from test import support
from test.support import os_helper
from test.support import warnings_helper
from test.support.os_helper import FakePath
from test import test_genericpath
from tempfile import TemporaryFile
Expand Down Expand Up @@ -298,12 +299,13 @@ def test_isabs(self):
tester('ntpath.isabs("\\\\.\\C:")', 1)

def test_commonprefix(self):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto

tester('ntpath.commonprefix(["/home/swenson/spam", "/home/swen/spam"])',
"/home/swen")
tester('ntpath.commonprefix(["\\home\\swen\\spam", "\\home\\swen\\eggs"])',
"\\home\\swen\\")
tester('ntpath.commonprefix(["/home/swen/spam", "/home/swen/spam"])',
"/home/swen/spam")
with warnings_helper.check_warnings((".*commonpath().*", DeprecationWarning)):
tester('ntpath.commonprefix(["/home/swenson/spam", "/home/swen/spam"])',
"/home/swen")
tester('ntpath.commonprefix(["\\home\\swen\\spam", "\\home\\swen\\eggs"])',
"\\home\\swen\\")
tester('ntpath.commonprefix(["/home/swen/spam", "/home/swen/spam"])',
"/home/swen/spam")

def test_join(self):
tester('ntpath.join("")', '')
Expand Down
15 changes: 13 additions & 2 deletions Lib/unittest/util.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
"""Various utility functions."""

from collections import namedtuple, Counter
from os.path import commonprefix

__unittest = True

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

def _commonprefix(m, /):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def _commonprefix(m, /):
def _commonprefix(m):

as it's private, no need to enforce the /

if not m:
return ""
m = sorted(m)
prefix = m[0]
for item in m[1:]:
for i in range(len(prefix)):
if item[i] != prefix[i]:
prefix = prefix[:i]
break
Comment on lines +26 to +32
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use the min/max + enumerate approach instead?

return prefix

def _common_shorten_repr(*args):
args = tuple(map(safe_repr, args))
maxlen = max(map(len, args))
if maxlen <= _MAX_LENGTH:
return args

prefix = commonprefix(args)
prefix = _commonprefix(args)
prefixlen = len(prefix)

common_len = _MAX_LENGTH - \
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Deprecate :func:`os.path.commonprefix` in favor of
:func:`os.path.commonpath` for path segment prefixes.
Loading