mirror of https://github.com/python/cpython
[3.13] gh-113570: reprlib.repr does not use builtin __repr__ for reshadowed builtins (GH-113577) (GH-125654)
(cherry picked from commit 04d6dd23e2
)
Co-authored-by: George Pittock <66332098+georgepittock@users.noreply.github.com>
This commit is contained in:
parent
30d7e9e721
commit
d894d467a6
|
@ -36,6 +36,17 @@ def recursive_repr(fillvalue='...'):
|
||||||
return decorating_function
|
return decorating_function
|
||||||
|
|
||||||
class Repr:
|
class Repr:
|
||||||
|
_lookup = {
|
||||||
|
'tuple': 'builtins',
|
||||||
|
'list': 'builtins',
|
||||||
|
'array': 'array',
|
||||||
|
'set': 'builtins',
|
||||||
|
'frozenset': 'builtins',
|
||||||
|
'deque': 'collections',
|
||||||
|
'dict': 'builtins',
|
||||||
|
'str': 'builtins',
|
||||||
|
'int': 'builtins'
|
||||||
|
}
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, *, maxlevel=6, maxtuple=6, maxlist=6, maxarray=5, maxdict=4,
|
self, *, maxlevel=6, maxtuple=6, maxlist=6, maxarray=5, maxdict=4,
|
||||||
|
@ -60,13 +71,23 @@ class Repr:
|
||||||
return self.repr1(x, self.maxlevel)
|
return self.repr1(x, self.maxlevel)
|
||||||
|
|
||||||
def repr1(self, x, level):
|
def repr1(self, x, level):
|
||||||
typename = type(x).__name__
|
cls = type(x)
|
||||||
|
typename = cls.__name__
|
||||||
|
|
||||||
if ' ' in typename:
|
if ' ' in typename:
|
||||||
parts = typename.split()
|
parts = typename.split()
|
||||||
typename = '_'.join(parts)
|
typename = '_'.join(parts)
|
||||||
if hasattr(self, 'repr_' + typename):
|
|
||||||
return getattr(self, 'repr_' + typename)(x, level)
|
method = getattr(self, 'repr_' + typename, None)
|
||||||
else:
|
if method:
|
||||||
|
# not defined in this class
|
||||||
|
if typename not in self._lookup:
|
||||||
|
return method(x, level)
|
||||||
|
module = getattr(cls, '__module__', None)
|
||||||
|
# defined in this class and is the module intended
|
||||||
|
if module == self._lookup[typename]:
|
||||||
|
return method(x, level)
|
||||||
|
|
||||||
return self.repr_instance(x, level)
|
return self.repr_instance(x, level)
|
||||||
|
|
||||||
def _join(self, pieces, level):
|
def _join(self, pieces, level):
|
||||||
|
|
|
@ -580,6 +580,50 @@ class ReprTests(unittest.TestCase):
|
||||||
with self.assertRaisesRegex(expected_error, expected_msg):
|
with self.assertRaisesRegex(expected_error, expected_msg):
|
||||||
r.repr(test_object)
|
r.repr(test_object)
|
||||||
|
|
||||||
|
def test_shadowed_stdlib_array(self):
|
||||||
|
# Issue #113570: repr() should not be fooled by an array
|
||||||
|
class array:
|
||||||
|
def __repr__(self):
|
||||||
|
return "not array.array"
|
||||||
|
|
||||||
|
self.assertEqual(r(array()), "not array.array")
|
||||||
|
|
||||||
|
def test_shadowed_builtin(self):
|
||||||
|
# Issue #113570: repr() should not be fooled
|
||||||
|
# by a shadowed builtin function
|
||||||
|
class list:
|
||||||
|
def __repr__(self):
|
||||||
|
return "not builtins.list"
|
||||||
|
|
||||||
|
self.assertEqual(r(list()), "not builtins.list")
|
||||||
|
|
||||||
|
def test_custom_repr(self):
|
||||||
|
class MyRepr(Repr):
|
||||||
|
|
||||||
|
def repr_TextIOWrapper(self, obj, level):
|
||||||
|
if obj.name in {'<stdin>', '<stdout>', '<stderr>'}:
|
||||||
|
return obj.name
|
||||||
|
return repr(obj)
|
||||||
|
|
||||||
|
aRepr = MyRepr()
|
||||||
|
self.assertEqual(aRepr.repr(sys.stdin), "<stdin>")
|
||||||
|
|
||||||
|
def test_custom_repr_class_with_spaces(self):
|
||||||
|
class TypeWithSpaces:
|
||||||
|
pass
|
||||||
|
|
||||||
|
t = TypeWithSpaces()
|
||||||
|
type(t).__name__ = "type with spaces"
|
||||||
|
self.assertEqual(type(t).__name__, "type with spaces")
|
||||||
|
|
||||||
|
class MyRepr(Repr):
|
||||||
|
def repr_type_with_spaces(self, obj, level):
|
||||||
|
return "Type With Spaces"
|
||||||
|
|
||||||
|
|
||||||
|
aRepr = MyRepr()
|
||||||
|
self.assertEqual(aRepr.repr(t), "Type With Spaces")
|
||||||
|
|
||||||
def write_file(path, text):
|
def write_file(path, text):
|
||||||
with open(path, 'w', encoding='ASCII') as fp:
|
with open(path, 'w', encoding='ASCII') as fp:
|
||||||
fp.write(text)
|
fp.write(text)
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Fixed a bug in ``reprlib.repr`` where it incorrectly called the repr method on shadowed Python built-in types.
|
Loading…
Reference in New Issue