diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index d07447d66571e5..76df4f23a49a68 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -3569,6 +3569,7 @@ def test_cli_converters(self): "DWORD", "fildes", "float", + "gid_t", "HANDLE", "int", "long", @@ -3587,6 +3588,7 @@ def test_cli_converters(self): "size_t", "slice_index", "str", + "uid_t", "uint16", "uint32", "uint64", diff --git a/Lib/test/test_pwd.py b/Lib/test/test_pwd.py index 82acce85f1db57..2ad89444348376 100644 --- a/Lib/test/test_pwd.py +++ b/Lib/test/test_pwd.py @@ -61,8 +61,8 @@ def test_errors(self): self.assertRaises(TypeError, pwd.getpwuid, 0.0) self.assertRaises(TypeError, pwd.getpwuid, 0, 0) # should be out of uid_t range - self.assertRaises(KeyError, pwd.getpwuid, 2**128) - self.assertRaises(KeyError, pwd.getpwuid, -2**128) + self.assertRaises(OverflowError, pwd.getpwuid, 2**128) + self.assertRaises(OverflowError, pwd.getpwuid, -2**128) self.assertRaises(TypeError, pwd.getpwnam) self.assertRaises(TypeError, pwd.getpwnam, 42) self.assertRaises(TypeError, pwd.getpwnam, b'root') diff --git a/Misc/NEWS.d/next/Library/2026-08-22-19-00-00.gh-issue-156261.Nq4tWv.rst b/Misc/NEWS.d/next/Library/2026-08-22-19-00-00.gh-issue-156261.Nq4tWv.rst new file mode 100644 index 00000000000000..a641f8371b368f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-08-22-19-00-00.gh-issue-156261.Nq4tWv.rst @@ -0,0 +1,3 @@ +:func:`pwd.getpwuid` now raises :exc:`OverflowError` instead of +:exc:`KeyError` if the user id is out of the range of the C ``uid_t`` type, +as :func:`grp.getgrgid` does for the group id. diff --git a/Misc/NEWS.d/next/Tools-Demos/2026-08-23-18-10-00.gh-issue-156261.Rw8pKd.rst b/Misc/NEWS.d/next/Tools-Demos/2026-08-23-18-10-00.gh-issue-156261.Rw8pKd.rst index da5e42dfa74429..d2f55f626f6d32 100644 --- a/Misc/NEWS.d/next/Tools-Demos/2026-08-23-18-10-00.gh-issue-156261.Rw8pKd.rst +++ b/Misc/NEWS.d/next/Tools-Demos/2026-08-23-18-10-00.gh-issue-156261.Rw8pKd.rst @@ -1,3 +1,3 @@ -Argument Clinic: the ``pid_t``, ``Py_off_t``, ``HANDLE``, ``DWORD`` and -``BOOL`` converters, previously defined in 9 different files, are now -provided by Argument Clinic itself. +Argument Clinic: the ``pid_t``, ``uid_t``, ``gid_t``, ``Py_off_t``, +``HANDLE``, ``DWORD`` and ``BOOL`` converters, previously defined in +individual files, are now provided by Argument Clinic itself. diff --git a/Modules/clinic/grpmodule.c.h b/Modules/clinic/grpmodule.c.h index 665c2f2dfdac14..9f1ea181d9bc4c 100644 --- a/Modules/clinic/grpmodule.c.h +++ b/Modules/clinic/grpmodule.c.h @@ -20,7 +20,7 @@ PyDoc_STRVAR(grp_getgrgid__doc__, {"getgrgid", _PyCFunction_CAST(grp_getgrgid), METH_FASTCALL|METH_KEYWORDS, grp_getgrgid__doc__}, static PyObject * -grp_getgrgid_impl(PyObject *module, PyObject *id); +grp_getgrgid_impl(PyObject *module, gid_t gid); static PyObject * grp_getgrgid(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) @@ -54,15 +54,17 @@ grp_getgrgid(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject }; #undef KWTUPLE PyObject *argsbuf[1]; - PyObject *id; + gid_t gid; args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); if (!args) { goto exit; } - id = args[0]; - return_value = grp_getgrgid_impl(module, id); + if (!_Py_Gid_Converter(args[0], &gid)) { + goto exit; + } + return_value = grp_getgrgid_impl(module, gid); exit: return return_value; @@ -152,4 +154,4 @@ grp_getgrall(PyObject *module, PyObject *Py_UNUSED(ignored)) { return grp_getgrall_impl(module); } -/*[clinic end generated code: output=35aa81c00dbd3229 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=9052db62d986262c input=a9049054013a1b77]*/ diff --git a/Modules/clinic/pwdmodule.c.h b/Modules/clinic/pwdmodule.c.h index 43d4825031c7e6..64127ff8e494db 100644 --- a/Modules/clinic/pwdmodule.c.h +++ b/Modules/clinic/pwdmodule.c.h @@ -15,6 +15,24 @@ PyDoc_STRVAR(pwd_getpwuid__doc__, #define PWD_GETPWUID_METHODDEF \ {"getpwuid", (PyCFunction)pwd_getpwuid, METH_O, pwd_getpwuid__doc__}, +static PyObject * +pwd_getpwuid_impl(PyObject *module, uid_t uid); + +static PyObject * +pwd_getpwuid(PyObject *module, PyObject *arg) +{ + PyObject *return_value = NULL; + uid_t uid; + + if (!_Py_Uid_Converter(arg, &uid)) { + goto exit; + } + return_value = pwd_getpwuid_impl(module, uid); + +exit: + return return_value; +} + PyDoc_STRVAR(pwd_getpwnam__doc__, "getpwnam($module, name, /)\n" "--\n" @@ -73,4 +91,4 @@ pwd_getpwall(PyObject *module, PyObject *Py_UNUSED(ignored)) #ifndef PWD_GETPWALL_METHODDEF #define PWD_GETPWALL_METHODDEF #endif /* !defined(PWD_GETPWALL_METHODDEF) */ -/*[clinic end generated code: output=5a8fb12939ff4ea3 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=5bca0b2c2f4c5e89 input=a9049054013a1b77]*/ diff --git a/Modules/grpmodule.c b/Modules/grpmodule.c index 32ead259803614..fe1d16d8322005 100644 --- a/Modules/grpmodule.c +++ b/Modules/grpmodule.c @@ -117,7 +117,7 @@ mkgrent(PyObject *module, struct group *p) /*[clinic input] grp.getgrgid - id: object + id as gid: gid_t Return the group database entry for the given numeric group ID. @@ -125,18 +125,14 @@ If id is not valid, raise KeyError. [clinic start generated code]*/ static PyObject * -grp_getgrgid_impl(PyObject *module, PyObject *id) -/*[clinic end generated code: output=30797c289504a1ba input=15fa0e2ccf5cda25]*/ +grp_getgrgid_impl(PyObject *module, gid_t gid) +/*[clinic end generated code: output=a9e7385cd6df08da input=fca15128dd772588]*/ { PyObject *retval = NULL; int nomem = 0; char *buf = NULL, *buf2 = NULL; - gid_t gid; struct group *p; - if (!_Py_Gid_Converter(id, &gid)) { - return NULL; - } #ifdef HAVE_GETGRGID_R int status; Py_ssize_t bufsize; diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index a9375e48a11d89..9724187dda4bb6 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -3185,14 +3185,6 @@ class dir_fd_converter(CConverter): def c_default_init(self): self.c_default = 'DEFAULT_DIR_FD' -class uid_t_converter(CConverter): - type = "uid_t" - converter = '_Py_Uid_Converter' - -class gid_t_converter(CConverter): - type = "gid_t" - converter = '_Py_Gid_Converter' - class dev_t_converter(CConverter): type = 'dev_t' converter = '_Py_Dev_Converter' @@ -3249,7 +3241,7 @@ class confname_converter(CConverter): """, argname=argname, converter=self.converter, table=self.table) [python start generated code]*/ -/*[python end generated code: output=da39a3ee5e6b4b0d input=e459765bdf453ebf]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=7ceccf55bb600f61]*/ /*[clinic input] diff --git a/Modules/pwdmodule.c b/Modules/pwdmodule.c index 4a2b33f8700d10..be5e0d4d0c29ae 100644 --- a/Modules/pwdmodule.c +++ b/Modules/pwdmodule.c @@ -121,7 +121,7 @@ mkpwent(PyObject *module, struct passwd *p) /*[clinic input] pwd.getpwuid - uidobj: object + uidobj as uid: uid_t / Return the password database entry for the given numeric user ID. @@ -130,21 +130,14 @@ See `help(pwd)` for more on password database entries. [clinic start generated code]*/ static PyObject * -pwd_getpwuid(PyObject *module, PyObject *uidobj) -/*[clinic end generated code: output=c4ee1d4d429b86c4 input=ae64d507a1c6d3e8]*/ +pwd_getpwuid_impl(PyObject *module, uid_t uid) +/*[clinic end generated code: output=631bad376fa670c3 input=506d3a592ef19799]*/ { PyObject *retval = NULL; - uid_t uid; int nomem = 0; struct passwd *p; char *buf = NULL, *buf2 = NULL; - if (!_Py_Uid_Converter(uidobj, &uid)) { - if (PyErr_ExceptionMatches(PyExc_OverflowError)) - PyErr_Format(PyExc_KeyError, - "getpwuid(): uid not found"); - return NULL; - } #ifdef HAVE_GETPWUID_R int status; Py_ssize_t bufsize; diff --git a/Tools/clinic/libclinic/converters.py b/Tools/clinic/libclinic/converters.py index c2ac6fd22d5bdc..5f663a50ab8ce8 100644 --- a/Tools/clinic/libclinic/converters.py +++ b/Tools/clinic/libclinic/converters.py @@ -601,6 +601,16 @@ def parse_arg(self, argname: str, displayname: str, *, limited_capi: bool) -> st argname=argname) +class gid_t_converter(CConverter): + type = 'gid_t' + converter = '_Py_Gid_Converter' + + +class uid_t_converter(CConverter): + type = 'uid_t' + converter = '_Py_Uid_Converter' + + class pid_t_converter(CConverter): type = 'pid_t' format_unit = '" _Py_PARSE_PID "'