17db96d56Sopenharmony_ci# Author: Fred L. Drake, Jr. 27db96d56Sopenharmony_ci# fdrake@acm.org 37db96d56Sopenharmony_ci# 47db96d56Sopenharmony_ci# This is a simple little module I wrote to make life easier. I didn't 57db96d56Sopenharmony_ci# see anything quite like it in the library, though I may have overlooked 67db96d56Sopenharmony_ci# something. I wrote this when I was trying to read some heavily nested 77db96d56Sopenharmony_ci# tuples with fairly non-descriptive content. This is modeled very much 87db96d56Sopenharmony_ci# after Lisp/Scheme - style pretty-printing of lists. If you find it 97db96d56Sopenharmony_ci# useful, thank small children who sleep at night. 107db96d56Sopenharmony_ci 117db96d56Sopenharmony_ci"""Support to pretty-print lists, tuples, & dictionaries recursively. 127db96d56Sopenharmony_ci 137db96d56Sopenharmony_ciVery simple, but useful, especially in debugging data structures. 147db96d56Sopenharmony_ci 157db96d56Sopenharmony_ciClasses 167db96d56Sopenharmony_ci------- 177db96d56Sopenharmony_ci 187db96d56Sopenharmony_ciPrettyPrinter() 197db96d56Sopenharmony_ci Handle pretty-printing operations onto a stream using a configured 207db96d56Sopenharmony_ci set of formatting parameters. 217db96d56Sopenharmony_ci 227db96d56Sopenharmony_ciFunctions 237db96d56Sopenharmony_ci--------- 247db96d56Sopenharmony_ci 257db96d56Sopenharmony_cipformat() 267db96d56Sopenharmony_ci Format a Python object into a pretty-printed representation. 277db96d56Sopenharmony_ci 287db96d56Sopenharmony_cipprint() 297db96d56Sopenharmony_ci Pretty-print a Python object to a stream [default is sys.stdout]. 307db96d56Sopenharmony_ci 317db96d56Sopenharmony_cisaferepr() 327db96d56Sopenharmony_ci Generate a 'standard' repr()-like value, but protect against recursive 337db96d56Sopenharmony_ci data structures. 347db96d56Sopenharmony_ci 357db96d56Sopenharmony_ci""" 367db96d56Sopenharmony_ci 377db96d56Sopenharmony_ciimport collections as _collections 387db96d56Sopenharmony_ciimport dataclasses as _dataclasses 397db96d56Sopenharmony_ciimport re 407db96d56Sopenharmony_ciimport sys as _sys 417db96d56Sopenharmony_ciimport types as _types 427db96d56Sopenharmony_cifrom io import StringIO as _StringIO 437db96d56Sopenharmony_ci 447db96d56Sopenharmony_ci__all__ = ["pprint","pformat","isreadable","isrecursive","saferepr", 457db96d56Sopenharmony_ci "PrettyPrinter", "pp"] 467db96d56Sopenharmony_ci 477db96d56Sopenharmony_ci 487db96d56Sopenharmony_cidef pprint(object, stream=None, indent=1, width=80, depth=None, *, 497db96d56Sopenharmony_ci compact=False, sort_dicts=True, underscore_numbers=False): 507db96d56Sopenharmony_ci """Pretty-print a Python object to a stream [default is sys.stdout].""" 517db96d56Sopenharmony_ci printer = PrettyPrinter( 527db96d56Sopenharmony_ci stream=stream, indent=indent, width=width, depth=depth, 537db96d56Sopenharmony_ci compact=compact, sort_dicts=sort_dicts, 547db96d56Sopenharmony_ci underscore_numbers=underscore_numbers) 557db96d56Sopenharmony_ci printer.pprint(object) 567db96d56Sopenharmony_ci 577db96d56Sopenharmony_cidef pformat(object, indent=1, width=80, depth=None, *, 587db96d56Sopenharmony_ci compact=False, sort_dicts=True, underscore_numbers=False): 597db96d56Sopenharmony_ci """Format a Python object into a pretty-printed representation.""" 607db96d56Sopenharmony_ci return PrettyPrinter(indent=indent, width=width, depth=depth, 617db96d56Sopenharmony_ci compact=compact, sort_dicts=sort_dicts, 627db96d56Sopenharmony_ci underscore_numbers=underscore_numbers).pformat(object) 637db96d56Sopenharmony_ci 647db96d56Sopenharmony_cidef pp(object, *args, sort_dicts=False, **kwargs): 657db96d56Sopenharmony_ci """Pretty-print a Python object""" 667db96d56Sopenharmony_ci pprint(object, *args, sort_dicts=sort_dicts, **kwargs) 677db96d56Sopenharmony_ci 687db96d56Sopenharmony_cidef saferepr(object): 697db96d56Sopenharmony_ci """Version of repr() which can handle recursive data structures.""" 707db96d56Sopenharmony_ci return PrettyPrinter()._safe_repr(object, {}, None, 0)[0] 717db96d56Sopenharmony_ci 727db96d56Sopenharmony_cidef isreadable(object): 737db96d56Sopenharmony_ci """Determine if saferepr(object) is readable by eval().""" 747db96d56Sopenharmony_ci return PrettyPrinter()._safe_repr(object, {}, None, 0)[1] 757db96d56Sopenharmony_ci 767db96d56Sopenharmony_cidef isrecursive(object): 777db96d56Sopenharmony_ci """Determine if object requires a recursive representation.""" 787db96d56Sopenharmony_ci return PrettyPrinter()._safe_repr(object, {}, None, 0)[2] 797db96d56Sopenharmony_ci 807db96d56Sopenharmony_ciclass _safe_key: 817db96d56Sopenharmony_ci """Helper function for key functions when sorting unorderable objects. 827db96d56Sopenharmony_ci 837db96d56Sopenharmony_ci The wrapped-object will fallback to a Py2.x style comparison for 847db96d56Sopenharmony_ci unorderable types (sorting first comparing the type name and then by 857db96d56Sopenharmony_ci the obj ids). Does not work recursively, so dict.items() must have 867db96d56Sopenharmony_ci _safe_key applied to both the key and the value. 877db96d56Sopenharmony_ci 887db96d56Sopenharmony_ci """ 897db96d56Sopenharmony_ci 907db96d56Sopenharmony_ci __slots__ = ['obj'] 917db96d56Sopenharmony_ci 927db96d56Sopenharmony_ci def __init__(self, obj): 937db96d56Sopenharmony_ci self.obj = obj 947db96d56Sopenharmony_ci 957db96d56Sopenharmony_ci def __lt__(self, other): 967db96d56Sopenharmony_ci try: 977db96d56Sopenharmony_ci return self.obj < other.obj 987db96d56Sopenharmony_ci except TypeError: 997db96d56Sopenharmony_ci return ((str(type(self.obj)), id(self.obj)) < \ 1007db96d56Sopenharmony_ci (str(type(other.obj)), id(other.obj))) 1017db96d56Sopenharmony_ci 1027db96d56Sopenharmony_cidef _safe_tuple(t): 1037db96d56Sopenharmony_ci "Helper function for comparing 2-tuples" 1047db96d56Sopenharmony_ci return _safe_key(t[0]), _safe_key(t[1]) 1057db96d56Sopenharmony_ci 1067db96d56Sopenharmony_ciclass PrettyPrinter: 1077db96d56Sopenharmony_ci def __init__(self, indent=1, width=80, depth=None, stream=None, *, 1087db96d56Sopenharmony_ci compact=False, sort_dicts=True, underscore_numbers=False): 1097db96d56Sopenharmony_ci """Handle pretty printing operations onto a stream using a set of 1107db96d56Sopenharmony_ci configured parameters. 1117db96d56Sopenharmony_ci 1127db96d56Sopenharmony_ci indent 1137db96d56Sopenharmony_ci Number of spaces to indent for each level of nesting. 1147db96d56Sopenharmony_ci 1157db96d56Sopenharmony_ci width 1167db96d56Sopenharmony_ci Attempted maximum number of columns in the output. 1177db96d56Sopenharmony_ci 1187db96d56Sopenharmony_ci depth 1197db96d56Sopenharmony_ci The maximum depth to print out nested structures. 1207db96d56Sopenharmony_ci 1217db96d56Sopenharmony_ci stream 1227db96d56Sopenharmony_ci The desired output stream. If omitted (or false), the standard 1237db96d56Sopenharmony_ci output stream available at construction will be used. 1247db96d56Sopenharmony_ci 1257db96d56Sopenharmony_ci compact 1267db96d56Sopenharmony_ci If true, several items will be combined in one line. 1277db96d56Sopenharmony_ci 1287db96d56Sopenharmony_ci sort_dicts 1297db96d56Sopenharmony_ci If true, dict keys are sorted. 1307db96d56Sopenharmony_ci 1317db96d56Sopenharmony_ci """ 1327db96d56Sopenharmony_ci indent = int(indent) 1337db96d56Sopenharmony_ci width = int(width) 1347db96d56Sopenharmony_ci if indent < 0: 1357db96d56Sopenharmony_ci raise ValueError('indent must be >= 0') 1367db96d56Sopenharmony_ci if depth is not None and depth <= 0: 1377db96d56Sopenharmony_ci raise ValueError('depth must be > 0') 1387db96d56Sopenharmony_ci if not width: 1397db96d56Sopenharmony_ci raise ValueError('width must be != 0') 1407db96d56Sopenharmony_ci self._depth = depth 1417db96d56Sopenharmony_ci self._indent_per_level = indent 1427db96d56Sopenharmony_ci self._width = width 1437db96d56Sopenharmony_ci if stream is not None: 1447db96d56Sopenharmony_ci self._stream = stream 1457db96d56Sopenharmony_ci else: 1467db96d56Sopenharmony_ci self._stream = _sys.stdout 1477db96d56Sopenharmony_ci self._compact = bool(compact) 1487db96d56Sopenharmony_ci self._sort_dicts = sort_dicts 1497db96d56Sopenharmony_ci self._underscore_numbers = underscore_numbers 1507db96d56Sopenharmony_ci 1517db96d56Sopenharmony_ci def pprint(self, object): 1527db96d56Sopenharmony_ci if self._stream is not None: 1537db96d56Sopenharmony_ci self._format(object, self._stream, 0, 0, {}, 0) 1547db96d56Sopenharmony_ci self._stream.write("\n") 1557db96d56Sopenharmony_ci 1567db96d56Sopenharmony_ci def pformat(self, object): 1577db96d56Sopenharmony_ci sio = _StringIO() 1587db96d56Sopenharmony_ci self._format(object, sio, 0, 0, {}, 0) 1597db96d56Sopenharmony_ci return sio.getvalue() 1607db96d56Sopenharmony_ci 1617db96d56Sopenharmony_ci def isrecursive(self, object): 1627db96d56Sopenharmony_ci return self.format(object, {}, 0, 0)[2] 1637db96d56Sopenharmony_ci 1647db96d56Sopenharmony_ci def isreadable(self, object): 1657db96d56Sopenharmony_ci s, readable, recursive = self.format(object, {}, 0, 0) 1667db96d56Sopenharmony_ci return readable and not recursive 1677db96d56Sopenharmony_ci 1687db96d56Sopenharmony_ci def _format(self, object, stream, indent, allowance, context, level): 1697db96d56Sopenharmony_ci objid = id(object) 1707db96d56Sopenharmony_ci if objid in context: 1717db96d56Sopenharmony_ci stream.write(_recursion(object)) 1727db96d56Sopenharmony_ci self._recursive = True 1737db96d56Sopenharmony_ci self._readable = False 1747db96d56Sopenharmony_ci return 1757db96d56Sopenharmony_ci rep = self._repr(object, context, level) 1767db96d56Sopenharmony_ci max_width = self._width - indent - allowance 1777db96d56Sopenharmony_ci if len(rep) > max_width: 1787db96d56Sopenharmony_ci p = self._dispatch.get(type(object).__repr__, None) 1797db96d56Sopenharmony_ci if p is not None: 1807db96d56Sopenharmony_ci context[objid] = 1 1817db96d56Sopenharmony_ci p(self, object, stream, indent, allowance, context, level + 1) 1827db96d56Sopenharmony_ci del context[objid] 1837db96d56Sopenharmony_ci return 1847db96d56Sopenharmony_ci elif (_dataclasses.is_dataclass(object) and 1857db96d56Sopenharmony_ci not isinstance(object, type) and 1867db96d56Sopenharmony_ci object.__dataclass_params__.repr and 1877db96d56Sopenharmony_ci # Check dataclass has generated repr method. 1887db96d56Sopenharmony_ci hasattr(object.__repr__, "__wrapped__") and 1897db96d56Sopenharmony_ci "__create_fn__" in object.__repr__.__wrapped__.__qualname__): 1907db96d56Sopenharmony_ci context[objid] = 1 1917db96d56Sopenharmony_ci self._pprint_dataclass(object, stream, indent, allowance, context, level + 1) 1927db96d56Sopenharmony_ci del context[objid] 1937db96d56Sopenharmony_ci return 1947db96d56Sopenharmony_ci stream.write(rep) 1957db96d56Sopenharmony_ci 1967db96d56Sopenharmony_ci def _pprint_dataclass(self, object, stream, indent, allowance, context, level): 1977db96d56Sopenharmony_ci cls_name = object.__class__.__name__ 1987db96d56Sopenharmony_ci indent += len(cls_name) + 1 1997db96d56Sopenharmony_ci items = [(f.name, getattr(object, f.name)) for f in _dataclasses.fields(object) if f.repr] 2007db96d56Sopenharmony_ci stream.write(cls_name + '(') 2017db96d56Sopenharmony_ci self._format_namespace_items(items, stream, indent, allowance, context, level) 2027db96d56Sopenharmony_ci stream.write(')') 2037db96d56Sopenharmony_ci 2047db96d56Sopenharmony_ci _dispatch = {} 2057db96d56Sopenharmony_ci 2067db96d56Sopenharmony_ci def _pprint_dict(self, object, stream, indent, allowance, context, level): 2077db96d56Sopenharmony_ci write = stream.write 2087db96d56Sopenharmony_ci write('{') 2097db96d56Sopenharmony_ci if self._indent_per_level > 1: 2107db96d56Sopenharmony_ci write((self._indent_per_level - 1) * ' ') 2117db96d56Sopenharmony_ci length = len(object) 2127db96d56Sopenharmony_ci if length: 2137db96d56Sopenharmony_ci if self._sort_dicts: 2147db96d56Sopenharmony_ci items = sorted(object.items(), key=_safe_tuple) 2157db96d56Sopenharmony_ci else: 2167db96d56Sopenharmony_ci items = object.items() 2177db96d56Sopenharmony_ci self._format_dict_items(items, stream, indent, allowance + 1, 2187db96d56Sopenharmony_ci context, level) 2197db96d56Sopenharmony_ci write('}') 2207db96d56Sopenharmony_ci 2217db96d56Sopenharmony_ci _dispatch[dict.__repr__] = _pprint_dict 2227db96d56Sopenharmony_ci 2237db96d56Sopenharmony_ci def _pprint_ordered_dict(self, object, stream, indent, allowance, context, level): 2247db96d56Sopenharmony_ci if not len(object): 2257db96d56Sopenharmony_ci stream.write(repr(object)) 2267db96d56Sopenharmony_ci return 2277db96d56Sopenharmony_ci cls = object.__class__ 2287db96d56Sopenharmony_ci stream.write(cls.__name__ + '(') 2297db96d56Sopenharmony_ci self._format(list(object.items()), stream, 2307db96d56Sopenharmony_ci indent + len(cls.__name__) + 1, allowance + 1, 2317db96d56Sopenharmony_ci context, level) 2327db96d56Sopenharmony_ci stream.write(')') 2337db96d56Sopenharmony_ci 2347db96d56Sopenharmony_ci _dispatch[_collections.OrderedDict.__repr__] = _pprint_ordered_dict 2357db96d56Sopenharmony_ci 2367db96d56Sopenharmony_ci def _pprint_list(self, object, stream, indent, allowance, context, level): 2377db96d56Sopenharmony_ci stream.write('[') 2387db96d56Sopenharmony_ci self._format_items(object, stream, indent, allowance + 1, 2397db96d56Sopenharmony_ci context, level) 2407db96d56Sopenharmony_ci stream.write(']') 2417db96d56Sopenharmony_ci 2427db96d56Sopenharmony_ci _dispatch[list.__repr__] = _pprint_list 2437db96d56Sopenharmony_ci 2447db96d56Sopenharmony_ci def _pprint_tuple(self, object, stream, indent, allowance, context, level): 2457db96d56Sopenharmony_ci stream.write('(') 2467db96d56Sopenharmony_ci endchar = ',)' if len(object) == 1 else ')' 2477db96d56Sopenharmony_ci self._format_items(object, stream, indent, allowance + len(endchar), 2487db96d56Sopenharmony_ci context, level) 2497db96d56Sopenharmony_ci stream.write(endchar) 2507db96d56Sopenharmony_ci 2517db96d56Sopenharmony_ci _dispatch[tuple.__repr__] = _pprint_tuple 2527db96d56Sopenharmony_ci 2537db96d56Sopenharmony_ci def _pprint_set(self, object, stream, indent, allowance, context, level): 2547db96d56Sopenharmony_ci if not len(object): 2557db96d56Sopenharmony_ci stream.write(repr(object)) 2567db96d56Sopenharmony_ci return 2577db96d56Sopenharmony_ci typ = object.__class__ 2587db96d56Sopenharmony_ci if typ is set: 2597db96d56Sopenharmony_ci stream.write('{') 2607db96d56Sopenharmony_ci endchar = '}' 2617db96d56Sopenharmony_ci else: 2627db96d56Sopenharmony_ci stream.write(typ.__name__ + '({') 2637db96d56Sopenharmony_ci endchar = '})' 2647db96d56Sopenharmony_ci indent += len(typ.__name__) + 1 2657db96d56Sopenharmony_ci object = sorted(object, key=_safe_key) 2667db96d56Sopenharmony_ci self._format_items(object, stream, indent, allowance + len(endchar), 2677db96d56Sopenharmony_ci context, level) 2687db96d56Sopenharmony_ci stream.write(endchar) 2697db96d56Sopenharmony_ci 2707db96d56Sopenharmony_ci _dispatch[set.__repr__] = _pprint_set 2717db96d56Sopenharmony_ci _dispatch[frozenset.__repr__] = _pprint_set 2727db96d56Sopenharmony_ci 2737db96d56Sopenharmony_ci def _pprint_str(self, object, stream, indent, allowance, context, level): 2747db96d56Sopenharmony_ci write = stream.write 2757db96d56Sopenharmony_ci if not len(object): 2767db96d56Sopenharmony_ci write(repr(object)) 2777db96d56Sopenharmony_ci return 2787db96d56Sopenharmony_ci chunks = [] 2797db96d56Sopenharmony_ci lines = object.splitlines(True) 2807db96d56Sopenharmony_ci if level == 1: 2817db96d56Sopenharmony_ci indent += 1 2827db96d56Sopenharmony_ci allowance += 1 2837db96d56Sopenharmony_ci max_width1 = max_width = self._width - indent 2847db96d56Sopenharmony_ci for i, line in enumerate(lines): 2857db96d56Sopenharmony_ci rep = repr(line) 2867db96d56Sopenharmony_ci if i == len(lines) - 1: 2877db96d56Sopenharmony_ci max_width1 -= allowance 2887db96d56Sopenharmony_ci if len(rep) <= max_width1: 2897db96d56Sopenharmony_ci chunks.append(rep) 2907db96d56Sopenharmony_ci else: 2917db96d56Sopenharmony_ci # A list of alternating (non-space, space) strings 2927db96d56Sopenharmony_ci parts = re.findall(r'\S*\s*', line) 2937db96d56Sopenharmony_ci assert parts 2947db96d56Sopenharmony_ci assert not parts[-1] 2957db96d56Sopenharmony_ci parts.pop() # drop empty last part 2967db96d56Sopenharmony_ci max_width2 = max_width 2977db96d56Sopenharmony_ci current = '' 2987db96d56Sopenharmony_ci for j, part in enumerate(parts): 2997db96d56Sopenharmony_ci candidate = current + part 3007db96d56Sopenharmony_ci if j == len(parts) - 1 and i == len(lines) - 1: 3017db96d56Sopenharmony_ci max_width2 -= allowance 3027db96d56Sopenharmony_ci if len(repr(candidate)) > max_width2: 3037db96d56Sopenharmony_ci if current: 3047db96d56Sopenharmony_ci chunks.append(repr(current)) 3057db96d56Sopenharmony_ci current = part 3067db96d56Sopenharmony_ci else: 3077db96d56Sopenharmony_ci current = candidate 3087db96d56Sopenharmony_ci if current: 3097db96d56Sopenharmony_ci chunks.append(repr(current)) 3107db96d56Sopenharmony_ci if len(chunks) == 1: 3117db96d56Sopenharmony_ci write(rep) 3127db96d56Sopenharmony_ci return 3137db96d56Sopenharmony_ci if level == 1: 3147db96d56Sopenharmony_ci write('(') 3157db96d56Sopenharmony_ci for i, rep in enumerate(chunks): 3167db96d56Sopenharmony_ci if i > 0: 3177db96d56Sopenharmony_ci write('\n' + ' '*indent) 3187db96d56Sopenharmony_ci write(rep) 3197db96d56Sopenharmony_ci if level == 1: 3207db96d56Sopenharmony_ci write(')') 3217db96d56Sopenharmony_ci 3227db96d56Sopenharmony_ci _dispatch[str.__repr__] = _pprint_str 3237db96d56Sopenharmony_ci 3247db96d56Sopenharmony_ci def _pprint_bytes(self, object, stream, indent, allowance, context, level): 3257db96d56Sopenharmony_ci write = stream.write 3267db96d56Sopenharmony_ci if len(object) <= 4: 3277db96d56Sopenharmony_ci write(repr(object)) 3287db96d56Sopenharmony_ci return 3297db96d56Sopenharmony_ci parens = level == 1 3307db96d56Sopenharmony_ci if parens: 3317db96d56Sopenharmony_ci indent += 1 3327db96d56Sopenharmony_ci allowance += 1 3337db96d56Sopenharmony_ci write('(') 3347db96d56Sopenharmony_ci delim = '' 3357db96d56Sopenharmony_ci for rep in _wrap_bytes_repr(object, self._width - indent, allowance): 3367db96d56Sopenharmony_ci write(delim) 3377db96d56Sopenharmony_ci write(rep) 3387db96d56Sopenharmony_ci if not delim: 3397db96d56Sopenharmony_ci delim = '\n' + ' '*indent 3407db96d56Sopenharmony_ci if parens: 3417db96d56Sopenharmony_ci write(')') 3427db96d56Sopenharmony_ci 3437db96d56Sopenharmony_ci _dispatch[bytes.__repr__] = _pprint_bytes 3447db96d56Sopenharmony_ci 3457db96d56Sopenharmony_ci def _pprint_bytearray(self, object, stream, indent, allowance, context, level): 3467db96d56Sopenharmony_ci write = stream.write 3477db96d56Sopenharmony_ci write('bytearray(') 3487db96d56Sopenharmony_ci self._pprint_bytes(bytes(object), stream, indent + 10, 3497db96d56Sopenharmony_ci allowance + 1, context, level + 1) 3507db96d56Sopenharmony_ci write(')') 3517db96d56Sopenharmony_ci 3527db96d56Sopenharmony_ci _dispatch[bytearray.__repr__] = _pprint_bytearray 3537db96d56Sopenharmony_ci 3547db96d56Sopenharmony_ci def _pprint_mappingproxy(self, object, stream, indent, allowance, context, level): 3557db96d56Sopenharmony_ci stream.write('mappingproxy(') 3567db96d56Sopenharmony_ci self._format(object.copy(), stream, indent + 13, allowance + 1, 3577db96d56Sopenharmony_ci context, level) 3587db96d56Sopenharmony_ci stream.write(')') 3597db96d56Sopenharmony_ci 3607db96d56Sopenharmony_ci _dispatch[_types.MappingProxyType.__repr__] = _pprint_mappingproxy 3617db96d56Sopenharmony_ci 3627db96d56Sopenharmony_ci def _pprint_simplenamespace(self, object, stream, indent, allowance, context, level): 3637db96d56Sopenharmony_ci if type(object) is _types.SimpleNamespace: 3647db96d56Sopenharmony_ci # The SimpleNamespace repr is "namespace" instead of the class 3657db96d56Sopenharmony_ci # name, so we do the same here. For subclasses; use the class name. 3667db96d56Sopenharmony_ci cls_name = 'namespace' 3677db96d56Sopenharmony_ci else: 3687db96d56Sopenharmony_ci cls_name = object.__class__.__name__ 3697db96d56Sopenharmony_ci indent += len(cls_name) + 1 3707db96d56Sopenharmony_ci items = object.__dict__.items() 3717db96d56Sopenharmony_ci stream.write(cls_name + '(') 3727db96d56Sopenharmony_ci self._format_namespace_items(items, stream, indent, allowance, context, level) 3737db96d56Sopenharmony_ci stream.write(')') 3747db96d56Sopenharmony_ci 3757db96d56Sopenharmony_ci _dispatch[_types.SimpleNamespace.__repr__] = _pprint_simplenamespace 3767db96d56Sopenharmony_ci 3777db96d56Sopenharmony_ci def _format_dict_items(self, items, stream, indent, allowance, context, 3787db96d56Sopenharmony_ci level): 3797db96d56Sopenharmony_ci write = stream.write 3807db96d56Sopenharmony_ci indent += self._indent_per_level 3817db96d56Sopenharmony_ci delimnl = ',\n' + ' ' * indent 3827db96d56Sopenharmony_ci last_index = len(items) - 1 3837db96d56Sopenharmony_ci for i, (key, ent) in enumerate(items): 3847db96d56Sopenharmony_ci last = i == last_index 3857db96d56Sopenharmony_ci rep = self._repr(key, context, level) 3867db96d56Sopenharmony_ci write(rep) 3877db96d56Sopenharmony_ci write(': ') 3887db96d56Sopenharmony_ci self._format(ent, stream, indent + len(rep) + 2, 3897db96d56Sopenharmony_ci allowance if last else 1, 3907db96d56Sopenharmony_ci context, level) 3917db96d56Sopenharmony_ci if not last: 3927db96d56Sopenharmony_ci write(delimnl) 3937db96d56Sopenharmony_ci 3947db96d56Sopenharmony_ci def _format_namespace_items(self, items, stream, indent, allowance, context, level): 3957db96d56Sopenharmony_ci write = stream.write 3967db96d56Sopenharmony_ci delimnl = ',\n' + ' ' * indent 3977db96d56Sopenharmony_ci last_index = len(items) - 1 3987db96d56Sopenharmony_ci for i, (key, ent) in enumerate(items): 3997db96d56Sopenharmony_ci last = i == last_index 4007db96d56Sopenharmony_ci write(key) 4017db96d56Sopenharmony_ci write('=') 4027db96d56Sopenharmony_ci if id(ent) in context: 4037db96d56Sopenharmony_ci # Special-case representation of recursion to match standard 4047db96d56Sopenharmony_ci # recursive dataclass repr. 4057db96d56Sopenharmony_ci write("...") 4067db96d56Sopenharmony_ci else: 4077db96d56Sopenharmony_ci self._format(ent, stream, indent + len(key) + 1, 4087db96d56Sopenharmony_ci allowance if last else 1, 4097db96d56Sopenharmony_ci context, level) 4107db96d56Sopenharmony_ci if not last: 4117db96d56Sopenharmony_ci write(delimnl) 4127db96d56Sopenharmony_ci 4137db96d56Sopenharmony_ci def _format_items(self, items, stream, indent, allowance, context, level): 4147db96d56Sopenharmony_ci write = stream.write 4157db96d56Sopenharmony_ci indent += self._indent_per_level 4167db96d56Sopenharmony_ci if self._indent_per_level > 1: 4177db96d56Sopenharmony_ci write((self._indent_per_level - 1) * ' ') 4187db96d56Sopenharmony_ci delimnl = ',\n' + ' ' * indent 4197db96d56Sopenharmony_ci delim = '' 4207db96d56Sopenharmony_ci width = max_width = self._width - indent + 1 4217db96d56Sopenharmony_ci it = iter(items) 4227db96d56Sopenharmony_ci try: 4237db96d56Sopenharmony_ci next_ent = next(it) 4247db96d56Sopenharmony_ci except StopIteration: 4257db96d56Sopenharmony_ci return 4267db96d56Sopenharmony_ci last = False 4277db96d56Sopenharmony_ci while not last: 4287db96d56Sopenharmony_ci ent = next_ent 4297db96d56Sopenharmony_ci try: 4307db96d56Sopenharmony_ci next_ent = next(it) 4317db96d56Sopenharmony_ci except StopIteration: 4327db96d56Sopenharmony_ci last = True 4337db96d56Sopenharmony_ci max_width -= allowance 4347db96d56Sopenharmony_ci width -= allowance 4357db96d56Sopenharmony_ci if self._compact: 4367db96d56Sopenharmony_ci rep = self._repr(ent, context, level) 4377db96d56Sopenharmony_ci w = len(rep) + 2 4387db96d56Sopenharmony_ci if width < w: 4397db96d56Sopenharmony_ci width = max_width 4407db96d56Sopenharmony_ci if delim: 4417db96d56Sopenharmony_ci delim = delimnl 4427db96d56Sopenharmony_ci if width >= w: 4437db96d56Sopenharmony_ci width -= w 4447db96d56Sopenharmony_ci write(delim) 4457db96d56Sopenharmony_ci delim = ', ' 4467db96d56Sopenharmony_ci write(rep) 4477db96d56Sopenharmony_ci continue 4487db96d56Sopenharmony_ci write(delim) 4497db96d56Sopenharmony_ci delim = delimnl 4507db96d56Sopenharmony_ci self._format(ent, stream, indent, 4517db96d56Sopenharmony_ci allowance if last else 1, 4527db96d56Sopenharmony_ci context, level) 4537db96d56Sopenharmony_ci 4547db96d56Sopenharmony_ci def _repr(self, object, context, level): 4557db96d56Sopenharmony_ci repr, readable, recursive = self.format(object, context.copy(), 4567db96d56Sopenharmony_ci self._depth, level) 4577db96d56Sopenharmony_ci if not readable: 4587db96d56Sopenharmony_ci self._readable = False 4597db96d56Sopenharmony_ci if recursive: 4607db96d56Sopenharmony_ci self._recursive = True 4617db96d56Sopenharmony_ci return repr 4627db96d56Sopenharmony_ci 4637db96d56Sopenharmony_ci def format(self, object, context, maxlevels, level): 4647db96d56Sopenharmony_ci """Format object for a specific context, returning a string 4657db96d56Sopenharmony_ci and flags indicating whether the representation is 'readable' 4667db96d56Sopenharmony_ci and whether the object represents a recursive construct. 4677db96d56Sopenharmony_ci """ 4687db96d56Sopenharmony_ci return self._safe_repr(object, context, maxlevels, level) 4697db96d56Sopenharmony_ci 4707db96d56Sopenharmony_ci def _pprint_default_dict(self, object, stream, indent, allowance, context, level): 4717db96d56Sopenharmony_ci if not len(object): 4727db96d56Sopenharmony_ci stream.write(repr(object)) 4737db96d56Sopenharmony_ci return 4747db96d56Sopenharmony_ci rdf = self._repr(object.default_factory, context, level) 4757db96d56Sopenharmony_ci cls = object.__class__ 4767db96d56Sopenharmony_ci indent += len(cls.__name__) + 1 4777db96d56Sopenharmony_ci stream.write('%s(%s,\n%s' % (cls.__name__, rdf, ' ' * indent)) 4787db96d56Sopenharmony_ci self._pprint_dict(object, stream, indent, allowance + 1, context, level) 4797db96d56Sopenharmony_ci stream.write(')') 4807db96d56Sopenharmony_ci 4817db96d56Sopenharmony_ci _dispatch[_collections.defaultdict.__repr__] = _pprint_default_dict 4827db96d56Sopenharmony_ci 4837db96d56Sopenharmony_ci def _pprint_counter(self, object, stream, indent, allowance, context, level): 4847db96d56Sopenharmony_ci if not len(object): 4857db96d56Sopenharmony_ci stream.write(repr(object)) 4867db96d56Sopenharmony_ci return 4877db96d56Sopenharmony_ci cls = object.__class__ 4887db96d56Sopenharmony_ci stream.write(cls.__name__ + '({') 4897db96d56Sopenharmony_ci if self._indent_per_level > 1: 4907db96d56Sopenharmony_ci stream.write((self._indent_per_level - 1) * ' ') 4917db96d56Sopenharmony_ci items = object.most_common() 4927db96d56Sopenharmony_ci self._format_dict_items(items, stream, 4937db96d56Sopenharmony_ci indent + len(cls.__name__) + 1, allowance + 2, 4947db96d56Sopenharmony_ci context, level) 4957db96d56Sopenharmony_ci stream.write('})') 4967db96d56Sopenharmony_ci 4977db96d56Sopenharmony_ci _dispatch[_collections.Counter.__repr__] = _pprint_counter 4987db96d56Sopenharmony_ci 4997db96d56Sopenharmony_ci def _pprint_chain_map(self, object, stream, indent, allowance, context, level): 5007db96d56Sopenharmony_ci if not len(object.maps): 5017db96d56Sopenharmony_ci stream.write(repr(object)) 5027db96d56Sopenharmony_ci return 5037db96d56Sopenharmony_ci cls = object.__class__ 5047db96d56Sopenharmony_ci stream.write(cls.__name__ + '(') 5057db96d56Sopenharmony_ci indent += len(cls.__name__) + 1 5067db96d56Sopenharmony_ci for i, m in enumerate(object.maps): 5077db96d56Sopenharmony_ci if i == len(object.maps) - 1: 5087db96d56Sopenharmony_ci self._format(m, stream, indent, allowance + 1, context, level) 5097db96d56Sopenharmony_ci stream.write(')') 5107db96d56Sopenharmony_ci else: 5117db96d56Sopenharmony_ci self._format(m, stream, indent, 1, context, level) 5127db96d56Sopenharmony_ci stream.write(',\n' + ' ' * indent) 5137db96d56Sopenharmony_ci 5147db96d56Sopenharmony_ci _dispatch[_collections.ChainMap.__repr__] = _pprint_chain_map 5157db96d56Sopenharmony_ci 5167db96d56Sopenharmony_ci def _pprint_deque(self, object, stream, indent, allowance, context, level): 5177db96d56Sopenharmony_ci if not len(object): 5187db96d56Sopenharmony_ci stream.write(repr(object)) 5197db96d56Sopenharmony_ci return 5207db96d56Sopenharmony_ci cls = object.__class__ 5217db96d56Sopenharmony_ci stream.write(cls.__name__ + '(') 5227db96d56Sopenharmony_ci indent += len(cls.__name__) + 1 5237db96d56Sopenharmony_ci stream.write('[') 5247db96d56Sopenharmony_ci if object.maxlen is None: 5257db96d56Sopenharmony_ci self._format_items(object, stream, indent, allowance + 2, 5267db96d56Sopenharmony_ci context, level) 5277db96d56Sopenharmony_ci stream.write('])') 5287db96d56Sopenharmony_ci else: 5297db96d56Sopenharmony_ci self._format_items(object, stream, indent, 2, 5307db96d56Sopenharmony_ci context, level) 5317db96d56Sopenharmony_ci rml = self._repr(object.maxlen, context, level) 5327db96d56Sopenharmony_ci stream.write('],\n%smaxlen=%s)' % (' ' * indent, rml)) 5337db96d56Sopenharmony_ci 5347db96d56Sopenharmony_ci _dispatch[_collections.deque.__repr__] = _pprint_deque 5357db96d56Sopenharmony_ci 5367db96d56Sopenharmony_ci def _pprint_user_dict(self, object, stream, indent, allowance, context, level): 5377db96d56Sopenharmony_ci self._format(object.data, stream, indent, allowance, context, level - 1) 5387db96d56Sopenharmony_ci 5397db96d56Sopenharmony_ci _dispatch[_collections.UserDict.__repr__] = _pprint_user_dict 5407db96d56Sopenharmony_ci 5417db96d56Sopenharmony_ci def _pprint_user_list(self, object, stream, indent, allowance, context, level): 5427db96d56Sopenharmony_ci self._format(object.data, stream, indent, allowance, context, level - 1) 5437db96d56Sopenharmony_ci 5447db96d56Sopenharmony_ci _dispatch[_collections.UserList.__repr__] = _pprint_user_list 5457db96d56Sopenharmony_ci 5467db96d56Sopenharmony_ci def _pprint_user_string(self, object, stream, indent, allowance, context, level): 5477db96d56Sopenharmony_ci self._format(object.data, stream, indent, allowance, context, level - 1) 5487db96d56Sopenharmony_ci 5497db96d56Sopenharmony_ci _dispatch[_collections.UserString.__repr__] = _pprint_user_string 5507db96d56Sopenharmony_ci 5517db96d56Sopenharmony_ci def _safe_repr(self, object, context, maxlevels, level): 5527db96d56Sopenharmony_ci # Return triple (repr_string, isreadable, isrecursive). 5537db96d56Sopenharmony_ci typ = type(object) 5547db96d56Sopenharmony_ci if typ in _builtin_scalars: 5557db96d56Sopenharmony_ci return repr(object), True, False 5567db96d56Sopenharmony_ci 5577db96d56Sopenharmony_ci r = getattr(typ, "__repr__", None) 5587db96d56Sopenharmony_ci 5597db96d56Sopenharmony_ci if issubclass(typ, int) and r is int.__repr__: 5607db96d56Sopenharmony_ci if self._underscore_numbers: 5617db96d56Sopenharmony_ci return f"{object:_d}", True, False 5627db96d56Sopenharmony_ci else: 5637db96d56Sopenharmony_ci return repr(object), True, False 5647db96d56Sopenharmony_ci 5657db96d56Sopenharmony_ci if issubclass(typ, dict) and r is dict.__repr__: 5667db96d56Sopenharmony_ci if not object: 5677db96d56Sopenharmony_ci return "{}", True, False 5687db96d56Sopenharmony_ci objid = id(object) 5697db96d56Sopenharmony_ci if maxlevels and level >= maxlevels: 5707db96d56Sopenharmony_ci return "{...}", False, objid in context 5717db96d56Sopenharmony_ci if objid in context: 5727db96d56Sopenharmony_ci return _recursion(object), False, True 5737db96d56Sopenharmony_ci context[objid] = 1 5747db96d56Sopenharmony_ci readable = True 5757db96d56Sopenharmony_ci recursive = False 5767db96d56Sopenharmony_ci components = [] 5777db96d56Sopenharmony_ci append = components.append 5787db96d56Sopenharmony_ci level += 1 5797db96d56Sopenharmony_ci if self._sort_dicts: 5807db96d56Sopenharmony_ci items = sorted(object.items(), key=_safe_tuple) 5817db96d56Sopenharmony_ci else: 5827db96d56Sopenharmony_ci items = object.items() 5837db96d56Sopenharmony_ci for k, v in items: 5847db96d56Sopenharmony_ci krepr, kreadable, krecur = self.format( 5857db96d56Sopenharmony_ci k, context, maxlevels, level) 5867db96d56Sopenharmony_ci vrepr, vreadable, vrecur = self.format( 5877db96d56Sopenharmony_ci v, context, maxlevels, level) 5887db96d56Sopenharmony_ci append("%s: %s" % (krepr, vrepr)) 5897db96d56Sopenharmony_ci readable = readable and kreadable and vreadable 5907db96d56Sopenharmony_ci if krecur or vrecur: 5917db96d56Sopenharmony_ci recursive = True 5927db96d56Sopenharmony_ci del context[objid] 5937db96d56Sopenharmony_ci return "{%s}" % ", ".join(components), readable, recursive 5947db96d56Sopenharmony_ci 5957db96d56Sopenharmony_ci if (issubclass(typ, list) and r is list.__repr__) or \ 5967db96d56Sopenharmony_ci (issubclass(typ, tuple) and r is tuple.__repr__): 5977db96d56Sopenharmony_ci if issubclass(typ, list): 5987db96d56Sopenharmony_ci if not object: 5997db96d56Sopenharmony_ci return "[]", True, False 6007db96d56Sopenharmony_ci format = "[%s]" 6017db96d56Sopenharmony_ci elif len(object) == 1: 6027db96d56Sopenharmony_ci format = "(%s,)" 6037db96d56Sopenharmony_ci else: 6047db96d56Sopenharmony_ci if not object: 6057db96d56Sopenharmony_ci return "()", True, False 6067db96d56Sopenharmony_ci format = "(%s)" 6077db96d56Sopenharmony_ci objid = id(object) 6087db96d56Sopenharmony_ci if maxlevels and level >= maxlevels: 6097db96d56Sopenharmony_ci return format % "...", False, objid in context 6107db96d56Sopenharmony_ci if objid in context: 6117db96d56Sopenharmony_ci return _recursion(object), False, True 6127db96d56Sopenharmony_ci context[objid] = 1 6137db96d56Sopenharmony_ci readable = True 6147db96d56Sopenharmony_ci recursive = False 6157db96d56Sopenharmony_ci components = [] 6167db96d56Sopenharmony_ci append = components.append 6177db96d56Sopenharmony_ci level += 1 6187db96d56Sopenharmony_ci for o in object: 6197db96d56Sopenharmony_ci orepr, oreadable, orecur = self.format( 6207db96d56Sopenharmony_ci o, context, maxlevels, level) 6217db96d56Sopenharmony_ci append(orepr) 6227db96d56Sopenharmony_ci if not oreadable: 6237db96d56Sopenharmony_ci readable = False 6247db96d56Sopenharmony_ci if orecur: 6257db96d56Sopenharmony_ci recursive = True 6267db96d56Sopenharmony_ci del context[objid] 6277db96d56Sopenharmony_ci return format % ", ".join(components), readable, recursive 6287db96d56Sopenharmony_ci 6297db96d56Sopenharmony_ci rep = repr(object) 6307db96d56Sopenharmony_ci return rep, (rep and not rep.startswith('<')), False 6317db96d56Sopenharmony_ci 6327db96d56Sopenharmony_ci_builtin_scalars = frozenset({str, bytes, bytearray, float, complex, 6337db96d56Sopenharmony_ci bool, type(None)}) 6347db96d56Sopenharmony_ci 6357db96d56Sopenharmony_cidef _recursion(object): 6367db96d56Sopenharmony_ci return ("<Recursion on %s with id=%s>" 6377db96d56Sopenharmony_ci % (type(object).__name__, id(object))) 6387db96d56Sopenharmony_ci 6397db96d56Sopenharmony_ci 6407db96d56Sopenharmony_cidef _perfcheck(object=None): 6417db96d56Sopenharmony_ci import time 6427db96d56Sopenharmony_ci if object is None: 6437db96d56Sopenharmony_ci object = [("string", (1, 2), [3, 4], {5: 6, 7: 8})] * 100000 6447db96d56Sopenharmony_ci p = PrettyPrinter() 6457db96d56Sopenharmony_ci t1 = time.perf_counter() 6467db96d56Sopenharmony_ci p._safe_repr(object, {}, None, 0, True) 6477db96d56Sopenharmony_ci t2 = time.perf_counter() 6487db96d56Sopenharmony_ci p.pformat(object) 6497db96d56Sopenharmony_ci t3 = time.perf_counter() 6507db96d56Sopenharmony_ci print("_safe_repr:", t2 - t1) 6517db96d56Sopenharmony_ci print("pformat:", t3 - t2) 6527db96d56Sopenharmony_ci 6537db96d56Sopenharmony_cidef _wrap_bytes_repr(object, width, allowance): 6547db96d56Sopenharmony_ci current = b'' 6557db96d56Sopenharmony_ci last = len(object) // 4 * 4 6567db96d56Sopenharmony_ci for i in range(0, len(object), 4): 6577db96d56Sopenharmony_ci part = object[i: i+4] 6587db96d56Sopenharmony_ci candidate = current + part 6597db96d56Sopenharmony_ci if i == last: 6607db96d56Sopenharmony_ci width -= allowance 6617db96d56Sopenharmony_ci if len(repr(candidate)) > width: 6627db96d56Sopenharmony_ci if current: 6637db96d56Sopenharmony_ci yield repr(current) 6647db96d56Sopenharmony_ci current = part 6657db96d56Sopenharmony_ci else: 6667db96d56Sopenharmony_ci current = candidate 6677db96d56Sopenharmony_ci if current: 6687db96d56Sopenharmony_ci yield repr(current) 6697db96d56Sopenharmony_ci 6707db96d56Sopenharmony_ciif __name__ == "__main__": 6717db96d56Sopenharmony_ci _perfcheck() 672