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:
Petr Viktorin 2020-05-07 15:39:59 +02:00 committed by GitHub
parent 4638c64295
commit e1becf46b4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 797 additions and 51 deletions

View file

@ -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;