Author: Armin Rigo <[email protected]>
Branch:
Changeset: r73221:6bb6900ae05e
Date: 2014-08-31 12:18 +0200
http://bitbucket.org/pypy/pypy/changeset/6bb6900ae05e/
Log: Extend rpython.rlib.rpath to include the following functions:
risabs rabspath rsplitdrive rjoin
diff --git a/rpython/rlib/rpath.py b/rpython/rlib/rpath.py
--- a/rpython/rlib/rpath.py
+++ b/rpython/rlib/rpath.py
@@ -2,24 +2,122 @@
Minimal (and limited) RPython version of some functions contained in os.path.
"""
-import os.path
+import os
from rpython.rlib import rposix
-if os.name == 'posix':
- # the posix version is already RPython, just use it
- # (but catch exceptions)
- def rabspath(path):
- try:
- return os.path.abspath(path)
- except OSError:
- return path
-elif os.name == 'nt':
- def rabspath(path):
+
+def _posix_risabs(s):
+ """Test whether a path is absolute"""
+ return s.startswith('/')
+
+def _posix_rabspath(path):
+ """Return an absolute, **non-normalized** path.
+ **This version does not let exceptions propagate.**"""
+ try:
+ if not _posix_risabs(path):
+ cwd = os.getcwd()
+ path = _posix_rjoin(cwd, path)
+ return path
+ except OSError:
+ return path
+
+def _posix_rjoin(a, b):
+ """Join two pathname components, inserting '/' as needed.
+ If the second component is an absolute path, the first one
+ will be discarded. An empty last part will result in a path that
+ ends with a separator."""
+ path = a
+ if b.startswith('/'):
+ path = b
+ elif path == '' or path.endswith('/'):
+ path += b
+ else:
+ path += '/' + b
+ return path
+
+
+def _nt_risabs(s):
+ """Test whether a path is absolute"""
+ s = _nt_rsplitdrive(s)[1]
+ return s.startswith('/') or s.startswith('\\')
+
+def _nt_rabspath(path):
+ try:
if path == '':
path = os.getcwd()
- try:
- return rposix._getfullpathname(path)
- except OSError:
- return path
+ return rposix._getfullpathname(path)
+ except OSError:
+ return path
+
+def _nt_rsplitdrive(p):
+ """Split a pathname into drive/UNC sharepoint and relative path
+ specifiers.
+ Returns a 2-tuple (drive_or_unc, path); either part may be empty.
+ """
+ if len(p) > 1:
+ normp = p.replace(altsep, sep)
+ if normp.startswith('\\\\') and not normp.startswith('\\\\\\'):
+ # is a UNC path:
+ # vvvvvvvvvvvvvvvvvvvv drive letter or UNC path
+ # \\machine\mountpoint\directory\etc\...
+ # directory ^^^^^^^^^^^^^^^
+ index = normp.find('\\', 2)
+ if index < 0:
+ return '', p
+ index2 = normp.find('\\', index + 1)
+ # a UNC path can't have two slashes in a row
+ # (after the initial two)
+ if index2 == index + 1:
+ return '', p
+ if index2 < 0:
+ index2 = len(p)
+ return p[:index2], p[index2:]
+ if normp[1] == ':':
+ return p[:2], p[2:]
+ return '', p
+
+def _nt_rjoin(path, p):
+ """Join two or more pathname components, inserting "\\" as needed."""
+ result_drive, result_path = _nt_rsplitdrive(path)
+ p_drive, p_path = _nt_rsplitdrive(p)
+ p_is_rel = True
+ if p_path and p_path[0] in '\\/':
+ # Second path is absolute
+ if p_drive or not result_drive:
+ result_drive = p_drive
+ result_path = p_path
+ p_is_rel = False
+ elif p_drive and p_drive != result_drive:
+ if p_drive.lower() != result_drive.lower():
+ # Different drives => ignore the first path entirely
+ result_drive = p_drive
+ result_path = p_path
+ p_is_rel = False
+ else:
+ # Same drive in different case
+ result_drive = p_drive
+ if p_is_rel:
+ # Second path is relative to the first
+ if result_path and result_path[-1] not in '\\/':
+ result_path = result_path + '\\'
+ result_path = result_path + p_path
+ ## add separator between UNC and non-absolute path
+ if (result_path and result_path[0] not in '\\/' and
+ result_drive and result_drive[-1] != ':'):
+ return result_drive + '\\' + result_path
+ return result_drive + result_path
+
+
+if os.name == 'posix':
+ sep = altsep = '/'
+ risabs = _posix_risabs
+ rabspath = _posix_rabspath
+ rjoin = _posix_rjoin
+elif os.name == 'nt':
+ sep, altsep = '\\', '/'
+ risabs = _nt_risabs
+ rabspath = _nt_rabspath
+ rsplitdrive = _nt_rsplitdrive
+ rjoin = _nt_rjoin
else:
raise ImportError('Unsupported os: %s' % os.name)
diff --git a/rpython/rlib/test/test_rpath.py b/rpython/rlib/test/test_rpath.py
--- a/rpython/rlib/test/test_rpath.py
+++ b/rpython/rlib/test/test_rpath.py
@@ -2,17 +2,14 @@
import os
from rpython.rlib import rpath
-IS_WINDOWS = os.name == 'nt'
-
def test_rabspath_relative(tmpdir):
tmpdir.chdir()
assert rpath.rabspath('foo') == os.path.realpath(str(tmpdir.join('foo')))
[email protected]("IS_WINDOWS")
def test_rabspath_absolute_posix():
- assert rpath.rabspath('/foo') == '/foo'
+ assert rpath._posix_rabspath('/foo') == '/foo'
[email protected]("IS_WINDOWS")
[email protected]("os.name == 'nt'")
def test_missing_current_dir(tmpdir):
tmpdir1 = str(tmpdir) + '/temporary_removed'
curdir1 = os.getcwd()
@@ -25,7 +22,25 @@
os.chdir(curdir1)
assert result == '.'
[email protected]("not IS_WINDOWS")
+def test_rsplitdrive_nt():
+ assert rpath._nt_rsplitdrive('D:\\FOO/BAR') == ('D:', '\\FOO/BAR')
+ assert rpath._nt_rsplitdrive('//') == ('', '//')
+
[email protected]("os.name != 'nt'")
def test_rabspath_absolute_nt():
- curdrive, _ = os.path.splitdrive(os.getcwd())
+ curdrive = _ = rpath._nt_rsplitdrive(os.getcwd())
+ assert len(curdrive) == 2 and curdrive[1] == ':'
assert rpath.rabspath('\\foo') == '%s\\foo' % curdrive
+
+def test_risabs_posix():
+ assert rpath._posix_risabs('/foo/bar')
+ assert not rpath._posix_risabs('foo/bar')
+ assert not rpath._posix_risabs('\\foo\\bar')
+ assert not rpath._posix_risabs('C:\\foo\\bar')
+
+def test_risabs_nt():
+ assert rpath._nt_risabs('/foo/bar')
+ assert not rpath._nt_risabs('foo/bar')
+ assert rpath._nt_risabs('\\foo\\bar')
+ assert rpath._nt_risabs('C:\\FOO')
+ assert not rpath._nt_risabs('C:FOO')
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit