``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
.. 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
.............................
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);
...
}
(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
----------------------
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);
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()
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):
--- /dev/null
+Added function :c:func:`PyType_GetModuleByDef`, which allows accesss to
+module state when a method's defining class is not available.
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;
}
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;
}
}
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
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
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);
}
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");
}
#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)))
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))))
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;
}
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;
}
}
}
- 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);
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);
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);
}
#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)))
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);
}
"\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 \
"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__},
exit:
return return_value;
}
-/*[clinic end generated code: output=eb1b8c2ee6290be3 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=e8d074b4e6437438 input=a9049054013a1b77]*/
/* 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));
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;
}
}
#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"