diff -r d6e35146ae53 Doc/library/pprint.rst --- a/Doc/library/pprint.rst Sun Sep 29 01:49:07 2013 +0200 +++ b/Doc/library/pprint.rst Mon Sep 30 20:40:50 2013 +0300 @@ -29,14 +29,14 @@ .. 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``. Four additional parameters may be used to control the + formatted representation. The keywords are *indent*, *depth*, *width*, and *compact*. 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 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) every item of long sequence + will formatted in separated line. If *compact* is true, several items can + be combined in one line. >>> import pprint >>> stuff = ['spam', 'eggs', 'lumberjack', 'knights', 'ni'] @@ -58,6 +60,12 @@ '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,21 @@ 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'] @@ -257,6 +265,43 @@ 'upload_time': '2012-12-26T12:48:15', 'url': 'https://pypi.python.org/packages/2.7/T/Twisted/Twisted-12.3.0.win32-py2.7.msi'}]} +Compact representation:: + + >>> pprint.pprint(project_info, compact=True) + {'info': {'_pypi_hidden': False, '_pypi_ordering': 125, + 'author': 'Glyph Lefkowitz', 'author_email': 'glyph@twistedmatrix.com', + 'bugtrack_url': '', 'cheesecake_code_kwalitee_id': None, + 'cheesecake_documentation_id': None, + 'cheesecake_installability_id': None, + 'classifiers': ['Programming Language :: Python :: 2.6', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 2 :: Only'], + 'description': 'An extensible framework for Python programming, ' + 'with special focus\r\n' + 'on event-based network programming and ' + 'multiprotocol integration.', + 'docs_url': '', 'download_url': 'UNKNOWN', + 'home_page': 'http://twistedmatrix.com/', 'keywords': '', + 'license': 'MIT', 'maintainer': '', 'maintainer_email': '', + 'name': 'Twisted', 'package_url': 'http://pypi.python.org/pypi/Twisted', + 'platform': 'UNKNOWN', + 'release_url': 'http://pypi.python.org/pypi/Twisted/12.3.0', + 'requires_python': None, 'stable_version': None, + 'summary': 'An asynchronous networking framework written in Python', + 'version': '12.3.0'}, + 'urls': [{'comment_text': '', 'downloads': 71844, + 'filename': 'Twisted-12.3.0.tar.bz2', 'has_sig': False, + 'md5_digest': '6e289825f3bf5591cfd670874cc0862d', + 'packagetype': 'sdist', 'python_version': 'source', 'size': 2615733, + 'upload_time': '2012-12-26T12:47:03', + 'url': 'https://pypi.python.org/packages/source/T/Twisted/Twisted-12.3.0.tar.bz2'}, + {'comment_text': '', 'downloads': 5224, + 'filename': 'Twisted-12.3.0.win32-py2.7.msi', 'has_sig': False, + 'md5_digest': '6b778f5201b622a5519a2aca1a2fe512', + 'packagetype': 'bdist_msi', 'python_version': '2.7', 'size': 2916352, + 'upload_time': '2012-12-26T12:48:15', + 'url': 'https://pypi.python.org/packages/2.7/T/Twisted/Twisted-12.3.0.win32-py2.7.msi'}]} + The result can be limited to a certain *depth* (ellipsis is used for deeper contents):: diff -r d6e35146ae53 Lib/pprint.py --- a/Lib/pprint.py Sun Sep 29 01:49:07 2013 +0200 +++ b/Lib/pprint.py Mon Sep 30 20:40:50 2013 +0300 @@ -49,15 +49,18 @@ _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 @@ 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 @@ 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 @@ self._stream = stream else: self._stream = _sys.stdout + self._compact = bool(compact) def pprint(self, object): self._format(object, self._stream, 0, 0, {}, 0) @@ -172,24 +180,13 @@ length = _len(object) if length: context[objid] = 1 - indent = indent + self._indent_per_level if issubclass(typ, _OrderedDict): items = list(object.items()) else: items = sorted(object.items(), key=_safe_tuple) - key, ent = items[0] - rep = self._repr(key, context, level) - write(rep) - write(': ') - self._format(ent, stream, indent + _len(rep) + 2, - allowance + 1, context, level) - if length > 1: - for key, ent in items[1:]: - rep = self._repr(key, context, level) - write(',\n%s%s: ' % (' '*indent, rep)) - self._format(ent, stream, indent + _len(rep) + 2, - allowance + 1, context, level) - indent = indent - self._indent_per_level + self._format_dict_items(items, stream, + indent + self._indent_per_level, + allowance + 1, context, level) del context[objid] write('}') return @@ -225,15 +222,9 @@ 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(',') @@ -273,6 +264,59 @@ 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 _format_dict_items(self, items, stream, indent, allowance, context, + level): + write = stream.write + delimnl = ',\n' + ' ' * indent + delim = '' + width = max_width = self._width - indent - allowance + 4 + for key, ent in items: + rep = self._repr(key, context, level) + if self._compact: + rep2 = self._repr(ent, context, level) + w = _len(rep) + _len(rep2) + 4 + if width < w: + width = max_width + if delim: + delim = delimnl + if width >= w: + width -= w + write(delim) + delim = ', ' + write(rep) + write(': ') + write(rep2) + continue + write(delim) + delim = delimnl + write(rep) + write(': ') + self._format(ent, stream, indent + _len(rep) + 2, allowance, + context, level) + def _repr(self, object, context, level): repr, readable, recursive = self.format(object, context.copy(), self._depth, level) diff -r d6e35146ae53 Lib/test/test_pprint.py --- a/Lib/test/test_pprint.py Sun Sep 29 01:49:07 2013 +0200 +++ b/Lib/test/test_pprint.py Mon Sep 30 20:40:50 2013 +0300 @@ -513,6 +513,28 @@ 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) + o = {str(i): i for i in range(15)} + o['2'] = list(range(15)) + expected = """\ +{'0': 0, '1': 1, '10': 10, '11': 11, '12': 12, + '13': 13, '14': 14, + '2': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14], + '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, + '9': 9}""" + self.assertEqual(pprint.pformat(o, width=49, compact=True), expected) + class DottedPrettyPrinter(pprint.PrettyPrinter):