You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Improve Windows performance of pathlib.Path.is_file and friends #101357
We could implement / reuse the same fast paths that we did for os.path.* in #101324 for pathlib.Path.*. It will require a little more work, since the pathlib.Path API can return OSError under certain circumstances, whereas os.path would return False in those cases.
Pitch
We saw a 12-25% speedup doing this for os.path. It would be unfortunate if people chose the lower-level API for performance reasons because pathlib.Path didn't match it in performance.
We support subclassing as of #31691, which means that a user on Windows can do this:
classMyClass(pathlib.Path):
passP=MyClass()
... and expect that p works exactly as if it was a WindowsPath. But it's not actually a subclass of WindowsPath - its behaviour is controlled entirely by the value of its _flavour attribute.
Hence I'm hesistant to add things to WindowsPath and PosixPath.
We can do like what you implemented for os.path.realpath(). Add a strict=False keyword-only parameter to exists(), isfile(), isdir(), islink(), and isjunction(). In strict mode it ignores only a select set of errors. Move the definition of _ignore_error() into ntpath and posixpath, with _IGNORED_ERRNOS defined in genericpath.
👍 that sounds good to me! Just as long as we adjust the pathlib.Path code and not WindowsPath specifically if that's OK. Hopefully my draft PR illustrates what I mean here.
Should nt._exists() and the others be modified to raise an exception that gets handled by a wrapper function such as ntpath.exists()? Or should we have a list of ignored error codes in the C implementation that's kept in sync with _IGNORED_ERRNOS and _IGNORED_WINERRORS? I guess it would help to benchmark the performance cost of raising and handling an exception for common errors that should always be handled by returning False, such as ERROR_FILE_NOT_FOUND and ERROR_PATH_NOT_FOUND, compared to simply returning False from the builtin function.
This should be the complete set of ignored Windows error codes:
Oh, but we'd need to add optional follow_symlinks arguments to os.path.exists(), isfile() and isdir(), in order to support the equivalent arguments in pathlib methods. Or we'd need to add an islink() check to each of those pathlib methods, which would slow things back down.
Or switch function called in the pathlib methods based on that parameter.
In newer versions of Windows, stat is going to be almost as fast as the "fast path" functions (and only because we updated the fast path functions to use the faster stat call, or else they'd be slower), so eventually it won't matter too much which call is used. Not following symlinks should always be faster anyway.
Apologize for my confusion, it has been a while since I followed this ticket. I was wondering if someone could clarify a little bit about the situation.
From what I can see, the closing commit/PR only seems to change behaviors about OSErrors.
Would it still improve the performance of pathlib.Path.is_file (i.e. what this ticket is about)?
@zooba's comment seems to imply that the improvement was already made at other places, but needing "newer version of Windows".
In other words, if I upgraded to 3.14 in future, but have to use "older" version of Windows (for example. Win10), would I still get any notifiable performance improvement on pathlib.Path.is_file after this patch?
From what I can see, the closing commit/PR only seems to change behaviors about OSErrors. Would it still improve the performance of pathlib.Path.is_file (i.e. what this ticket is about)?
The change of OSError handling means the pathlib methods are now compatible with the os.path functions, and so we now call those functions:
Activity
barneygale commentedon Jan 26, 2023
It would be a shame to lose the generic implementations in pathlib -- they'll be useful in a future
AbstractPathclass wherestat()is abstract.eryksun commentedon Jan 26, 2023
@barneygale, wouldn't this enhancement entail
WindowsPathoverriding the basePathimplementations?barneygale commentedon Jan 27, 2023
We support subclassing as of #31691, which means that a user on Windows can do this:
... and expect that
pworks exactly as if it was aWindowsPath. But it's not actually a subclass ofWindowsPath- its behaviour is controlled entirely by the value of its_flavourattribute.Hence I'm hesistant to add things to
WindowsPathandPosixPath.pythongh-101357: use `os.path.exists()` etc from pathlib
pythongh-101357: use `os.path.exists()` etc from pathlib
eryksun commentedon Jan 27, 2023
We can do like what you implemented for
os.path.realpath(). Add astrict=Falsekeyword-only parameter toexists(),isfile(),isdir(),islink(), andisjunction(). In strict mode it ignores only a select set of errors. Move the definition of_ignore_error()intontpathandposixpath, with_IGNORED_ERRNOSdefined ingenericpath.barneygale commentedon Jan 27, 2023
👍 that sounds good to me! Just as long as we adjust the
pathlib.Pathcode and notWindowsPathspecifically if that's OK. Hopefully my draft PR illustrates what I mean here.eryksun commentedon Jan 27, 2023
Should
nt._exists()and the others be modified to raise an exception that gets handled by a wrapper function such asntpath.exists()? Or should we have a list of ignored error codes in the C implementation that's kept in sync with_IGNORED_ERRNOSand_IGNORED_WINERRORS? I guess it would help to benchmark the performance cost of raising and handling an exception for common errors that should always be handled by returningFalse, such asERROR_FILE_NOT_FOUNDandERROR_PATH_NOT_FOUND, compared to simply returningFalsefrom the builtin function.This should be the complete set of ignored Windows error codes:
1 remaining item
barneygale commentedon Jan 26, 2024
Oh, but we'd need to add optional
follow_symlinksarguments toos.path.exists(),isfile()andisdir(), in order to support the equivalent arguments in pathlib methods. Or we'd need to add anislink()check to each of those pathlib methods, which would slow things back down.zooba commentedon Jan 29, 2024
Or switch function called in the pathlib methods based on that parameter.
In newer versions of Windows,
statis going to be almost as fast as the "fast path" functions (and only because we updated the fast path functions to use the faster stat call, or else they'd be slower), so eventually it won't matter too much which call is used. Not following symlinks should always be faster anyway.pythonGH-101357: Suppress `OSError` from `pathlib.Path.exists()` and …
Merge branch 'main' into pythongh-101357
barneygale commentedon May 8, 2024
PR: #118243
GH-101357: Suppress `OSError` from `pathlib.Path.exists()` and `is_*(…
barneygale commentedon May 14, 2024
Resolved in 3.14 / fbe6a09 / #118243. Thanks everyone.
fireattack commentedon May 14, 2024
Apologize for my confusion, it has been a while since I followed this ticket. I was wondering if someone could clarify a little bit about the situation.
From what I can see, the closing commit/PR only seems to change behaviors about
OSErrors.Would it still improve the performance of
pathlib.Path.is_file(i.e. what this ticket is about)?@zooba's comment seems to imply that the improvement was already made at other places, but needing "newer version of Windows".
In other words, if I upgraded to 3.14 in future, but have to use "older" version of Windows (for example. Win10), would I still get any notifiable performance improvement on
pathlib.Path.is_fileafter this patch?Thanks in advance!
barneygale commentedon May 14, 2024
The change of
OSErrorhandling means thepathlibmethods are now compatible with theos.pathfunctions, and so we now call those functions:cpython/Lib/pathlib/_local.py
Lines 505 to 549 in fbe6a09
fireattack commentedon May 14, 2024
Thank you, now I understand.
pythonGH-101357: Suppress `OSError` from `pathlib.Path.exists()` and …