Skip to content

Commit c06c001

Browse files
authored
gh-92734: Add indentation feature to reprlib.Repr (GH-92735)
1 parent aa3b4cf commit c06c001

File tree

4 files changed

+421
-5
lines changed

4 files changed

+421
-5
lines changed

Doc/library/reprlib.rst

+61-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ This module provides a class, an instance, and a function:
1919

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

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

144144

145+
.. attribute:: Repr.indent
146+
147+
If this attribute is set to ``None`` (the default), the output is formatted
148+
with no line breaks or indentation, like the standard :func:`repr`.
149+
For example:
150+
151+
.. code-block:: pycon
152+
153+
>>> example = [
154+
1, 'spam', {'a': 2, 'b': 'spam eggs', 'c': {3: 4.5, 6: []}}, 'ham']
155+
>>> import reprlib
156+
>>> aRepr = reprlib.Repr()
157+
>>> print(aRepr.repr(example))
158+
[1, 'spam', {'a': 2, 'b': 'spam eggs', 'c': {3: 4.5, 6: []}}, 'ham']
159+
160+
If :attr:`~Repr.indent` is set to a string, each recursion level
161+
is placed on its own line, indented by that string:
162+
163+
.. code-block:: pycon
164+
165+
>>> aRepr.indent = '-->'
166+
>>> print(aRepr.repr(example))
167+
[
168+
-->1,
169+
-->'spam',
170+
-->{
171+
-->-->'a': 2,
172+
-->-->'b': 'spam eggs',
173+
-->-->'c': {
174+
-->-->-->3: 4.5,
175+
-->-->-->6: [],
176+
-->-->},
177+
-->},
178+
-->'ham',
179+
]
180+
181+
Setting :attr:`~Repr.indent` to a positive integer value behaves as if it
182+
was set to a string with that number of spaces:
183+
184+
.. code-block:: pycon
185+
186+
>>> aRepr.indent = 4
187+
>>> print(aRepr.repr(example))
188+
[
189+
1,
190+
'spam',
191+
{
192+
'a': 2,
193+
'b': 'spam eggs',
194+
'c': {
195+
3: 4.5,
196+
6: [],
197+
},
198+
},
199+
'ham',
200+
]
201+
202+
.. versionadded:: 3.12
203+
204+
145205
.. method:: Repr.repr(obj)
146206

147207
The equivalent to the built-in :func:`repr` that uses the formatting imposed by

Lib/reprlib.py

+25-4
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class Repr:
3838
def __init__(
3939
self, *, maxlevel=6, maxtuple=6, maxlist=6, maxarray=5, maxdict=4,
4040
maxset=6, maxfrozenset=6, maxdeque=6, maxstring=30, maxlong=40,
41-
maxother=30, fillvalue='...',
41+
maxother=30, fillvalue='...', indent=None,
4242
):
4343
self.maxlevel = maxlevel
4444
self.maxtuple = maxtuple
@@ -52,6 +52,7 @@ def __init__(
5252
self.maxlong = maxlong
5353
self.maxother = maxother
5454
self.fillvalue = fillvalue
55+
self.indent = indent
5556

5657
def repr(self, x):
5758
return self.repr1(x, self.maxlevel)
@@ -66,6 +67,26 @@ def repr1(self, x, level):
6667
else:
6768
return self.repr_instance(x, level)
6869

70+
def _join(self, pieces, level):
71+
if self.indent is None:
72+
return ', '.join(pieces)
73+
if not pieces:
74+
return ''
75+
indent = self.indent
76+
if isinstance(indent, int):
77+
if indent < 0:
78+
raise ValueError(
79+
f'Repr.indent cannot be negative int (was {indent!r})'
80+
)
81+
indent *= ' '
82+
try:
83+
sep = ',\n' + (self.maxlevel - level + 1) * indent
84+
except TypeError as error:
85+
raise TypeError(
86+
f'Repr.indent must be a str, int or None, not {type(indent)}'
87+
) from error
88+
return sep.join(('', *pieces, ''))[1:-len(indent) or None]
89+
6990
def _repr_iterable(self, x, level, left, right, maxiter, trail=''):
7091
n = len(x)
7192
if level <= 0 and n:
@@ -76,8 +97,8 @@ def _repr_iterable(self, x, level, left, right, maxiter, trail=''):
7697
pieces = [repr1(elem, newlevel) for elem in islice(x, maxiter)]
7798
if n > maxiter:
7899
pieces.append(self.fillvalue)
79-
s = ', '.join(pieces)
80-
if n == 1 and trail:
100+
s = self._join(pieces, level)
101+
if n == 1 and trail and self.indent is None:
81102
right = trail + right
82103
return '%s%s%s' % (left, s, right)
83104

@@ -124,7 +145,7 @@ def repr_dict(self, x, level):
124145
pieces.append('%s: %s' % (keyrepr, valrepr))
125146
if n > self.maxdict:
126147
pieces.append(self.fillvalue)
127-
s = ', '.join(pieces)
148+
s = self._join(pieces, level)
128149
return '{%s}' % (s,)
129150

130151
def repr_str(self, x, level):

0 commit comments

Comments
 (0)