-
-
Notifications
You must be signed in to change notification settings - Fork 33.2k
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
| def repr1(self, x, level): | |
| typename = type(x).__name__ | |
| if ' ' in typename: | |
| parts = typename.split() | |
| typename = '_'.join(parts) | |
| if hasattr(self, 'repr_' + typename): | |
| return getattr(self, 'repr_' + typename)(x, level) | |
| else: | |
| return self.repr_instance(x, level) |
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
raggedlibrary to provide aragged.arraybecause 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. ↩