diff options
author | Antoine Pitrou <solipsis@pitrou.net> | 2013-03-23 19:30:39 (GMT) |
---|---|---|
committer | Antoine Pitrou <solipsis@pitrou.net> | 2013-03-23 19:30:39 (GMT) |
commit | 64c16c3311d6ef8077498096e8874756477027de (patch) | |
tree | ba260cf3e542da7d488e71e472893b63050a3181 /Lib | |
parent | 4a8ea9e2a6d07bb069419274fb4dd75cfb6e3e55 (diff) | |
download | cpython-64c16c3311d6ef8077498096e8874756477027de.zip cpython-64c16c3311d6ef8077498096e8874756477027de.tar.gz cpython-64c16c3311d6ef8077498096e8874756477027de.tar.bz2 |
Issue #17150: pprint now uses line continuations to wrap long string literals.
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/pprint.py | 39 | ||||
-rw-r--r-- | Lib/test/test_pprint.py | 38 |
2 files changed, 72 insertions, 5 deletions
diff --git a/Lib/pprint.py b/Lib/pprint.py index ae96dde..1f98f5c 100644 --- a/Lib/pprint.py +++ b/Lib/pprint.py @@ -34,6 +34,7 @@ saferepr() """ +import re import sys as _sys from collections import OrderedDict as _OrderedDict from io import StringIO as _StringIO @@ -158,13 +159,10 @@ class PrettyPrinter: return rep = self._repr(object, context, level - 1) typ = _type(object) - sepLines = _len(rep) > (self._width - 1 - indent - allowance) + max_width = self._width - 1 - indent - allowance + sepLines = _len(rep) > max_width write = stream.write - if self._depth and level > self._depth: - write(rep) - return - if sepLines: r = getattr(typ, "__repr__", None) if issubclass(typ, dict): @@ -242,6 +240,37 @@ class PrettyPrinter: write(endchar) return + if issubclass(typ, str) and len(object) > 0 and r is str.__repr__: + def _str_parts(s): + """ + Return a list of string literals comprising the repr() + of the given string using literal concatenation. + """ + lines = s.splitlines(True) + for i, line in enumerate(lines): + rep = repr(line) + if _len(rep) <= max_width: + yield rep + else: + # A list of alternating (non-space, space) strings + parts = re.split(r'(\s+)', line) + [''] + current = '' + for i in range(0, len(parts), 2): + part = parts[i] + parts[i+1] + candidate = current + part + if len(repr(candidate)) > max_width: + if current: + yield repr(current) + current = part + else: + current = candidate + if current: + yield repr(current) + for i, rep in enumerate(_str_parts(object)): + if i > 0: + write('\n' + ' '*indent) + write(rep) + return write(rep) def _repr(self, object, context, level): diff --git a/Lib/test/test_pprint.py b/Lib/test/test_pprint.py index d492d75..bf136de 100644 --- a/Lib/test/test_pprint.py +++ b/Lib/test/test_pprint.py @@ -1,3 +1,5 @@ +# -*- coding: utf-8 -*- + import pprint import test.support import unittest @@ -475,6 +477,42 @@ class QueryTestCase(unittest.TestCase): self.assertEqual(pprint.pformat(dict.fromkeys(keys, 0)), '{%r: 0, %r: 0}' % tuple(sorted(keys, key=id))) + def test_str_wrap(self): + # pprint tries to wrap strings intelligently + fox = 'the quick brown fox jumped over a lazy dog' + self.assertEqual(pprint.pformat(fox, width=20), """\ +'the quick brown ' +'fox jumped over ' +'a lazy dog'""") + self.assertEqual(pprint.pformat({'a': 1, 'b': fox, 'c': 2}, + width=26), """\ +{'a': 1, + 'b': 'the quick brown ' + 'fox jumped over ' + 'a lazy dog', + 'c': 2}""") + # With some special characters + # - \n always triggers a new line in the pprint + # - \t and \n are escaped + # - non-ASCII is allowed + # - an apostrophe doesn't disrupt the pprint + special = "Portons dix bons \"whiskys\"\nà l'avocat goujat\t qui fumait au zoo" + self.assertEqual(pprint.pformat(special, width=20), """\ +'Portons dix bons ' +'"whiskys"\\n' +"à l'avocat " +'goujat\\t qui ' +'fumait au zoo'""") + # An unwrappable string is formatted as its repr + unwrappable = "x" * 100 + self.assertEqual(pprint.pformat(unwrappable, width=80), repr(unwrappable)) + self.assertEqual(pprint.pformat(''), "''") + # Check that the pprint is a usable repr + special *= 10 + for width in range(3, 40): + formatted = pprint.pformat(special, width=width) + self.assertEqual(eval("(" + formatted + ")"), special) + class DottedPrettyPrinter(pprint.PrettyPrinter): |