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
8 changes: 8 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,14 @@ 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. The :func:`os.path.commonprefix`
function is being deprecated due to having a misleading name and module.
The function is not safe to use for path prefixes despite being included in a
module about path manipulation, meaning it is easy to accidentally
introduce path traversal vulnerabilities into Python programs by using this
function.

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

Expand Down
8 changes: 8 additions & 0 deletions Doc/library/os.path.rst
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,14 @@ 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.
The :func:`os.path.commonprefix` function is being deprecated due to
having a misleading name and module. The function is not safe to use for
path prefixes despite being included in a module about path manipulation,
meaning it is easy to accidentally introduce path traversal
vulnerabilities into Python programs by using this function.


.. 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]))
Copy link
Member

Choose a reason for hiding this comment

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

Ah, this call is safe since it pass two lists of strings, and not two strings.


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

def test_commonprefix(self):
with warnings_helper.check_warnings((".*commonpath().*", DeprecationWarning)):
self.do_test_commonprefix()

def do_test_commonprefix(self):
commonprefix = self.pathmodule.commonprefix
self.assertEqual(
commonprefix([]),
Expand Down Expand Up @@ -606,8 +610,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
5 changes: 5 additions & 0 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,6 +299,10 @@ def test_isabs(self):
tester('ntpath.isabs("\\\\.\\C:")', 1)

def test_commonprefix(self):
with warnings_helper.check_warnings((".*commonpath().*", DeprecationWarning)):
self.do_test_commonprefix()

def do_test_commonprefix(self):
tester('ntpath.commonprefix(["/home/swenson/spam", "/home/swen/spam"])',
"/home/swen")
tester('ntpath.commonprefix(["\\home\\swen\\spam", "\\home\\swen\\eggs"])',
Expand Down
13 changes: 11 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,23 @@ def _shorten(s, prefixlen, suffixlen):
s = '%s[%d chars]%s' % (s[:prefixlen], skip, s[len(s) - suffixlen:])
return s

def _common_prefix(m):
if not m:
return ""
s1 = min(m)
s2 = max(m)
for i, c in enumerate(s1):
if c != s2[i]:
return s1[:i]
return s1

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 = _common_prefix(args)
prefixlen = len(prefix)

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

The :func:`os.path.commonprefix` function is being deprecated due to
having a misleading name and module. The function is not safe to use for
path prefixes despite being included in a module about path manipulation,
meaning it is easy to accidentally introduce path traversal
vulnerabilities into Python programs by using this function.
Loading