diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h index 27c6c8731cb3f9..bbf8544b09f0fb 100644 --- a/Include/internal/pycore_typeobject.h +++ b/Include/internal/pycore_typeobject.h @@ -143,6 +143,11 @@ extern PyTypeObject _PyBufferWrapper_Type; extern 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/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index 11dec031d3d79f..3298b5ad38c191 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -1098,6 +1098,21 @@ class Data(_testcapi.ObjExtraData): del d.extra self.assertIsNone(d.extra) + def test_get_type_module_name(self): + from collections import OrderedDict + ht = _testcapi.get_heaptype_for_name() + for cls, expected in { + int: 'builtins', + OrderedDict: 'collections', + ht: '_testcapi', + }.items(): + with self.subTest(repr(cls)): + modname = _testinternalcapi.get_type_module_name(cls) + self.assertEqual(modname, expected) + + ht.__module__ = 'test_module' + modname = _testinternalcapi.get_type_module_name(ht) + self.assertEqual(modname, 'test_module') @requires_limited_api class TestHeapTypeRelative(unittest.TestCase): diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 300025ce3705fe..62db3c372da9e2 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -569,6 +569,12 @@ static PyType_Spec HeapTypeNameType_Spec = { .slots = HeapTypeNameType_slots, }; +static PyObject * +get_heaptype_for_name(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return PyType_FromSpec(&HeapTypeNameType_Spec); +} + static PyObject * test_get_type_name(PyObject *self, PyObject *Py_UNUSED(ignored)) { @@ -3210,6 +3216,7 @@ static PyMethodDef TestMethods[] = { {"py_buildvalue_ints", py_buildvalue_ints, METH_VARARGS}, {"test_buildvalue_N", test_buildvalue_N, METH_NOARGS}, {"test_get_statictype_slots", test_get_statictype_slots, METH_NOARGS}, + {"get_heaptype_for_name", get_heaptype_for_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_dict", test_get_type_dict, METH_NOARGS}, diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index 7dba29a54d79b7..ca435f27a64b43 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -27,6 +27,7 @@ #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() @@ -1608,6 +1609,14 @@ 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 PyMethodDef module_functions[] = { {"get_configs", get_configs, METH_NOARGS}, {"get_recursion_depth", get_recursion_depth, METH_NOARGS}, @@ -1669,6 +1678,7 @@ 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}, {NULL, NULL} /* sentinel */ }; diff --git a/Objects/typeobject.c b/Objects/typeobject.c index f44e30cf0446a5..cb7bd78519a6e3 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4560,6 +4560,12 @@ PyType_GetQualName(PyTypeObject *type) return type_qualname(type, NULL); } +PyObject * +_PyType_GetModuleName(PyTypeObject *type) +{ + return type_module(type, NULL); +} + void * PyType_GetSlot(PyTypeObject *type, int slot) {
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: