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

Commit50923bf

Browse files
committed
gh-111696: Add %T format to PyUnicode_FromFormat()
* Add "%T" and "%#T" formats to PyUnicode_FromFormat().* Add type.__fullyqualname__ read-only attribute.
1 parentf62c7cc commit50923bf

File tree

11 files changed

+171
-22
lines changed

11 files changed

+171
-22
lines changed

‎Doc/c-api/unicode.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,8 @@ APIs:
423423
| ``-``| The converted value is left adjusted (overrides the ``0``|
424424
|| flag if both are given).|
425425
+-------+-------------------------------------------------------------+
426+
| ``#``| Alternate form|
427+
+-------+-------------------------------------------------------------+
426428
427429
The length modifiers for following integer conversions (``d``, ``i``,
428430
``o``, ``u``, ``x``, or ``X``) specify the type of the argument
@@ -518,6 +520,17 @@ APIs:
518520
- :c:expr:`PyObject*`
519521
- The result of calling :c:func:`PyObject_Repr`.
520522
523+
* - ``T``
524+
- :c:expr:`PyObject*`
525+
- Get the name of an object type (``type.__name__``): the result of calling
526+
``PyType_GetName(Py_TYPE(obj))``.
527+
528+
* - ``#T``
529+
- :c:expr:`PyObject*`
530+
- Get the fully qualified name of an object type
531+
(:attr:`class.__fullyqualname__`): the result of calling
532+
``PyObject_GetAttrString(Py_TYPE(obj),"__fullyqualname__")``.
533+
521534
..note::
522535
The width formatter unit is number of characters rather than bytes.
523536
The precision formatter unit is number of bytes or:c:type:`wchar_t`
@@ -553,6 +566,9 @@ APIs:
553566
In previous versions it caused all the rest of the format string to be
554567
copied as-is to the result string, and any extra arguments discarded.
555568
569+
.. versionchanged:: 3.13
570+
Support for ``"%T"`` and ``"%#T"`` added.
571+
556572
557573
.. c:function:: PyObject* PyUnicode_FromFormatV(const char *format, va_list vargs)
558574

‎Doc/library/stdtypes.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5493,6 +5493,16 @@ types, where they are relevant. Some of these are not reported by the
54935493
..versionadded::3.3
54945494

54955495

5496+
..attribute::class.__fullyqualname__
5497+
5498+
The fully qualified name of the class instance:
5499+
``f"{class.__module__}.{class.__qualname__}"``, or
5500+
``f"{class.__qualname__}"`` if ``class.__module__`` is equal to
5501+
``"builtins"``.
5502+
5503+
..versionadded::3.13
5504+
5505+
54965506
..attribute::definition.__type_params__
54975507

54985508
The:ref:`type parameters<type-params>` of generic classes, functions,

‎Doc/library/string.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,20 @@ The available presentation types for :class:`float` and
588588
|| as altered by the other format modifiers.|
589589
+---------+----------------------------------------------------------+
590590

591+
The available presentation types for:class:`type` values are:
592+
593+
+----------+----------------------------------------------------------+
594+
| Type| Meaning|
595+
+==========+==========================================================+
596+
| ``'T'``| Format the type name (``type.__name__``).|
597+
+----------+----------------------------------------------------------+
598+
| ``'#T'``| Format the type fully qualified name|
599+
|| (:attr:`class.__fullyqualname__`).|
600+
+----------+----------------------------------------------------------+
601+
602+
..versionchanged::3.13
603+
Add ``T`` and ``T#`` formats for:class:`type` values.
604+
591605

592606
.. _formatexamples:
593607

‎Doc/whatsnew/3.13.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,11 @@ Other Language Changes
125125
equivalent of the:option:`-X frozen_modules <-X>` command-line option.
126126
(Contributed by Yilei Yang in:gh:`111374`.)
127127

128+
* Add:attr:`__fullyqualname__ <class.__fullyqualname__>` read-only attribute
129+
to types: the fully qualified type name.
130+
(Contributed by Victor Stinner in:gh:`111696`.)
131+
132+
128133
New Modules
129134
===========
130135

@@ -1127,6 +1132,12 @@ New Features
11271132
* Add:c:func:`PyUnicode_AsUTF8` function to the limited C API.
11281133
(Contributed by Victor Stinner in:gh:`111089`.)
11291134

1135+
* Add support for ``"%T"`` and ``"%#T"`` formats to
1136+
:c:func:`PyUnicode_FromFormat`: ``"%T"`` formats the name of an object type
1137+
(``type.__name__``) and ``"%#T"`` formats the fully qualifed name of an
1138+
object type (:attr:`class.__fullyqualname__`).
1139+
(Contributed by Victor Stinner in:gh:`111696`.)
1140+
11301141

11311142
Porting to Python 3.13
11321143
----------------------

‎Include/internal/pycore_typeobject.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,10 @@ extern PyTypeObject _PyBufferWrapper_Type;
143143
externPyObject*_PySuper_Lookup(PyTypeObject*su_type,PyObject*su_obj,
144144
PyObject*name,int*meth_found);
145145

146+
externPyObject*_PyType_GetFullyQualName(
147+
PyTypeObject*type,
148+
intignore_module_error);
149+
146150
#ifdef__cplusplus
147151
}
148152
#endif

‎Lib/test/test_builtin.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2430,6 +2430,7 @@ def test_new_type(self):
24302430
self.assertEqual(A.__name__,'A')
24312431
self.assertEqual(A.__qualname__,'A')
24322432
self.assertEqual(A.__module__,__name__)
2433+
self.assertEqual(A.__fullyqualname__,f'{__name__}.A')
24332434
self.assertEqual(A.__bases__, (object,))
24342435
self.assertIs(A.__base__,object)
24352436
x=A()
@@ -2443,6 +2444,7 @@ def ham(self):
24432444
self.assertEqual(C.__name__,'C')
24442445
self.assertEqual(C.__qualname__,'C')
24452446
self.assertEqual(C.__module__,__name__)
2447+
self.assertEqual(C.__fullyqualname__,f'{__name__}.C')
24462448
self.assertEqual(C.__bases__, (B,int))
24472449
self.assertIs(C.__base__,int)
24482450
self.assertIn('spam',C.__dict__)
@@ -2468,6 +2470,7 @@ def test_type_name(self):
24682470
self.assertEqual(A.__name__,name)
24692471
self.assertEqual(A.__qualname__,name)
24702472
self.assertEqual(A.__module__,__name__)
2473+
self.assertEqual(A.__fullyqualname__,f'{__name__}.{name}')
24712474
withself.assertRaises(ValueError):
24722475
type('A\x00B', (), {})
24732476
withself.assertRaises(UnicodeEncodeError):
@@ -2482,6 +2485,7 @@ def test_type_name(self):
24822485
self.assertEqual(C.__name__,name)
24832486
self.assertEqual(C.__qualname__,'C')
24842487
self.assertEqual(C.__module__,__name__)
2488+
self.assertEqual(C.__fullyqualname__,f'{__name__}.C')
24852489

24862490
A=type('C', (), {})
24872491
withself.assertRaises(ValueError):
@@ -2499,13 +2503,15 @@ def test_type_qualname(self):
24992503
self.assertEqual(A.__name__,'A')
25002504
self.assertEqual(A.__qualname__,'B.C')
25012505
self.assertEqual(A.__module__,__name__)
2506+
self.assertEqual(A.__fullyqualname__,f'{__name__}.B.C')
25022507
withself.assertRaises(TypeError):
25032508
type('A', (), {'__qualname__':b'B'})
25042509
self.assertEqual(A.__qualname__,'B.C')
25052510

25062511
A.__qualname__='D.E'
25072512
self.assertEqual(A.__name__,'A')
25082513
self.assertEqual(A.__qualname__,'D.E')
2514+
self.assertEqual(A.__fullyqualname__,f'{__name__}.D.E')
25092515
withself.assertRaises(TypeError):
25102516
A.__qualname__=b'B'
25112517
self.assertEqual(A.__qualname__,'D.E')

‎Lib/test/test_capi/test_unicode.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,24 @@ def check_format(expected, format, *args):
584584
check_format('xyz',
585585
b'%V',None,b'xyz')
586586

587+
# test %T and %#T
588+
check_format('type: str',
589+
b'type: %T','abc')
590+
check_format('type: str',
591+
b'type: %#T','abc')
592+
classLocalType:
593+
pass
594+
obj=LocalType()
595+
name='LocalType'
596+
check_format(f'type:{name}',
597+
b'type: %T',py_object(obj))
598+
check_format(f'type:{name[:3]}',
599+
b'type: %.3T',py_object(obj))
600+
check_format(f'type:{name.rjust(20)}',
601+
b'type: %20T',py_object(obj))
602+
check_format(f'type:{LocalType.__module__}.{LocalType.__qualname__}',
603+
b'type: %#T',py_object(obj))
604+
587605
# test %ls
588606
check_format('abc',b'%ls',c_wchar_p('abc'))
589607
check_format('\u4eba\u6c11',b'%ls',c_wchar_p('\u4eba\u6c11'))
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Add support for ``"%T"`` and ``"%#T"`` formats to
2+
:c:func:`PyUnicode_FromFormat`: ``"%T"`` formats the name of an object type
3+
(``type.__name__``) and ``"%#T"`` formats the fully qualifed name of an object
4+
type (:attr:`class.__fullyqualname__`). Patch by Victor Stinner.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Add:attr:`__fullyqualname__ <class.__fullyqualname__>` read-only attribute
2+
to types: the fully qualified type name. Patch by Victor Stinner.

‎Objects/typeobject.c

Lines changed: 62 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1036,6 +1036,12 @@ type_qualname(PyTypeObject *type, void *context)
10361036
}
10371037
}
10381038

1039+
staticPyObject*
1040+
type_fullyqualname(PyTypeObject*type,void*context)
1041+
{
1042+
return_PyType_GetFullyQualName(type,0);
1043+
}
1044+
10391045
staticint
10401046
type_set_name(PyTypeObject*type,PyObject*value,void*context)
10411047
{
@@ -1598,6 +1604,7 @@ type___subclasscheck___impl(PyTypeObject *self, PyObject *subclass)
15981604
staticPyGetSetDeftype_getsets[]= {
15991605
{"__name__", (getter)type_name, (setter)type_set_name,NULL},
16001606
{"__qualname__", (getter)type_qualname, (setter)type_set_qualname,NULL},
1607+
{"__fullyqualname__", (getter)type_fullyqualname,NULL,NULL},
16011608
{"__bases__", (getter)type_get_bases, (setter)type_set_bases,NULL},
16021609
{"__mro__", (getter)type_get_mro,NULL,NULL},
16031610
{"__module__", (getter)type_module, (setter)type_set_module,NULL},
@@ -1615,33 +1622,18 @@ static PyObject *
16151622
type_repr(PyTypeObject*type)
16161623
{
16171624
if (type->tp_name==NULL) {
1618-
// type_repr() called before the type is fully initialized
1619-
// by PyType_Ready().
1625+
//Iftype_repr() is called before the type is fully initialized
1626+
// by PyType_Ready(), just format the type memory address.
16201627
returnPyUnicode_FromFormat("<class at %p>",type);
16211628
}
16221629

1623-
PyObject*mod,*name,*rtn;
1624-
1625-
mod=type_module(type,NULL);
1626-
if (mod==NULL)
1627-
PyErr_Clear();
1628-
elseif (!PyUnicode_Check(mod)) {
1629-
Py_SETREF(mod,NULL);
1630-
}
1631-
name=type_qualname(type,NULL);
1632-
if (name==NULL) {
1633-
Py_XDECREF(mod);
1630+
PyObject*fullqualname=_PyType_GetFullyQualName(type,1);
1631+
if (fullqualname==NULL) {
16341632
returnNULL;
16351633
}
1636-
1637-
if (mod!=NULL&& !_PyUnicode_Equal(mod,&_Py_ID(builtins)))
1638-
rtn=PyUnicode_FromFormat("<class '%U.%U'>",mod,name);
1639-
else
1640-
rtn=PyUnicode_FromFormat("<class '%s'>",type->tp_name);
1641-
1642-
Py_XDECREF(mod);
1643-
Py_DECREF(name);
1644-
returnrtn;
1634+
PyObject*result=PyUnicode_FromFormat("<class '%U'>",fullqualname);
1635+
Py_DECREF(fullqualname);
1636+
returnresult;
16451637
}
16461638

16471639
staticPyObject*
@@ -4560,6 +4552,53 @@ PyType_GetQualName(PyTypeObject *type)
45604552
returntype_qualname(type,NULL);
45614553
}
45624554

4555+
4556+
PyObject*
4557+
_PyType_GetFullyQualName(PyTypeObject*type,intignore_module_error)
4558+
{
4559+
// type is a static type and PyType_Ready() was not called on it yet?
4560+
if (type->tp_name==NULL) {
4561+
PyErr_SetString(PyExc_TypeError,"static type not initialized");
4562+
returnNULL;
4563+
}
4564+
4565+
if (!(type->tp_flags&Py_TPFLAGS_HEAPTYPE)) {
4566+
// Static type
4567+
returnPyUnicode_FromString(type->tp_name);
4568+
}
4569+
4570+
PyObject*qualname=type_qualname(type,NULL);
4571+
if (qualname==NULL) {
4572+
returnNULL;
4573+
}
4574+
4575+
PyObject*module=type_module(type,NULL);
4576+
if (module==NULL) {
4577+
if (ignore_module_error) {
4578+
// type_repr() ignores type_module() errors
4579+
PyErr_Clear();
4580+
returnqualname;
4581+
}
4582+
4583+
Py_DECREF(qualname);
4584+
returnNULL;
4585+
}
4586+
4587+
PyObject*result;
4588+
if (PyUnicode_Check(module)
4589+
&& !_PyUnicode_Equal(module,&_Py_ID(builtins)))
4590+
{
4591+
result=PyUnicode_FromFormat("%U.%U",module,qualname);
4592+
}
4593+
else {
4594+
result=Py_NewRef(qualname);
4595+
}
4596+
Py_DECREF(module);
4597+
Py_DECREF(qualname);
4598+
returnresult;
4599+
}
4600+
4601+
45634602
void*
45644603
PyType_GetSlot(PyTypeObject*type,intslot)
45654604
{
@@ -5250,6 +5289,7 @@ type___sizeof___impl(PyTypeObject *self)
52505289
returnPyLong_FromSize_t(size);
52515290
}
52525291

5292+
52535293
staticPyMethodDeftype_methods[]= {
52545294
TYPE_MRO_METHODDEF
52555295
TYPE___SUBCLASSES___METHODDEF

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp