Patch 1339796: add a relpath() function to os.path.

This commit is contained in:
Collin Winter 2007-03-16 22:16:08 +00:00
parent 6de691d78c
commit 6f187743ff
7 changed files with 77 additions and 3 deletions

View File

@ -189,6 +189,15 @@ operating system).
\versionadded{2.2} \versionadded{2.2}
\end{funcdesc} \end{funcdesc}
\begin{funcdesc}{relpath}{path\optional{, start}}
Return a relative filepath to \var{path} either from the current
directory or from an optional \var{start} point.
\var{start} defaults to \member{os.curdir}.
Availability: Windows, \UNIX.
\versionadded{2.6}
\end{funcdesc}
\begin{funcdesc}{samefile}{path1, path2} \begin{funcdesc}{samefile}{path1, path2}
Return \code{True} if both pathname arguments refer to the same file or Return \code{True} if both pathname arguments refer to the same file or
directory (as indicated by device number and i-node number). directory (as indicated by device number and i-node number).

View File

@ -16,7 +16,7 @@
"getatime","getctime", "islink","exists","lexists","isdir","isfile", "getatime","getctime", "islink","exists","lexists","isdir","isfile",
"ismount","walk","expanduser","expandvars","normpath","abspath", "ismount","walk","expanduser","expandvars","normpath","abspath",
"splitunc","curdir","pardir","sep","pathsep","defpath","altsep", "splitunc","curdir","pardir","sep","pathsep","defpath","altsep",
"extsep","devnull","realpath","supports_unicode_filenames"] "extsep","devnull","realpath","supports_unicode_filenames","relpath"]
# strings representing various path-related bits and pieces # strings representing various path-related bits and pieces
curdir = '.' curdir = '.'
@ -465,3 +465,29 @@ def abspath(path):
# Win9x family and earlier have no Unicode filename support. # Win9x family and earlier have no Unicode filename support.
supports_unicode_filenames = (hasattr(sys, "getwindowsversion") and supports_unicode_filenames = (hasattr(sys, "getwindowsversion") and
sys.getwindowsversion()[3] >= 2) sys.getwindowsversion()[3] >= 2)
def relpath(path, start=curdir):
"""Return a relative version of a path"""
if not path:
raise ValueError("no path specified")
start_list = abspath(start).split(sep)
path_list = abspath(path).split(sep)
if start_list[0].lower() != path_list[0].lower():
unc_path, rest = splitunc(path)
unc_start, rest = splitunc(start)
if bool(unc_path) ^ bool(unc_start):
raise ValueError("Cannot mix UNC and non-UNC paths (%s and %s)"
% (path, start))
else:
raise ValueError("path is on drive %s, start on drive %s"
% (path_list[0], start_list[0]))
# Work out how much of the filepath is shared by start and path.
for i in range(min(len(start_list), len(path_list))):
if start_list[i].lower() != path_list[i].lower():
break
else:
i += 1
rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
return join(*rel_list)

View File

@ -21,7 +21,7 @@
"ismount","walk","expanduser","expandvars","normpath","abspath", "ismount","walk","expanduser","expandvars","normpath","abspath",
"samefile","sameopenfile","samestat", "samefile","sameopenfile","samestat",
"curdir","pardir","sep","pathsep","defpath","altsep","extsep", "curdir","pardir","sep","pathsep","defpath","altsep","extsep",
"devnull","realpath","supports_unicode_filenames"] "devnull","realpath","supports_unicode_filenames","relpath"]
# strings representing various path-related bits and pieces # strings representing various path-related bits and pieces
curdir = '.' curdir = '.'
@ -382,3 +382,18 @@ def _resolve_link(path):
return path return path
supports_unicode_filenames = False supports_unicode_filenames = False
def relpath(path, start=curdir):
"""Return a relative version of a path"""
if not path:
raise ValueError("no path specified")
start_list = abspath(start).split(sep)
path_list = abspath(path).split(sep)
# Work out how much of the filepath is shared by start and path.
i = len(commonprefix([start_list, path_list]))
rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
return join(*rel_list)

View File

@ -157,6 +157,16 @@ def tester(fn, wantResult):
else: else:
tester('ntpath.abspath("C:\\")', "C:\\") tester('ntpath.abspath("C:\\")', "C:\\")
currentdir = os.path.split(os.getcwd())[-1]
tester('ntpath.relpath("a")', 'a')
tester('ntpath.relpath(os.path.abspath("a"))', 'a')
tester('ntpath.relpath("a/b")', 'a\\b')
tester('ntpath.relpath("../a/b")', '..\\a\\b')
tester('ntpath.relpath("a", "../b")', '..\\'+currentdir+'\\a')
tester('ntpath.relpath("a/b", "../c")', '..\\'+currentdir+'\\a\\b')
tester('ntpath.relpath("a", "b/c")', '..\\..\\a')
tester('ntpath.relpath("//conky/mountpoint/a", "//conky/mountpoint/b/c")', '..\\..\\a')
if errors: if errors:
raise TestFailed(str(errors) + " errors.") raise TestFailed(str(errors) + " errors.")
elif verbose: elif verbose:

View File

@ -2,7 +2,7 @@
from test import test_support from test import test_support
import posixpath, os import posixpath, os
from posixpath import realpath, abspath, join, dirname, basename from posixpath import realpath, abspath, join, dirname, basename, relpath
# An absolute path to a temporary filename for testing. We can't rely on TESTFN # An absolute path to a temporary filename for testing. We can't rely on TESTFN
# being an absolute path, so we need this. # being an absolute path, so we need this.
@ -479,6 +479,17 @@ def test_realpath_resolve_first(self):
safe_rmdir(ABSTFN + "/k") safe_rmdir(ABSTFN + "/k")
safe_rmdir(ABSTFN) safe_rmdir(ABSTFN)
def test_relpath(self):
currentdir = os.path.split(os.getcwd())[-1]
self.assertRaises(ValueError, posixpath.relpath, "")
self.assertEqual(posixpath.relpath("a"), "a")
self.assertEqual(posixpath.relpath(os.path.abspath("a")), "a")
self.assertEqual(posixpath.relpath("a/b"), "a/b")
self.assertEqual(posixpath.relpath("../a/b"), "../a/b")
self.assertEqual(posixpath.relpath("a", "../b"), "../"+currentdir+"/a")
self.assertEqual(posixpath.relpath("a/b", "../c"), "../"+currentdir+"/a/b")
self.assertEqual(posixpath.relpath("a", "b/c"), "../../a")
def test_main(): def test_main():
test_support.run_unittest(PosixPathTest) test_support.run_unittest(PosixPathTest)

View File

@ -36,6 +36,7 @@ Luigi Ballabio
Michael J. Barber Michael J. Barber
Chris Barker Chris Barker
Quentin Barnes Quentin Barnes
Richard Barran
Cesar Eduardo Barros Cesar Eduardo Barros
Des Barry Des Barry
Ulf Bartelt Ulf Bartelt

View File

@ -191,6 +191,8 @@ Library
of those present. Also, it tries the Windows default browser before of those present. Also, it tries the Windows default browser before
trying Mozilla variants. trying Mozilla variants.
- Patch #1339796: add a relpath() function to os.path.
- Patch #1681153: the wave module now closes a file object it opened if - Patch #1681153: the wave module now closes a file object it opened if
initialization failed. initialization failed.