Issue #19104: pprint now produces evaluable output for wrapped strings.

This commit is contained in:
Serhiy Storchaka 2014-12-20 20:58:28 +02:00
commit 3c6fe4da88
3 changed files with 47 additions and 36 deletions

View File

@ -235,35 +235,41 @@ class PrettyPrinter:
return return
if issubclass(typ, str) and len(object) > 0 and r is str.__repr__: if issubclass(typ, str) and len(object) > 0 and r is str.__repr__:
def _str_parts(s): chunks = []
""" lines = object.splitlines(True)
Return a list of string literals comprising the repr() if level == 1:
of the given string using literal concatenation. indent += 1
""" max_width -= 2
lines = s.splitlines(True) for i, line in enumerate(lines):
for i, line in enumerate(lines): rep = repr(line)
rep = repr(line) if len(rep) <= max_width:
if len(rep) <= max_width: chunks.append(rep)
yield rep else:
else: # A list of alternating (non-space, space) strings
# A list of alternating (non-space, space) strings parts = re.split(r'(\s+)', line) + ['']
parts = re.split(r'(\s+)', line) + [''] current = ''
current = '' for i in range(0, len(parts), 2):
for i in range(0, len(parts), 2): part = parts[i] + parts[i+1]
part = parts[i] + parts[i+1] candidate = current + part
candidate = current + part if len(repr(candidate)) > max_width:
if len(repr(candidate)) > max_width: if current:
if current: chunks.append(repr(current))
yield repr(current) current = part
current = part else:
else: current = candidate
current = candidate if current:
if current: chunks.append(repr(current))
yield repr(current) if len(chunks) == 1:
for i, rep in enumerate(_str_parts(object)): write(rep)
return
if level == 1:
write('(')
for i, rep in enumerate(chunks):
if i > 0: if i > 0:
write('\n' + ' '*indent) write('\n' + ' '*indent)
write(rep) write(rep)
if level == 1:
write(')')
return return
write(rep) write(rep)

View File

@ -536,9 +536,10 @@ frozenset2({0,
# pprint tries to wrap strings intelligently # pprint tries to wrap strings intelligently
fox = 'the quick brown fox jumped over a lazy dog' fox = 'the quick brown fox jumped over a lazy dog'
self.assertEqual(pprint.pformat(fox, width=20), """\ self.assertEqual(pprint.pformat(fox, width=20), """\
'the quick brown ' ('the quick '
'fox jumped over ' 'brown fox '
'a lazy dog'""") 'jumped over a '
'lazy dog')""")
self.assertEqual(pprint.pformat({'a': 1, 'b': fox, 'c': 2}, self.assertEqual(pprint.pformat({'a': 1, 'b': fox, 'c': 2},
width=26), """\ width=26), """\
{'a': 1, {'a': 1,
@ -552,12 +553,12 @@ frozenset2({0,
# - non-ASCII is allowed # - non-ASCII is allowed
# - an apostrophe doesn't disrupt the pprint # - an apostrophe doesn't disrupt the pprint
special = "Portons dix bons \"whiskys\"\nà l'avocat goujat\t qui fumait au zoo" special = "Portons dix bons \"whiskys\"\nà l'avocat goujat\t qui fumait au zoo"
self.assertEqual(pprint.pformat(special, width=20), """\ self.assertEqual(pprint.pformat(special, width=21), """\
'Portons dix bons ' ('Portons dix '
'"whiskys"\\n' 'bons "whiskys"\\n'
"à l'avocat " "à l'avocat "
'goujat\\t qui ' 'goujat\\t qui '
'fumait au zoo'""") 'fumait au zoo')""")
# An unwrappable string is formatted as its repr # An unwrappable string is formatted as its repr
unwrappable = "x" * 100 unwrappable = "x" * 100
self.assertEqual(pprint.pformat(unwrappable, width=80), repr(unwrappable)) self.assertEqual(pprint.pformat(unwrappable, width=80), repr(unwrappable))
@ -566,7 +567,9 @@ frozenset2({0,
special *= 10 special *= 10
for width in range(3, 40): for width in range(3, 40):
formatted = pprint.pformat(special, width=width) formatted = pprint.pformat(special, width=width)
self.assertEqual(eval("(" + formatted + ")"), special) self.assertEqual(eval(formatted), special)
formatted = pprint.pformat([special] * 2, width=width)
self.assertEqual(eval(formatted), [special] * 2)
def test_compact(self): def test_compact(self):
o = ([list(range(i * i)) for i in range(5)] + o = ([list(range(i * i)) for i in range(5)] +

View File

@ -196,6 +196,8 @@ Core and Builtins
Library Library
------- -------
- Issue #19104: pprint now produces evaluable output for wrapped strings.
- Issue #23071: Added missing names to codecs.__all__. Patch by Martin Panter. - Issue #23071: Added missing names to codecs.__all__. Patch by Martin Panter.
- Issue #22783: Pickling now uses the NEWOBJ opcode instead of the NEWOBJ_EX - Issue #22783: Pickling now uses the NEWOBJ opcode instead of the NEWOBJ_EX