From 2bb71f50a02edc3acb526baa03f3059159da3add Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 14 Mar 2024 19:17:43 +0100 Subject: [PATCH] gh-111696, PEP 737: Add PyType_GetModuleName() function (#116824) Co-authored-by: Eric Snow --- Doc/c-api/type.rst | 7 +++++++ Doc/data/stable_abi.dat | 1 + Doc/whatsnew/3.13.rst | 4 ++++ Include/internal/pycore_typeobject.h | 4 ---- Include/object.h | 3 ++- Lib/test/test_capi/test_misc.py | 5 +++-- Lib/test/test_stable_abi_ctypes.py | 1 + ...-03-14-18-00-32.gh-issue-111696.L6oIPq.rst | 3 +++ Misc/stable_abi.toml | 2 ++ Modules/_functoolsmodule.c | 2 +- Modules/_testcapimodule.c | 9 ++++++++ Modules/_testinternalcapi.c | 9 -------- Objects/typeobject.c | 21 ++++++++++++------- PC/python3dll.c | 1 + Python/crossinterp.c | 3 +-- 15 files changed, 48 insertions(+), 27 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2024-03-14-18-00-32.gh-issue-111696.L6oIPq.rst diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst index c5234233ba7124a..0cae5c09505ebe1 100644 --- a/Doc/c-api/type.rst +++ b/Doc/c-api/type.rst @@ -193,6 +193,13 @@ Type Objects .. versionadded:: 3.13 +.. c:function:: PyObject* PyType_GetModuleName(PyTypeObject *type) + + Return the type's module name. Equivalent to getting the ``type.__module__`` + attribute. + + .. versionadded:: 3.13 + .. c:function:: void* PyType_GetSlot(PyTypeObject *type, int slot) Return the function pointer stored in the given slot. If the diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat index 03fe3cef3843b68..9d0ad3d036dac34 100644 --- a/Doc/data/stable_abi.dat +++ b/Doc/data/stable_abi.dat @@ -679,6 +679,7 @@ function,PyType_GenericNew,3.2,, function,PyType_GetFlags,3.2,, function,PyType_GetFullyQualifiedName,3.13,, function,PyType_GetModule,3.10,, +function,PyType_GetModuleName,3.13,, function,PyType_GetModuleState,3.10,, function,PyType_GetName,3.11,, function,PyType_GetQualName,3.11,, diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index cbb5e02aef1ce3e..f42197c001f18f6 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -1664,6 +1664,10 @@ New Features to ``"builtins"``. (Contributed by Victor Stinner in :gh:`111696`.) +* Add :c:func:`PyType_GetModuleName` function to get the type's module name. + Equivalent to getting the ``type.__module__`` attribute. + (Contributed by Eric Snow and Victor Stinner in :gh:`111696`.) + Porting to Python 3.13 ---------------------- diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h index c214111fed6f97a..5c32d49e85c97b7 100644 --- a/Include/internal/pycore_typeobject.h +++ b/Include/internal/pycore_typeobject.h @@ -151,10 +151,6 @@ PyAPI_FUNC(PyObject*) _PySuper_Lookup(PyTypeObject *su_type, PyObject *su_obj, PyObject *name, int *meth_found); -// This is exported for the _testinternalcapi module. -PyAPI_FUNC(PyObject *) _PyType_GetModuleName(PyTypeObject *); - - #ifdef __cplusplus } #endif diff --git a/Include/object.h b/Include/object.h index 3f6f1ab1e68cc66..34141af7b7f7ef7 100644 --- a/Include/object.h +++ b/Include/object.h @@ -523,7 +523,8 @@ PyAPI_FUNC(PyObject *) PyType_GetName(PyTypeObject *); PyAPI_FUNC(PyObject *) PyType_GetQualName(PyTypeObject *); #endif #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030D0000 -PyAPI_FUNC(PyObject *) PyType_GetFullyQualifiedName(PyTypeObject *); +PyAPI_FUNC(PyObject *) PyType_GetFullyQualifiedName(PyTypeObject *type); +PyAPI_FUNC(PyObject *) PyType_GetModuleName(PyTypeObject *type); #endif #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030C0000 PyAPI_FUNC(PyObject *) PyType_FromMetaclass(PyTypeObject*, PyObject*, PyType_Spec*, PyObject*); diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index 6b4f535cc6550a0..eb0bc13911701a7 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -1104,8 +1104,9 @@ def test_get_type_name(self): class MyType: pass - from _testcapi import get_type_name, get_type_qualname, get_type_fullyqualname - from _testinternalcapi import get_type_module_name + from _testcapi import ( + get_type_name, get_type_qualname, + get_type_fullyqualname, get_type_module_name) from collections import OrderedDict ht = _testcapi.get_heaptype_for_name() diff --git a/Lib/test/test_stable_abi_ctypes.py b/Lib/test/test_stable_abi_ctypes.py index f0b449ac1708a18..117c27d27b38dcb 100644 --- a/Lib/test/test_stable_abi_ctypes.py +++ b/Lib/test/test_stable_abi_ctypes.py @@ -708,6 +708,7 @@ def test_windows_feature_macros(self): "PyType_GetFlags", "PyType_GetFullyQualifiedName", "PyType_GetModule", + "PyType_GetModuleName", "PyType_GetModuleState", "PyType_GetName", "PyType_GetQualName", diff --git a/Misc/NEWS.d/next/C API/2024-03-14-18-00-32.gh-issue-111696.L6oIPq.rst b/Misc/NEWS.d/next/C API/2024-03-14-18-00-32.gh-issue-111696.L6oIPq.rst new file mode 100644 index 000000000000000..7973d7b16e5826b --- /dev/null +++ b/Misc/NEWS.d/next/C API/2024-03-14-18-00-32.gh-issue-111696.L6oIPq.rst @@ -0,0 +1,3 @@ +Add :c:func:`PyType_GetModuleName` function to get the type's module name. +Equivalent to getting the ``type.__module__`` attribute. Patch by Eric Snow +and Victor Stinner. diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml index c76a3cea4da3f7c..c68adf8db079f99 100644 --- a/Misc/stable_abi.toml +++ b/Misc/stable_abi.toml @@ -2498,3 +2498,5 @@ # "abi-only" since 3.10. (Same story as PyCFunctionFast.) [function.PyType_GetFullyQualifiedName] added = '3.13' +[function.PyType_GetModuleName] + added = '3.13' diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c index d2212d40550a3c7..f23b6e0d62bfb1b 100644 --- a/Modules/_functoolsmodule.c +++ b/Modules/_functoolsmodule.c @@ -402,7 +402,7 @@ partial_repr(partialobject *pto) goto done; } - mod = _PyType_GetModuleName(Py_TYPE(pto)); + mod = PyType_GetModuleName(Py_TYPE(pto)); if (mod == NULL) { goto error; } diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 07f96466abdfc90..7928cd7d6fe1aeb 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -622,6 +622,14 @@ get_type_fullyqualname(PyObject *self, PyObject *type) } +static PyObject * +get_type_module_name(PyObject *self, PyObject *type) +{ + assert(PyType_Check(type)); + return PyType_GetModuleName((PyTypeObject *)type); +} + + static PyObject * test_get_type_dict(PyObject *self, PyObject *Py_UNUSED(ignored)) { @@ -3268,6 +3276,7 @@ static PyMethodDef TestMethods[] = { {"get_type_name", get_type_name, METH_O}, {"get_type_qualname", get_type_qualname, METH_O}, {"get_type_fullyqualname", get_type_fullyqualname, METH_O}, + {"get_type_module_name", get_type_module_name, METH_O}, {"test_get_type_dict", test_get_type_dict, METH_NOARGS}, {"_test_thread_state", test_thread_state, METH_VARARGS}, #ifndef MS_WINDOWS diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index db8817418950b92..b3076a8f548b621 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -28,7 +28,6 @@ #include "pycore_pathconfig.h" // _PyPathConfig_ClearGlobal() #include "pycore_pyerrors.h" // _PyErr_ChainExceptions1() #include "pycore_pystate.h" // _PyThreadState_GET() -#include "pycore_typeobject.h" // _PyType_GetModuleName() #include "interpreteridobject.h" // PyInterpreterID_LookUp() @@ -1631,13 +1630,6 @@ perf_trampoline_set_persist_after_fork(PyObject *self, PyObject *args) } -static PyObject * -get_type_module_name(PyObject *self, PyObject *type) -{ - assert(PyType_Check(type)); - return _PyType_GetModuleName((PyTypeObject *)type); -} - static PyObject * get_rare_event_counters(PyObject *self, PyObject *type) { @@ -1741,7 +1733,6 @@ static PyMethodDef module_functions[] = { {"get_crossinterp_data", get_crossinterp_data, METH_VARARGS}, {"restore_crossinterp_data", restore_crossinterp_data, METH_VARARGS}, _TESTINTERNALCAPI_TEST_LONG_NUMBITS_METHODDEF - {"get_type_module_name", get_type_module_name, METH_O}, {"get_rare_event_counters", get_rare_event_counters, METH_NOARGS}, {"reset_rare_event_counters", reset_rare_event_counters, METH_NOARGS}, #ifdef Py_GIL_DISABLED diff --git a/Objects/typeobject.c b/Objects/typeobject.c index e51adac7e9d6368..1c5729c589da938 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -1164,10 +1164,9 @@ type_set_qualname(PyTypeObject *type, PyObject *value, void *context) } static PyObject * -type_module(PyTypeObject *type, void *context) +type_module(PyTypeObject *type) { PyObject *mod; - if (type->tp_flags & Py_TPFLAGS_HEAPTYPE) { PyObject *dict = lookup_tp_dict(type); if (PyDict_GetItemRef(dict, &_Py_ID(__module__), &mod) == 0) { @@ -1189,6 +1188,12 @@ type_module(PyTypeObject *type, void *context) return mod; } +static PyObject * +type_get_module(PyTypeObject *type, void *context) +{ + return type_module(type); +} + static int type_set_module(PyTypeObject *type, PyObject *value, void *context) { @@ -1214,7 +1219,7 @@ PyType_GetFullyQualifiedName(PyTypeObject *type) return NULL; } - PyObject *module = type_module(type, NULL); + PyObject *module = type_module(type); if (module == NULL) { Py_DECREF(qualname); return NULL; @@ -1722,7 +1727,7 @@ static PyGetSetDef type_getsets[] = { {"__qualname__", (getter)type_qualname, (setter)type_set_qualname, NULL}, {"__bases__", (getter)type_get_bases, (setter)type_set_bases, NULL}, {"__mro__", (getter)type_get_mro, NULL, NULL}, - {"__module__", (getter)type_module, (setter)type_set_module, NULL}, + {"__module__", (getter)type_get_module, (setter)type_set_module, NULL}, {"__abstractmethods__", (getter)type_abstractmethods, (setter)type_set_abstractmethods, NULL}, {"__dict__", (getter)type_dict, NULL, NULL}, @@ -1743,7 +1748,7 @@ type_repr(PyObject *self) return PyUnicode_FromFormat("", type); } - PyObject *mod = type_module(type, NULL); + PyObject *mod = type_module(type); if (mod == NULL) { PyErr_Clear(); } @@ -4734,9 +4739,9 @@ PyType_GetQualName(PyTypeObject *type) } PyObject * -_PyType_GetModuleName(PyTypeObject *type) +PyType_GetModuleName(PyTypeObject *type) { - return type_module(type, NULL); + return type_module(type); } void * @@ -5850,7 +5855,7 @@ object_repr(PyObject *self) PyObject *mod, *name, *rtn; type = Py_TYPE(self); - mod = type_module(type, NULL); + mod = type_module(type); if (mod == NULL) PyErr_Clear(); else if (!PyUnicode_Check(mod)) { diff --git a/PC/python3dll.c b/PC/python3dll.c index 81d55af70743839..dbfa3f23bb586df 100755 --- a/PC/python3dll.c +++ b/PC/python3dll.c @@ -639,6 +639,7 @@ EXPORT_FUNC(PyType_GenericNew) EXPORT_FUNC(PyType_GetFlags) EXPORT_FUNC(PyType_GetFullyQualifiedName) EXPORT_FUNC(PyType_GetModule) +EXPORT_FUNC(PyType_GetModuleName) EXPORT_FUNC(PyType_GetModuleState) EXPORT_FUNC(PyType_GetName) EXPORT_FUNC(PyType_GetQualName) diff --git a/Python/crossinterp.c b/Python/crossinterp.c index 143b261f9a53960..18dec4dd9590443 100644 --- a/Python/crossinterp.c +++ b/Python/crossinterp.c @@ -7,7 +7,6 @@ #include "pycore_initconfig.h" // _PyStatus_OK() #include "pycore_namespace.h" //_PyNamespace_New() #include "pycore_pyerrors.h" // _PyErr_Clear() -#include "pycore_typeobject.h" // _PyType_GetModuleName() #include "pycore_weakref.h" // _PyWeakref_GET_REF() @@ -510,7 +509,7 @@ _excinfo_init_type(struct _excinfo_type *info, PyObject *exc) } // __module__ - strobj = _PyType_GetModuleName(type); + strobj = PyType_GetModuleName(type); if (strobj == NULL) { return -1; }