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

gh-111696: type(str) returns the fully qualified name#112129

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Closed
vstinner wants to merge2 commits intopython:mainfromvstinner:type_str
Closed
Show file tree
Hide file tree
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletionsDoc/whatsnew/3.13.rst
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -125,6 +125,11 @@ Other Language Changes
equivalent of the :option:`-X frozen_modules <-X>` command-line option.
(Contributed by Yilei Yang in :gh:`111374`.)

* Formatting a type as a string now formats the type fully qualified name,
instead of formating its representation (`<class ...>`).
(Contributed by Victor Stinner in :gh:`111696`.)


New Modules
===========

Expand Down
2 changes: 1 addition & 1 deletionLib/dataclasses.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -849,7 +849,7 @@ def _get_field(cls, a_name, a_type, default_kw_only):
# indicator for mutability. Read the __hash__ attribute from the class,
# not the instance.
if f._field_type is _FIELD and f.default.__class__.__hash__ is None:
raise ValueError(f'mutable default {type(f.default)} for field '
raise ValueError(f'mutable default {type(f.default)!r} for field '
f'{f.name} is not allowed: use default_factory')

return f
Expand Down
2 changes: 1 addition & 1 deletionLib/enum.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -729,7 +729,7 @@ def __call__(cls, value, names=None, *values, module=None, qualname=None, type=N
if names is None and type is None:
# no body? no data-type? possibly wrong usage
raise TypeError(
f"{cls} has no members; specify `names=()` if you meant to create a new, empty, enum"
f"{cls!r} has no members; specify `names=()` if you meant to create a new, empty, enum"
)
return cls._create_(
class_name=value,
Expand Down
2 changes: 1 addition & 1 deletionLib/functools.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -793,7 +793,7 @@ def _find_impl(cls, registry):
and match not in cls.__mro__
and not issubclass(match, t)):
raise RuntimeError("Ambiguous dispatch: {} or {}".format(
match, t))
repr(match), repr(t)))
break
if t in registry:
match = t
Expand Down
2 changes: 1 addition & 1 deletionLib/idlelib/idle_test/test_searchbase.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -100,7 +100,7 @@ def test_make_frame(self):
self.dialog.frame = Frame(self.root)
frame, label = self.dialog.make_frame()
self.assertEqual(label, '')
self.assertEqual(str(type(frame)), "<class 'tkinter.ttk.Frame'>")
self.assertEqual(repr(type(frame)), "<class 'tkinter.ttk.Frame'>")
# self.assertIsInstance(frame, Frame) fails when test is run by
# test_idle not run from IDLE editor. See issue 33987 PR.

Expand Down
2 changes: 1 addition & 1 deletionLib/optparse.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -667,7 +667,7 @@ def _check_choice(self):
elif not isinstance(self.choices, (tuple, list)):
raise OptionError(
"choices must be a list of strings ('%s' supplied)"
%str(type(self.choices)).split("'")[1], self)
%repr(type(self.choices)).split("'")[1], self)
elif self.choices is not None:
raise OptionError(
"must not supply choices for type %r" % self.type, self)
Expand Down
2 changes: 1 addition & 1 deletionLib/pdb.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -1729,7 +1729,7 @@ def do_whatis(self, arg):
self.message('Class %s.%s' % (value.__module__, value.__qualname__))
return
# None of the above...
self.message(type(value))
self.message(repr(type(value)))

complete_whatis = _complete_expression

Expand Down
4 changes: 2 additions & 2 deletionsLib/test/test_cmd_line_script.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -153,7 +153,7 @@ def _check_import_error(self, script_exec_args, expected_msg,
self.assertIn(expected_msg.encode('utf-8'), err)

def test_dash_c_loader(self):
rc, out, err = assert_python_ok("-c", "print(__loader__)")
rc, out, err = assert_python_ok("-c", "print(repr(__loader__))")
expected = repr(importlib.machinery.BuiltinImporter).encode("utf-8")
self.assertIn(expected, out)

Expand All@@ -163,7 +163,7 @@ def test_stdin_loader(self):
# stdin is an interactive tty.
p = spawn_python()
try:
p.stdin.write(b"print(__loader__)\n")
p.stdin.write(b"print(repr(__loader__))\n")
p.stdin.flush()
finally:
out = kill_python(p)
Expand Down
4 changes: 2 additions & 2 deletionsLib/test/test_dataclasses/__init__.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -738,7 +738,7 @@ def test_disallowed_mutable_defaults(self):
with self.subTest(typ=typ):
# Can't use a zero-length value.
with self.assertRaisesRegex(ValueError,
f'mutable default {typ} for field '
f'mutable default {typ!r} for field '
'x is not allowed'):
@dataclass
class Point:
Expand All@@ -747,7 +747,7 @@ class Point:

# Nor a non-zero-length value
with self.assertRaisesRegex(ValueError,
f'mutable default {typ} for field '
f'mutable default {typ!r} for field '
'y is not allowed'):
@dataclass
class Point:
Expand Down
10 changes: 5 additions & 5 deletionsLib/test/test_descrtut.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -38,16 +38,16 @@ def merge(self, other):

Here's the new type at work:

>>> print(defaultdict) # show our type
>>> print(repr(defaultdict)) # show our type
<class 'test.test_descrtut.defaultdict'>
>>> print(type(defaultdict)) # its metatype
>>> print(repr(type(defaultdict))) # its metatype
<class 'type'>
>>> a = defaultdict(default=0.0) # create an instance
>>> print(a) # show the instance
{}
>>> print(type(a)) # show its type
>>> print(repr(type(a))) # show its type
<class 'test.test_descrtut.defaultdict'>
>>> print(a.__class__) # show its class
>>> print(repr(a.__class__)) # show its class
<class 'test.test_descrtut.defaultdict'>
>>> print(type(a) is a.__class__) # its type is its class
True
Expand DownExpand Up@@ -261,7 +261,7 @@ def merge(self, other):
>>> class C:
... @classmethod
... def foo(cls, y):
... print("classmethod", cls, y)
... print("classmethod",repr(cls), y)

>>> C.foo(1)
classmethod <class 'test.test_descrtut.C'> 1
Expand Down
6 changes: 3 additions & 3 deletionsLib/xmlrpc/server.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -270,7 +270,7 @@ def _marshaled_dispatch(self, data, dispatch_method = None, path = None):
encoding=self.encoding)
except BaseException as exc:
response = dumps(
Fault(1, "%s:%s" % (type(exc), exc)),
Fault(1, "%s:%s" % (repr(type(exc)), exc)),
encoding=self.encoding, allow_none=self.allow_none,
)

Expand DownExpand Up@@ -365,7 +365,7 @@ def system_multicall(self, call_list):
except BaseException as exc:
results.append(
{'faultCode' : 1,
'faultString' : "%s:%s" % (type(exc), exc)}
'faultString' : "%s:%s" % (repr(type(exc)), exc)}
)
return results

Expand DownExpand Up@@ -628,7 +628,7 @@ def _marshaled_dispatch(self, data, dispatch_method = None, path = None):
# (each dispatcher should have handled their own
# exceptions)
response = dumps(
Fault(1, "%s:%s" % (type(exc), exc)),
Fault(1, "%s:%s" % (repr(type(exc)), exc)),
encoding=self.encoding, allow_none=self.allow_none)
response = response.encode(self.encoding, 'xmlcharrefreplace')
return response
Expand Down
84 changes: 62 additions & 22 deletionsObjects/typeobject.c
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -1596,37 +1596,75 @@ static PyGetSetDef type_getsets[] = {
{0}
};

static PyObject*
type_repr(PyTypeObject *type)
static PyObject*
type_fullyqualname(PyTypeObject *type, int ignore_module_error)
{
// type is a static type and PyType_Ready() was not called on it yet?
if (type->tp_name == NULL) {
// type_repr() called before the type is fully initialized
// by PyType_Ready().
return PyUnicode_FromFormat("<class at %p>", type);
PyErr_SetString(PyExc_TypeError, "static type not initialized");
return NULL;
}

PyObject *mod, *name, *rtn;
if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
// Static type
return PyUnicode_FromString(type->tp_name);
}

mod = type_module(type, NULL);
if (mod == NULL)
PyErr_Clear();
else if (!PyUnicode_Check(mod)) {
Py_SETREF(mod, NULL);
PyObject *qualname = type_qualname(type, NULL);
if (qualname == NULL) {
return NULL;
}
name = type_qualname(type, NULL);
if (name == NULL) {
Py_XDECREF(mod);

PyObject *module = type_module(type, NULL);
if (module == NULL) {
if (ignore_module_error) {
// type_repr() ignores type_module() errors
PyErr_Clear();
return qualname;
}

Py_DECREF(qualname);
return NULL;
}

if (mod != NULL && !_PyUnicode_Equal(mod, &_Py_ID(builtins)))
rtn = PyUnicode_FromFormat("<class '%U.%U'>", mod, name);
else
rtn = PyUnicode_FromFormat("<class '%s'>", type->tp_name);
PyObject *result;
if (PyUnicode_Check(module)
&& !_PyUnicode_Equal(module, &_Py_ID(builtins)))
{
result = PyUnicode_FromFormat("%U.%U", module, qualname);
}
else {
result = Py_NewRef(qualname);
}
Py_DECREF(module);
Py_DECREF(qualname);
return result;
}

Py_XDECREF(mod);
Py_DECREF(name);
return rtn;

static PyObject *
type_str(PyTypeObject *type)
{
return type_fullyqualname(type, 0);
}


static PyObject *
type_repr(PyTypeObject *type)
{
if (type->tp_name == NULL) {
// If type_repr() is called before the type is fully initialized
// by PyType_Ready(), just format the type memory address.
return PyUnicode_FromFormat("<class at %p>", type);
}

PyObject *fullqualname = type_fullyqualname(type, 1);
if (fullqualname == NULL) {
return NULL;
}
PyObject *result = PyUnicode_FromFormat("<class '%U'>", fullqualname);
Py_DECREF(fullqualname);
return result;
}

static PyObject *
Expand DownExpand Up@@ -4540,6 +4578,7 @@ PyType_GetQualName(PyTypeObject *type)
return type_qualname(type, NULL);
}


void *
PyType_GetSlot(PyTypeObject *type, int slot)
{
Expand DownExpand Up@@ -5230,6 +5269,7 @@ type___sizeof___impl(PyTypeObject *self)
return PyLong_FromSize_t(size);
}


static PyMethodDef type_methods[] = {
TYPE_MRO_METHODDEF
TYPE___SUBCLASSES___METHODDEF
Expand DownExpand Up@@ -5354,7 +5394,7 @@ PyTypeObject PyType_Type = {
0, /* tp_as_mapping */
0, /* tp_hash */
(ternaryfunc)type_call, /* tp_call */
0, /* tp_str */
(reprfunc)type_str, /* tp_str */
(getattrofunc)_Py_type_getattro, /* tp_getattro */
(setattrofunc)type_setattro, /* tp_setattro */
0, /* tp_as_buffer */
Expand Down

[8]ページ先頭

©2009-2025 Movatter.jp