[Python-checkins] bpo-46613: Add PyType_GetModuleByDef to the public API (GH-31081)

encukou webhook-mailer at python.org
Fri Feb 11 11:22:17 EST 2022


https://github.com/python/cpython/commit/204946986feee7bc80b233350377d24d20fcb1b8
commit: 204946986feee7bc80b233350377d24d20fcb1b8
branch: main
author: Petr Viktorin <encukou at gmail.com>
committer: encukou <encukou at gmail.com>
date: 2022-02-11T17:22:11+01:00
summary:

bpo-46613: Add PyType_GetModuleByDef to the public API (GH-31081)

* Make PyType_GetModuleByDef public (remove underscore)

Co-authored-by: Victor Stinner <vstinner at python.org>

files:
A Misc/NEWS.d/next/C API/2022-02-02-17-58-49.bpo-46613.__ZdpH.rst
M Doc/c-api/type.rst
M Doc/howto/clinic.rst
M Doc/whatsnew/3.11.rst
M Include/cpython/object.h
M Lib/test/test_capi.py
M Modules/_csv.c
M Modules/_functoolsmodule.c
M Modules/_queuemodule.c
M Modules/_randommodule.c
M Modules/_sqlite/module.h
M Modules/_ssl.c
M Modules/_ssl.h
M Modules/_struct.c
M Modules/_testmultiphase.c
M Modules/_threadmodule.c
M Modules/arraymodule.c
M Modules/cjkcodecs/multibytecodec.c
M Modules/clinic/_testmultiphase.c.h
M Objects/typeobject.c
M Python/Python-tokenize.c

diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst
index 97a818ab2ccd0..e6a5a0ea9c121 100644
--- a/Doc/c-api/type.rst
+++ b/Doc/c-api/type.rst
@@ -149,6 +149,8 @@ Type Objects
    ``Py_TYPE(self)`` may be a *subclass* of the intended class, and subclasses
    are not necessarily defined in the same module as their superclass.
    See :c:type:`PyCMethod` to get the class that defines the method.
+   See :c:func:`PyType_GetModuleByDef` for cases when ``PyCMethod`` cannot
+   be used.
 
    .. versionadded:: 3.9
 
@@ -166,6 +168,21 @@ Type Objects
 
    .. versionadded:: 3.9
 
+.. c:function:: PyObject* PyType_GetModuleByDef(PyTypeObject *type, struct PyModuleDef *def)
+
+   Find the first superclass whose module was created from
+   the given :c:type:`PyModuleDef` *def*, and return that module.
+
+   If no module is found, raises a :py:class:`TypeError` and returns ``NULL``.
+
+   This function is intended to be used together with
+   :c:func:`PyModule_GetState()` to get module state from slot methods (such as
+   :c:member:`~PyTypeObject.tp_init` or :c:member:`~PyNumberMethods.nb_add`)
+   and other places where a method's defining class cannot be passed using the
+   :c:type:`PyCMethod` calling convention.
+
+   .. versionadded:: 3.11
+
 
 Creating Heap-Allocated Types
 .............................
diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst
index a3c4330296bed..04b1a2cac0b04 100644
--- a/Doc/howto/clinic.rst
+++ b/Doc/howto/clinic.rst
@@ -1249,15 +1249,15 @@ The ``defining_class`` converter is not compatible with ``__init__`` and ``__new
 methods, which cannot use the ``METH_METHOD`` convention.
 
 It is not possible to use ``defining_class`` with slot methods.  In order to
-fetch the module state from such methods, use ``_PyType_GetModuleByDef`` to
-look up the module and then :c:func:`PyModule_GetState` to fetch the module
+fetch the module state from such methods, use :c:func:`PyType_GetModuleByDef`
+to look up the module and then :c:func:`PyModule_GetState` to fetch the module
 state.  Example from the ``setattro`` slot method in
 ``Modules/_threadmodule.c``::
 
     static int
     local_setattro(localobject *self, PyObject *name, PyObject *v)
     {
-        PyObject *module = _PyType_GetModuleByDef(Py_TYPE(self), &thread_module);
+        PyObject *module = PyType_GetModuleByDef(Py_TYPE(self), &thread_module);
         thread_module_state *state = get_thread_state(module);
         ...
     }
diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst
index 5738745ba1323..95fce1e8e1082 100644
--- a/Doc/whatsnew/3.11.rst
+++ b/Doc/whatsnew/3.11.rst
@@ -708,6 +708,11 @@ New Features
 
   (Contributed by Christian Heimes in :issue:`45459`.)
 
+* Added the :c:data:`PyType_GetModuleByDef` function, used to get the module
+  in which a method was defined, in cases where this information is not
+  available directly (via :c:type:`PyCMethod`).
+  (Contributed by Petr Viktorin in :issue:`46613`.)
+
 
 Porting to Python 3.11
 ----------------------
diff --git a/Include/cpython/object.h b/Include/cpython/object.h
index a3632cf1dcf81..2ee97ba0b40af 100644
--- a/Include/cpython/object.h
+++ b/Include/cpython/object.h
@@ -265,7 +265,7 @@ PyAPI_FUNC(PyTypeObject *) _PyType_CalculateMetaclass(PyTypeObject *, PyObject *
 PyAPI_FUNC(PyObject *) _PyType_GetDocFromInternalDoc(const char *, const char *);
 PyAPI_FUNC(PyObject *) _PyType_GetTextSignatureFromInternalDoc(const char *, const char *);
 struct PyModuleDef;
-PyAPI_FUNC(PyObject *) _PyType_GetModuleByDef(PyTypeObject *, struct PyModuleDef *);
+PyAPI_FUNC(PyObject *) PyType_GetModuleByDef(PyTypeObject *, struct PyModuleDef *);
 
 struct _Py_Identifier;
 PyAPI_FUNC(int) PyObject_Print(PyObject *, FILE *, int);
diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py
index 089088d97a66e..8832292a9991a 100644
--- a/Lib/test/test_capi.py
+++ b/Lib/test/test_capi.py
@@ -1071,7 +1071,7 @@ def test_state_access(self):
                     increment_count(1, 2, 3)
 
     def test_get_module_bad_def(self):
-        # _PyType_GetModuleByDef fails gracefully if it doesn't
+        # PyType_GetModuleByDef fails gracefully if it doesn't
         # find what it's looking for.
         # see bpo-46433
         instance = self.module.StateAccessType()
@@ -1079,7 +1079,7 @@ def test_get_module_bad_def(self):
             instance.getmodulebydef_bad_def()
 
     def test_get_module_static_in_mro(self):
-        # Here, the class _PyType_GetModuleByDef is looking for
+        # Here, the class PyType_GetModuleByDef is looking for
         # appears in the MRO after a static type (Exception).
         # see bpo-46433
         class Subclass(BaseException, self.module.StateAccessType):
diff --git a/Misc/NEWS.d/next/C API/2022-02-02-17-58-49.bpo-46613.__ZdpH.rst b/Misc/NEWS.d/next/C API/2022-02-02-17-58-49.bpo-46613.__ZdpH.rst
new file mode 100644
index 0000000000000..9d0fca7a06b89
--- /dev/null
+++ b/Misc/NEWS.d/next/C API/2022-02-02-17-58-49.bpo-46613.__ZdpH.rst	
@@ -0,0 +1,2 @@
+Added function :c:func:`PyType_GetModuleByDef`, which allows accesss to
+module state when a method's defining class is not available.
diff --git a/Modules/_csv.c b/Modules/_csv.c
index d2cb77f9f0334..f59d42a022e41 100644
--- a/Modules/_csv.c
+++ b/Modules/_csv.c
@@ -374,7 +374,7 @@ static char *dialect_kws[] = {
 static _csvstate *
 _csv_state_from_type(PyTypeObject *type, const char *name)
 {
-    PyObject *module = _PyType_GetModuleByDef(type, &_csvmodule);
+    PyObject *module = PyType_GetModuleByDef(type, &_csvmodule);
     if (module == NULL) {
         return NULL;
     }
diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c
index 1f6b852f6d99b..0974fc704ffbd 100644
--- a/Modules/_functoolsmodule.c
+++ b/Modules/_functoolsmodule.c
@@ -51,7 +51,7 @@ partial_call(partialobject *pto, PyObject *args, PyObject *kwargs);
 static inline _functools_state *
 get_functools_state_by_type(PyTypeObject *type)
 {
-    PyObject *module = _PyType_GetModuleByDef(type, &_functools_module);
+    PyObject *module = PyType_GetModuleByDef(type, &_functools_module);
     if (module == NULL) {
         return NULL;
     }
diff --git a/Modules/_queuemodule.c b/Modules/_queuemodule.c
index 413387fecc4cd..af19dd6c198b6 100644
--- a/Modules/_queuemodule.c
+++ b/Modules/_queuemodule.c
@@ -21,7 +21,7 @@ simplequeue_get_state(PyObject *module)
 }
 static struct PyModuleDef queuemodule;
 #define simplequeue_get_state_by_type(type) \
-    (simplequeue_get_state(_PyType_GetModuleByDef(type, &queuemodule)))
+    (simplequeue_get_state(PyType_GetModuleByDef(type, &queuemodule)))
 
 typedef struct {
     PyObject_HEAD
diff --git a/Modules/_randommodule.c b/Modules/_randommodule.c
index 45860e342eb43..d96c0371ec7f8 100644
--- a/Modules/_randommodule.c
+++ b/Modules/_randommodule.c
@@ -99,7 +99,7 @@ get_random_state(PyObject *module)
 static struct PyModuleDef _randommodule;
 
 #define _randomstate_type(type) \
-    (get_random_state(_PyType_GetModuleByDef(type, &_randommodule)))
+    (get_random_state(PyType_GetModuleByDef(type, &_randommodule)))
 
 typedef struct {
     PyObject_HEAD
diff --git a/Modules/_sqlite/module.h b/Modules/_sqlite/module.h
index 1d319f1ed5541..a248d044af8fd 100644
--- a/Modules/_sqlite/module.h
+++ b/Modules/_sqlite/module.h
@@ -74,7 +74,7 @@ extern struct PyModuleDef _sqlite3module;
 static inline pysqlite_state *
 pysqlite_get_state_by_type(PyTypeObject *tp)
 {
-    PyObject *module = _PyType_GetModuleByDef(tp, &_sqlite3module);
+    PyObject *module = PyType_GetModuleByDef(tp, &_sqlite3module);
     assert(module != NULL);
     return pysqlite_get_state(module);
 }
diff --git a/Modules/_ssl.c b/Modules/_ssl.c
index 07f0580ef6fc5..d7e041fed3cb3 100644
--- a/Modules/_ssl.c
+++ b/Modules/_ssl.c
@@ -2988,8 +2988,8 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version)
     int result;
 
    /* slower approach, walk MRO and get borrowed reference to module.
-    * _PyType_GetModuleByDef is required for SSLContext subclasses */
-    PyObject *module = _PyType_GetModuleByDef(type, &_sslmodule_def);
+    * PyType_GetModuleByDef is required for SSLContext subclasses */
+    PyObject *module = PyType_GetModuleByDef(type, &_sslmodule_def);
     if (module == NULL) {
         PyErr_SetString(PyExc_RuntimeError,
                         "Cannot find internal module state");
diff --git a/Modules/_ssl.h b/Modules/_ssl.h
index 5fe6504a9dd7b..5593a455de4dc 100644
--- a/Modules/_ssl.h
+++ b/Modules/_ssl.h
@@ -42,7 +42,7 @@ get_ssl_state(PyObject *module)
 }
 
 #define get_state_type(type) \
-    (get_ssl_state(_PyType_GetModuleByDef(type, &_sslmodule_def)))
+    (get_ssl_state(PyType_GetModuleByDef(type, &_sslmodule_def)))
 #define get_state_ctx(c) (((PySSLContext *)(c))->state)
 #define get_state_sock(s) (((PySSLSocket *)(s))->ctx->state)
 #define get_state_obj(o) ((_sslmodulestate *)PyType_GetModuleState(Py_TYPE(o)))
diff --git a/Modules/_struct.c b/Modules/_struct.c
index 7d05ec5ac7c50..a2e14e89d26d4 100644
--- a/Modules/_struct.c
+++ b/Modules/_struct.c
@@ -38,7 +38,7 @@ get_struct_state(PyObject *module)
 static struct PyModuleDef _structmodule;
 
 #define get_struct_state_structinst(self) \
-    (get_struct_state(_PyType_GetModuleByDef(Py_TYPE(self), &_structmodule)))
+    (get_struct_state(PyType_GetModuleByDef(Py_TYPE(self), &_structmodule)))
 #define get_struct_state_iterinst(self) \
     (get_struct_state(PyType_GetModule(Py_TYPE(self))))
 
diff --git a/Modules/_testmultiphase.c b/Modules/_testmultiphase.c
index f7bde9895eb09..4905269177bf3 100644
--- a/Modules/_testmultiphase.c
+++ b/Modules/_testmultiphase.c
@@ -136,21 +136,21 @@ _testmultiphase.StateAccessType.get_defining_module
 
 Return the module of the defining class.
 
-Also tests that result of _PyType_GetModuleByDef matches defining_class's
+Also tests that result of PyType_GetModuleByDef matches defining_class's
 module.
 [clinic start generated code]*/
 
 static PyObject *
 _testmultiphase_StateAccessType_get_defining_module_impl(StateAccessTypeObject *self,
                                                          PyTypeObject *cls)
-/*[clinic end generated code: output=ba2a14284a5d0921 input=356f999fc16e0933]*/
+/*[clinic end generated code: output=ba2a14284a5d0921 input=d2c7245c8a9d06f8]*/
 {
     PyObject *retval;
     retval = PyType_GetModule(cls);
     if (retval == NULL) {
         return NULL;
     }
-    assert(_PyType_GetModuleByDef(Py_TYPE(self), &def_meth_state_access) == retval);
+    assert(PyType_GetModuleByDef(Py_TYPE(self), &def_meth_state_access) == retval);
     Py_INCREF(retval);
     return retval;
 }
@@ -160,15 +160,15 @@ _testmultiphase.StateAccessType.getmodulebydef_bad_def
 
     cls: defining_class
 
-Test that result of _PyType_GetModuleByDef with a bad def is NULL.
+Test that result of PyType_GetModuleByDef with a bad def is NULL.
 [clinic start generated code]*/
 
 static PyObject *
 _testmultiphase_StateAccessType_getmodulebydef_bad_def_impl(StateAccessTypeObject *self,
                                                             PyTypeObject *cls)
-/*[clinic end generated code: output=64509074dfcdbd31 input=906047715ee293cd]*/
+/*[clinic end generated code: output=64509074dfcdbd31 input=edaff09aa4788204]*/
 {
-    _PyType_GetModuleByDef(Py_TYPE(self), &def_nonmodule);  // should raise
+    PyType_GetModuleByDef(Py_TYPE(self), &def_nonmodule);  // should raise
     assert(PyErr_Occurred());
     return NULL;
 }
diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c
index 072b79a75f3af..ca74f9d6977e2 100644
--- a/Modules/_threadmodule.c
+++ b/Modules/_threadmodule.c
@@ -786,7 +786,7 @@ local_new(PyTypeObject *type, PyObject *args, PyObject *kw)
         }
     }
 
-    PyObject *module = _PyType_GetModuleByDef(type, &thread_module);
+    PyObject *module = PyType_GetModuleByDef(type, &thread_module);
     thread_module_state *state = get_thread_state(module);
 
     localobject *self = (localobject *)type->tp_alloc(type, 0);
@@ -925,7 +925,7 @@ _ldict(localobject *self, thread_module_state *state)
 static int
 local_setattro(localobject *self, PyObject *name, PyObject *v)
 {
-    PyObject *module = _PyType_GetModuleByDef(Py_TYPE(self), &thread_module);
+    PyObject *module = PyType_GetModuleByDef(Py_TYPE(self), &thread_module);
     thread_module_state *state = get_thread_state(module);
 
     PyObject *ldict = _ldict(self, state);
@@ -977,7 +977,7 @@ static PyType_Spec local_type_spec = {
 static PyObject *
 local_getattro(localobject *self, PyObject *name)
 {
-    PyObject *module = _PyType_GetModuleByDef(Py_TYPE(self), &thread_module);
+    PyObject *module = PyType_GetModuleByDef(Py_TYPE(self), &thread_module);
     thread_module_state *state = get_thread_state(module);
 
     PyObject *ldict = _ldict(self, state);
diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c
index 4aaab0c531435..e516f54ab61e6 100644
--- a/Modules/arraymodule.c
+++ b/Modules/arraymodule.c
@@ -67,7 +67,7 @@ get_array_state(PyObject *module)
 }
 
 #define find_array_state_by_type(tp) \
-    (get_array_state(_PyType_GetModuleByDef(tp, &arraymodule)))
+    (get_array_state(PyType_GetModuleByDef(tp, &arraymodule)))
 #define get_array_state_by_class(cls) \
     (get_array_state(PyType_GetModule(cls)))
 
diff --git a/Modules/cjkcodecs/multibytecodec.c b/Modules/cjkcodecs/multibytecodec.c
index df48a0deec7e9..acfe96654a226 100644
--- a/Modules/cjkcodecs/multibytecodec.c
+++ b/Modules/cjkcodecs/multibytecodec.c
@@ -33,7 +33,7 @@ static struct PyModuleDef _multibytecodecmodule;
 static _multibytecodec_state *
 _multibyte_codec_find_state_by_type(PyTypeObject *type)
 {
-    PyObject *module = _PyType_GetModuleByDef(type, &_multibytecodecmodule);
+    PyObject *module = PyType_GetModuleByDef(type, &_multibytecodecmodule);
     assert(module != NULL);
     return _multibytecodec_get_state(module);
 }
diff --git a/Modules/clinic/_testmultiphase.c.h b/Modules/clinic/_testmultiphase.c.h
index 17c28d54ce575..b8ee93c6e19ea 100644
--- a/Modules/clinic/_testmultiphase.c.h
+++ b/Modules/clinic/_testmultiphase.c.h
@@ -8,7 +8,7 @@ PyDoc_STRVAR(_testmultiphase_StateAccessType_get_defining_module__doc__,
 "\n"
 "Return the module of the defining class.\n"
 "\n"
-"Also tests that result of _PyType_GetModuleByDef matches defining_class\'s\n"
+"Also tests that result of PyType_GetModuleByDef matches defining_class\'s\n"
 "module.");
 
 #define _TESTMULTIPHASE_STATEACCESSTYPE_GET_DEFINING_MODULE_METHODDEF    \
@@ -39,7 +39,7 @@ PyDoc_STRVAR(_testmultiphase_StateAccessType_getmodulebydef_bad_def__doc__,
 "getmodulebydef_bad_def($self, /)\n"
 "--\n"
 "\n"
-"Test that result of _PyType_GetModuleByDef with a bad def is NULL.");
+"Test that result of PyType_GetModuleByDef with a bad def is NULL.");
 
 #define _TESTMULTIPHASE_STATEACCESSTYPE_GETMODULEBYDEF_BAD_DEF_METHODDEF    \
     {"getmodulebydef_bad_def", (PyCFunction)(void(*)(void))_testmultiphase_StateAccessType_getmodulebydef_bad_def, METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _testmultiphase_StateAccessType_getmodulebydef_bad_def__doc__},
@@ -131,4 +131,4 @@ _testmultiphase_StateAccessType_get_count(StateAccessTypeObject *self, PyTypeObj
 exit:
     return return_value;
 }
-/*[clinic end generated code: output=eb1b8c2ee6290be3 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=e8d074b4e6437438 input=a9049054013a1b77]*/
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index ef3549ce68f7f..3f8f36a9c4648 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -3714,13 +3714,9 @@ PyType_GetModuleState(PyTypeObject *type)
 
 /* Get the module of the first superclass where the module has the
  * given PyModuleDef.
- * Implemented by walking the MRO, is relatively slow.
- *
- * This is internal API for experimentation within stdlib. Discussion:
- * https://mail.python.org/archives/list/capi-sig@python.org/thread/T3P2QNLNLBRFHWSKYSTPMVEIL2EEKFJU/
  */
 PyObject *
-_PyType_GetModuleByDef(PyTypeObject *type, struct PyModuleDef *def)
+PyType_GetModuleByDef(PyTypeObject *type, struct PyModuleDef *def)
 {
     assert(PyType_Check(type));
 
@@ -3749,7 +3745,7 @@ _PyType_GetModuleByDef(PyTypeObject *type, struct PyModuleDef *def)
 
     PyErr_Format(
         PyExc_TypeError,
-        "_PyType_GetModuleByDef: No superclass of '%s' has the given module",
+        "PyType_GetModuleByDef: No superclass of '%s' has the given module",
         type->tp_name);
     return NULL;
 }
diff --git a/Python/Python-tokenize.c b/Python/Python-tokenize.c
index d3ebbe1331a15..6acfc2a7cfd26 100644
--- a/Python/Python-tokenize.c
+++ b/Python/Python-tokenize.c
@@ -13,7 +13,7 @@ get_tokenize_state(PyObject *module) {
 }
 
 #define _tokenize_get_state_by_type(type) \
-    get_tokenize_state(_PyType_GetModuleByDef(type, &_tokenizemodule))
+    get_tokenize_state(PyType_GetModuleByDef(type, &_tokenizemodule))
 
 #include "clinic/Python-tokenize.c.h"
 



More information about the Python-checkins mailing list