Issue #19132: The pprint module now supports compact mode.
authorSerhiy Storchaka <storchaka@gmail.com>
Wed, 2 Oct 2013 08:56:18 +0000 (11:56 +0300)
committerSerhiy Storchaka <storchaka@gmail.com>
Wed, 2 Oct 2013 08:56:18 +0000 (11:56 +0300)
Doc/library/pprint.rst
Doc/whatsnew/3.4.rst
Lib/pprint.py
Lib/test/test_pprint.py
Misc/NEWS

index 8d57c5d4ed843773c16b5bcdd02577023bcea7e1..ec9de43cb213d0b4acd44f5cee2631e5f8cdc34e 100644 (file)
@@ -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']
index 0690e70f625db7aa0181d5b84354b24ca9708971..2e3cab5898f081394ef4830dc4fa20b92e898e32 100644 (file)
@@ -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
 -------
 
index f4bc59bab44f6a2971045ead9a6d6f45af413db1..a7dfe28908939584a09536eddca698e016f7dfaf 100644 (file)
@@ -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)
index 5a2050fc6a5fc2e119e2c909a765c385476e3e3a..3d364c4595747380e50bf801d981d9438f27587c 100644 (file)
@@ -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):
 
index f3a6e1a576dc56a4a0f5ca676c5ec28b412191fa..9cf8adafac41a03f2048a771d8471c015c9c14d2 100644 (file)
--- 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.