Issue #23741: Slightly refactor the pprint module to make it a little more

extesible.  No public API is added.
This commit is contained in:
Serhiy Storchaka 2015-03-24 18:45:23 +02:00
parent 72bd327db0
commit 8e2aa88a40

View file

@ -152,130 +152,141 @@ class PrettyPrinter:
return readable and not recursive return readable and not recursive
def _format(self, object, stream, indent, allowance, context, level): def _format(self, object, stream, indent, allowance, context, level):
level = level + 1
objid = id(object) objid = id(object)
if objid in context: if objid in context:
stream.write(_recursion(object)) stream.write(_recursion(object))
self._recursive = True self._recursive = True
self._readable = False self._readable = False
return return
rep = self._repr(object, context, level - 1) rep = self._repr(object, context, level)
typ = type(object)
max_width = self._width - indent - allowance max_width = self._width - indent - allowance
sepLines = len(rep) > max_width if len(rep) > max_width:
p = self._dispatch.get(type(object).__repr__, None)
if p is not None:
context[objid] = 1
p(self, object, stream, indent, allowance, context, level + 1)
del context[objid]
return
elif isinstance(object, dict):
context[objid] = 1
self._pprint_dict(object, stream, indent, allowance,
context, level + 1)
del context[objid]
return
stream.write(rep)
_dispatch = {}
def _pprint_dict(self, object, stream, indent, allowance, context, level):
write = stream.write write = stream.write
write('{')
if self._indent_per_level > 1:
write((self._indent_per_level - 1) * ' ')
length = len(object)
if length:
if isinstance(object, _OrderedDict):
items = list(object.items())
else:
items = sorted(object.items(), key=_safe_tuple)
self._format_dict_items(items, stream, indent, allowance + 1,
context, level)
write('}')
if sepLines: _dispatch[dict.__repr__] = _pprint_dict
r = getattr(typ, "__repr__", None) _dispatch[_OrderedDict.__repr__] = _pprint_dict
if issubclass(typ, dict):
write('{')
if self._indent_per_level > 1:
write((self._indent_per_level - 1) * ' ')
length = len(object)
if length:
context[objid] = 1
if issubclass(typ, _OrderedDict):
items = list(object.items())
else:
items = sorted(object.items(), key=_safe_tuple)
self._format_dict_items(items, stream,
indent + self._indent_per_level,
allowance + 1,
context, level)
del context[objid]
write('}')
return
if ((issubclass(typ, list) and r is list.__repr__) or def _pprint_list(self, object, stream, indent, allowance, context, level):
(issubclass(typ, tuple) and r is tuple.__repr__) or stream.write('[')
(issubclass(typ, set) and r is set.__repr__) or self._format_items(object, stream, indent, allowance + 1,
(issubclass(typ, frozenset) and r is frozenset.__repr__) context, level)
): stream.write(']')
length = len(object)
if issubclass(typ, list):
write('[')
endchar = ']'
elif issubclass(typ, tuple):
write('(')
if length == 1:
endchar = ',)'
else:
endchar = ')'
else:
if not length:
write(rep)
return
if typ is set:
write('{')
endchar = '}'
else:
write(typ.__name__)
write('({')
endchar = '})'
indent += len(typ.__name__) + 1
object = sorted(object, key=_safe_key)
if self._indent_per_level > 1:
write((self._indent_per_level - 1) * ' ')
if length:
context[objid] = 1
self._format_items(object, stream,
indent + self._indent_per_level,
allowance + len(endchar),
context, level)
del context[objid]
write(endchar)
return
if issubclass(typ, str) and len(object) > 0 and r is str.__repr__: _dispatch[list.__repr__] = _pprint_list
chunks = []
lines = object.splitlines(True) def _pprint_tuple(self, object, stream, indent, allowance, context, level):
if level == 1: stream.write('(')
indent += 1 endchar = ',)' if len(object) == 1 else ')'
allowance += 1 self._format_items(object, stream, indent, allowance + len(endchar),
max_width1 = max_width = self._width - indent context, level)
for i, line in enumerate(lines): stream.write(endchar)
rep = repr(line)
if i == len(lines) - 1: _dispatch[tuple.__repr__] = _pprint_tuple
max_width1 -= allowance
if len(rep) <= max_width1: def _pprint_set(self, object, stream, indent, allowance, context, level):
chunks.append(rep) if not len(object):
else: stream.write(repr(object))
# A list of alternating (non-space, space) strings return
parts = re.findall(r'\S*\s*', line) typ = object.__class__
assert parts if typ is set:
assert not parts[-1] stream.write('{')
parts.pop() # drop empty last part endchar = '}'
max_width2 = max_width else:
current = '' stream.write(typ.__name__ + '({')
for j, part in enumerate(parts): endchar = '})'
candidate = current + part indent += len(typ.__name__) + 1
if j == len(parts) - 1 and i == len(lines) - 1: object = sorted(object, key=_safe_key)
max_width2 -= allowance self._format_items(object, stream, indent, allowance + len(endchar),
if len(repr(candidate)) > max_width2: context, level)
if current: stream.write(endchar)
chunks.append(repr(current))
current = part _dispatch[set.__repr__] = _pprint_set
else: _dispatch[frozenset.__repr__] = _pprint_set
current = candidate
def _pprint_str(self, object, stream, indent, allowance, context, level):
write = stream.write
if not len(object):
write(repr(object))
return
chunks = []
lines = object.splitlines(True)
if level == 1:
indent += 1
allowance += 1
max_width1 = max_width = self._width - indent
for i, line in enumerate(lines):
rep = repr(line)
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.findall(r'\S*\s*', line)
assert parts
assert not parts[-1]
parts.pop() # drop empty last part
max_width2 = max_width
current = ''
for j, part in enumerate(parts):
candidate = current + part
if j == len(parts) - 1 and i == len(lines) - 1:
max_width2 -= allowance
if len(repr(candidate)) > max_width2:
if current: if current:
chunks.append(repr(current)) chunks.append(repr(current))
if len(chunks) == 1: current = part
write(rep) else:
return current = candidate
if level == 1: if current:
write('(') chunks.append(repr(current))
for i, rep in enumerate(chunks): if len(chunks) == 1:
if i > 0: write(rep)
write('\n' + ' '*indent) return
write(rep) if level == 1:
if level == 1: write('(')
write(')') for i, rep in enumerate(chunks):
return if i > 0:
write(rep) write('\n' + ' '*indent)
write(rep)
if level == 1:
write(')')
_dispatch[str.__repr__] = _pprint_str
def _format_dict_items(self, items, stream, indent, allowance, context, def _format_dict_items(self, items, stream, indent, allowance, context,
level): level):
write = stream.write write = stream.write
indent += self._indent_per_level
delimnl = ',\n' + ' ' * indent delimnl = ',\n' + ' ' * indent
last_index = len(items) - 1 last_index = len(items) - 1
for i, (key, ent) in enumerate(items): for i, (key, ent) in enumerate(items):
@ -291,6 +302,9 @@ class PrettyPrinter:
def _format_items(self, items, stream, indent, allowance, context, level): def _format_items(self, items, stream, indent, allowance, context, level):
write = stream.write write = stream.write
indent += self._indent_per_level
if self._indent_per_level > 1:
write((self._indent_per_level - 1) * ' ')
delimnl = ',\n' + ' ' * indent delimnl = ',\n' + ' ' * indent
delim = '' delim = ''
width = max_width = self._width - indent + 1 width = max_width = self._width - indent + 1