mirror of https://github.com/python/cpython
gh-105227: Add PyType_GetDict() (GH-105747)
This compensates for static builtin types having `tp_dict` set to `NULL`. Co-authored-by: Petr Viktorin <encukou@gmail.com>
This commit is contained in:
parent
3e23fa71f4
commit
a840806d33
|
@ -50,6 +50,23 @@ Type Objects
|
||||||
The return type is now ``unsigned long`` rather than ``long``.
|
The return type is now ``unsigned long`` rather than ``long``.
|
||||||
|
|
||||||
|
|
||||||
|
.. c:function:: PyObject* PyType_GetDict(PyTypeObject* type)
|
||||||
|
|
||||||
|
Return the type object's internal namespace, which is otherwise only
|
||||||
|
exposed via a read-only proxy (``cls.__dict__``). This is a
|
||||||
|
replacement for accessing :c:member:`~PyTypeObject.tp_dict` directly.
|
||||||
|
The returned dictionary must be treated as read-only.
|
||||||
|
|
||||||
|
This function is meant for specific embedding and language-binding cases,
|
||||||
|
where direct access to the dict is necessary and indirect access
|
||||||
|
(e.g. via the proxy or :c:func:`PyObject_GetAttr`) isn't adequate.
|
||||||
|
|
||||||
|
Extension modules should continue to use ``tp_dict``,
|
||||||
|
directly or indirectly, when setting up their own types.
|
||||||
|
|
||||||
|
.. versionadded:: 3.12
|
||||||
|
|
||||||
|
|
||||||
.. c:function:: void PyType_Modified(PyTypeObject *type)
|
.. c:function:: void PyType_Modified(PyTypeObject *type)
|
||||||
|
|
||||||
Invalidate the internal lookup cache for the type and all of its
|
Invalidate the internal lookup cache for the type and all of its
|
||||||
|
|
|
@ -1717,7 +1717,19 @@ and :c:type:`PyType_Type` effectively act as defaults.)
|
||||||
called; it may also be initialized to a dictionary containing initial attributes
|
called; it may also be initialized to a dictionary containing initial attributes
|
||||||
for the type. Once :c:func:`PyType_Ready` has initialized the type, extra
|
for the type. Once :c:func:`PyType_Ready` has initialized the type, extra
|
||||||
attributes for the type may be added to this dictionary only if they don't
|
attributes for the type may be added to this dictionary only if they don't
|
||||||
correspond to overloaded operations (like :meth:`__add__`).
|
correspond to overloaded operations (like :meth:`__add__`). Once
|
||||||
|
initialization for the type has finished, this field should be
|
||||||
|
treated as read-only.
|
||||||
|
|
||||||
|
Some types may not store their dictionary in this slot.
|
||||||
|
Use :c:func:`PyType_GetDict` to retreive the dictionary for an arbitrary
|
||||||
|
type.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.12
|
||||||
|
|
||||||
|
Internals detail: For static builtin types, this is always ``NULL``.
|
||||||
|
Instead, the dict for such types is stored on ``PyInterpreterState``.
|
||||||
|
Use :c:func:`PyType_GetDict` to get the dict for an arbitrary type.
|
||||||
|
|
||||||
**Inheritance:**
|
**Inheritance:**
|
||||||
|
|
||||||
|
|
|
@ -284,6 +284,7 @@ PyAPI_FUNC(PyTypeObject *) _PyType_CalculateMetaclass(PyTypeObject *, PyObject *
|
||||||
PyAPI_FUNC(PyObject *) _PyType_GetDocFromInternalDoc(const char *, const char *);
|
PyAPI_FUNC(PyObject *) _PyType_GetDocFromInternalDoc(const char *, const char *);
|
||||||
PyAPI_FUNC(PyObject *) _PyType_GetTextSignatureFromInternalDoc(const char *, const char *);
|
PyAPI_FUNC(PyObject *) _PyType_GetTextSignatureFromInternalDoc(const char *, const char *);
|
||||||
PyAPI_FUNC(PyObject *) PyType_GetModuleByDef(PyTypeObject *, PyModuleDef *);
|
PyAPI_FUNC(PyObject *) PyType_GetModuleByDef(PyTypeObject *, PyModuleDef *);
|
||||||
|
PyAPI_FUNC(PyObject *) PyType_GetDict(PyTypeObject *);
|
||||||
|
|
||||||
PyAPI_FUNC(int) PyObject_Print(PyObject *, FILE *, int);
|
PyAPI_FUNC(int) PyObject_Print(PyObject *, FILE *, int);
|
||||||
PyAPI_FUNC(void) _Py_BreakPoint(void);
|
PyAPI_FUNC(void) _Py_BreakPoint(void);
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
The new :c:func:`PyType_GetDict` provides the dictionary for the given type
|
||||||
|
object that is normally exposed by ``cls.__dict__``. Normally it's
|
||||||
|
sufficient to use :c:member:`~PyTypeObject.tp_dict`, but for the static
|
||||||
|
builtin types :c:member:`!tp_dict` is now always ``NULL``. :c:func:`!PyType_GetDict()`
|
||||||
|
provides the correct dict object instead.
|
|
@ -638,6 +638,30 @@ test_get_type_qualname(PyObject *self, PyObject *Py_UNUSED(ignored))
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
test_get_type_dict(PyObject *self, PyObject *Py_UNUSED(ignored))
|
||||||
|
{
|
||||||
|
/* Test for PyType_GetDict */
|
||||||
|
|
||||||
|
// Assert ints have a `to_bytes` method
|
||||||
|
PyObject *long_dict = PyType_GetDict(&PyLong_Type);
|
||||||
|
assert(long_dict);
|
||||||
|
assert(PyDict_GetItemString(long_dict, "to_bytes")); // borrowed ref
|
||||||
|
Py_DECREF(long_dict);
|
||||||
|
|
||||||
|
// Make a new type, add an attribute to it and assert it's there
|
||||||
|
PyObject *HeapTypeNameType = PyType_FromSpec(&HeapTypeNameType_Spec);
|
||||||
|
assert(HeapTypeNameType);
|
||||||
|
assert(PyObject_SetAttrString(
|
||||||
|
HeapTypeNameType, "new_attr", Py_NewRef(Py_None)) >= 0);
|
||||||
|
PyObject *type_dict = PyType_GetDict((PyTypeObject*)HeapTypeNameType);
|
||||||
|
assert(type_dict);
|
||||||
|
assert(PyDict_GetItemString(type_dict, "new_attr")); // borrowed ref
|
||||||
|
Py_DECREF(HeapTypeNameType);
|
||||||
|
Py_DECREF(type_dict);
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
pyobject_repr_from_null(PyObject *self, PyObject *Py_UNUSED(ignored))
|
pyobject_repr_from_null(PyObject *self, PyObject *Py_UNUSED(ignored))
|
||||||
{
|
{
|
||||||
|
@ -3472,6 +3496,7 @@ static PyMethodDef TestMethods[] = {
|
||||||
{"test_get_statictype_slots", test_get_statictype_slots, METH_NOARGS},
|
{"test_get_statictype_slots", test_get_statictype_slots, METH_NOARGS},
|
||||||
{"test_get_type_name", test_get_type_name, METH_NOARGS},
|
{"test_get_type_name", test_get_type_name, METH_NOARGS},
|
||||||
{"test_get_type_qualname", test_get_type_qualname, METH_NOARGS},
|
{"test_get_type_qualname", test_get_type_qualname, METH_NOARGS},
|
||||||
|
{"test_get_type_dict", test_get_type_dict, METH_NOARGS},
|
||||||
{"_test_thread_state", test_thread_state, METH_VARARGS},
|
{"_test_thread_state", test_thread_state, METH_VARARGS},
|
||||||
#ifndef MS_WINDOWS
|
#ifndef MS_WINDOWS
|
||||||
{"_spawn_pthread_waiter", spawn_pthread_waiter, METH_NOARGS},
|
{"_spawn_pthread_waiter", spawn_pthread_waiter, METH_NOARGS},
|
||||||
|
|
|
@ -237,6 +237,13 @@ _PyType_GetDict(PyTypeObject *self)
|
||||||
return lookup_tp_dict(self);
|
return lookup_tp_dict(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
PyType_GetDict(PyTypeObject *self)
|
||||||
|
{
|
||||||
|
PyObject *dict = lookup_tp_dict(self);
|
||||||
|
return _Py_XNewRef(dict);
|
||||||
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
set_tp_dict(PyTypeObject *self, PyObject *dict)
|
set_tp_dict(PyTypeObject *self, PyObject *dict)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue