Skip to content

Commit 0b0d93c

Browse files
committed
Add _PyType_GetModuleByDef
1 parent 1d34699 commit 0b0d93c

File tree

4 files changed

+52
-3
lines changed

4 files changed

+52
-3
lines changed

Include/cpython/object.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,8 @@ PyAPI_FUNC(PyObject *) _PyObject_LookupSpecial(PyObject *, _Py_Identifier *);
296296
PyAPI_FUNC(PyTypeObject *) _PyType_CalculateMetaclass(PyTypeObject *, PyObject *);
297297
PyAPI_FUNC(PyObject *) _PyType_GetDocFromInternalDoc(const char *, const char *);
298298
PyAPI_FUNC(PyObject *) _PyType_GetTextSignatureFromInternalDoc(const char *, const char *);
299+
struct PyModuleDef;
300+
PyAPI_FUNC(PyObject *) _PyType_GetModuleByDef(PyTypeObject *, struct PyModuleDef *);
299301

300302
struct _Py_Identifier;
301303
PyAPI_FUNC(int) PyObject_Print(PyObject *, FILE *, int);

Modules/_testmultiphase.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,24 +121,30 @@ static PyType_Spec Example_Type_spec = {
121121
};
122122

123123

124+
static PyModuleDef def_meth_state_access;
125+
124126
/*[clinic input]
125127
_testmultiphase.StateAccessType.get_defining_module
126128
127129
cls: defining_class
128130
129131
Return the module of the defining class.
132+
133+
Also tests that result of _PyType_GetModuleByDef matches defining_class's
134+
module.
130135
[clinic start generated code]*/
131136

132137
static PyObject *
133138
_testmultiphase_StateAccessType_get_defining_module_impl(StateAccessTypeObject *self,
134139
PyTypeObject *cls)
135-
/*[clinic end generated code: output=ba2a14284a5d0921 input=946149f91cf72c0d]*/
140+
/*[clinic end generated code: output=ba2a14284a5d0921 input=356f999fc16e0933]*/
136141
{
137142
PyObject *retval;
138143
retval = PyType_GetModule(cls);
139144
if (retval == NULL) {
140145
return NULL;
141146
}
147+
assert(_PyType_GetModuleByDef(Py_TYPE(self), &def_meth_state_access) == retval);
142148
Py_INCREF(retval);
143149
return retval;
144150
}

Modules/clinic/_testmultiphase.c.h

Lines changed: 5 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Objects/typeobject.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3155,6 +3155,44 @@ PyType_GetModuleState(PyTypeObject *type)
31553155
return PyModule_GetState(m);
31563156
}
31573157

3158+
3159+
/* Get the module of the first superclass where the module has the
3160+
* given PyModuleDef.
3161+
* Implemented by walking the MRO, is relatively slow.
3162+
*
3163+
* This is internal API for experimentation within stdlib. Discussion:
3164+
* https://mail.python.org/archives/list/capi-sig@python.org/thread/T3P2QNLNLBRFHWSKYSTPMVEIL2EEKFJU/
3165+
*/
3166+
PyObject *
3167+
_PyType_GetModuleByDef(PyTypeObject *type, struct PyModuleDef *def)
3168+
{
3169+
assert(PyType_Check(type));
3170+
assert(type->tp_mro);
3171+
int i;
3172+
for (i = 0; i < PyTuple_GET_SIZE(type->tp_mro); i++) {
3173+
PyObject *super = PyTuple_GET_ITEM(type->tp_mro, i);
3174+
if (!PyType_HasFeature((PyTypeObject *)super, Py_TPFLAGS_HEAPTYPE)) {
3175+
/* Currently, there's no way for static types to inherit
3176+
* from heap types, but to allow that possibility,
3177+
* we `continue` rather than `break`.
3178+
* We'll just potentially loop a few more times before throwing
3179+
* the error.
3180+
*/
3181+
continue;
3182+
}
3183+
PyHeapTypeObject *ht = (PyHeapTypeObject*)super;
3184+
if (ht->ht_module && PyModule_GetDef(ht->ht_module) == def) {
3185+
return ht->ht_module;
3186+
}
3187+
}
3188+
PyErr_Format(
3189+
PyExc_TypeError,
3190+
"_PyType_GetModuleByDef: No superclass of '%s' has the given module",
3191+
type->tp_name);
3192+
return NULL;
3193+
}
3194+
3195+
31583196
/* Internal API to look for a name through the MRO, bypassing the method cache.
31593197
This returns a borrowed reference, and might set an exception.
31603198
'error' is set to: -1: error with exception; 1: error without exception; 0: ok */

0 commit comments

Comments
 (0)