From 76f4a76dfd78732291fed96071a2c580c2fc85a8 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Fri, 11 Oct 2024 12:41:59 -0700 Subject: [PATCH] [3.13] gh-124917: Allow keyword args to os.path.exists/lexists on Windows (GH-124918) (cherry picked from commit cc2938a18967c9d462ebb18bc09f73e4364aa7d2) Co-authored-by: Jelle Zijlstra --- Lib/test/test_genericpath.py | 4 + ...-10-02-21-11-18.gh-issue-124917.Lnwh5b.rst | 2 + Modules/clinic/posixmodule.c.h | 78 ++++++++++++++++--- Modules/posixmodule.c | 6 +- 4 files changed, 77 insertions(+), 13 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-02-21-11-18.gh-issue-124917.Lnwh5b.rst diff --git a/Lib/test/test_genericpath.py b/Lib/test/test_genericpath.py index bf04b3fecf7057..6d2593cb4cf228 100644 --- a/Lib/test/test_genericpath.py +++ b/Lib/test/test_genericpath.py @@ -156,6 +156,10 @@ def test_exists(self): self.assertIs(self.pathmodule.lexists(filename + '\x00'), False) self.assertIs(self.pathmodule.lexists(bfilename + b'\x00'), False) + # Keyword arguments are accepted + self.assertIs(self.pathmodule.exists(path=filename), True) + self.assertIs(self.pathmodule.lexists(path=filename), True) + @unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()") @unittest.skipIf(is_emscripten, "Emscripten pipe fds have no stat") def test_exists_fd(self): diff --git a/Misc/NEWS.d/next/Library/2024-10-02-21-11-18.gh-issue-124917.Lnwh5b.rst b/Misc/NEWS.d/next/Library/2024-10-02-21-11-18.gh-issue-124917.Lnwh5b.rst new file mode 100644 index 00000000000000..f208793859bbf8 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-02-21-11-18.gh-issue-124917.Lnwh5b.rst @@ -0,0 +1,2 @@ +Allow calling :func:`os.path.exists` and :func:`os.path.lexists` with +keyword arguments on Windows. Fixes a regression in 3.13.0. diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h index d7af87dc946aeb..6a3aacf13e74ad 100644 --- a/Modules/clinic/posixmodule.c.h +++ b/Modules/clinic/posixmodule.c.h @@ -2015,25 +2015,55 @@ os__path_splitroot(PyObject *module, PyObject *const *args, Py_ssize_t nargs, Py #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."); #define OS__PATH_EXISTS_METHODDEF \ - {"_path_exists", (PyCFunction)os__path_exists, METH_O, os__path_exists__doc__}, + {"_path_exists", _PyCFunction_CAST(os__path_exists), METH_FASTCALL|METH_KEYWORDS, os__path_exists__doc__}, static int os__path_exists_impl(PyObject *module, path_t *path); static PyObject * -os__path_exists(PyObject *module, PyObject *arg) +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]; path_t path = PATH_T_INITIALIZE_P("_path_exists", "path", 0, 0, 1, 1); int _return_value; - if (!path_converter(arg, &path)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + if (!path_converter(args[0], &path)) { goto exit; } _return_value = os__path_exists_impl(module, &path); @@ -2054,25 +2084,55 @@ os__path_exists(PyObject *module, PyObject *arg) #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."); #define OS__PATH_LEXISTS_METHODDEF \ - {"_path_lexists", (PyCFunction)os__path_lexists, METH_O, os__path_lexists__doc__}, + {"_path_lexists", _PyCFunction_CAST(os__path_lexists), METH_FASTCALL|METH_KEYWORDS, os__path_lexists__doc__}, static int os__path_lexists_impl(PyObject *module, path_t *path); static PyObject * -os__path_lexists(PyObject *module, PyObject *arg) +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]; path_t path = PATH_T_INITIALIZE_P("_path_lexists", "path", 0, 0, 1, 1); int _return_value; - if (!path_converter(arg, &path)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + if (!path_converter(args[0], &path)) { goto exit; } _return_value = os__path_lexists_impl(module, &path); @@ -12819,4 +12879,4 @@ os__is_inputhook_installed(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=ee0e3772de1bf216 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=a4410a686958d8e6 input=a9049054013a1b77]*/ diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 1b5dc278e9d41b..bb01957d5cc0af 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -5391,7 +5391,6 @@ _testFileType(path_t *path, int testedType) os._path_exists -> bool path: path_t(allow_fd=True, suppress_value_error=True) - / Test whether a path exists. Returns False for broken symbolic links. @@ -5399,7 +5398,7 @@ Test whether a path exists. Returns False for broken symbolic links. static int os__path_exists_impl(PyObject *module, path_t *path) -/*[clinic end generated code: output=8da13acf666e16ba input=29198507a6082a57]*/ +/*[clinic end generated code: output=8da13acf666e16ba input=142beabfc66783eb]*/ { return _testFileExists(path, TRUE); } @@ -5409,7 +5408,6 @@ os__path_exists_impl(PyObject *module, path_t *path) os._path_lexists -> bool path: path_t(allow_fd=True, suppress_value_error=True) - / Test whether a path exists. Returns True for broken symbolic links. @@ -5417,7 +5415,7 @@ Test whether a path exists. Returns True for broken symbolic links. static int os__path_lexists_impl(PyObject *module, path_t *path) -/*[clinic end generated code: output=e7240ed5fc45bff3 input=03d9fed8bc6ce96f]*/ +/*[clinic end generated code: output=e7240ed5fc45bff3 input=208205112a3cc1ed]*/ { return _testFileExists(path, FALSE); } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy