https://github.com/python/cpython/commit/db3ffd065ca31e3c0c7c3a4f313102b3e3564fb9
commit: db3ffd065ca31e3c0c7c3a4f313102b3e3564fb9
branch: main
author: Serhiy Storchaka <[email protected]>
committer: serhiy-storchaka <[email protected]>
date: 2026-09-27T19:08:10+03:00
summary:

gh-156261: Use the uid_t and gid_t converters in the pwd and grp modules 
(GH-156294)

They are moved to Argument Clinic, so that pwd.getpwuid() and
grp.getgrgid() can declare the type of their parameter instead of
converting it in the "impl" function.

pwd.getpwuid() now raises OverflowError instead of KeyError for a user id
out of the range of uid_t, as grp.getgrgid() already did.

files:
A Misc/NEWS.d/next/Library/2026-08-22-19-00-00.gh-issue-156261.Nq4tWv.rst
M Lib/test/test_clinic.py
M Lib/test/test_pwd.py
M Misc/NEWS.d/next/Tools-Demos/2026-08-23-18-10-00.gh-issue-156261.Rw8pKd.rst
M Modules/clinic/grpmodule.c.h
M Modules/clinic/pwdmodule.c.h
M Modules/grpmodule.c
M Modules/posixmodule.c
M Modules/pwdmodule.c
M Tools/clinic/libclinic/converters.py

diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py
index f5334f70768dc45..2243c43bdcbf808 100644
--- a/Lib/test/test_clinic.py
+++ b/Lib/test/test_clinic.py
@@ -4014,6 +4014,7 @@ def test_cli_converters(self):
             "DWORD",
             "fildes",
             "float",
+            "gid_t",
             "HANDLE",
             "int",
             "long",
@@ -4032,6 +4033,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 82acce85f1db572..2ad89444348376d 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 000000000000000..a641f8371b368fd
--- /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 da5e42dfa744297..d2f55f626f6d329 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 665c2f2dfdac148..9f1ea181d9bc4ca 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 43d4825031c7e61..64127ff8e494db8 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 32ead2598036146..fe1d16d8322005c 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 12ad333c5e5f27b..0a451b8a833e67e 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -3204,14 +3204,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'
@@ -3268,7 +3260,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 4a2b33f8700d101..be5e0d4d0c29ae3 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 c2ac6fd22d5bdc9..5f663a50ab8ce8a 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 "'

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to