diff --git a/Doc/library/pprint.rst b/Doc/library/pprint.rst index 8d57c5d4ed8..ec9de43cb21 100644 --- a/Doc/library/pprint.rst +++ b/Doc/library/pprint.rst @@ -29,14 +29,14 @@ The :mod:`pprint` module defines one class: .. First the implementation class: -.. class:: PrettyPrinter(indent=1, width=80, depth=None, stream=None) +.. class:: PrettyPrinter(indent=1, width=80, depth=None, stream=None, *, \ + compact=False) Construct a :class:`PrettyPrinter` instance. This constructor understands several keyword parameters. An output stream may be set using the *stream* keyword; the only method used on the stream object is the file protocol's :meth:`write` method. If not specified, the :class:`PrettyPrinter` adopts - ``sys.stdout``. Three additional parameters may be used to control the - formatted representation. The keywords are *indent*, *depth*, and *width*. The + ``sys.stdout``. The amount of indentation added for each recursive level is specified by *indent*; the default is one. Other values can cause output to look a little odd, but can 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: the depth of the objects being formatted. The desired output width is constrained using the *width* parameter; the default is 80 characters. If a structure cannot be formatted within the constrained width, a best effort will - be made. + be made. If *compact* is false (the default) each item of a long sequence + will be formatted on a separate line. If *compact* is true, as many items + as will fit within the *width* will be formatted on each output line. >>> import pprint >>> stuff = ['spam', 'eggs', 'lumberjack', 'knights', 'ni'] @@ -58,6 +60,12 @@ The :mod:`pprint` module defines one class: 'lumberjack', 'knights', 'ni'] + >>> pp = pprint.PrettyPrinter(width=41, compact=True) + >>> pp.pprint(stuff) + [['spam', 'eggs', 'lumberjack', + 'knights', 'ni'], + 'spam', 'eggs', 'lumberjack', 'knights', + 'ni'] >>> tup = ('spam', ('eggs', ('lumberjack', ('knights', ('ni', ('dead', ... ('parrot', ('fresh fruit',)))))))) >>> pp = pprint.PrettyPrinter(depth=6) @@ -67,21 +75,22 @@ The :mod:`pprint` module defines one class: The :mod:`pprint` module also provides several shortcut functions: -.. function:: pformat(object, indent=1, width=80, depth=None) +.. function:: pformat(object, indent=1, width=80, depth=None, *, compact=False) - Return the formatted representation of *object* as a string. *indent*, *width* - and *depth* will be passed to the :class:`PrettyPrinter` constructor as - formatting parameters. + Return the formatted representation of *object* as a string. *indent*, + *width*, *depth* and *compact* will be passed to the :class:`PrettyPrinter` + constructor as formatting parameters. -.. function:: pprint(object, stream=None, indent=1, width=80, depth=None) +.. function:: pprint(object, stream=None, indent=1, width=80, depth=None, *, \ + compact=False) Prints the formatted representation of *object* on *stream*, followed by a newline. If *stream* is ``None``, ``sys.stdout`` is used. This may be used in the interactive interpreter instead of the :func:`print` function for inspecting values (you can even reassign ``print = pprint.pprint`` for use - within a scope). *indent*, *width* and *depth* will be passed to the - :class:`PrettyPrinter` constructor as formatting parameters. + within a scope). *indent*, *width*, *depth* and *compact* will be passed + to the :class:`PrettyPrinter` constructor as formatting parameters. >>> import pprint >>> stuff = ['spam', 'eggs', 'lumberjack', 'knights', 'ni'] diff --git a/Doc/whatsnew/3.4.rst b/Doc/whatsnew/3.4.rst index 0690e70f625..2e3cab5898f 100644 --- a/Doc/whatsnew/3.4.rst +++ b/Doc/whatsnew/3.4.rst @@ -314,6 +314,13 @@ POP3 server. (Contributed by Lorenzo Catucci in :issue:`4473`.) +pprint +------ + +The :mod::`pprint` module now supports *compact* mode for formatting long +sequences (:issue:`19132`). + + smtplib ------- diff --git a/Lib/pprint.py b/Lib/pprint.py index f4bc59bab44..a7dfe289089 100644 --- a/Lib/pprint.py +++ b/Lib/pprint.py @@ -49,15 +49,18 @@ _len = len _type = type -def pprint(object, stream=None, indent=1, width=80, depth=None): +def pprint(object, stream=None, indent=1, width=80, depth=None, *, + compact=False): """Pretty-print a Python object to a stream [default is sys.stdout].""" printer = PrettyPrinter( - stream=stream, indent=indent, width=width, depth=depth) + stream=stream, indent=indent, width=width, depth=depth, + compact=compact) printer.pprint(object) -def pformat(object, indent=1, width=80, depth=None): +def pformat(object, indent=1, width=80, depth=None, *, compact=False): """Format a Python object into a pretty-printed representation.""" - return PrettyPrinter(indent=indent, width=width, depth=depth).pformat(object) + return PrettyPrinter(indent=indent, width=width, depth=depth, + compact=compact).pformat(object) def saferepr(object): """Version of repr() which can handle recursive data structures.""" @@ -102,7 +105,8 @@ def _safe_tuple(t): return _safe_key(t[0]), _safe_key(t[1]) class PrettyPrinter: - def __init__(self, indent=1, width=80, depth=None, stream=None): + def __init__(self, indent=1, width=80, depth=None, stream=None, *, + compact=False): """Handle pretty printing operations onto a stream using a set of configured parameters. @@ -119,6 +123,9 @@ class PrettyPrinter: The desired output stream. If omitted (or false), the standard output stream available at construction will be used. + compact + If true, several items will be combined in one line. + """ indent = int(indent) width = int(width) @@ -132,6 +139,7 @@ class PrettyPrinter: self._stream = stream else: self._stream = _sys.stdout + self._compact = bool(compact) def pprint(self, object): self._format(object, self._stream, 0, 0, {}, 0) @@ -223,15 +231,9 @@ class PrettyPrinter: write((self._indent_per_level - 1) * ' ') if length: context[objid] = 1 - indent = indent + self._indent_per_level - self._format(object[0], stream, indent, allowance + 1, - context, level) - if length > 1: - for ent in object[1:]: - write(',\n' + ' '*indent) - self._format(ent, stream, indent, - allowance + 1, context, level) - indent = indent - self._indent_per_level + self._format_items(object, stream, + indent + self._indent_per_level, + allowance + 1, context, level) del context[objid] if issubclass(typ, tuple) and length == 1: write(',') @@ -271,6 +273,29 @@ class PrettyPrinter: return write(rep) + def _format_items(self, items, stream, indent, allowance, context, level): + write = stream.write + delimnl = ',\n' + ' ' * indent + delim = '' + width = max_width = self._width - indent - allowance + 2 + for ent in items: + if self._compact: + rep = self._repr(ent, context, level) + w = _len(rep) + 2 + if width < w: + width = max_width + if delim: + delim = delimnl + if width >= w: + width -= w + write(delim) + delim = ', ' + write(rep) + continue + write(delim) + delim = delimnl + self._format(ent, stream, indent, allowance, context, level) + def _repr(self, object, context, level): repr, readable, recursive = self.format(object, context.copy(), self._depth, level) diff --git a/Lib/test/test_pprint.py b/Lib/test/test_pprint.py index 5a2050fc6a5..3d364c45957 100644 --- a/Lib/test/test_pprint.py +++ b/Lib/test/test_pprint.py @@ -568,6 +568,18 @@ frozenset2({0, formatted = pprint.pformat(special, width=width) self.assertEqual(eval("(" + formatted + ")"), special) + def test_compact(self): + o = ([list(range(i * i)) for i in range(5)] + + [list(range(i)) for i in range(6)]) + expected = """\ +[[], [0], [0, 1, 2, 3], + [0, 1, 2, 3, 4, 5, 6, 7, 8], + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15], + [], [0], [0, 1], [0, 1, 2], [0, 1, 2, 3], + [0, 1, 2, 3, 4]]""" + self.assertEqual(pprint.pformat(o, width=48, compact=True), expected) + class DottedPrettyPrinter(pprint.PrettyPrinter): diff --git a/Misc/NEWS b/Misc/NEWS index f3a6e1a576d..9cf8adafac4 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,8 @@ Core and Builtins Library ------- +- Issue #19132: The pprint module now supports compact mode. + - Issue #19137: The pprint module now correctly formats instances of set and frozenset subclasses.