Skip to content
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add indentation feature to reprlib.Repr #92734

Closed
finefoot opened this issue May 12, 2022 · 3 comments
Closed

Add indentation feature to reprlib.Repr #92734

finefoot opened this issue May 12, 2022 · 3 comments
Labels
stdlib Python modules in the Lib dir type-feature A feature request or enhancement

Comments

@finefoot
Copy link
Contributor

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,
]
@finefoot finefoot added the type-feature A feature request or enhancement label May 12, 2022
@erlend-aasland erlend-aasland added the stdlib Python modules in the Lib dir label May 16, 2022
@gvanrossum
Copy link
Member

OT: Maybe @finefoot would be interested in doing something about #85555?

@gvanrossum
Copy link
Member

OT squared: Despite their different design goals, maybe we could try to unify pprint and reprlib? Despite their differences they seem to have considerable overlap.

@hauntsaninja
Copy link
Contributor

Looks like all the on-topic things were completed, thanks everyone!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stdlib Python modules in the Lib dir type-feature A feature request or enhancement
Projects
None yet
Development

No branches or pull requests

4 participants