Author: Armin Rigo <ar...@tunes.org> 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'))) -@py.test.mark.skipif("IS_WINDOWS") def test_rabspath_absolute_posix(): - assert rpath.rabspath('/foo') == '/foo' + assert rpath._posix_rabspath('/foo') == '/foo' -@py.test.mark.skipif("IS_WINDOWS") +@py.test.mark.skipif("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 == '.' -@py.test.mark.skipif("not IS_WINDOWS") +def test_rsplitdrive_nt(): + assert rpath._nt_rsplitdrive('D:\\FOO/BAR') == ('D:', '\\FOO/BAR') + assert rpath._nt_rsplitdrive('//') == ('', '//') + +@py.test.mark.skipif("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 pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit