:c:macro:`Py_TPFLAGS_ITEMS_AT_END` set.
.. versionadded:: 3.12
+
+.. c:function:: int PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg)
+
+ Visit the managed dictionary of *obj*.
+
+ This function must only be called in a traverse function of the type which
+ has the :c:macro:`Py_TPFLAGS_MANAGED_DICT` flag set.
+
+ .. versionadded:: 3.13
+
+.. c:function:: void PyObject_ClearManagedDict(PyObject *obj)
+
+ Clear the managed dictionary of *obj*.
+
+ This function must only be called in a traverse function of the type which
+ has the :c:macro:`Py_TPFLAGS_MANAGED_DICT` flag set.
+
+ .. versionadded:: 3.13
If this flag is set, :c:macro:`Py_TPFLAGS_HAVE_GC` should also be set.
+ The type traverse function must call :c:func:`PyObject_VisitManagedDict`
+ and its clear function must call :c:func:`PyObject_ClearManagedDict`.
+
.. versionadded:: 3.12
**Inheritance:**
debugging aid you may want to visit it anyway just so the :mod:`gc` module's
:func:`~gc.get_referents` function will include it.
+ Heap types (:c:macro:`Py_TPFLAGS_HEAPTYPE`) must visit their type with::
+
+ Py_VISIT(Py_TYPE(self));
+
+ It is only needed since Python 3.9. To support Python 3.8 and older, this
+ line must be conditionnal::
+
+ #if PY_VERSION_HEX >= 0x03090000
+ Py_VISIT(Py_TYPE(self));
+ #endif
+
+ If the :c:macro:`Py_TPFLAGS_MANAGED_DICT` bit is set in the
+ :c:member:`~PyTypeObject.tp_flags` field, the traverse function must call
+ :c:func:`PyObject_VisitManagedDict` like this::
+
+ PyObject_VisitManagedDict((PyObject*)self, visit, arg);
+
.. warning::
When implementing :c:member:`~PyTypeObject.tp_traverse`, only the
members that the instance *owns* (by having :term:`strong references
so that *self* knows the contained object can no longer be used. The
:c:func:`Py_CLEAR` macro performs the operations in a safe order.
+ If the :c:macro:`Py_TPFLAGS_MANAGED_DICT` bit is set in the
+ :c:member:`~PyTypeObject.tp_flags` field, the traverse function must call
+ :c:func:`PyObject_ClearManagedDict` like this::
+
+ PyObject_ClearManagedDict((PyObject*)self);
+
Note that :c:member:`~PyTypeObject.tp_clear` is not *always* called
before an instance is deallocated. For example, when reference counting
is enough to determine that an object is no longer used, the cyclic garbage
field is ``NULL`` then no :attr:`~object.__dict__` gets created for instances.
If the :c:macro:`Py_TPFLAGS_MANAGED_DICT` bit is set in the
- :c:member:`~PyTypeObject.tp_dict` field, then
+ :c:member:`~PyTypeObject.tp_flags` field, then
:c:member:`~PyTypeObject.tp_dictoffset` will be set to ``-1``, to indicate
that it is unsafe to use this field.
The use of ``tp_dictoffset`` and ``tp_weaklistoffset`` is still
supported, but does not fully support multiple inheritance
(:gh:`95589`), and performance may be worse.
- Classes declaring :c:macro:`Py_TPFLAGS_MANAGED_DICT` should call
+ Classes declaring :c:macro:`Py_TPFLAGS_MANAGED_DICT` must call
:c:func:`!_PyObject_VisitManagedDict` and :c:func:`!_PyObject_ClearManagedDict`
to traverse and clear their instance's dictionaries.
To clear weakrefs, call :c:func:`PyObject_ClearWeakRefs`, as before.
references) now supports the :ref:`Limited API <limited-c-api>`.
(Contributed by Victor Stinner in :gh:`108634`.)
+* Add :c:func:`PyObject_VisitManagedDict` and
+ :c:func:`PyObject_ClearManagedDict` functions which must be called by the
+ traverse and clear functions of a type using
+ :c:macro:`Py_TPFLAGS_MANAGED_DICT` flag.
+ (Contributed by Victor Stinner in :gh:`107073`.)
+
Porting to Python 3.13
----------------------
PyAPI_FUNC(void *) PyObject_GetItemData(PyObject *obj);
-PyAPI_FUNC(int) _PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg);
-PyAPI_FUNC(void) _PyObject_ClearManagedDict(PyObject *obj);
+PyAPI_FUNC(int) PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg);
+PyAPI_FUNC(void) PyObject_ClearManagedDict(PyObject *obj);
#define TYPE_MAX_WATCHERS 8
--- /dev/null
+Add :c:func:`PyObject_VisitManagedDict` and :c:func:`PyObject_ClearManagedDict`
+functions which must be called by the traverse and clear functions of a type
+using :c:macro:`Py_TPFLAGS_MANAGED_DICT` flag. Patch by Victor Stinner.
Py_CLEAR(fut->fut_source_tb);
Py_CLEAR(fut->fut_cancel_msg);
Py_CLEAR(fut->fut_cancelled_exc);
- _PyObject_ClearManagedDict((PyObject *)fut);
+ PyObject_ClearManagedDict((PyObject *)fut);
return 0;
}
Py_VISIT(fut->fut_source_tb);
Py_VISIT(fut->fut_cancel_msg);
Py_VISIT(fut->fut_cancelled_exc);
- _PyObject_VisitManagedDict((PyObject *)fut, visit, arg);
+ PyObject_VisitManagedDict((PyObject *)fut, visit, arg);
return 0;
}
Py_VISIT(fut->fut_source_tb);
Py_VISIT(fut->fut_cancel_msg);
Py_VISIT(fut->fut_cancelled_exc);
- _PyObject_VisitManagedDict((PyObject *)fut, visit, arg);
+ PyObject_VisitManagedDict((PyObject *)fut, visit, arg);
return 0;
}
heapmanaged_traverse(HeapCTypeObject *self, visitproc visit, void *arg)
{
Py_VISIT(Py_TYPE(self));
- return _PyObject_VisitManagedDict((PyObject *)self, visit, arg);
+ return PyObject_VisitManagedDict((PyObject *)self, visit, arg);
}
static int
heapmanaged_clear(HeapCTypeObject *self)
{
- _PyObject_ClearManagedDict((PyObject *)self);
+ PyObject_ClearManagedDict((PyObject *)self);
return 0;
}
heapmanaged_dealloc(HeapCTypeObject *self)
{
PyTypeObject *tp = Py_TYPE(self);
- _PyObject_ClearManagedDict((PyObject *)self);
+ PyObject_ClearManagedDict((PyObject *)self);
PyObject_GC_UnTrack(self);
PyObject_GC_Del(self);
Py_DECREF(tp);
static PyObject *
clear_managed_dict(PyObject *self, PyObject *obj)
{
- _PyObject_ClearManagedDict(obj);
+ PyObject_ClearManagedDict(obj);
Py_RETURN_NONE;
}
}
int
-_PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg)
+PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg)
{
PyTypeObject *tp = Py_TYPE(obj);
if((tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0) {
}
void
-_PyObject_ClearManagedDict(PyObject *obj)
+PyObject_ClearManagedDict(PyObject *obj)
{
PyTypeObject *tp = Py_TYPE(obj);
if((tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0) {
assert(base->tp_dictoffset == 0);
if (type->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
assert(type->tp_dictoffset == -1);
- int err = _PyObject_VisitManagedDict(self, visit, arg);
+ int err = PyObject_VisitManagedDict(self, visit, arg);
if (err) {
return err;
}
__dict__ slots (as in the case 'self.__dict__ is self'). */
if (type->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
if ((base->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0) {
- _PyObject_ClearManagedDict(self);
+ PyObject_ClearManagedDict(self);
}
}
else if (type->tp_dictoffset != base->tp_dictoffset) {
Py_XDECREF(tv->evaluate_bound);
Py_XDECREF(tv->constraints);
Py_XDECREF(tv->evaluate_constraints);
- _PyObject_ClearManagedDict(self);
+ PyObject_ClearManagedDict(self);
PyObject_ClearWeakRefs(self);
Py_TYPE(self)->tp_free(self);
Py_VISIT(tv->evaluate_bound);
Py_VISIT(tv->constraints);
Py_VISIT(tv->evaluate_constraints);
- _PyObject_VisitManagedDict(self, visit, arg);
+ PyObject_VisitManagedDict(self, visit, arg);
return 0;
}
Py_CLEAR(self->evaluate_bound);
Py_CLEAR(self->constraints);
Py_CLEAR(self->evaluate_constraints);
- _PyObject_ClearManagedDict((PyObject *)self);
+ PyObject_ClearManagedDict((PyObject *)self);
return 0;
}
Py_DECREF(ps->name);
Py_XDECREF(ps->bound);
- _PyObject_ClearManagedDict(self);
+ PyObject_ClearManagedDict(self);
PyObject_ClearWeakRefs(self);
Py_TYPE(self)->tp_free(self);
Py_VISIT(Py_TYPE(self));
paramspecobject *ps = (paramspecobject *)self;
Py_VISIT(ps->bound);
- _PyObject_VisitManagedDict(self, visit, arg);
+ PyObject_VisitManagedDict(self, visit, arg);
return 0;
}
paramspec_clear(paramspecobject *self)
{
Py_CLEAR(self->bound);
- _PyObject_ClearManagedDict((PyObject *)self);
+ PyObject_ClearManagedDict((PyObject *)self);
return 0;
}
typevartupleobject *tvt = (typevartupleobject *)self;
Py_DECREF(tvt->name);
- _PyObject_ClearManagedDict(self);
+ PyObject_ClearManagedDict(self);
PyObject_ClearWeakRefs(self);
Py_TYPE(self)->tp_free(self);
typevartuple_traverse(PyObject *self, visitproc visit, void *arg)
{
Py_VISIT(Py_TYPE(self));
- _PyObject_VisitManagedDict(self, visit, arg);
+ PyObject_VisitManagedDict(self, visit, arg);
return 0;
}
static int
typevartuple_clear(PyObject *self)
{
- _PyObject_ClearManagedDict(self);
+ PyObject_ClearManagedDict(self);
return 0;
}