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

gh-92734: Add indentation feature to reprlib.Repr #92735

Merged
merged 18 commits into from
Sep 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 61 additions & 1 deletion Doc/library/reprlib.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ This module provides a class, an instance, and a function:

.. class:: Repr(*, maxlevel=6, maxtuple=6, maxlist=6, maxarray=5, maxdict=4, \
maxset=6, maxfrozenset=6, maxdeque=6, maxstring=30, maxlong=40, \
maxother=30, fillvalue="...")
maxother=30, fillvalue="...", indent=None)

Class which provides formatting services useful in implementing functions
similar to the built-in :func:`repr`; size limits for different object types
Expand Down Expand Up @@ -142,6 +142,66 @@ which format specific object types.
similar manner as :attr:`maxstring`. The default is ``20``.


.. attribute:: Repr.indent

If this attribute is set to ``None`` (the default), the output is formatted
with no line breaks or indentation, like the standard :func:`repr`.
finefoot marked this conversation as resolved.
Show resolved Hide resolved
For example:

.. code-block:: pycon

>>> example = [
1, 'spam', {'a': 2, 'b': 'spam eggs', 'c': {3: 4.5, 6: []}}, 'ham']
>>> import reprlib
>>> aRepr = reprlib.Repr()
>>> print(aRepr.repr(example))
[1, 'spam', {'a': 2, 'b': 'spam eggs', 'c': {3: 4.5, 6: []}}, 'ham']

If :attr:`~Repr.indent` is set to a string, each recursion level
is placed on its own line, indented by that string:

.. code-block:: pycon

>>> aRepr.indent = '-->'
>>> print(aRepr.repr(example))
[
-->1,
-->'spam',
-->{
-->-->'a': 2,
-->-->'b': 'spam eggs',
-->-->'c': {
-->-->-->3: 4.5,
-->-->-->6: [],
-->-->},
-->},
-->'ham',
]

Setting :attr:`~Repr.indent` to a positive integer value behaves as if it
was set to a string with that number of spaces:

.. code-block:: pycon

>>> aRepr.indent = 4
>>> print(aRepr.repr(example))
[
1,
'spam',
{
'a': 2,
'b': 'spam eggs',
'c': {
3: 4.5,
6: [],
},
},
'ham',
]

finefoot marked this conversation as resolved.
Show resolved Hide resolved
.. versionadded:: 3.12


.. method:: Repr.repr(obj)

The equivalent to the built-in :func:`repr` that uses the formatting imposed by
Expand Down
29 changes: 25 additions & 4 deletions Lib/reprlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class Repr:
def __init__(
self, *, maxlevel=6, maxtuple=6, maxlist=6, maxarray=5, maxdict=4,
maxset=6, maxfrozenset=6, maxdeque=6, maxstring=30, maxlong=40,
maxother=30, fillvalue='...',
maxother=30, fillvalue='...', indent=None,
):
self.maxlevel = maxlevel
self.maxtuple = maxtuple
Expand All @@ -52,6 +52,7 @@ def __init__(
self.maxlong = maxlong
self.maxother = maxother
self.fillvalue = fillvalue
self.indent = indent

def repr(self, x):
return self.repr1(x, self.maxlevel)
Expand All @@ -66,6 +67,26 @@ def repr1(self, x, level):
else:
return self.repr_instance(x, level)

def _join(self, pieces, level):
if self.indent is None:
return ', '.join(pieces)
if not pieces:
return ''
indent = self.indent
if isinstance(indent, int):
if indent < 0:
raise ValueError(
f'Repr.indent cannot be negative int (was {indent!r})'
)
indent *= ' '
try:
sep = ',\n' + (self.maxlevel - level + 1) * indent
except TypeError as error:
raise TypeError(
f'Repr.indent must be a str, int or None, not {type(indent)}'
) from error
return sep.join(('', *pieces, ''))[1:-len(indent) or None]

def _repr_iterable(self, x, level, left, right, maxiter, trail=''):
n = len(x)
if level <= 0 and n:
Expand All @@ -76,8 +97,8 @@ def _repr_iterable(self, x, level, left, right, maxiter, trail=''):
pieces = [repr1(elem, newlevel) for elem in islice(x, maxiter)]
if n > maxiter:
pieces.append(self.fillvalue)
s = ', '.join(pieces)
if n == 1 and trail:
s = self._join(pieces, level)
if n == 1 and trail and self.indent is None:
right = trail + right
return '%s%s%s' % (left, s, right)

Expand Down Expand Up @@ -124,7 +145,7 @@ def repr_dict(self, x, level):
pieces.append('%s: %s' % (keyrepr, valrepr))
if n > self.maxdict:
pieces.append(self.fillvalue)
s = ', '.join(pieces)
s = self._join(pieces, level)
return '{%s}' % (s,)

def repr_str(self, x, level):
Expand Down
Loading