Skip to content

Commit 96b392d

Browse files
authored
gh-118263: Add additional arguments to path_t (Argument Clinic type) in posixmodule (GH-118355)
1 parent f0ed186 commit 96b392d

File tree

7 files changed

+389
-359
lines changed

7 files changed

+389
-359
lines changed

Lib/ntpath.py

+5-37
Original file line numberDiff line numberDiff line change
@@ -168,19 +168,12 @@ def splitdrive(p):
168168

169169

170170
try:
171-
from nt import _path_splitroot_ex
171+
from nt import _path_splitroot_ex as splitroot
172172
except ImportError:
173173
def splitroot(p):
174-
"""Split a pathname into drive, root and tail. The drive is defined
175-
exactly as in splitdrive(). On Windows, the root may be a single path
176-
separator or an empty string. The tail contains anything after the root.
177-
For example:
178-
179-
splitroot('//server/share/') == ('//server/share', '/', '')
180-
splitroot('C:/Users/Barney') == ('C:', '/', 'Users/Barney')
181-
splitroot('C:///spam///ham') == ('C:', '/', '//spam///ham')
182-
splitroot('Windows/notepad') == ('', '', 'Windows/notepad')
183-
"""
174+
"""Split a pathname into drive, root and tail.
175+
176+
The tail contains anything after the root."""
184177
p = os.fspath(p)
185178
if isinstance(p, bytes):
186179
sep = b'\\'
@@ -220,23 +213,6 @@ def splitroot(p):
220213
else:
221214
# Relative path, e.g. Windows
222215
return empty, empty, p
223-
else:
224-
def splitroot(p):
225-
"""Split a pathname into drive, root and tail. The drive is defined
226-
exactly as in splitdrive(). On Windows, the root may be a single path
227-
separator or an empty string. The tail contains anything after the root.
228-
For example:
229-
230-
splitroot('//server/share/') == ('//server/share', '/', '')
231-
splitroot('C:/Users/Barney') == ('C:', '/', 'Users/Barney')
232-
splitroot('C:///spam///ham') == ('C:', '/', '//spam///ham')
233-
splitroot('Windows/notepad') == ('', '', 'Windows/notepad')
234-
"""
235-
p = os.fspath(p)
236-
if isinstance(p, bytes):
237-
drive, root, tail = _path_splitroot_ex(os.fsdecode(p))
238-
return os.fsencode(drive), os.fsencode(root), os.fsencode(tail)
239-
return _path_splitroot_ex(p)
240216

241217

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

543519
except ImportError:
544520
def normpath(path):
@@ -577,14 +553,6 @@ def normpath(path):
577553
comps.append(curdir)
578554
return prefix + sep.join(comps)
579555

580-
else:
581-
def normpath(path):
582-
"""Normalize path, eliminating double slashes, etc."""
583-
path = os.fspath(path)
584-
if isinstance(path, bytes):
585-
return os.fsencode(_path_normpath(os.fsdecode(path))) or b"."
586-
return _path_normpath(path) or "."
587-
588556

589557
def _abspath_fallback(path):
590558
"""Return the absolute version of a path as a fallback function in case

Lib/posixpath.py

+5-36
Original file line numberDiff line numberDiff line change
@@ -135,18 +135,12 @@ def splitdrive(p):
135135

136136

137137
try:
138-
from posix import _path_splitroot_ex
138+
from posix import _path_splitroot_ex as splitroot
139139
except ImportError:
140140
def splitroot(p):
141-
"""Split a pathname into drive, root and tail. On Posix, drive is always
142-
empty; the root may be empty, a single slash, or two slashes. The tail
143-
contains anything after the root. For example:
144-
145-
splitroot('foo/bar') == ('', '', 'foo/bar')
146-
splitroot('/foo/bar') == ('', '/', 'foo/bar')
147-
splitroot('//foo/bar') == ('', '//', 'foo/bar')
148-
splitroot('///foo/bar') == ('', '/', '//foo/bar')
149-
"""
141+
"""Split a pathname into drive, root and tail.
142+
143+
The tail contains anything after the root."""
150144
p = os.fspath(p)
151145
if isinstance(p, bytes):
152146
sep = b'/'
@@ -164,23 +158,6 @@ def splitroot(p):
164158
# Precisely two leading slashes, e.g.: '//foo'. Implementation defined per POSIX, see
165159
# https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13
166160
return empty, p[:2], p[2:]
167-
else:
168-
def splitroot(p):
169-
"""Split a pathname into drive, root and tail. On Posix, drive is always
170-
empty; the root may be empty, a single slash, or two slashes. The tail
171-
contains anything after the root. For example:
172-
173-
splitroot('foo/bar') == ('', '', 'foo/bar')
174-
splitroot('/foo/bar') == ('', '/', 'foo/bar')
175-
splitroot('//foo/bar') == ('', '//', 'foo/bar')
176-
splitroot('///foo/bar') == ('', '/', '//foo/bar')
177-
"""
178-
p = os.fspath(p)
179-
if isinstance(p, bytes):
180-
# Optimisation: the drive is always empty
181-
_, root, tail = _path_splitroot_ex(os.fsdecode(p))
182-
return b'', os.fsencode(root), os.fsencode(tail)
183-
return _path_splitroot_ex(p)
184161

185162

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

365342
try:
366-
from posix import _path_normpath
343+
from posix import _path_normpath as normpath
367344

368345
except ImportError:
369346
def normpath(path):
@@ -394,14 +371,6 @@ def normpath(path):
394371
path = initial_slashes + sep.join(comps)
395372
return path or dot
396373

397-
else:
398-
def normpath(path):
399-
"""Normalize path, eliminating double slashes, etc."""
400-
path = os.fspath(path)
401-
if isinstance(path, bytes):
402-
return os.fsencode(_path_normpath(os.fsdecode(path))) or b"."
403-
return _path_normpath(path) or "."
404-
405374

406375
def abspath(path):
407376
"""Return an absolute path."""

Lib/test/test_ntpath.py

+4
Original file line numberDiff line numberDiff line change
@@ -1129,6 +1129,10 @@ def test_fast_paths_in_use(self):
11291129
# There are fast paths of these functions implemented in posixmodule.c.
11301130
# Confirm that they are being used, and not the Python fallbacks in
11311131
# genericpath.py.
1132+
self.assertTrue(os.path.splitroot is nt._path_splitroot_ex)
1133+
self.assertFalse(inspect.isfunction(os.path.splitroot))
1134+
self.assertTrue(os.path.normpath is nt._path_normpath)
1135+
self.assertFalse(inspect.isfunction(os.path.normpath))
11321136
self.assertTrue(os.path.isdir is nt._path_isdir)
11331137
self.assertFalse(inspect.isfunction(os.path.isdir))
11341138
self.assertTrue(os.path.isfile is nt._path_isfile)

Lib/test/test_posixpath.py

+12-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1+
import inspect
12
import os
23
import posixpath
34
import sys
45
import unittest
56
from posixpath import realpath, abspath, dirname, basename
67
from test import test_genericpath
78
from test.support import import_helper
8-
from test.support import os_helper
9+
from test.support import cpython_only, os_helper
910
from test.support.os_helper import FakePath
1011
from unittest import mock
1112

@@ -283,6 +284,16 @@ def fake_lstat(path):
283284
def test_isjunction(self):
284285
self.assertFalse(posixpath.isjunction(ABSTFN))
285286

287+
@unittest.skipIf(sys.platform == 'win32', "Fast paths are not for win32")
288+
@cpython_only
289+
def test_fast_paths_in_use(self):
290+
# There are fast paths of these functions implemented in posixmodule.c.
291+
# Confirm that they are being used, and not the Python fallbacks
292+
self.assertTrue(os.path.splitroot is posix._path_splitroot_ex)
293+
self.assertFalse(inspect.isfunction(os.path.splitroot))
294+
self.assertTrue(os.path.normpath is posix._path_normpath)
295+
self.assertFalse(inspect.isfunction(os.path.normpath))
296+
286297
def test_expanduser(self):
287298
self.assertEqual(posixpath.expanduser("foo"), "foo")
288299
self.assertEqual(posixpath.expanduser(b"foo"), b"foo")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Speed up :func:`os.path.splitroot` & :func:`os.path.normpath` with a direct C call.

0 commit comments

Comments
 (0)