Skip to content

Commit 7c411a4

Browse files
Issue #19132: The pprint module now supports compact mode.
1 parent 092bd38 commit 7c411a4

5 files changed

Lines changed: 80 additions & 25 deletions

File tree

‎Doc/library/pprint.rst‎

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,14 @@ The :mod:`pprint` module defines one class:
2929
.. First the implementation class:
3030
3131
32-
.. class:: PrettyPrinter(indent=1, width=80, depth=None, stream=None)
32+
.. class:: PrettyPrinter(indent=1, width=80, depth=None, stream=None, *, \
33+
compact=False)
3334

3435
Construct a :class:`PrettyPrinter` instance. This constructor understands
3536
several keyword parameters. An output stream may be set using the *stream*
3637
keyword; the only method used on the stream object is the file protocol's
3738
:meth:`write` method. If not specified, the :class:`PrettyPrinter` adopts
38-
``sys.stdout``. Three additional parameters may be used to control the
39-
formatted representation. The keywords are *indent*, *depth*, and *width*. The
39+
``sys.stdout``. The
4040
amount of indentation added for each recursive level is specified by *indent*;
4141
the default is one. Other values can cause output to look a little odd, but can
4242
make nesting easier to spot. The number of levels which may be printed is
@@ -45,7 +45,9 @@ The :mod:`pprint` module defines one class:
4545
the depth of the objects being formatted. The desired output width is
4646
constrained using the *width* parameter; the default is 80 characters. If a
4747
structure cannot be formatted within the constrained width, a best effort will
48-
be made.
48+
be made. If *compact* is false (the default) each item of a long sequence
49+
will be formatted on a separate line. If *compact* is true, as many items
50+
as will fit within the *width* will be formatted on each output line.
4951

5052
>>> import pprint
5153
>>> stuff = ['spam', 'eggs', 'lumberjack', 'knights', 'ni']
@@ -58,6 +60,12 @@ The :mod:`pprint` module defines one class:
5860
'lumberjack',
5961
'knights',
6062
'ni']
63+
>>> pp = pprint.PrettyPrinter(width=41, compact=True)
64+
>>> pp.pprint(stuff)
65+
[['spam', 'eggs', 'lumberjack',
66+
'knights', 'ni'],
67+
'spam', 'eggs', 'lumberjack', 'knights',
68+
'ni']
6169
>>> tup = ('spam', ('eggs', ('lumberjack', ('knights', ('ni', ('dead',
6270
... ('parrot', ('fresh fruit',))))))))
6371
>>> pp = pprint.PrettyPrinter(depth=6)
@@ -67,21 +75,22 @@ The :mod:`pprint` module defines one class:
6775

6876
The :mod:`pprint` module also provides several shortcut functions:
6977

70-
.. function:: pformat(object, indent=1, width=80, depth=None)
78+
.. function:: pformat(object, indent=1, width=80, depth=None, *, compact=False)
7179

72-
Return the formatted representation of *object* as a string. *indent*, *width*
73-
and *depth* will be passed to the :class:`PrettyPrinter` constructor as
74-
formatting parameters.
80+
Return the formatted representation of *object* as a string. *indent*,
81+
*width*, *depth* and *compact* will be passed to the :class:`PrettyPrinter`
82+
constructor as formatting parameters.
7583

7684

77-
.. function:: pprint(object, stream=None, indent=1, width=80, depth=None)
85+
.. function:: pprint(object, stream=None, indent=1, width=80, depth=None, *, \
86+
compact=False)
7887

7988
Prints the formatted representation of *object* on *stream*, followed by a
8089
newline. If *stream* is ``None``, ``sys.stdout`` is used. This may be used
8190
in the interactive interpreter instead of the :func:`print` function for
8291
inspecting values (you can even reassign ``print = pprint.pprint`` for use
83-
within a scope). *indent*, *width* and *depth* will be passed to the
84-
:class:`PrettyPrinter` constructor as formatting parameters.
92+
within a scope). *indent*, *width*, *depth* and *compact* will be passed
93+
to the :class:`PrettyPrinter` constructor as formatting parameters.
8594

8695
>>> import pprint
8796
>>> stuff = ['spam', 'eggs', 'lumberjack', 'knights', 'ni']

‎Doc/whatsnew/3.4.rst‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,13 @@ POP3 server.
314314
(Contributed by Lorenzo Catucci in :issue:`4473`.)
315315

316316

317+
pprint
318+
------
319+
320+
The :mod::`pprint` module now supports *compact* mode for formatting long
321+
sequences (:issue:`19132`).
322+
323+
317324
smtplib
318325
-------
319326

‎Lib/pprint.py‎

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,18 @@
4949
_type = type
5050

5151

52-
def pprint(object, stream=None, indent=1, width=80, depth=None):
52+
def pprint(object, stream=None, indent=1, width=80, depth=None, *,
53+
compact=False):
5354
"""Pretty-print a Python object to a stream [default is sys.stdout]."""
5455
printer = PrettyPrinter(
55-
stream=stream, indent=indent, width=width, depth=depth)
56+
stream=stream, indent=indent, width=width, depth=depth,
57+
compact=compact)
5658
printer.pprint(object)
5759

58-
def pformat(object, indent=1, width=80, depth=None):
60+
def pformat(object, indent=1, width=80, depth=None, *, compact=False):
5961
"""Format a Python object into a pretty-printed representation."""
60-
return PrettyPrinter(indent=indent, width=width, depth=depth).pformat(object)
62+
return PrettyPrinter(indent=indent, width=width, depth=depth,
63+
compact=compact).pformat(object)
6164

6265
def saferepr(object):
6366
"""Version of repr() which can handle recursive data structures."""
@@ -102,7 +105,8 @@ def _safe_tuple(t):
102105
return _safe_key(t[0]), _safe_key(t[1])
103106

104107
class PrettyPrinter:
105-
def __init__(self, indent=1, width=80, depth=None, stream=None):
108+
def __init__(self, indent=1, width=80, depth=None, stream=None, *,
109+
compact=False):
106110
"""Handle pretty printing operations onto a stream using a set of
107111
configured parameters.
108112
@@ -119,6 +123,9 @@ def __init__(self, indent=1, width=80, depth=None, stream=None):
119123
The desired output stream. If omitted (or false), the standard
120124
output stream available at construction will be used.
121125
126+
compact
127+
If true, several items will be combined in one line.
128+
122129
"""
123130
indent = int(indent)
124131
width = int(width)
@@ -132,6 +139,7 @@ def __init__(self, indent=1, width=80, depth=None, stream=None):
132139
self._stream = stream
133140
else:
134141
self._stream = _sys.stdout
142+
self._compact = bool(compact)
135143

136144
def pprint(self, object):
137145
self._format(object, self._stream, 0, 0, {}, 0)
@@ -223,15 +231,9 @@ def _format(self, object, stream, indent, allowance, context, level):
223231
write((self._indent_per_level - 1) * ' ')
224232
if length:
225233
context[objid] = 1
226-
indent = indent + self._indent_per_level
227-
self._format(object[0], stream, indent, allowance + 1,
228-
context, level)
229-
if length > 1:
230-
for ent in object[1:]:
231-
write(',\n' + ' '*indent)
232-
self._format(ent, stream, indent,
233-
allowance + 1, context, level)
234-
indent = indent - self._indent_per_level
234+
self._format_items(object, stream,
235+
indent + self._indent_per_level,
236+
allowance + 1, context, level)
235237
del context[objid]
236238
if issubclass(typ, tuple) and length == 1:
237239
write(',')
@@ -271,6 +273,29 @@ def _str_parts(s):
271273
return
272274
write(rep)
273275

276+
def _format_items(self, items, stream, indent, allowance, context, level):
277+
write = stream.write
278+
delimnl = ',\n' + ' ' * indent
279+
delim = ''
280+
width = max_width = self._width - indent - allowance + 2
281+
for ent in items:
282+
if self._compact:
283+
rep = self._repr(ent, context, level)
284+
w = _len(rep) + 2
285+
if width < w:
286+
width = max_width
287+
if delim:
288+
delim = delimnl
289+
if width >= w:
290+
width -= w
291+
write(delim)
292+
delim = ', '
293+
write(rep)
294+
continue
295+
write(delim)
296+
delim = delimnl
297+
self._format(ent, stream, indent, allowance, context, level)
298+
274299
def _repr(self, object, context, level):
275300
repr, readable, recursive = self.format(object, context.copy(),
276301
self._depth, level)

‎Lib/test/test_pprint.py‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,18 @@ def test_str_wrap(self):
568568
formatted = pprint.pformat(special, width=width)
569569
self.assertEqual(eval("(" + formatted + ")"), special)
570570

571+
def test_compact(self):
572+
o = ([list(range(i * i)) for i in range(5)] +
573+
[list(range(i)) for i in range(6)])
574+
expected = """\
575+
[[], [0], [0, 1, 2, 3],
576+
[0, 1, 2, 3, 4, 5, 6, 7, 8],
577+
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
578+
14, 15],
579+
[], [0], [0, 1], [0, 1, 2], [0, 1, 2, 3],
580+
[0, 1, 2, 3, 4]]"""
581+
self.assertEqual(pprint.pformat(o, width=48, compact=True), expected)
582+
571583

572584
class DottedPrettyPrinter(pprint.PrettyPrinter):
573585

‎Misc/NEWS‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ Core and Builtins
1313
Library
1414
-------
1515

16+
- Issue #19132: The pprint module now supports compact mode.
17+
1618
- Issue #19137: The pprint module now correctly formats instances of set and
1719
frozenset subclasses.
1820

0 commit comments

Comments
 (0)