Description
With reprlib.Repr
, it's possible to print object representations with a limit of recursive depth to increase readability of large objects. "This is used in the Python debugger and may be useful in other contexts as well."[1] For example, I'm using reprlib
to log lines for debugging. In the same line of thought, it makes sense to be able to format the output to increase readability even further. One measure to do so is to insert line breaks with indentation.
Example
>>> example = [1, [2, "foo", b"bar", {"a": 1, "b": "abc def ghi", "c": {1: 2, 3: 4, 5: [], 6: {}}}], 3]
At first glance, pprint.PrettyPrinter
might be an alternative solution:
>>> import pprint
>>> pprint.pprint(example, indent=4)
[ 1,
[ 2,
'foo',
b'bar',
{'a': 1, 'b': 'abc def ghi', 'c': {1: 2, 3: 4, 5: [], 6: {}}}],
3]
>>> pprint.pprint(example, indent=4, depth=3)
[1, [2, 'foo', b'bar', {'a': 1, 'b': 'abc def ghi', 'c': {...}}], 3]
However, in the first example above, the inner dict
has not been expanded by line breaks and indentation. In the second example, after reducing depth
, everything is suddenly printed onto one line only. This is the case, because the motivation and goal of pprint
is to optimize output for a given width
to pretty print - not to produce consistent output for debugging purposes. This becomes even more apparent when reducing width
:
>>> pprint.pprint(example, indent=4, depth=3, width=10)
[ 1,
[ 2,
'foo',
b'bar',
{ 'a': 1,
'b': 'abc '
'def '
'ghi',
'c': { 1: 2,
3: 4,
5: [ ],
6: { }}}],
3]
Note how strings that are too long for width
, like "abc def ghi"
in example
, get split into multiple lines. This is not optimal for logging output where the width of the output (i.e. the actual line length) is usually not restricted.
Using json.dumps
produces a similar output as the requested indentation feature for reprlib
:
>>> import json
>>> print(json.dumps({"a": 1, "b": [2, 3]}, indent=4))
{
"a": 1,
"b": [
2,
3
]
}
However, it is subject to the known restrictions when converting Python objects to JSON:
>>> json.dumps(example)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.9/json/__init__.py", line 231, in dumps
return _default_encoder.encode(obj)
File "/usr/lib/python3.9/json/encoder.py", line 199, in encode
chunks = self.iterencode(o, _one_shot=True)
File "/usr/lib/python3.9/json/encoder.py", line 257, in iterencode
return _iterencode(o, 0)
File "/usr/lib/python3.9/json/encoder.py", line 179, in default
raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type bytes is not JSON serializable
Therefore, it would be useful to add the following indentation feature to reprlib
:
>>> import reprlib
>>> print(reprlib.repr(example)) # regular output
[1, [2, 'foo', b'bar', {'a': 1, 'b': 'abc def ghi', 'c': {1: 2, 3: 4, 5: [], 6: {}}}], 3]
>>> reprlib.aRepr.indent = 4
>>> print(reprlib.repr(example)) # output with 4 spaces indentation
[
1,
[
2,
'foo',
b'bar',
{
'a': 1,
'b': 'abc def ghi',
'c': {
1: 2,
3: 4,
5: [],
6: {},
},
},
],
3,
]
>>> reprlib.aRepr.maxlevel = 3
>>> print(reprlib.repr(example)) # same as above, but with reduced depth
[
1,
[
2,
'foo',
b'bar',
{
'a': 1,
'b': 'abc def ghi',
'c': {...},
},
],
3,
]
>>> reprlib.aRepr.indent = "........"
>>> print(reprlib.repr(example)) # custom indentation string
[
........1,
........[
................2,
................'foo',
................b'bar',
................{
........................'a': 1,
........................'b': 'abc def ghi',
........................'c': {...},
................},
........],
........3,
]