From ab76c06e4b9e5116d46c8456bebdab3427589e72 Mon Sep 17 00:00:00 2001 From: nineteendo Date: Sat, 13 Apr 2024 12:03:17 +0200 Subject: [PATCH 1/8] Speedup `ntpath.exists` Co-authored-by: Eryk Sun --- Lib/ntpath.py | 1 + Lib/test/test_genericpath.py | 33 +++++---- Lib/test/test_ntpath.py | 2 + Modules/clinic/posixmodule.c.h | 65 ++++++++++++++++- Modules/posixmodule.c | 129 ++++++++++++++++++++------------- 5 files changed, 164 insertions(+), 66 deletions(-) diff --git a/Lib/ntpath.py b/Lib/ntpath.py index f5d1a2195dd633..d8da88993e9a38 100644 --- a/Lib/ntpath.py +++ b/Lib/ntpath.py @@ -899,6 +899,7 @@ def commonpath(paths): from nt import _path_isfile as isfile from nt import _path_islink as islink from nt import _path_exists as exists + from nt import _path_lexists as lexists except ImportError: # Use genericpath.* as imported above pass diff --git a/Lib/test/test_genericpath.py b/Lib/test/test_genericpath.py index f407ee3caf154c..58ad4aba0c9db4 100644 --- a/Lib/test/test_genericpath.py +++ b/Lib/test/test_genericpath.py @@ -128,31 +128,34 @@ def test_filetime(self): ) def test_exists(self): + def check_exists(filename, expected): + bfilename = os.fsencode(filename) + self.assertIs(self.pathmodule.exists(filename), expected) + self.assertIs(self.pathmodule.exists(bfilename), expected) + + def check_lexists(filename, expected): + bfilename = os.fsencode(filename) + self.assertIs(self.pathmodule.lexists(filename), expected) + self.assertIs(self.pathmodule.lexists(bfilename), expected) + filename = os_helper.TESTFN bfilename = os.fsencode(filename) self.addCleanup(os_helper.unlink, filename) - self.assertIs(self.pathmodule.exists(filename), False) - self.assertIs(self.pathmodule.exists(bfilename), False) + check_exists(filename, False) + check_lexists(filename, False) create_file(filename) - self.assertIs(self.pathmodule.exists(filename), True) - self.assertIs(self.pathmodule.exists(bfilename), True) - + check_exists(filename, True) self.assertIs(self.pathmodule.exists(filename + '\udfff'), False) self.assertIs(self.pathmodule.exists(bfilename + b'\xff'), False) - self.assertIs(self.pathmodule.exists(filename + '\x00'), False) - self.assertIs(self.pathmodule.exists(bfilename + b'\x00'), False) - - if self.pathmodule is not genericpath: - self.assertIs(self.pathmodule.lexists(filename), True) - self.assertIs(self.pathmodule.lexists(bfilename), True) + check_exists(filename + '\x00', False) - self.assertIs(self.pathmodule.lexists(filename + '\udfff'), False) - self.assertIs(self.pathmodule.lexists(bfilename + b'\xff'), False) - self.assertIs(self.pathmodule.lexists(filename + '\x00'), False) - self.assertIs(self.pathmodule.lexists(bfilename + b'\x00'), False) + check_lexists(filename, True) + self.assertIs(self.pathmodule.lexists(filename + '\udfff'), False) + self.assertIs(self.pathmodule.lexists(bfilename + b'\xff'), False) + check_lexists(filename + '\x00', False) @unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()") @unittest.skipIf(is_emscripten, "Emscripten pipe fds have no stat") diff --git a/Lib/test/test_ntpath.py b/Lib/test/test_ntpath.py index 31156130fcc747..28706298618e04 100644 --- a/Lib/test/test_ntpath.py +++ b/Lib/test/test_ntpath.py @@ -1115,6 +1115,8 @@ def test_fast_paths_in_use(self): self.assertFalse(inspect.isfunction(os.path.islink)) self.assertTrue(os.path.exists is nt._path_exists) self.assertFalse(inspect.isfunction(os.path.exists)) + self.assertTrue(os.path.lexists is nt._path_lexists) + self.assertFalse(inspect.isfunction(os.path.lexists)) @unittest.skipIf(os.name != 'nt', "Dev Drives only exist on Win32") def test_isdevdrive(self): diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h index 0398629e3c10ce..c2c85fb9fbeb36 100644 --- a/Modules/clinic/posixmodule.c.h +++ b/Modules/clinic/posixmodule.c.h @@ -2191,6 +2191,65 @@ os__path_exists(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObj #if defined(MS_WINDOWS) +PyDoc_STRVAR(os__path_lexists__doc__, +"_path_lexists($module, /, path)\n" +"--\n" +"\n" +"Test whether a path exists. Returns True for broken symbolic links"); + +#define OS__PATH_LEXISTS_METHODDEF \ + {"_path_lexists", _PyCFunction_CAST(os__path_lexists), METH_FASTCALL|METH_KEYWORDS, os__path_lexists__doc__}, + +static PyObject * +os__path_lexists_impl(PyObject *module, PyObject *path); + +static PyObject * +os__path_lexists(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(path), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"path", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "_path_lexists", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *path; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + path = args[0]; + return_value = os__path_lexists_impl(module, path); + +exit: + return return_value; +} + +#endif /* defined(MS_WINDOWS) */ + +#if defined(MS_WINDOWS) + PyDoc_STRVAR(os__path_islink__doc__, "_path_islink($module, /, path)\n" "--\n" @@ -12051,6 +12110,10 @@ os__supports_virtual_terminal(PyObject *module, PyObject *Py_UNUSED(ignored)) #define OS__PATH_EXISTS_METHODDEF #endif /* !defined(OS__PATH_EXISTS_METHODDEF) */ +#ifndef OS__PATH_LEXISTS_METHODDEF + #define OS__PATH_LEXISTS_METHODDEF +#endif /* !defined(OS__PATH_LEXISTS_METHODDEF) */ + #ifndef OS__PATH_ISLINK_METHODDEF #define OS__PATH_ISLINK_METHODDEF #endif /* !defined(OS__PATH_ISLINK_METHODDEF) */ @@ -12602,4 +12665,4 @@ os__supports_virtual_terminal(PyObject *module, PyObject *Py_UNUSED(ignored)) #ifndef OS__SUPPORTS_VIRTUAL_TERMINAL_METHODDEF #define OS__SUPPORTS_VIRTUAL_TERMINAL_METHODDEF #endif /* !defined(OS__SUPPORTS_VIRTUAL_TERMINAL_METHODDEF) */ -/*[clinic end generated code: output=511f0788a6b90db0 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=a2b2651b67aa67fa input=a9049054013a1b77]*/ diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 5e54cf64cd563e..991be86f4e62ed 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -5280,25 +5280,12 @@ os__path_isfile_impl(PyObject *module, PyObject *path) } -/*[clinic input] -os._path_exists - - path: 'O' - -Test whether a path exists. Returns False for broken symbolic links - -[clinic start generated code]*/ - static PyObject * -os__path_exists_impl(PyObject *module, PyObject *path) -/*[clinic end generated code: output=f508c3b35e13a249 input=380f77cdfa0f7ae8]*/ +nt_exists(PyObject *path, int follow_symlinks) { - HANDLE hfile; - BOOL close_file = TRUE; path_t _path = PATH_T_INITIALIZE("exists", "path", 0, 1); - int result; - BOOL slow_path = TRUE; - FILE_STAT_BASIC_INFORMATION statInfo; + HANDLE hfile; + int result = 0; if (!path_converter(path, &_path)) { path_cleanup(&_path); @@ -5310,49 +5297,56 @@ os__path_exists_impl(PyObject *module, PyObject *path) } Py_BEGIN_ALLOW_THREADS - if (_path.wide) { + if (_path.fd != -1) { + hfile = _Py_get_osfhandle_noraise(_path.fd); + if (hfile != INVALID_HANDLE_VALUE) { + result = 1; + } + } + else if (_path.wide) { + BOOL slow_path = TRUE; + FILE_STAT_BASIC_INFORMATION statInfo; if (_Py_GetFileInformationByName(_path.wide, FileStatBasicByNameInfo, - &statInfo, sizeof(statInfo))) { - if (!(statInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) { + &statInfo, sizeof(statInfo))) + { + if (!(statInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) || + !follow_symlinks && + IsReparseTagNameSurrogate(statInfo.ReparseTag)) + { slow_path = FALSE; result = 1; } - } else if (_Py_GetFileInformationByName_ErrorIsTrustworthy(GetLastError())) { - slow_path = FALSE; - result = 0; - } - } - if (slow_path) { - if (_path.fd != -1) { - hfile = _Py_get_osfhandle_noraise(_path.fd); - close_file = FALSE; - } - else { - hfile = CreateFileW(_path.wide, FILE_READ_ATTRIBUTES, 0, NULL, - OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); - } - if (hfile != INVALID_HANDLE_VALUE) { - result = 1; - if (close_file) { - CloseHandle(hfile); - } + } else if (_Py_GetFileInformationByName_ErrorIsTrustworthy( + GetLastError())) + { + slow_path = FALSE; } - else { + if (slow_path) { STRUCT_STAT st; - switch (GetLastError()) { - case ERROR_ACCESS_DENIED: - case ERROR_SHARING_VIOLATION: - case ERROR_CANT_ACCESS_FILE: - case ERROR_INVALID_PARAMETER: - if (STAT(_path.wide, &st)) { - result = 0; + if (!follow_symlinks) { + if (!LSTAT(_path.wide, &st)) { + result = 1; } - else { + } + else { + hfile = CreateFileW(_path.wide, FILE_READ_ATTRIBUTES, 0, NULL, + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, + NULL); + if (hfile != INVALID_HANDLE_VALUE) { + CloseHandle(hfile); result = 1; } - break; - default: - result = 0; + else { + switch (GetLastError()) { + case ERROR_ACCESS_DENIED: + case ERROR_SHARING_VIOLATION: + case ERROR_CANT_ACCESS_FILE: + case ERROR_INVALID_PARAMETER: + if (!STAT(_path.wide, &st)) { + result = 1; + } + } + } } } } @@ -5366,6 +5360,40 @@ os__path_exists_impl(PyObject *module, PyObject *path) } +/*[clinic input] +os._path_exists + + path: 'O' + +Test whether a path exists. Returns False for broken symbolic links + +[clinic start generated code]*/ + +static PyObject * +os__path_exists_impl(PyObject *module, PyObject *path) +/*[clinic end generated code: output=f508c3b35e13a249 input=380f77cdfa0f7ae8]*/ +{ + return nt_exists(path, 1); +} + + +/*[clinic input] +os._path_lexists + + path: 'O' + +Test whether a path exists. Returns True for broken symbolic links + +[clinic start generated code]*/ + +static PyObject * +os__path_lexists_impl(PyObject *module, PyObject *path) +/*[clinic end generated code: output=b9a42a50b1df6651 input=5f14942c64196ba2]*/ +{ + return nt_exists(path, 0); +} + + /*[clinic input] os._path_islink @@ -16843,6 +16871,7 @@ static PyMethodDef posix_methods[] = { OS__PATH_ISFILE_METHODDEF OS__PATH_ISLINK_METHODDEF OS__PATH_EXISTS_METHODDEF + OS__PATH_LEXISTS_METHODDEF OS__SUPPORTS_VIRTUAL_TERMINAL_METHODDEF {NULL, NULL} /* Sentinel */ From 1c5350d251b56a325dba753184f79bfb808e63b8 Mon Sep 17 00:00:00 2001 From: nineteendo Date: Sat, 13 Apr 2024 12:13:29 +0200 Subject: [PATCH 2/8] Update comment --- Lib/ntpath.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/ntpath.py b/Lib/ntpath.py index d8da88993e9a38..06466bb9cb9017 100644 --- a/Lib/ntpath.py +++ b/Lib/ntpath.py @@ -892,8 +892,8 @@ def commonpath(paths): try: - # The isdir(), isfile(), islink() and exists() implementations in - # genericpath use os.stat(). This is overkill on Windows. Use simpler + # The isdir(), isfile(), islink(), exists() and lexists() implementations + # in genericpath use os.stat(). This is overkill on Windows. Use simpler # builtin functions if they are available. from nt import _path_isdir as isdir from nt import _path_isfile as isfile From d7017ac6063c483d6a21dacf3544b3cb844bb669 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Sat, 13 Apr 2024 11:30:10 +0000 Subject: [PATCH 3/8] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2024-04-13-11-30-09.gh-issue-117841.eW4w_y.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-04-13-11-30-09.gh-issue-117841.eW4w_y.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-04-13-11-30-09.gh-issue-117841.eW4w_y.rst b/Misc/NEWS.d/next/Core and Builtins/2024-04-13-11-30-09.gh-issue-117841.eW4w_y.rst new file mode 100644 index 00000000000000..cd73fc06b90b77 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2024-04-13-11-30-09.gh-issue-117841.eW4w_y.rst @@ -0,0 +1 @@ +Speedup :func:`os.path.lexists` on Windows. From 29633380cb0d8f845c694867967a38e7f90feb46 Mon Sep 17 00:00:00 2001 From: nineteendo Date: Mon, 15 Apr 2024 07:59:24 +0200 Subject: [PATCH 4/8] Improve `nt_exists()` Co-authored-by: Eryk Sun --- Modules/posixmodule.c | 58 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 9 deletions(-) diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 991be86f4e62ed..bf8af2b8576f8b 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -5285,6 +5285,7 @@ nt_exists(PyObject *path, int follow_symlinks) { path_t _path = PATH_T_INITIALIZE("exists", "path", 0, 1); HANDLE hfile; + BOOL traverse = follow_symlinks; int result = 0; if (!path_converter(path, &_path)) { @@ -5307,7 +5308,7 @@ nt_exists(PyObject *path, int follow_symlinks) BOOL slow_path = TRUE; FILE_STAT_BASIC_INFORMATION statInfo; if (_Py_GetFileInformationByName(_path.wide, FileStatBasicByNameInfo, - &statInfo, sizeof(statInfo))) + &statInfo, sizeof(statInfo))) { if (!(statInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) || !follow_symlinks && @@ -5316,27 +5317,66 @@ nt_exists(PyObject *path, int follow_symlinks) slow_path = FALSE; result = 1; } - } else if (_Py_GetFileInformationByName_ErrorIsTrustworthy( + else { + // reparse point but not name-surrogate + traverse = TRUE; + } + } + else if (_Py_GetFileInformationByName_ErrorIsTrustworthy( GetLastError())) { slow_path = FALSE; } if (slow_path) { - STRUCT_STAT st; - if (!follow_symlinks) { - if (!LSTAT(_path.wide, &st)) { - result = 1; + BOOL traverse = follow_symlinks; + if (!traverse) { + hfile = CreateFileW(_path.wide, FILE_READ_ATTRIBUTES, 0, NULL, + OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | + FILE_FLAG_BACKUP_SEMANTICS, NULL); + if (hfile != INVALID_HANDLE_VALUE) { + FILE_ATTRIBUTE_TAG_INFO info; + if (GetFileInformationByHandleEx(hfile, + FileAttributeTagInfo, &info, sizeof(info))) + { + if (!(info.FileAttributes & + FILE_ATTRIBUTE_REPARSE_POINT) || + IsReparseTagNameSurrogate(info.ReparseTag)) + { + result = 1; + } + else { + // reparse point but not name-surrogate + traverse = TRUE; + } + } + else { + // device or legacy filesystem + result = 1; + } + CloseHandle(hfile); + } + else { + STRUCT_STAT st; + switch (GetLastError()) { + case ERROR_ACCESS_DENIED: + case ERROR_SHARING_VIOLATION: + case ERROR_CANT_ACCESS_FILE: + case ERROR_INVALID_PARAMETER: + if (!LSTAT(_path.wide, &st)) { + result = 1; + } + } } } - else { + if (traverse) { hfile = CreateFileW(_path.wide, FILE_READ_ATTRIBUTES, 0, NULL, - OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, - NULL); + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); if (hfile != INVALID_HANDLE_VALUE) { CloseHandle(hfile); result = 1; } else { + STRUCT_STAT st; switch (GetLastError()) { case ERROR_ACCESS_DENIED: case ERROR_SHARING_VIOLATION: From e833f0468cdf2fb6c453e75d995af6e91900d980 Mon Sep 17 00:00:00 2001 From: Nice Zombies Date: Mon, 15 Apr 2024 22:35:43 +0200 Subject: [PATCH 5/8] Apply suggestions from code review Co-authored-by: Serhiy Storchaka --- Modules/posixmodule.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index bf8af2b8576f8b..ec401ab0873521 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -5403,9 +5403,10 @@ nt_exists(PyObject *path, int follow_symlinks) /*[clinic input] os._path_exists - path: 'O' + path: object + / -Test whether a path exists. Returns False for broken symbolic links +Test whether a path exists. Returns False for broken symbolic links. [clinic start generated code]*/ @@ -5420,9 +5421,10 @@ os__path_exists_impl(PyObject *module, PyObject *path) /*[clinic input] os._path_lexists - path: 'O' + path: object + / -Test whether a path exists. Returns True for broken symbolic links +Test whether a path exists. Returns True for broken symbolic links. [clinic start generated code]*/ From d0493c2ebe196f502e9629a5162e005f525b6dd6 Mon Sep 17 00:00:00 2001 From: nineteendo Date: Mon, 15 Apr 2024 22:48:10 +0200 Subject: [PATCH 6/8] Revert helper functions --- Lib/test/test_genericpath.py | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/Lib/test/test_genericpath.py b/Lib/test/test_genericpath.py index 58ad4aba0c9db4..bf04b3fecf7057 100644 --- a/Lib/test/test_genericpath.py +++ b/Lib/test/test_genericpath.py @@ -128,34 +128,33 @@ def test_filetime(self): ) def test_exists(self): - def check_exists(filename, expected): - bfilename = os.fsencode(filename) - self.assertIs(self.pathmodule.exists(filename), expected) - self.assertIs(self.pathmodule.exists(bfilename), expected) - - def check_lexists(filename, expected): - bfilename = os.fsencode(filename) - self.assertIs(self.pathmodule.lexists(filename), expected) - self.assertIs(self.pathmodule.lexists(bfilename), expected) - filename = os_helper.TESTFN bfilename = os.fsencode(filename) self.addCleanup(os_helper.unlink, filename) - check_exists(filename, False) - check_lexists(filename, False) + self.assertIs(self.pathmodule.exists(filename), False) + self.assertIs(self.pathmodule.exists(bfilename), False) + + self.assertIs(self.pathmodule.lexists(filename), False) + self.assertIs(self.pathmodule.lexists(bfilename), False) create_file(filename) - check_exists(filename, True) + self.assertIs(self.pathmodule.exists(filename), True) + self.assertIs(self.pathmodule.exists(bfilename), True) + self.assertIs(self.pathmodule.exists(filename + '\udfff'), False) self.assertIs(self.pathmodule.exists(bfilename + b'\xff'), False) - check_exists(filename + '\x00', False) + self.assertIs(self.pathmodule.exists(filename + '\x00'), False) + self.assertIs(self.pathmodule.exists(bfilename + b'\x00'), False) + + self.assertIs(self.pathmodule.lexists(filename), True) + self.assertIs(self.pathmodule.lexists(bfilename), True) - check_lexists(filename, True) self.assertIs(self.pathmodule.lexists(filename + '\udfff'), False) self.assertIs(self.pathmodule.lexists(bfilename + b'\xff'), False) - check_lexists(filename + '\x00', False) + self.assertIs(self.pathmodule.lexists(filename + '\x00'), False) + self.assertIs(self.pathmodule.lexists(bfilename + b'\x00'), False) @unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()") @unittest.skipIf(is_emscripten, "Emscripten pipe fds have no stat") From 4403f4a635b359981e13b330d941baf2963a0027 Mon Sep 17 00:00:00 2001 From: nineteendo Date: Mon, 15 Apr 2024 22:53:48 +0200 Subject: [PATCH 7/8] Update argument clinic --- Modules/clinic/posixmodule.c.h | 106 +++------------------------------ Modules/posixmodule.c | 8 +-- 2 files changed, 11 insertions(+), 103 deletions(-) diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h index c2c85fb9fbeb36..cd7d8d8ff170f4 100644 --- a/Modules/clinic/posixmodule.c.h +++ b/Modules/clinic/posixmodule.c.h @@ -2133,118 +2133,26 @@ os__path_isfile(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObj #if defined(MS_WINDOWS) PyDoc_STRVAR(os__path_exists__doc__, -"_path_exists($module, /, path)\n" +"_path_exists($module, path, /)\n" "--\n" "\n" -"Test whether a path exists. Returns False for broken symbolic links"); +"Test whether a path exists. Returns False for broken symbolic links."); #define OS__PATH_EXISTS_METHODDEF \ - {"_path_exists", _PyCFunction_CAST(os__path_exists), METH_FASTCALL|METH_KEYWORDS, os__path_exists__doc__}, - -static PyObject * -os__path_exists_impl(PyObject *module, PyObject *path); - -static PyObject * -os__path_exists(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -{ - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - - #define NUM_KEYWORDS 1 - static struct { - PyGC_Head _this_is_not_used; - PyObject_VAR_HEAD - PyObject *ob_item[NUM_KEYWORDS]; - } _kwtuple = { - .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(path), }, - }; - #undef NUM_KEYWORDS - #define KWTUPLE (&_kwtuple.ob_base.ob_base) - - #else // !Py_BUILD_CORE - # define KWTUPLE NULL - #endif // !Py_BUILD_CORE - - static const char * const _keywords[] = {"path", NULL}; - static _PyArg_Parser _parser = { - .keywords = _keywords, - .fname = "_path_exists", - .kwtuple = KWTUPLE, - }; - #undef KWTUPLE - PyObject *argsbuf[1]; - PyObject *path; - - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); - if (!args) { - goto exit; - } - path = args[0]; - return_value = os__path_exists_impl(module, path); - -exit: - return return_value; -} + {"_path_exists", (PyCFunction)os__path_exists, METH_O, os__path_exists__doc__}, #endif /* defined(MS_WINDOWS) */ #if defined(MS_WINDOWS) PyDoc_STRVAR(os__path_lexists__doc__, -"_path_lexists($module, /, path)\n" +"_path_lexists($module, path, /)\n" "--\n" "\n" -"Test whether a path exists. Returns True for broken symbolic links"); +"Test whether a path exists. Returns True for broken symbolic links."); #define OS__PATH_LEXISTS_METHODDEF \ - {"_path_lexists", _PyCFunction_CAST(os__path_lexists), METH_FASTCALL|METH_KEYWORDS, os__path_lexists__doc__}, - -static PyObject * -os__path_lexists_impl(PyObject *module, PyObject *path); - -static PyObject * -os__path_lexists(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -{ - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - - #define NUM_KEYWORDS 1 - static struct { - PyGC_Head _this_is_not_used; - PyObject_VAR_HEAD - PyObject *ob_item[NUM_KEYWORDS]; - } _kwtuple = { - .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(path), }, - }; - #undef NUM_KEYWORDS - #define KWTUPLE (&_kwtuple.ob_base.ob_base) - - #else // !Py_BUILD_CORE - # define KWTUPLE NULL - #endif // !Py_BUILD_CORE - - static const char * const _keywords[] = {"path", NULL}; - static _PyArg_Parser _parser = { - .keywords = _keywords, - .fname = "_path_lexists", - .kwtuple = KWTUPLE, - }; - #undef KWTUPLE - PyObject *argsbuf[1]; - PyObject *path; - - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); - if (!args) { - goto exit; - } - path = args[0]; - return_value = os__path_lexists_impl(module, path); - -exit: - return return_value; -} + {"_path_lexists", (PyCFunction)os__path_lexists, METH_O, os__path_lexists__doc__}, #endif /* defined(MS_WINDOWS) */ @@ -12665,4 +12573,4 @@ os__supports_virtual_terminal(PyObject *module, PyObject *Py_UNUSED(ignored)) #ifndef OS__SUPPORTS_VIRTUAL_TERMINAL_METHODDEF #define OS__SUPPORTS_VIRTUAL_TERMINAL_METHODDEF #endif /* !defined(OS__SUPPORTS_VIRTUAL_TERMINAL_METHODDEF) */ -/*[clinic end generated code: output=a2b2651b67aa67fa input=a9049054013a1b77]*/ +/*[clinic end generated code: output=66245167be59b12f input=a9049054013a1b77]*/ diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index ec401ab0873521..4bce924f388d97 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -5411,8 +5411,8 @@ Test whether a path exists. Returns False for broken symbolic links. [clinic start generated code]*/ static PyObject * -os__path_exists_impl(PyObject *module, PyObject *path) -/*[clinic end generated code: output=f508c3b35e13a249 input=380f77cdfa0f7ae8]*/ +os__path_exists(PyObject *module, PyObject *path) +/*[clinic end generated code: output=617b7575ba0644bc input=242708cabb67c407]*/ { return nt_exists(path, 1); } @@ -5429,8 +5429,8 @@ Test whether a path exists. Returns True for broken symbolic links. [clinic start generated code]*/ static PyObject * -os__path_lexists_impl(PyObject *module, PyObject *path) -/*[clinic end generated code: output=b9a42a50b1df6651 input=5f14942c64196ba2]*/ +os__path_lexists(PyObject *module, PyObject *path) +/*[clinic end generated code: output=c7c89aa6d6e341df input=536ed4b0a7d4f723]*/ { return nt_exists(path, 0); } From 7a9038f03255455381e3016a1bcc3bfded8e69c0 Mon Sep 17 00:00:00 2001 From: Nice Zombies Date: Mon, 22 Apr 2024 20:58:23 +0200 Subject: [PATCH 8/8] Update 2024-04-13-11-30-09.gh-issue-117841.eW4w_y.rst --- .../2024-04-13-11-30-09.gh-issue-117841.eW4w_y.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-04-13-11-30-09.gh-issue-117841.eW4w_y.rst b/Misc/NEWS.d/next/Core and Builtins/2024-04-13-11-30-09.gh-issue-117841.eW4w_y.rst index cd73fc06b90b77..3a562884283b1c 100644 --- a/Misc/NEWS.d/next/Core and Builtins/2024-04-13-11-30-09.gh-issue-117841.eW4w_y.rst +++ b/Misc/NEWS.d/next/Core and Builtins/2024-04-13-11-30-09.gh-issue-117841.eW4w_y.rst @@ -1 +1 @@ -Speedup :func:`os.path.lexists` on Windows. +Speedup :func:`os.path.lexists` on Windows with a native implementation.