github.com/grumpyhome/grumpy@v0.3.1-0.20201208125205-7b775405bdf1/grumpy-runtime-src/third_party/stdlib/pprint.py (about) 1 # Author: Fred L. Drake, Jr. 2 # fdrake@acm.org 3 # 4 # This is a simple little module I wrote to make life easier. I didn't 5 # see anything quite like it in the library, though I may have overlooked 6 # something. I wrote this when I was trying to read some heavily nested 7 # tuples with fairly non-descriptive content. This is modeled very much 8 # after Lisp/Scheme - style pretty-printing of lists. If you find it 9 # useful, thank small children who sleep at night. 10 11 """Support to pretty-print lists, tuples, & dictionaries recursively. 12 13 Very simple, but useful, especially in debugging data structures. 14 15 Classes 16 ------- 17 18 PrettyPrinter() 19 Handle pretty-printing operations onto a stream using a configured 20 set of formatting parameters. 21 22 Functions 23 --------- 24 25 pformat() 26 Format a Python object into a pretty-printed representation. 27 28 pprint() 29 Pretty-print a Python object to a stream [default is sys.stdout]. 30 31 saferepr() 32 Generate a 'standard' repr()-like value, but protect against recursive 33 data structures. 34 35 """ 36 37 import sys as _sys 38 import warnings 39 import StringIO 40 _StringIO = StringIO.StringIO 41 42 # try: 43 # from cStringIO import StringIO as _StringIO 44 # except ImportError: 45 # from StringIO import StringIO as _StringIO 46 47 __all__ = ["pprint","pformat","isreadable","isrecursive","saferepr", 48 "PrettyPrinter"] 49 50 # cache these for faster access: 51 _commajoin = ", ".join 52 _id = id 53 _len = len 54 _type = type 55 56 57 def pprint(o, stream=None, indent=1, width=80, depth=None): 58 """Pretty-print a Python o to a stream [default is sys.stdout].""" 59 printer = PrettyPrinter( 60 stream=stream, indent=indent, width=width, depth=depth) 61 printer.pprint(o) 62 63 def pformat(o, indent=1, width=80, depth=None): 64 """Format a Python o into a pretty-printed representation.""" 65 return PrettyPrinter(indent=indent, width=width, depth=depth).pformat(o) 66 67 def saferepr(o): 68 """Version of repr() which can handle recursive data structures.""" 69 return _safe_repr(o, {}, None, 0)[0] 70 71 def isreadable(o): 72 """Determine if saferepr(o) is readable by eval().""" 73 return _safe_repr(o, {}, None, 0)[1] 74 75 def isrecursive(o): 76 """Determine if o requires a recursive representation.""" 77 return _safe_repr(o, {}, None, 0)[2] 78 79 def _sorted(iterable): 80 with warnings.catch_warnings(): 81 if _sys.py3kwarning: 82 warnings.filterwarnings("ignore", "comparing unequal types " 83 "not supported", DeprecationWarning) 84 return sorted(iterable) 85 86 class PrettyPrinter(object): 87 def __init__(self, indent=1, width=80, depth=None, stream=None): 88 """Handle pretty printing operations onto a stream using a set of 89 configured parameters. 90 91 indent 92 Number of spaces to indent for each level of nesting. 93 94 width 95 Attempted maximum number of columns in the output. 96 97 depth 98 The maximum depth to print out nested structures. 99 100 stream 101 The desired output stream. If omitted (or false), the standard 102 output stream available at construction will be used. 103 104 """ 105 indent = int(indent) 106 width = int(width) 107 assert indent >= 0, "indent must be >= 0" 108 assert depth is None or depth > 0, "depth must be > 0" 109 assert width, "width must be != 0" 110 self._depth = depth 111 self._indent_per_level = indent 112 self._width = width 113 if stream is not None: 114 self._stream = stream 115 else: 116 self._stream = _sys.stdout 117 118 def pprint(self, o): 119 self._format(o, self._stream, 0, 0, {}, 0) 120 self._stream.write("\n") 121 122 def pformat(self, o): 123 sio = _StringIO() 124 self._format(o, sio, 0, 0, {}, 0) 125 return sio.getvalue() 126 127 def isrecursive(self, o): 128 return self.format(o, {}, 0, 0)[2] 129 130 def isreadable(self, o): 131 s, readable, recursive = self.format(o, {}, 0, 0) 132 return readable and not recursive 133 134 def _format(self, o, stream, indent, allowance, context, level): 135 level = level + 1 136 objid = _id(o) 137 if objid in context: 138 stream.write(_recursion(o)) 139 self._recursive = True 140 self._readable = False 141 return 142 rep = self._repr(o, context, level - 1) 143 typ = _type(o) 144 sepLines = _len(rep) > (self._width - 1 - indent - allowance) 145 write = stream.write 146 147 if self._depth and level > self._depth: 148 write(rep) 149 return 150 151 r = getattr(typ, "__repr__", None) 152 if issubclass(typ, dict):# and r == dict.__repr__: 153 write('{') 154 if self._indent_per_level > 1: 155 write((self._indent_per_level - 1) * ' ') 156 length = _len(o) 157 if length: 158 context[objid] = 1 159 indent = indent + self._indent_per_level 160 items = _sorted(o.items()) 161 key, ent = items[0] 162 rep = self._repr(key, context, level) 163 write(rep) 164 write(': ') 165 self._format(ent, stream, indent + _len(rep) + 2, 166 allowance + 1, context, level) 167 if length > 1: 168 for key, ent in items[1:]: 169 rep = self._repr(key, context, level) 170 if sepLines: 171 write(',\n%s%s: ' % (' '*indent, rep)) 172 else: 173 write(', %s: ' % rep) 174 self._format(ent, stream, indent + _len(rep) + 2, 175 allowance + 1, context, level) 176 indent = indent - self._indent_per_level 177 del context[objid] 178 write('}') 179 return 180 181 # if ((issubclass(typ, list) and r == list.__repr__) or 182 # (issubclass(typ, tuple) and r == tuple.__repr__) or 183 # (issubclass(typ, set) and r == set.__repr__) or 184 # (issubclass(typ, frozenset) and r == frozenset.__repr__) 185 if ((issubclass(typ, list)) or 186 (issubclass(typ, tuple)) or 187 (issubclass(typ, set)) or 188 (issubclass(typ, frozenset)) 189 ): 190 length = _len(o) 191 if issubclass(typ, list): 192 write('[') 193 endchar = ']' 194 elif issubclass(typ, tuple): 195 write('(') 196 endchar = ')' 197 else: 198 if not length: 199 write(rep) 200 return 201 write(typ.__name__) 202 write('([') 203 endchar = '])' 204 indent += len(typ.__name__) + 1 205 o = _sorted(o) 206 if self._indent_per_level > 1 and sepLines: 207 write((self._indent_per_level - 1) * ' ') 208 if length: 209 context[objid] = 1 210 indent = indent + self._indent_per_level 211 self._format(o[0], stream, indent, allowance + 1, 212 context, level) 213 if length > 1: 214 for ent in o[1:]: 215 if sepLines: 216 write(',\n' + ' '*indent) 217 else: 218 write(', ') 219 self._format(ent, stream, indent, 220 allowance + 1, context, level) 221 indent = indent - self._indent_per_level 222 del context[objid] 223 if issubclass(typ, tuple) and length == 1: 224 write(',') 225 write(endchar) 226 return 227 228 write(rep) 229 230 def _repr(self, o, context, level): 231 repr1, readable, recursive = self.format(o, dict(context), 232 self._depth, level) 233 if not readable: 234 self._readable = False 235 if recursive: 236 self._recursive = True 237 return repr1 238 239 def format(self, o, context, maxlevels, level): 240 """Format o for a specific context, returning a string 241 and flags indicating whether the representation is 'readable' 242 and whether the o represents a recursive construct. 243 """ 244 return _safe_repr(o, context, maxlevels, level) 245 246 247 # Return triple (repr_string, isreadable, isrecursive). 248 249 def _safe_repr(o, context, maxlevels, level): 250 typ = _type(o) 251 if typ is str: 252 # if 'locale' not in _sys.modules: 253 # return repr(o), True, False 254 if "'" in o and '"' not in o: 255 closure = '"' 256 quotes = {'"': '\\"'} 257 else: 258 closure = "'" 259 quotes = {"'": "\\'"} 260 qget = quotes.get 261 sio = _StringIO() 262 write = sio.write 263 for char in o: 264 # if char.isalpha(): 265 if 'a' <= char <= 'z' or 'A' <= char <= 'Z': 266 write(char) 267 else: 268 write(qget(char, repr(char)[1:-1])) 269 return ("%s%s%s" % (closure, sio.getvalue(), closure)), True, False 270 271 r = getattr(typ, "__repr__", None) 272 if issubclass(typ, dict):# and r == dict.__repr__: 273 if not o: 274 return "{}", True, False 275 objid = _id(o) 276 if maxlevels and level >= maxlevels: 277 return "{...}", False, objid in context 278 if objid in context: 279 return _recursion(o), False, True 280 context[objid] = 1 281 readable = True 282 recursive = False 283 components = [] 284 append = components.append 285 level += 1 286 saferepr = _safe_repr 287 for k, v in _sorted(o.items()): 288 krepr, kreadable, krecur = saferepr(k, context, maxlevels, level) 289 vrepr, vreadable, vrecur = saferepr(v, context, maxlevels, level) 290 append("%s: %s" % (krepr, vrepr)) 291 readable = readable and kreadable and vreadable 292 if krecur or vrecur: 293 recursive = True 294 del context[objid] 295 return "{%s}" % _commajoin(components), readable, recursive 296 297 # if (issubclass(typ, list) and r == list.__repr__) or \ 298 # (issubclass(typ, tuple) and r == tuple.__repr__): 299 if (issubclass(typ, list)) or \ 300 (issubclass(typ, tuple)): 301 if issubclass(typ, list): 302 if not o: 303 return "[]", True, False 304 format = "[%s]" 305 elif _len(o) == 1: 306 format = "(%s,)" 307 else: 308 if not o: 309 return "()", True, False 310 format = "(%s)" 311 objid = _id(o) 312 if maxlevels and level >= maxlevels: 313 return format % "...", False, objid in context 314 if objid in context: 315 return _recursion(o), False, True 316 context[objid] = 1 317 readable = True 318 recursive = False 319 components = [] 320 append = components.append 321 level += 1 322 for x in o: 323 orepr, oreadable, orecur = _safe_repr(x, context, maxlevels, level) 324 append(orepr) 325 if not oreadable: 326 readable = False 327 if orecur: 328 recursive = True 329 del context[objid] 330 return format % _commajoin(components), readable, recursive 331 332 rep = repr(o) 333 return rep, (rep and not rep.startswith('<')), False 334 335 336 def _recursion(o): 337 return ("<Recursion on %s with id=%s>" 338 % (_type(o).__name__, _id(o))) 339 340 341 # def _perfcheck(o=None): 342 # import time 343 # if o is None: 344 # o = [("string", (1, 2), [3, 4], {5: 6, 7: 8})] * 100000 345 # p = PrettyPrinter() 346 # t1 = time.time() 347 # _safe_repr(o, {}, None, 0) 348 # t2 = time.time() 349 # p.pformat(o) 350 # t3 = time.time() 351 # print "_safe_repr:", t2 - t1 352 # print "pformat:", t3 - t2 353 354 # if __name__ == "__main__": 355 # _perfcheck()