Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitfb705ba

Browse files
committed
gh-111696, PEP 737: Add PyType_GetFullyQualifiedName() function
Rewrite tests on type names in Python, they were written in C.
1 parenta76288a commitfb705ba

File tree

11 files changed

+158
-102
lines changed

11 files changed

+158
-102
lines changed

‎Doc/c-api/type.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,14 @@ Type Objects
185185
186186
..versionadded::3.11
187187
188+
..c:function:: PyObject*PyType_GetFullyQualifiedName(PyTypeObject *type)
189+
190+
Return the type's fully qualified name. Equivalent to
191+
``f"{type.__module__}.{type.__qualname__}"``, or ``type.__qualname__`` if
192+
``type.__module__`` is not a string or is equal to ``"builtins"``.
193+
194+
..versionadded::3.13
195+
188196
..c:function::void*PyType_GetSlot(PyTypeObject *type, int slot)
189197
190198
Return the function pointer stored in the given slot. If the

‎Doc/data/stable_abi.dat

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎Doc/whatsnew/3.13.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1649,6 +1649,12 @@ New Features
16491649
between native integer types and Python:class:`int` objects.
16501650
(Contributed by Steve Dower in:gh:`111140`.)
16511651

1652+
* Add:c:func:`PyType_GetFullyQualifiedName` function to get the type's fully
1653+
qualified name. Equivalent to ``f"{type.__module__}.{type.__qualname__}"``,
1654+
or ``type.__qualname__`` if ``type.__module__`` is not a string or is equal
1655+
to ``"builtins"``.
1656+
(Contributed by Victor Stinner in:gh:`111696`.)
1657+
16521658

16531659
Porting to Python 3.13
16541660
----------------------

‎Include/object.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,9 @@ PyAPI_FUNC(void *) PyType_GetModuleState(PyTypeObject *);
522522
PyAPI_FUNC(PyObject*)PyType_GetName(PyTypeObject*);
523523
PyAPI_FUNC(PyObject*)PyType_GetQualName(PyTypeObject*);
524524
#endif
525+
#if !defined(Py_LIMITED_API)||Py_LIMITED_API+0 >=0x030D0000
526+
PyAPI_FUNC(PyObject*)PyType_GetFullyQualifiedName(PyTypeObject*);
527+
#endif
525528
#if !defined(Py_LIMITED_API)||Py_LIMITED_API+0 >=0x030C0000
526529
PyAPI_FUNC(PyObject*)PyType_FromMetaclass(PyTypeObject*,PyObject*,PyType_Spec*,PyObject*);
527530
PyAPI_FUNC(void*)PyObject_GetTypeData(PyObject*obj,PyTypeObject*cls);

‎Lib/test/test_capi/test_misc.py

Lines changed: 55 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1100,21 +1100,65 @@ class Data(_testcapi.ObjExtraData):
11001100
deld.extra
11011101
self.assertIsNone(d.extra)
11021102

1103-
deftest_get_type_module_name(self):
1103+
deftest_get_type_name(self):
1104+
classMyType:
1105+
pass
1106+
1107+
from_testcapiimportget_type_name,get_type_qualname,get_type_fullyqualname
1108+
from_testinternalcapiimportget_type_module_name
1109+
11041110
fromcollectionsimportOrderedDict
11051111
ht=_testcapi.get_heaptype_for_name()
1106-
forcls,expectedin {
1107-
int:'builtins',
1108-
OrderedDict:'collections',
1109-
ht:'_testcapi',
1110-
}.items():
1111-
withself.subTest(repr(cls)):
1112-
modname=_testinternalcapi.get_type_module_name(cls)
1113-
self.assertEqual(modname,expected)
1112+
forcls,fullname,modname,qualname,namein (
1113+
(int,
1114+
'int',
1115+
'builtins',
1116+
'int',
1117+
'int'),
1118+
(OrderedDict,
1119+
'collections.OrderedDict',
1120+
'collections',
1121+
'OrderedDict',
1122+
'OrderedDict'),
1123+
(ht,
1124+
'_testcapi.HeapTypeNameType',
1125+
'_testcapi',
1126+
'HeapTypeNameType',
1127+
'HeapTypeNameType'),
1128+
(MyType,
1129+
f'{__name__}.CAPITest.test_get_type_name.<locals>.MyType',
1130+
__name__,
1131+
'CAPITest.test_get_type_name.<locals>.MyType',
1132+
'MyType'),
1133+
):
1134+
withself.subTest(cls=repr(cls)):
1135+
self.assertEqual(get_type_fullyqualname(cls),fullname)
1136+
self.assertEqual(get_type_module_name(cls),modname)
1137+
self.assertEqual(get_type_qualname(cls),qualname)
1138+
self.assertEqual(get_type_name(cls),name)
11141139

1140+
# override __module__
11151141
ht.__module__='test_module'
1116-
modname=_testinternalcapi.get_type_module_name(ht)
1117-
self.assertEqual(modname,'test_module')
1142+
self.assertEqual(get_type_fullyqualname(ht),'test_module.HeapTypeNameType')
1143+
self.assertEqual(get_type_module_name(ht),'test_module')
1144+
self.assertEqual(get_type_qualname(ht),'HeapTypeNameType')
1145+
self.assertEqual(get_type_name(ht),'HeapTypeNameType')
1146+
1147+
# override __name__ and __qualname__
1148+
MyType.__name__='my_name'
1149+
MyType.__qualname__='my_qualname'
1150+
self.assertEqual(get_type_fullyqualname(MyType),f'{__name__}.my_qualname')
1151+
self.assertEqual(get_type_module_name(MyType),__name__)
1152+
self.assertEqual(get_type_qualname(MyType),'my_qualname')
1153+
self.assertEqual(get_type_name(MyType),'my_name')
1154+
1155+
# override also __module__
1156+
MyType.__module__='my_module'
1157+
self.assertEqual(get_type_fullyqualname(MyType),'my_module.my_qualname')
1158+
self.assertEqual(get_type_module_name(MyType),'my_module')
1159+
self.assertEqual(get_type_qualname(MyType),'my_qualname')
1160+
self.assertEqual(get_type_name(MyType),'my_name')
1161+
11181162

11191163
@requires_limited_api
11201164
classTestHeapTypeRelative(unittest.TestCase):

‎Lib/test/test_stable_abi_ctypes.py

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Add:c:func:`PyType_GetFullyQualifiedName` function to get the type's fully
2+
qualified name. Equivalent to ``f"{type.__module__}.{type.__qualname__}"``, or
3+
``type.__qualname__`` if ``type.__module__`` is not a string or is equal to
4+
``"builtins"``. Patch by Victor Stinner.

‎Misc/stable_abi.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2496,3 +2496,5 @@
24962496
[typedef.PyCFunctionFastWithKeywords]
24972497
added ='3.13'
24982498
# "abi-only" since 3.10. (Same story as PyCFunctionFast.)
2499+
[function.PyType_GetFullyQualifiedName]
2500+
added ='3.13'

‎Modules/_testcapimodule.c

Lines changed: 17 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -597,83 +597,31 @@ get_heaptype_for_name(PyObject *self, PyObject *Py_UNUSED(ignored))
597597
returnPyType_FromSpec(&HeapTypeNameType_Spec);
598598
}
599599

600+
600601
staticPyObject*
601-
test_get_type_name(PyObject*self,PyObject*Py_UNUSED(ignored))
602+
get_type_name(PyObject*self,PyObject*type)
602603
{
603-
PyObject*tp_name=PyType_GetName(&PyLong_Type);
604-
assert(strcmp(PyUnicode_AsUTF8(tp_name),"int")==0);
605-
Py_DECREF(tp_name);
606-
607-
tp_name=PyType_GetName(&PyModule_Type);
608-
assert(strcmp(PyUnicode_AsUTF8(tp_name),"module")==0);
609-
Py_DECREF(tp_name);
610-
611-
PyObject*HeapTypeNameType=PyType_FromSpec(&HeapTypeNameType_Spec);
612-
if (HeapTypeNameType==NULL) {
613-
Py_RETURN_NONE;
614-
}
615-
tp_name=PyType_GetName((PyTypeObject*)HeapTypeNameType);
616-
assert(strcmp(PyUnicode_AsUTF8(tp_name),"HeapTypeNameType")==0);
617-
Py_DECREF(tp_name);
618-
619-
PyObject*name=PyUnicode_FromString("test_name");
620-
if (name==NULL) {
621-
gotodone;
622-
}
623-
if (PyObject_SetAttrString(HeapTypeNameType,"__name__",name)<0) {
624-
Py_DECREF(name);
625-
gotodone;
626-
}
627-
tp_name=PyType_GetName((PyTypeObject*)HeapTypeNameType);
628-
assert(strcmp(PyUnicode_AsUTF8(tp_name),"test_name")==0);
629-
Py_DECREF(name);
630-
Py_DECREF(tp_name);
631-
632-
done:
633-
Py_DECREF(HeapTypeNameType);
634-
Py_RETURN_NONE;
604+
assert(PyType_Check(type));
605+
returnPyType_GetName((PyTypeObject*)type);
635606
}
636607

637608

638609
staticPyObject*
639-
test_get_type_qualname(PyObject*self,PyObject*Py_UNUSED(ignored))
610+
get_type_qualname(PyObject*self,PyObject*type)
640611
{
641-
PyObject*tp_qualname=PyType_GetQualName(&PyLong_Type);
642-
assert(strcmp(PyUnicode_AsUTF8(tp_qualname),"int")==0);
643-
Py_DECREF(tp_qualname);
644-
645-
tp_qualname=PyType_GetQualName(&PyODict_Type);
646-
assert(strcmp(PyUnicode_AsUTF8(tp_qualname),"OrderedDict")==0);
647-
Py_DECREF(tp_qualname);
648-
649-
PyObject*HeapTypeNameType=PyType_FromSpec(&HeapTypeNameType_Spec);
650-
if (HeapTypeNameType==NULL) {
651-
Py_RETURN_NONE;
652-
}
653-
tp_qualname=PyType_GetQualName((PyTypeObject*)HeapTypeNameType);
654-
assert(strcmp(PyUnicode_AsUTF8(tp_qualname),"HeapTypeNameType")==0);
655-
Py_DECREF(tp_qualname);
612+
assert(PyType_Check(type));
613+
returnPyType_GetQualName((PyTypeObject*)type);
614+
}
656615

657-
PyObject*spec_name=PyUnicode_FromString(HeapTypeNameType_Spec.name);
658-
if (spec_name==NULL) {
659-
gotodone;
660-
}
661-
if (PyObject_SetAttrString(HeapTypeNameType,
662-
"__qualname__",spec_name)<0) {
663-
Py_DECREF(spec_name);
664-
gotodone;
665-
}
666-
tp_qualname=PyType_GetQualName((PyTypeObject*)HeapTypeNameType);
667-
assert(strcmp(PyUnicode_AsUTF8(tp_qualname),
668-
"_testcapi.HeapTypeNameType")==0);
669-
Py_DECREF(spec_name);
670-
Py_DECREF(tp_qualname);
671616

672-
done:
673-
Py_DECREF(HeapTypeNameType);
674-
Py_RETURN_NONE;
617+
staticPyObject*
618+
get_type_fullyqualname(PyObject*self,PyObject*type)
619+
{
620+
assert(PyType_Check(type));
621+
returnPyType_GetFullyQualifiedName((PyTypeObject*)type);
675622
}
676623

624+
677625
staticPyObject*
678626
test_get_type_dict(PyObject*self,PyObject*Py_UNUSED(ignored))
679627
{
@@ -3317,8 +3265,9 @@ static PyMethodDef TestMethods[] = {
33173265
{"test_buildvalue_N",test_buildvalue_N,METH_NOARGS},
33183266
{"test_get_statictype_slots",test_get_statictype_slots,METH_NOARGS},
33193267
{"get_heaptype_for_name",get_heaptype_for_name,METH_NOARGS},
3320-
{"test_get_type_name",test_get_type_name,METH_NOARGS},
3321-
{"test_get_type_qualname",test_get_type_qualname,METH_NOARGS},
3268+
{"get_type_name",get_type_name,METH_O},
3269+
{"get_type_qualname",get_type_qualname,METH_O},
3270+
{"get_type_fullyqualname",get_type_fullyqualname,METH_O},
33223271
{"test_get_type_dict",test_get_type_dict,METH_NOARGS},
33233272
{"_test_thread_state",test_thread_state,METH_VARARGS},
33243273
#ifndefMS_WINDOWS

‎Objects/typeobject.c

Lines changed: 60 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1201,6 +1201,59 @@ type_set_module(PyTypeObject *type, PyObject *value, void *context)
12011201
returnPyDict_SetItem(dict,&_Py_ID(__module__),value);
12021202
}
12031203

1204+
1205+
staticPyObject*
1206+
type_fullyqualname(PyTypeObject*type,intis_repr)
1207+
{
1208+
// type is a static type and PyType_Ready() was not called on it yet?
1209+
if (type->tp_name==NULL) {
1210+
PyErr_SetString(PyExc_TypeError,"static type not initialized");
1211+
returnNULL;
1212+
}
1213+
1214+
if (!(type->tp_flags&Py_TPFLAGS_HEAPTYPE)) {
1215+
returnPyUnicode_FromString(type->tp_name);
1216+
}
1217+
1218+
PyObject*qualname=type_qualname(type,NULL);
1219+
if (qualname==NULL) {
1220+
returnNULL;
1221+
}
1222+
1223+
PyObject*module=type_module(type,NULL);
1224+
if (module==NULL) {
1225+
if (is_repr) {
1226+
// type_repr() ignores type_module() errors
1227+
PyErr_Clear();
1228+
returnqualname;
1229+
}
1230+
1231+
Py_DECREF(qualname);
1232+
returnNULL;
1233+
}
1234+
1235+
PyObject*result;
1236+
if (PyUnicode_Check(module)
1237+
&& !_PyUnicode_Equal(module,&_Py_ID(builtins)))
1238+
{
1239+
result=PyUnicode_FromFormat("%U.%U",module,qualname);
1240+
}
1241+
else {
1242+
result=Py_NewRef(qualname);
1243+
}
1244+
Py_DECREF(module);
1245+
Py_DECREF(qualname);
1246+
returnresult;
1247+
}
1248+
1249+
1250+
PyObject*
1251+
PyType_GetFullyQualifiedName(PyTypeObject*type)
1252+
{
1253+
returntype_fullyqualname(type,0);
1254+
}
1255+
1256+
12041257
staticPyObject*
12051258
type_abstractmethods(PyTypeObject*type,void*context)
12061259
{
@@ -1699,37 +1752,21 @@ static PyGetSetDef type_getsets[] = {
16991752
};
17001753

17011754
staticPyObject*
1702-
type_repr(PyObject*self)
1755+
type_repr(PyTypeObject*type)
17031756
{
1704-
PyTypeObject*type= (PyTypeObject*)self;
17051757
if (type->tp_name==NULL) {
1706-
// type_repr() called before the type is fully initialized
1707-
// by PyType_Ready().
1758+
//Iftype_repr() is called before the type is fully initialized
1759+
// by PyType_Ready(), just format the type memory address.
17081760
returnPyUnicode_FromFormat("<class at %p>",type);
17091761
}
17101762

1711-
PyObject*mod,*name,*rtn;
1712-
1713-
mod=type_module(type,NULL);
1714-
if (mod==NULL)
1715-
PyErr_Clear();
1716-
elseif (!PyUnicode_Check(mod)) {
1717-
Py_SETREF(mod,NULL);
1718-
}
1719-
name=type_qualname(type,NULL);
1763+
PyObject*name=type_fullyqualname(type,1);
17201764
if (name==NULL) {
1721-
Py_XDECREF(mod);
17221765
returnNULL;
17231766
}
1724-
1725-
if (mod!=NULL&& !_PyUnicode_Equal(mod,&_Py_ID(builtins)))
1726-
rtn=PyUnicode_FromFormat("<class '%U.%U'>",mod,name);
1727-
else
1728-
rtn=PyUnicode_FromFormat("<class '%s'>",type->tp_name);
1729-
1730-
Py_XDECREF(mod);
1767+
PyObject*result=PyUnicode_FromFormat("<class '%U'>",name);
17311768
Py_DECREF(name);
1732-
returnrtn;
1769+
returnresult;
17331770
}
17341771

17351772
staticPyObject*
@@ -5617,7 +5654,7 @@ PyTypeObject PyType_Type = {
56175654
0,/* tp_getattr */
56185655
0,/* tp_setattr */
56195656
0,/* tp_as_async */
5620-
type_repr,/* tp_repr */
5657+
(reprfunc)type_repr,/* tp_repr */
56215658
&type_as_number,/* tp_as_number */
56225659
0,/* tp_as_sequence */
56235660
0,/* tp_as_mapping */

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp