]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-148829: Add PySentinel_CheckExact() (#149725)
authorscoder <stefan_ml@behnel.de>
Wed, 13 May 2026 10:10:37 +0000 (12:10 +0200)
committerGitHub <noreply@github.com>
Wed, 13 May 2026 10:10:37 +0000 (10:10 +0000)
Doc/c-api/sentinel.rst
Include/cpython/sentinelobject.h
Lib/test/test_capi/test_object.py
Misc/NEWS.d/next/C_API/2026-05-12-16-47-21.gh-issue-149725.HZLBTZ.rst [new file with mode: 0644]
Modules/_testcapi/object.c

index 89e0a28bf3b835bc4ff8cd7b358bc3039afbaa9b..937cae18e86f5071acc19363e824d440f4347589 100644 (file)
@@ -14,8 +14,20 @@ Sentinel objects
 
 .. c:function:: int PySentinel_Check(PyObject *o)
 
-   Return true if *o* is a :class:`sentinel` object.  The :class:`sentinel` type
-   does not allow subclasses, so this check is exact.
+   Return true if *o* is a :class:`sentinel` object or a subtype.
+   The :class:`sentinel` type does not currently allow subclasses,
+   so this check is exact.
+   Future Python versions may choose to allow subtyping.
+   This function always succeeds.
+
+   .. versionadded:: 3.15
+
+.. c:function:: int PySentinel_CheckExact(PyObject *o)
+
+   Return true if *o* is a :class:`sentinel` object, but not a subtype.
+   The :class:`sentinel` type does not currently allow subclasses.
+   Future Python versions may choose to allow subtyping.
+   This function always succeeds.
 
    .. versionadded:: 3.15
 
index 0b6ff0f17e6f8c146bb27a1db22b3af3ed2228f5..8d5b1886ce543686e986c9d011cf0ead6953e068 100644 (file)
@@ -9,7 +9,10 @@ extern "C" {
 
 PyAPI_DATA(PyTypeObject) PySentinel_Type;
 
-#define PySentinel_Check(op) Py_IS_TYPE((op), &PySentinel_Type)
+#define PySentinel_CheckExact(op) Py_IS_TYPE((op), &PySentinel_Type)
+
+/* Alias as long as subclasses are not allowed. */
+#define PySentinel_Check(op) PySentinel_CheckExact(op)
 
 PyAPI_FUNC(PyObject *) PySentinel_New(
     const char *name,
index 635deaa73f7efab2ab8ba69b4b5abe1726f13eb3..e6fd068dc20d8d4c5250311192083381d58c5d85 100644 (file)
@@ -71,6 +71,8 @@ class SentinelTest(unittest.TestCase):
         self.assertIs(type(marker), sentinel)
         self.assertTrue(_testcapi.pysentinel_check(marker))
         self.assertFalse(_testcapi.pysentinel_check(object()))
+        self.assertTrue(_testcapi.pysentinel_checkexact(marker))
+        self.assertFalse(_testcapi.pysentinel_checkexact(object()))
         self.assertEqual(marker.__name__, "CAPI_SENTINEL")
         self.assertEqual(marker.__module__, __name__)
         self.assertEqual(repr(marker), "CAPI_SENTINEL")
diff --git a/Misc/NEWS.d/next/C_API/2026-05-12-16-47-21.gh-issue-149725.HZLBTZ.rst b/Misc/NEWS.d/next/C_API/2026-05-12-16-47-21.gh-issue-149725.HZLBTZ.rst
new file mode 100644 (file)
index 0000000..9772143
--- /dev/null
@@ -0,0 +1,2 @@
+Add :c:func:`PySentinel_CheckExact` for exact :class:`sentinel` type tests
+to accompany the existing :c:func:`PySentinel_Check`.
index 6e5c8dcbb725fa5fb4f8bba86e634a1b24d1a563..c62dc1144df6881576cff493c1bf09d06548cd60 100644 (file)
@@ -572,6 +572,12 @@ pysentinel_check(PyObject *self, PyObject *obj)
     return PyBool_FromLong(PySentinel_Check(obj));
 }
 
+static PyObject *
+pysentinel_checkexact(PyObject *self, PyObject *obj)
+{
+    return PyBool_FromLong(PySentinel_CheckExact(obj));
+}
+
 
 static PyMethodDef test_methods[] = {
     {"call_pyobject_print", call_pyobject_print, METH_VARARGS},
@@ -604,6 +610,7 @@ static PyMethodDef test_methods[] = {
     {"pyobject_dump", pyobject_dump, METH_VARARGS},
     {"pysentinel_new", pysentinel_new, METH_VARARGS},
     {"pysentinel_check", pysentinel_check, METH_O},
+    {"pysentinel_checkexact", pysentinel_checkexact, METH_O},
     {NULL},
 };