mirror of
https://github.com/python/cpython.git
synced 2025-10-09 16:34:44 +00:00
bpo-38787: C API for module state access from extension methods (PEP 573) (GH-19936)
Module C state is now accessible from C-defined heap type methods (PEP 573). Patch by Marcel Plch and Petr Viktorin. Co-authored-by: Marcel Plch <mplch@redhat.com> Co-authored-by: Victor Stinner <vstinner@python.org>
This commit is contained in:
parent
4638c64295
commit
e1becf46b4
19 changed files with 797 additions and 51 deletions
|
@ -2708,6 +2708,9 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
|
|||
if (qualname != NULL && _PyDict_DelItemId(dict, &PyId___qualname__) < 0)
|
||||
goto error;
|
||||
|
||||
/* Set ht_module */
|
||||
et->ht_module = NULL;
|
||||
|
||||
/* Set tp_doc to a copy of dict['__doc__'], if the latter is there
|
||||
and is a string. The __doc__ accessor will first look for tp_doc;
|
||||
if that fails, it will still look into __dict__.
|
||||
|
@ -2939,6 +2942,12 @@ PyType_FromSpec_tp_traverse(PyObject *self, visitproc visit, void *arg)
|
|||
|
||||
PyObject *
|
||||
PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)
|
||||
{
|
||||
return PyType_FromModuleAndSpec(NULL, spec, bases);
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases)
|
||||
{
|
||||
PyHeapTypeObject *res;
|
||||
PyObject *modname;
|
||||
|
@ -2998,6 +3007,9 @@ PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)
|
|||
Py_INCREF(res->ht_qualname);
|
||||
type->tp_name = spec->name;
|
||||
|
||||
Py_XINCREF(module);
|
||||
res->ht_module = module;
|
||||
|
||||
/* Adjust for empty tuple bases */
|
||||
if (!bases) {
|
||||
base = &PyBaseObject_Type;
|
||||
|
@ -3176,6 +3188,40 @@ PyType_GetSlot(PyTypeObject *type, int slot)
|
|||
return *(void**)(((char*)type) + slotoffsets[slot]);
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PyType_GetModule(PyTypeObject *type)
|
||||
{
|
||||
assert(PyType_Check(type));
|
||||
if (!_PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE)) {
|
||||
PyErr_Format(
|
||||
PyExc_TypeError,
|
||||
"PyType_GetModule: Type '%s' is not a heap type",
|
||||
type->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyHeapTypeObject* et = (PyHeapTypeObject*)type;
|
||||
if (!et->ht_module) {
|
||||
PyErr_Format(
|
||||
PyExc_TypeError,
|
||||
"PyType_GetModule: Type '%s' has no associated module",
|
||||
type->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
return et->ht_module;
|
||||
|
||||
}
|
||||
|
||||
void *
|
||||
PyType_GetModuleState(PyTypeObject *type)
|
||||
{
|
||||
PyObject *m = PyType_GetModule(type);
|
||||
if (m == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return PyModule_GetState(m);
|
||||
}
|
||||
|
||||
/* Internal API to look for a name through the MRO, bypassing the method cache.
|
||||
This returns a borrowed reference, and might set an exception.
|
||||
'error' is set to: -1: error with exception; 1: error without exception; 0: ok */
|
||||
|
@ -3503,8 +3549,10 @@ type_dealloc(PyTypeObject *type)
|
|||
Py_XDECREF(et->ht_name);
|
||||
Py_XDECREF(et->ht_qualname);
|
||||
Py_XDECREF(et->ht_slots);
|
||||
if (et->ht_cached_keys)
|
||||
if (et->ht_cached_keys) {
|
||||
_PyDictKeys_DecRef(et->ht_cached_keys);
|
||||
}
|
||||
Py_XDECREF(et->ht_module);
|
||||
Py_TYPE(type)->tp_free((PyObject *)type);
|
||||
}
|
||||
|
||||
|
@ -3694,6 +3742,7 @@ type_traverse(PyTypeObject *type, visitproc visit, void *arg)
|
|||
Py_VISIT(type->tp_mro);
|
||||
Py_VISIT(type->tp_bases);
|
||||
Py_VISIT(type->tp_base);
|
||||
Py_VISIT(((PyHeapTypeObject *)type)->ht_module);
|
||||
|
||||
/* There's no need to visit type->tp_subclasses or
|
||||
((PyHeapTypeObject *)type)->ht_slots, because they can't be involved
|
||||
|
@ -3715,10 +3764,13 @@ type_clear(PyTypeObject *type)
|
|||
the dict, so that other objects caught in a reference cycle
|
||||
don't start calling destroyed methods.
|
||||
|
||||
Otherwise, the only field we need to clear is tp_mro, which is
|
||||
Otherwise, the we need to clear tp_mro, which is
|
||||
part of a hard cycle (its first element is the class itself) that
|
||||
won't be broken otherwise (it's a tuple and tuples don't have a
|
||||
tp_clear handler). None of the other fields need to be
|
||||
tp_clear handler).
|
||||
We also need to clear ht_module, if present: the module usually holds a
|
||||
reference to its class. None of the other fields need to be
|
||||
|
||||
cleared, and here's why:
|
||||
|
||||
tp_cache:
|
||||
|
@ -3743,8 +3795,11 @@ type_clear(PyTypeObject *type)
|
|||
((PyHeapTypeObject *)type)->ht_cached_keys = NULL;
|
||||
_PyDictKeys_DecRef(cached_keys);
|
||||
}
|
||||
if (type->tp_dict)
|
||||
if (type->tp_dict) {
|
||||
PyDict_Clear(type->tp_dict);
|
||||
}
|
||||
Py_CLEAR(((PyHeapTypeObject *)type)->ht_module);
|
||||
|
||||
Py_CLEAR(type->tp_mro);
|
||||
|
||||
return 0;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue