Kaydet (Commit) 6f187743 authored tarafından Collin Winter's avatar Collin Winter

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

üst 6de691d7
...@@ -189,6 +189,15 @@ operating system). ...@@ -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).
......
...@@ -16,7 +16,7 @@ __all__ = ["normcase","isabs","join","splitdrive","split","splitext", ...@@ -16,7 +16,7 @@ __all__ = ["normcase","isabs","join","splitdrive","split","splitext",
"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 @@ realpath = abspath ...@@ -465,3 +465,29 @@ realpath = abspath
# 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)
...@@ -21,7 +21,7 @@ __all__ = ["normcase","isabs","join","splitdrive","split","splitext", ...@@ -21,7 +21,7 @@ __all__ = ["normcase","isabs","join","splitdrive","split","splitext",
"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): ...@@ -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)
...@@ -157,6 +157,16 @@ except ImportError: ...@@ -157,6 +157,16 @@ except ImportError:
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:
......
...@@ -2,7 +2,7 @@ import unittest ...@@ -2,7 +2,7 @@ import unittest
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 @@ class PosixPathTest(unittest.TestCase): ...@@ -479,6 +479,17 @@ class PosixPathTest(unittest.TestCase):
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)
......
...@@ -36,6 +36,7 @@ Luigi Ballabio ...@@ -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
......
...@@ -191,6 +191,8 @@ Library ...@@ -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.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment