Issue #19105: pprint now more efficiently uses free space at the right.
This commit is contained in:
parent
8089cd642f
commit
a750ce3325
|
@ -161,7 +161,7 @@ class PrettyPrinter:
|
|||
return
|
||||
rep = self._repr(object, context, level - 1)
|
||||
typ = type(object)
|
||||
max_width = self._width - 1 - indent - allowance
|
||||
max_width = self._width - indent - allowance
|
||||
sepLines = len(rep) > max_width
|
||||
write = stream.write
|
||||
|
||||
|
@ -174,24 +174,14 @@ class PrettyPrinter:
|
|||
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
|
||||
|
@ -207,7 +197,10 @@ class PrettyPrinter:
|
|||
endchar = ']'
|
||||
elif issubclass(typ, tuple):
|
||||
write('(')
|
||||
endchar = ')'
|
||||
if length == 1:
|
||||
endchar = ',)'
|
||||
else:
|
||||
endchar = ')'
|
||||
else:
|
||||
if not length:
|
||||
write(rep)
|
||||
|
@ -227,10 +220,9 @@ class PrettyPrinter:
|
|||
context[objid] = 1
|
||||
self._format_items(object, stream,
|
||||
indent + self._indent_per_level,
|
||||
allowance + 1, context, level)
|
||||
allowance + len(endchar),
|
||||
context, level)
|
||||
del context[objid]
|
||||
if issubclass(typ, tuple) and length == 1:
|
||||
write(',')
|
||||
write(endchar)
|
||||
return
|
||||
|
||||
|
@ -239,19 +231,27 @@ class PrettyPrinter:
|
|||
lines = object.splitlines(True)
|
||||
if level == 1:
|
||||
indent += 1
|
||||
max_width -= 2
|
||||
allowance += 1
|
||||
max_width1 = max_width = self._width - indent
|
||||
for i, line in enumerate(lines):
|
||||
rep = repr(line)
|
||||
if len(rep) <= max_width:
|
||||
if i == len(lines) - 1:
|
||||
max_width1 -= allowance
|
||||
if len(rep) <= max_width1:
|
||||
chunks.append(rep)
|
||||
else:
|
||||
# A list of alternating (non-space, space) strings
|
||||
parts = re.split(r'(\s+)', line) + ['']
|
||||
parts = re.findall(r'\S*\s*', line)
|
||||
assert parts
|
||||
assert not parts[-1]
|
||||
parts.pop() # drop empty last part
|
||||
max_width2 = max_width
|
||||
current = ''
|
||||
for i in range(0, len(parts), 2):
|
||||
part = parts[i] + parts[i+1]
|
||||
for j, part in enumerate(parts):
|
||||
candidate = current + part
|
||||
if len(repr(candidate)) > max_width:
|
||||
if j == len(parts) - 1 and i == len(lines) - 1:
|
||||
max_width2 -= allowance
|
||||
if len(repr(candidate)) > max_width2:
|
||||
if current:
|
||||
chunks.append(repr(current))
|
||||
current = part
|
||||
|
@ -273,12 +273,41 @@ class PrettyPrinter:
|
|||
return
|
||||
write(rep)
|
||||
|
||||
def _format_dict_items(self, items, stream, indent, allowance, context,
|
||||
level):
|
||||
write = stream.write
|
||||
delimnl = ',\n' + ' ' * indent
|
||||
last_index = len(items) - 1
|
||||
for i, (key, ent) in enumerate(items):
|
||||
last = i == last_index
|
||||
rep = self._repr(key, context, level)
|
||||
write(rep)
|
||||
write(': ')
|
||||
self._format(ent, stream, indent + len(rep) + 2,
|
||||
allowance if last else 1,
|
||||
context, level)
|
||||
if not last:
|
||||
write(delimnl)
|
||||
|
||||
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:
|
||||
width = max_width = self._width - indent + 1
|
||||
it = iter(items)
|
||||
try:
|
||||
next_ent = next(it)
|
||||
except StopIteration:
|
||||
return
|
||||
last = False
|
||||
while not last:
|
||||
ent = next_ent
|
||||
try:
|
||||
next_ent = next(it)
|
||||
except StopIteration:
|
||||
last = True
|
||||
max_width -= allowance
|
||||
width -= allowance
|
||||
if self._compact:
|
||||
rep = self._repr(ent, context, level)
|
||||
w = len(rep) + 2
|
||||
|
@ -294,7 +323,9 @@ class PrettyPrinter:
|
|||
continue
|
||||
write(delim)
|
||||
delim = delimnl
|
||||
self._format(ent, stream, indent, allowance, context, level)
|
||||
self._format(ent, stream, indent,
|
||||
allowance if last else 1,
|
||||
context, level)
|
||||
|
||||
def _repr(self, object, context, level):
|
||||
repr, readable, recursive = self.format(object, context.copy(),
|
||||
|
|
|
@ -191,11 +191,53 @@ class QueryTestCase(unittest.TestCase):
|
|||
o2 = dict(first=1, second=2, third=3)
|
||||
o = [o1, o2]
|
||||
expected = """\
|
||||
[ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
|
||||
{'first': 1, 'second': 2, 'third': 3}]"""
|
||||
self.assertEqual(pprint.pformat(o, indent=4, width=42), expected)
|
||||
expected = """\
|
||||
[ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
|
||||
{ 'first': 1,
|
||||
'second': 2,
|
||||
'third': 3}]"""
|
||||
self.assertEqual(pprint.pformat(o, indent=4, width=42), expected)
|
||||
self.assertEqual(pprint.pformat(o, indent=4, width=41), expected)
|
||||
|
||||
def test_width(self):
|
||||
expected = """\
|
||||
[[[[[[1, 2, 3],
|
||||
'1 2']]]],
|
||||
{1: [1, 2, 3],
|
||||
2: [12, 34]},
|
||||
'abc def ghi',
|
||||
('ab cd ef',),
|
||||
set2({1, 23}),
|
||||
[[[[[1, 2, 3],
|
||||
'1 2']]]]]"""
|
||||
o = eval(expected)
|
||||
self.assertEqual(pprint.pformat(o, width=15), expected)
|
||||
self.assertEqual(pprint.pformat(o, width=16), expected)
|
||||
self.assertEqual(pprint.pformat(o, width=25), expected)
|
||||
self.assertEqual(pprint.pformat(o, width=14), """\
|
||||
[[[[[[1,
|
||||
2,
|
||||
3],
|
||||
'1 '
|
||||
'2']]]],
|
||||
{1: [1,
|
||||
2,
|
||||
3],
|
||||
2: [12,
|
||||
34]},
|
||||
'abc def '
|
||||
'ghi',
|
||||
('ab cd '
|
||||
'ef',),
|
||||
set2({1,
|
||||
23}),
|
||||
[[[[[1,
|
||||
2,
|
||||
3],
|
||||
'1 '
|
||||
'2']]]]]""")
|
||||
|
||||
def test_sorted_dict(self):
|
||||
# Starting in Python 2.5, pprint sorts dict displays by key regardless
|
||||
|
@ -535,13 +577,12 @@ frozenset2({0,
|
|||
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(fox, width=19), """\
|
||||
('the quick brown '
|
||||
'fox jumped over '
|
||||
'a lazy dog')""")
|
||||
self.assertEqual(pprint.pformat({'a': 1, 'b': fox, 'c': 2},
|
||||
width=26), """\
|
||||
width=25), """\
|
||||
{'a': 1,
|
||||
'b': 'the quick brown '
|
||||
'fox jumped over '
|
||||
|
@ -553,12 +594,34 @@ frozenset2({0,
|
|||
# - 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=21), """\
|
||||
('Portons dix '
|
||||
'bons "whiskys"\\n'
|
||||
self.assertEqual(pprint.pformat(special, width=68), repr(special))
|
||||
self.assertEqual(pprint.pformat(special, width=31), """\
|
||||
('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')""")
|
||||
self.assertEqual(pprint.pformat([[[[[special]]]]], width=35), """\
|
||||
[[[[['Portons dix bons "whiskys"\\n'
|
||||
"à l'avocat goujat\\t qui "
|
||||
'fumait au zoo']]]]]""")
|
||||
self.assertEqual(pprint.pformat([[[[[special]]]]], width=25), """\
|
||||
[[[[['Portons dix bons '
|
||||
'"whiskys"\\n'
|
||||
"à l'avocat "
|
||||
'goujat\\t qui '
|
||||
'fumait au zoo']]]]]""")
|
||||
self.assertEqual(pprint.pformat([[[[[special]]]]], width=23), """\
|
||||
[[[[['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))
|
||||
|
@ -581,7 +644,19 @@ frozenset2({0,
|
|||
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)
|
||||
self.assertEqual(pprint.pformat(o, width=47, compact=True), expected)
|
||||
|
||||
def test_compact_width(self):
|
||||
levels = 20
|
||||
number = 10
|
||||
o = [0] * number
|
||||
for i in range(levels - 1):
|
||||
o = [o]
|
||||
for w in range(levels * 2 + 1, levels + 3 * number - 1):
|
||||
lines = pprint.pformat(o, width=w, compact=True).splitlines()
|
||||
maxwidth = max(map(len, lines))
|
||||
self.assertLessEqual(maxwidth, w)
|
||||
self.assertGreater(maxwidth, w - 3)
|
||||
|
||||
|
||||
class DottedPrettyPrinter(pprint.PrettyPrinter):
|
||||
|
|
Loading…
Reference in New Issue