Description
Bug report
Bug description:
Code like the following:
import reprlib
class array:
def __repr__(self):
return "not array.array!"
reprlib.repr(array())
raises
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/jpivarski/mambaforge/lib/python3.10/reprlib.py", line 52, in repr
return self.repr1(x, self.maxlevel)
File "/home/jpivarski/mambaforge/lib/python3.10/reprlib.py", line 60, in repr1
return getattr(self, 'repr_' + typename)(x, level)
File "/home/jpivarski/mambaforge/lib/python3.10/reprlib.py", line 86, in repr_array
header = "array('%s', [" % x.typecode
AttributeError: 'array' object has no attribute 'typecode'
because reprlib uses type(x).__name__
to infer that x
has type array.array
, rather than my user-defined class:
Lines 62 to 70 in cf34b77
Perhaps there's good reason to check the __name__
string instead of isinstance(x, array.array)
, to avoid unnecessarily importing the array
module for start-up time or for minimizing clutter in the sys.modules
. However, this test should check both the __name__
string and the __module__
string.
This affects any user-defined classes with the following names:
- tuple
- list
- array
- set
- frozenset
- deque
- dict
- str
- int
- instance
Some of these, admittedly, would be bad names for user-defined classes, but others are more reasonable, such as array
and deque
.1
Since these methods are publicly available on class reprlib.Repr
, the method names can't change, but the lookup could be replaced using a dict like
class Repr:
_lookup = {
("builtins", "tuple"): repr_tuple,
("builtins", "list"): repr_list,
("array", "array"): repr_array,
("builtins", "set"): repr_set,
("builtins", "frozenset"): repr_frozenset,
("collections", "deque"): repr_deque,
("builtins", "dict"): repr_dict,
("builtins", "str"): repr_str,
("builtins", "int"): repr_int,
}
I encountered this in pytest. My error output contained
x = <[ValueError('the truth value of an array whose length is not 1 is ambiguous; use ak.any() or ak.all()') raised in repr()] array object at 0x779b54763700>
y = array([1, 2, 3])
or
x = <[AttributeError("'array' object has no attribute 'typecode'") raised in repr()] array object at 0x728278bacd60>
y = array([1, 2, 3])
for reasons that had nothing to do with the actual error, and the array.__repr__
code itself is error-free. (pytest overrides reprlib to provide a SafeRepr.)
Thanks!
CPython versions tested on:
3.10
Operating systems tested on:
Linux
Linked PRs
- gh-113570: reprlib.repr does not use builtin __repr__ for reshadowed builtins #113577
- [3.13] gh-113570: reprlib.repr does not use builtin __repr__ for reshadowed builtins (GH-113577) #125654
- [3.12] gh-113570: reprlib.repr does not use builtin __repr__ for reshadowed builtins (GH-113577) #125655
Footnotes
-
In my case, I want the
ragged
library to provide aragged.array
because it reads like English that way. I also don't want to change the__name__
of my class to differ from its actual name. In particular, the Array API specification uses "array
" as a type name. ↩