8000 gh-126782: Support qualified referencing for `ntpath.abspath()` by nineteendo · Pull Request #119849 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

gh-126782: Support qualified referencing for ntpath.abspath() #119849

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 12 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
Improve accuracy of ntpath.normpath() & ntpath.abspath()
  • Loading branch information
nineteendo committed May 31, 2024
commit a7687c468ea88ec5fd2d71a48ed2e1d57183a8c6
3 changes: 2 additions & 1 deletion Include/internal/pycore_fileutils.h
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,8 @@ extern size_t _Py_find_basename(const wchar_t *filename);
// Export for '_testinternalcapi' shared extension
PyAPI_FUNC(wchar_t*) _Py_normpath(wchar_t *path, Py_ssize_t size);

extern wchar_t *_Py_normpath_and_size(wchar_t *path, Py_ssize_t size, Py_ssize_t *length);
extern wchar_t *_Py_normpath_and_size(wchar_t *path, Py_ssize_t size, Py_ssize_t *length,
int explicit_curdir);

// The Windows Games API family does not provide these functions
// so provide our own implementations. Remove them in case they get added
Expand Down
48 changes: 30 additions & 18 deletions Lib/ntpath.py
Original file line number Diff line number Diff line change
Expand Up @@ -554,36 +554,48 @@ def normpath(path):
return prefix + sep.join(comps)


def _abspath_fallback(path):
"""Return the absolute version of a path as a fallback function in case
`nt._getfullpathname` is not available or raises OSError. See bpo-31047 for
more.

"""

path = os.fspath(path)
if not isabs(path):
if isinstance(path, bytes):
cwd = os.getcwdb()
else:
cwd = os.getcwd()
path = join(cwd, path)
return normpath(path)

# Return an absolute path.
try:
from nt import _getfullpathname

except ImportError: # not running on Windows - mock up something sensible
abspath = _abspath_fallback
def abspath(path):
"""Return the absolute version of a path."""
path = os.fspath(path)
if not isabs(path):
if isinstance(path, bytes):
cwd = os.getcwdb()
else:
cwd = os.getcwd()
path = join(cwd, path)
return normpath(path)

else: # use native Windows method on Windows
def abspath(path):
"""Return the absolute version of a path."""
try:
return _getfullpathname(normpath(path))
except (OSError, ValueError):
return _abspath_fallback(path)
# See gh-75230, handle outside for cleaner traceback
pass
path = os.fspath(path)
if not isabs(path):
if isinstance(path, bytes):
sep = b'/'
cwd = os.getcwdb()
else:
sep = '/'
cwd = os.getcwd()
drive, root, path = splitroot(path)
if drive and drive != splitroot(cwd)[0]:
try:
path = join(_getfullpathname(drive), path)
except (OSError, ValueError):
# Invalid drive \x00: on Windows; assume root directory
path = drive + sep + path
else:
path = join(cwd, root + path)
return normpath(path)

try:
from nt import _findfirstfile, _getfinalpathname, readlink as _nt_readlink
Expand Down
19 changes: 19 additions & 0 deletions Lib/test/test_ntpath.py
EDBE
Original file line number Diff line number Diff line change
Expand Up @@ -347,13 +347,15 @@ def test_normpath(self):

tester("ntpath.normpath('..')", r'..')
tester("ntpath.normpath('.')", r'.')
tester("ntpath.normpath('c:.')", 'c:')
tester("ntpath.normpath('')", r'.')
tester("ntpath.normpath('/')", '\\')
tester("ntpath.normpath('c:/')", 'c:\\')
tester("ntpath.normpath('/../.././..')", '\\')
tester("ntpath.normpath('c:/../../..')", 'c:\\')
tester("ntpath.normpath('../.././..')", r'..\..\..')
tester("ntpath.normpath('K:../.././..')", r'K:..\..\..')
tester("ntpath.normpath('./a/b')", r'a\b')
tester("ntpath.normpath('C:////a/b')", r'C:\a\b')
tester("ntpath.normpath('//machine/share//a/b')", r'\\machine\share\a\b')

Expand Down Expand Up @@ -806,6 +808,9 @@ def test_abspath(self):
tester('ntpath.abspath("C:\\spam. . .")', "C:\\spam")
tester('ntpath.abspath("C:/nul")', "\\\\.\\nul")
tester('ntpath.abspath("C:\\nul")', "\\\\.\\nul")
self.assertTrue(ntpath.isabs(ntpath.abspath("C:spam")))
self.assertTrue(ntpath.isabs(ntpath.abspath("C:\x00")))
self.assertTrue(ntpath.isabs(ntpath.abspath("\x00:spam")))
tester('ntpath.abspath("//..")', "\\\\")
tester('ntpath.abspath("//../")', "\\\\..\\")
tester('ntpath.abspath("//../..")', "\\\\..\\")
Expand Down Expand Up @@ -836,6 +841,20 @@ def test_abspath(self):
tester('ntpath.abspath("")', cwd_dir)
tester('ntpath.abspath(" ")', cwd_dir + "\\ ")
tester('ntpath.abspath("?")', cwd_dir + "\\?")
tester('ntpath.abspath("con")', r"\\.\con")
# bpo-45354: Windows 11 changed MS-DOS device name handling
if sys.getwindowsversion()[:3] < (10, 0, 22000):
tester('ntpath.abspath("./con")', r"\\.\con")
tester('ntpath.abspath("foo/../con")', r"\\.\con")
tester('ntpath.abspath("con/foo/..")', r"\\.\con")
tester('ntpath.abspath("con/.")', r"\\.\con")
else:
tester('ntpath.abspath("./con")', cwd_dir + r"\con")
tester('ntpath.abspath("foo/../con")', cwd_dir + r"\con")
tester('ntpath.abspath("con/foo/..")', cwd_dir + r"\con")
tester('ntpath.abspath("con/.")', cwd_dir + r"\con")
tester('ntpath.abspath("./Z:spam")', cwd_dir + r"\Z:spam")
tester('ntpath.abspath("spam/../Z:eggs")', cwd_dir + r"\Z:eggs")
drive, _ = ntpath.splitdrive(cwd_dir)
tester('ntpath.abspath("/abc/")', drive + "\\abc")

Expand Down
1 change: 1 addition & 0 deletions Lib/test/test_posixpath.py
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,7 @@ def test_expanduser_pwd2(self):
("///..//./foo/.//bar", "/foo/bar"),
(".", "."),
(".//.", "."),
("./foo/bar", "foo/bar"),
("..", ".."),
("../", ".."),
("../foo", "../foo"),
Expand Down
73 changes: 72 additions & 1 deletion Modules/clinic/posixmodule.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 26 additions & 4 deletions Modules/posixmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -5526,21 +5526,25 @@ os__path_splitroot_ex_impl(PyObject *module, path_t *path)


/*[clinic input]
os._path_normpath
os._path_normpath_ex

path: path_t(make_wide=True, nonstrict=True)
*
explicit_curdir: bool = False

Normalize path, eliminating double slashes, etc.
[clinic start generated code]*/

static PyObject *
os__path_normpath_impl(PyObject *module, path_t *path)
/*[clinic end generated code: output=d353e7ed9410c044 input=3d4ac23b06332dcb]*/
os__path_normpath_ex_impl(PyObject *module, path_t *path,
int explicit_curdir)
/*[clinic end generated code: output=4c4c3bf33a70fe57 input=90fe0dfc4b3a751b]*/
{
PyObject *result;
Py_ssize_t norm_len;
wchar_t *norm_path = _Py_normpath_and_size((wchar_t *)path->wide,
path->length, &norm_len);
path->length, &norm_len,
explicit_curdir);
if (!norm_len) {
result = PyUnicode_FromOrdinal('.');
}
Expand All @@ -5553,6 +5557,23 @@ os__path_normpath_impl(P 9E82 yObject *module, path_t *path)
return result;
}


/*[clinic input]
os._path_normpath

path: path_t(make_wide=True, nonstrict=True)

Normalize path, eliminating double slashes, etc.
[clinic start generated code]*/

static PyObject *
os__path_normpath_impl(PyObject *module, path_t *path)
/*[clinic end generated code: output=d353e7ed9410c044 input=3d4ac23b06332dcb]*/
{

return os__path_normpath_ex_impl(module, path, 0);
}

/*[clinic input]
os.mkdir

Expand Down Expand Up @@ -16891,6 +16912,7 @@ static PyMethodDef posix_methods[] = {
OS__GETVOLUMEPATHNAME_METHODDEF
OS__PATH_SPLITROOT_METHODDEF
OS__PATH_SPLITROOT_EX_METHODDEF
OS__PATH_NORMPATH_EX_METHODDEF
OS__PATH_NORMPATH_METHODDEF
OS_GETLOADAVG_METHODDEF
OS_URANDOM_METHODDEF
Expand Down
Loading
0