Skip to content

Commit

Permalink
gh-118263: Add additional arguments to path_t (Argument Clinic type) …
Browse files Browse the repository at this point in the history
…in posixmodule (GH-118355)

(cherry picked from commit 96b392d)

Co-authored-by: Nice Zombies <nineteendo19d0@gmail.com>
  • Loading branch information
miss-islington and nineteendo committed May 24, 2024
1 parent 217d57f commit cc38ee1
Show file tree
Hide file tree
Showing 7 changed files with 389 additions and 359 deletions.
42 changes: 5 additions & 37 deletions Lib/ntpath.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,19 +168,12 @@ def splitdrive(p):


try:
from nt import _path_splitroot_ex
from nt import _path_splitroot_ex as splitroot
except ImportError:
def splitroot(p):
"""Split a pathname into drive, root and tail. The drive is defined
exactly as in splitdrive(). On Windows, the root may be a single path
separator or an empty string. The tail contains anything after the root.
For example:
splitroot('//server/share/') == ('//server/share', '/', '')
splitroot('C:/Users/Barney') == ('C:', '/', 'Users/Barney')
splitroot('C:///spam///ham') == ('C:', '/', '//spam///ham')
splitroot('Windows/notepad') == ('', '', 'Windows/notepad')
"""
"""Split a pathname into drive, root and tail.
The tail contains anything after the root."""
p = os.fspath(p)
if isinstance(p, bytes):
sep = b'\\'
Expand Down Expand Up @@ -220,23 +213,6 @@ def splitroot(p):
else:
# Relative path, e.g. Windows
return empty, empty, p
else:
def splitroot(p):
"""Split a pathname into drive, root and tail. The drive is defined
exactly as in splitdrive(). On Windows, the root may be a single path
separator or an empty string. The tail contains anything after the root.
For example:
splitroot('//server/share/') == ('//server/share', '/', '')
splitroot('C:/Users/Barney') == ('C:', '/', 'Users/Barney')
splitroot('C:///spam///ham') == ('C:', '/', '//spam///ham')
splitroot('Windows/notepad') == ('', '', 'Windows/notepad')
"""
p = os.fspath(p)
if isinstance(p, bytes):
drive, root, tail = _path_splitroot_ex(os.fsdecode(p))
return os.fsencode(drive), os.fsencode(root), os.fsencode(tail)
return _path_splitroot_ex(p)


# Split a path in head (everything up to the last '/') and tail (the
Expand Down Expand Up @@ -538,7 +514,7 @@ def expandvars(path):
# Previously, this function also truncated pathnames to 8+3 format,
# but as this module is called "ntpath", that's obviously wrong!
try:
from nt import _path_normpath
from nt import _path_normpath as normpath

except ImportError:
def normpath(path):
Expand Down Expand Up @@ -577,14 +553,6 @@ def normpath(path):
comps.append(curdir)
return prefix + sep.join(comps)

else:
def normpath(path):
"""Normalize path, eliminating double slashes, etc."""
path = os.fspath(path)
if isinstance(path, bytes):
return os.fsencode(_path_normpath(os.fsdecode(path))) or b"."
return _path_normpath(path) or "."


def _abspath_fallback(path):
"""Return the absolute version of a path as a fallback function in case
Expand Down
41 changes: 5 additions & 36 deletions Lib/posixpath.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,18 +135,12 @@ def splitdrive(p):


try:
from posix import _path_splitroot_ex
from posix import _path_splitroot_ex as splitroot
except ImportError:
def splitroot(p):
"""Split a pathname into drive, root and tail. On Posix, drive is always
empty; the root may be empty, a single slash, or two slashes. The tail
contains anything after the root. For example:
splitroot('foo/bar') == ('', '', 'foo/bar')
splitroot('/foo/bar') == ('', '/', 'foo/bar')
splitroot('//foo/bar') == ('', '//', 'foo/bar')
splitroot('///foo/bar') == ('', '/', '//foo/bar')
"""
"""Split a pathname into drive, root and tail.
The tail contains anything after the root."""
p = os.fspath(p)
if isinstance(p, bytes):
sep = b'/'
Expand All @@ -164,23 +158,6 @@ def splitroot(p):
# Precisely two leading slashes, e.g.: '//foo'. Implementation defined per POSIX, see
# https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13
return empty, p[:2], p[2:]
else:
def splitroot(p):
"""Split a pathname into drive, root and tail. On Posix, drive is always
empty; the root may be empty, a single slash, or two slashes. The tail
contains anything after the root. For example:
splitroot('foo/bar') == ('', '', 'foo/bar')
splitroot('/foo/bar') == ('', '/', 'foo/bar')
splitroot('//foo/bar') == ('', '//', 'foo/bar')
splitroot('///foo/bar') == ('', '/', '//foo/bar')
"""
p = os.fspath(p)
if isinstance(p, bytes):
# Optimisation: the drive is always empty
_, root, tail = _path_splitroot_ex(os.fsdecode(p))
return b'', os.fsencode(root), os.fsencode(tail)
return _path_splitroot_ex(p)


# Return the tail (basename) part of a path, same as split(path)[1].
Expand Down Expand Up @@ -363,7 +340,7 @@ def expandvars(path):
# if it contains symbolic links!

try:
from posix import _path_normpath
from posix import _path_normpath as normpath

except ImportError:
def normpath(path):
Expand Down Expand Up @@ -394,14 +371,6 @@ def normpath(path):
path = initial_slashes + sep.join(comps)
return path or dot

else:
def normpath(path):
"""Normalize path, eliminating double slashes, etc."""
path = os.fspath(path)
if isinstance(path, bytes):
return os.fsencode(_path_normpath(os.fsdecode(path))) or b"."
return _path_normpath(path) or "."


def abspath(path):
"""Return an absolute path."""
Expand Down
4 changes: 4 additions & 0 deletions Lib/test/test_ntpath.py
Original file line number Diff line number Diff line change
Expand Up @@ -1129,6 +1129,10 @@ def test_fast_paths_in_use(self):
# There are fast paths of these functions implemented in posixmodule.c.
# Confirm that they are being used, and not the Python fallbacks in
# genericpath.py.
self.assertTrue(os.path.splitroot is nt._path_splitroot_ex)
self.assertFalse(inspect.isfunction(os.path.splitroot))
self.assertTrue(os.path.normpath is nt._path_normpath)
self.assertFalse(inspect.isfunction(os.path.normpath))
self.assertTrue(os.path.isdir is nt._path_isdir)
self.assertFalse(inspect.isfunction(os.path.isdir))
self.assertTrue(os.path.isfile is nt._path_isfile)
Expand Down
13 changes: 12 additions & 1 deletion Lib/test/test_posixpath.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import inspect
import os
import posixpath
import sys
import unittest
from posixpath import realpath, abspath, dirname, basename
from test import test_genericpath
from test.support import import_helper
from test.support import os_helper
from test.support import cpython_only, os_helper
from test.support.os_helper import FakePath
from unittest import mock

Expand Down Expand Up @@ -283,6 +284,16 @@ def fake_lstat(path):
def test_isjunction(self):
self.assertFalse(posixpath.isjunction(ABSTFN))

@unittest.skipIf(sys.platform == 'win32', "Fast paths are not for win32")
@cpython_only
def test_fast_paths_in_use(self):
# There are fast paths of these functions implemented in posixmodule.c.
# Confirm that they are being used, and not the Python fallbacks
self.assertTrue(os.path.splitroot is posix._path_splitroot_ex)
self.assertFalse(inspect.isfunction(os.path.splitroot))
self.assertTrue(os.path.normpath is posix._path_normpath)
self.assertFalse(inspect.isfunction(os.path.normpath))

def test_expanduser(self):
self.assertEqual(posixpath.expanduser("foo"), "foo")
self.assertEqual(posixpath.expanduser(b"foo"), b"foo")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Speed up :func:`os.path.splitroot` & :func:`os.path.normpath` with a direct C call.
Loading

0 comments on commit cc38ee1

Please sign in to comment.