summaryrefslogtreecommitdiff
path: root/Lib/pprint.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/pprint.py')
-rw-r--r--Lib/pprint.py355
1 files changed, 232 insertions, 123 deletions
diff --git a/Lib/pprint.py b/Lib/pprint.py
index 2cbffed5d8..723ea9c3dc 100644
--- a/Lib/pprint.py
+++ b/Lib/pprint.py
@@ -34,9 +34,10 @@ saferepr()
"""
+import collections as _collections
import re
import sys as _sys
-from collections import OrderedDict as _OrderedDict
+import types as _types
from io import StringIO as _StringIO
__all__ = ["pprint","pformat","isreadable","isrecursive","saferepr",
@@ -85,14 +86,10 @@ class _safe_key:
def __lt__(self, other):
try:
- rv = self.obj.__lt__(other.obj)
+ return self.obj < other.obj
except TypeError:
- rv = NotImplemented
-
- if rv is NotImplemented:
- rv = (str(type(self.obj)), id(self.obj)) < \
- (str(type(other.obj)), id(other.obj))
- return rv
+ return ((str(type(self.obj)), id(self.obj)) < \
+ (str(type(other.obj)), id(other.obj)))
def _safe_tuple(t):
"Helper function for comparing 2-tuples"
@@ -123,9 +120,12 @@ class PrettyPrinter:
"""
indent = int(indent)
width = int(width)
- assert indent >= 0, "indent must be >= 0"
- assert depth is None or depth > 0, "depth must be > 0"
- assert width, "width must be != 0"
+ if indent < 0:
+ raise ValueError('indent must be >= 0')
+ if depth is not None and depth <= 0:
+ raise ValueError('depth must be > 0')
+ if not width:
+ raise ValueError('width must be != 0')
self._depth = depth
self._indent_per_level = indent
self._width = width
@@ -152,133 +152,223 @@ class PrettyPrinter:
return readable and not recursive
def _format(self, object, stream, indent, allowance, context, level):
- level = level + 1
objid = id(object)
if objid in context:
stream.write(_recursion(object))
self._recursive = True
self._readable = False
return
- rep = self._repr(object, context, level - 1)
- typ = type(object)
- max_width = self._width - 1 - indent - allowance
- sepLines = len(rep) > max_width
- write = stream.write
-
- if sepLines:
- r = getattr(typ, "__repr__", None)
- 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
- 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
- del context[objid]
- write('}')
+ rep = self._repr(object, context, level)
+ max_width = self._width - indent - allowance
+ 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
-
- if ((issubclass(typ, list) and r is list.__repr__) or
- (issubclass(typ, tuple) and r is tuple.__repr__) or
- (issubclass(typ, set) and r is set.__repr__) or
- (issubclass(typ, frozenset) and r is frozenset.__repr__)
- ):
- length = len(object)
- if issubclass(typ, list):
- write('[')
- endchar = ']'
- elif issubclass(typ, tuple):
- write('(')
- 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 + 1, context, level)
- del context[objid]
- if issubclass(typ, tuple) and length == 1:
- write(',')
- write(endchar)
+ elif isinstance(object, dict):
+ context[objid] = 1
+ self._pprint_dict(object, stream, indent, allowance,
+ context, level + 1)
+ del context[objid]
return
+ stream.write(rep)
- if issubclass(typ, str) and len(object) > 0 and r is str.__repr__:
- chunks = []
- lines = object.splitlines(True)
- if level == 1:
- indent += 1
- max_width -= 2
- for i, line in enumerate(lines):
- rep = repr(line)
- if len(rep) <= max_width:
- chunks.append(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:
- chunks.append(repr(current))
- current = part
- else:
- current = candidate
+ _dispatch = {}
+
+ def _pprint_dict(self, object, stream, indent, allowance, context, level):
+ write = stream.write
+ write('{')
+ if self._indent_per_level > 1:
+ write((self._indent_per_level - 1) * ' ')
+ length = len(object)
+ if length:
+ items = sorted(object.items(), key=_safe_tuple)
+ self._format_dict_items(items, stream, indent, allowance + 1,
+ context, level)
+ write('}')
+
+ _dispatch[dict.__repr__] = _pprint_dict
+
+ def _pprint_ordered_dict(self, object, stream, indent, allowance, context, level):
+ if not len(object):
+ stream.write(repr(object))
+ return
+ cls = object.__class__
+ stream.write(cls.__name__ + '(')
+ self._format(list(object.items()), stream,
+ indent + len(cls.__name__) + 1, allowance + 1,
+ context, level)
+ stream.write(')')
+
+ _dispatch[_collections.OrderedDict.__repr__] = _pprint_ordered_dict
+
+ def _pprint_list(self, object, stream, indent, allowance, context, level):
+ stream.write('[')
+ self._format_items(object, stream, indent, allowance + 1,
+ context, level)
+ stream.write(']')
+
+ _dispatch[list.__repr__] = _pprint_list
+
+ def _pprint_tuple(self, object, stream, indent, allowance, context, level):
+ stream.write('(')
+ endchar = ',)' if len(object) == 1 else ')'
+ self._format_items(object, stream, indent, allowance + len(endchar),
+ context, level)
+ stream.write(endchar)
+
+ _dispatch[tuple.__repr__] = _pprint_tuple
+
+ def _pprint_set(self, object, stream, indent, allowance, context, level):
+ if not len(object):
+ stream.write(repr(object))
+ return
+ typ = object.__class__
+ if typ is set:
+ stream.write('{')
+ endchar = '}'
+ else:
+ stream.write(typ.__name__ + '({')
+ endchar = '})'
+ indent += len(typ.__name__) + 1
+ object = sorted(object, key=_safe_key)
+ self._format_items(object, stream, indent, allowance + len(endchar),
+ context, level)
+ stream.write(endchar)
+
+ _dispatch[set.__repr__] = _pprint_set
+ _dispatch[frozenset.__repr__] = _pprint_set
+
+ 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:
chunks.append(repr(current))
- if len(chunks) == 1:
- write(rep)
- return
- if level == 1:
- write('(')
- for i, rep in enumerate(chunks):
- if i > 0:
- write('\n' + ' '*indent)
- write(rep)
- if level == 1:
- write(')')
- return
- write(rep)
+ current = part
+ else:
+ current = candidate
+ if current:
+ chunks.append(repr(current))
+ if len(chunks) == 1:
+ write(rep)
+ return
+ if level == 1:
+ write('(')
+ for i, rep in enumerate(chunks):
+ if i > 0:
+ write('\n' + ' '*indent)
+ write(rep)
+ if level == 1:
+ write(')')
+
+ _dispatch[str.__repr__] = _pprint_str
+
+ def _pprint_bytes(self, object, stream, indent, allowance, context, level):
+ write = stream.write
+ if len(object) <= 4:
+ write(repr(object))
+ return
+ parens = level == 1
+ if parens:
+ indent += 1
+ allowance += 1
+ write('(')
+ delim = ''
+ for rep in _wrap_bytes_repr(object, self._width - indent, allowance):
+ write(delim)
+ write(rep)
+ if not delim:
+ delim = '\n' + ' '*indent
+ if parens:
+ write(')')
+
+ _dispatch[bytes.__repr__] = _pprint_bytes
+
+ def _pprint_bytearray(self, object, stream, indent, allowance, context, level):
+ write = stream.write
+ write('bytearray(')
+ self._pprint_bytes(bytes(object), stream, indent + 10,
+ allowance + 1, context, level + 1)
+ write(')')
+
+ _dispatch[bytearray.__repr__] = _pprint_bytearray
+
+ def _pprint_mappingproxy(self, object, stream, indent, allowance, context, level):
+ stream.write('mappingproxy(')
+ self._format(object.copy(), stream, indent + 13, allowance + 1,
+ context, level)
+ stream.write(')')
+
+ _dispatch[_types.MappingProxyType.__repr__] = _pprint_mappingproxy
+
+ def _format_dict_items(self, items, stream, indent, allowance, context,
+ level):
+ write = stream.write
+ indent += self._indent_per_level
+ 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
+ indent += self._indent_per_level
+ if self._indent_per_level > 1:
+ write((self._indent_per_level - 1) * ' ')
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 +384,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(),
@@ -418,5 +510,22 @@ def _perfcheck(object=None):
print("_safe_repr:", t2 - t1)
print("pformat:", t3 - t2)
+def _wrap_bytes_repr(object, width, allowance):
+ current = b''
+ last = len(object) // 4 * 4
+ for i in range(0, len(object), 4):
+ part = object[i: i+4]
+ candidate = current + part
+ if i == last:
+ width -= allowance
+ if len(repr(candidate)) > width:
+ if current:
+ yield repr(current)
+ current = part
+ else:
+ current = candidate
+ if current:
+ yield repr(current)
+
if __name__ == "__main__":
_perfcheck()