Skip to content

Add indentation feature to reprlib.Repr #92734

Closed

Description

@finefoot

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,
]

Activity

  1. added
    stdlibStandard Library Python modules in the Lib/ directory
    on May 16, 2022
  2. added a commit that references this issue on Sep 8, 2022
  3. gvanrossum commented on Sep 9, 2022

    @gvanrossum
    Member

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

  4. gvanrossum commented on Sep 9, 2022

    @gvanrossum
    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.

  5. hauntsaninja commented on Sep 7, 2023

    @hauntsaninja
    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

Metadata

Metadata

Assignees

No one assigned

    Labels

    stdlibStandard Library Python modules in the Lib/ directorytype-featureA feature request or enhancement

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions