1 | n/a | # Author: Fred L. Drake, Jr. |
---|
2 | n/a | # fdrake@acm.org |
---|
3 | n/a | # |
---|
4 | n/a | # This is a simple little module I wrote to make life easier. I didn't |
---|
5 | n/a | # see anything quite like it in the library, though I may have overlooked |
---|
6 | n/a | # something. I wrote this when I was trying to read some heavily nested |
---|
7 | n/a | # tuples with fairly non-descriptive content. This is modeled very much |
---|
8 | n/a | # after Lisp/Scheme - style pretty-printing of lists. If you find it |
---|
9 | n/a | # useful, thank small children who sleep at night. |
---|
10 | n/a | |
---|
11 | n/a | """Support to pretty-print lists, tuples, & dictionaries recursively. |
---|
12 | n/a | |
---|
13 | n/a | Very simple, but useful, especially in debugging data structures. |
---|
14 | n/a | |
---|
15 | n/a | Classes |
---|
16 | n/a | ------- |
---|
17 | n/a | |
---|
18 | n/a | PrettyPrinter() |
---|
19 | n/a | Handle pretty-printing operations onto a stream using a configured |
---|
20 | n/a | set of formatting parameters. |
---|
21 | n/a | |
---|
22 | n/a | Functions |
---|
23 | n/a | --------- |
---|
24 | n/a | |
---|
25 | n/a | pformat() |
---|
26 | n/a | Format a Python object into a pretty-printed representation. |
---|
27 | n/a | |
---|
28 | n/a | pprint() |
---|
29 | n/a | Pretty-print a Python object to a stream [default is sys.stdout]. |
---|
30 | n/a | |
---|
31 | n/a | saferepr() |
---|
32 | n/a | Generate a 'standard' repr()-like value, but protect against recursive |
---|
33 | n/a | data structures. |
---|
34 | n/a | |
---|
35 | n/a | """ |
---|
36 | n/a | |
---|
37 | n/a | import collections as _collections |
---|
38 | n/a | import re |
---|
39 | n/a | import sys as _sys |
---|
40 | n/a | import types as _types |
---|
41 | n/a | from io import StringIO as _StringIO |
---|
42 | n/a | |
---|
43 | n/a | __all__ = ["pprint","pformat","isreadable","isrecursive","saferepr", |
---|
44 | n/a | "PrettyPrinter"] |
---|
45 | n/a | |
---|
46 | n/a | |
---|
47 | n/a | def pprint(object, stream=None, indent=1, width=80, depth=None, *, |
---|
48 | n/a | compact=False): |
---|
49 | n/a | """Pretty-print a Python object to a stream [default is sys.stdout].""" |
---|
50 | n/a | printer = PrettyPrinter( |
---|
51 | n/a | stream=stream, indent=indent, width=width, depth=depth, |
---|
52 | n/a | compact=compact) |
---|
53 | n/a | printer.pprint(object) |
---|
54 | n/a | |
---|
55 | n/a | def pformat(object, indent=1, width=80, depth=None, *, compact=False): |
---|
56 | n/a | """Format a Python object into a pretty-printed representation.""" |
---|
57 | n/a | return PrettyPrinter(indent=indent, width=width, depth=depth, |
---|
58 | n/a | compact=compact).pformat(object) |
---|
59 | n/a | |
---|
60 | n/a | def saferepr(object): |
---|
61 | n/a | """Version of repr() which can handle recursive data structures.""" |
---|
62 | n/a | return _safe_repr(object, {}, None, 0)[0] |
---|
63 | n/a | |
---|
64 | n/a | def isreadable(object): |
---|
65 | n/a | """Determine if saferepr(object) is readable by eval().""" |
---|
66 | n/a | return _safe_repr(object, {}, None, 0)[1] |
---|
67 | n/a | |
---|
68 | n/a | def isrecursive(object): |
---|
69 | n/a | """Determine if object requires a recursive representation.""" |
---|
70 | n/a | return _safe_repr(object, {}, None, 0)[2] |
---|
71 | n/a | |
---|
72 | n/a | class _safe_key: |
---|
73 | n/a | """Helper function for key functions when sorting unorderable objects. |
---|
74 | n/a | |
---|
75 | n/a | The wrapped-object will fallback to a Py2.x style comparison for |
---|
76 | n/a | unorderable types (sorting first comparing the type name and then by |
---|
77 | n/a | the obj ids). Does not work recursively, so dict.items() must have |
---|
78 | n/a | _safe_key applied to both the key and the value. |
---|
79 | n/a | |
---|
80 | n/a | """ |
---|
81 | n/a | |
---|
82 | n/a | __slots__ = ['obj'] |
---|
83 | n/a | |
---|
84 | n/a | def __init__(self, obj): |
---|
85 | n/a | self.obj = obj |
---|
86 | n/a | |
---|
87 | n/a | def __lt__(self, other): |
---|
88 | n/a | try: |
---|
89 | n/a | return self.obj < other.obj |
---|
90 | n/a | except TypeError: |
---|
91 | n/a | return ((str(type(self.obj)), id(self.obj)) < \ |
---|
92 | n/a | (str(type(other.obj)), id(other.obj))) |
---|
93 | n/a | |
---|
94 | n/a | def _safe_tuple(t): |
---|
95 | n/a | "Helper function for comparing 2-tuples" |
---|
96 | n/a | return _safe_key(t[0]), _safe_key(t[1]) |
---|
97 | n/a | |
---|
98 | n/a | class PrettyPrinter: |
---|
99 | n/a | def __init__(self, indent=1, width=80, depth=None, stream=None, *, |
---|
100 | n/a | compact=False): |
---|
101 | n/a | """Handle pretty printing operations onto a stream using a set of |
---|
102 | n/a | configured parameters. |
---|
103 | n/a | |
---|
104 | n/a | indent |
---|
105 | n/a | Number of spaces to indent for each level of nesting. |
---|
106 | n/a | |
---|
107 | n/a | width |
---|
108 | n/a | Attempted maximum number of columns in the output. |
---|
109 | n/a | |
---|
110 | n/a | depth |
---|
111 | n/a | The maximum depth to print out nested structures. |
---|
112 | n/a | |
---|
113 | n/a | stream |
---|
114 | n/a | The desired output stream. If omitted (or false), the standard |
---|
115 | n/a | output stream available at construction will be used. |
---|
116 | n/a | |
---|
117 | n/a | compact |
---|
118 | n/a | If true, several items will be combined in one line. |
---|
119 | n/a | |
---|
120 | n/a | """ |
---|
121 | n/a | indent = int(indent) |
---|
122 | n/a | width = int(width) |
---|
123 | n/a | if indent < 0: |
---|
124 | n/a | raise ValueError('indent must be >= 0') |
---|
125 | n/a | if depth is not None and depth <= 0: |
---|
126 | n/a | raise ValueError('depth must be > 0') |
---|
127 | n/a | if not width: |
---|
128 | n/a | raise ValueError('width must be != 0') |
---|
129 | n/a | self._depth = depth |
---|
130 | n/a | self._indent_per_level = indent |
---|
131 | n/a | self._width = width |
---|
132 | n/a | if stream is not None: |
---|
133 | n/a | self._stream = stream |
---|
134 | n/a | else: |
---|
135 | n/a | self._stream = _sys.stdout |
---|
136 | n/a | self._compact = bool(compact) |
---|
137 | n/a | |
---|
138 | n/a | def pprint(self, object): |
---|
139 | n/a | self._format(object, self._stream, 0, 0, {}, 0) |
---|
140 | n/a | self._stream.write("\n") |
---|
141 | n/a | |
---|
142 | n/a | def pformat(self, object): |
---|
143 | n/a | sio = _StringIO() |
---|
144 | n/a | self._format(object, sio, 0, 0, {}, 0) |
---|
145 | n/a | return sio.getvalue() |
---|
146 | n/a | |
---|
147 | n/a | def isrecursive(self, object): |
---|
148 | n/a | return self.format(object, {}, 0, 0)[2] |
---|
149 | n/a | |
---|
150 | n/a | def isreadable(self, object): |
---|
151 | n/a | s, readable, recursive = self.format(object, {}, 0, 0) |
---|
152 | n/a | return readable and not recursive |
---|
153 | n/a | |
---|
154 | n/a | def _format(self, object, stream, indent, allowance, context, level): |
---|
155 | n/a | objid = id(object) |
---|
156 | n/a | if objid in context: |
---|
157 | n/a | stream.write(_recursion(object)) |
---|
158 | n/a | self._recursive = True |
---|
159 | n/a | self._readable = False |
---|
160 | n/a | return |
---|
161 | n/a | rep = self._repr(object, context, level) |
---|
162 | n/a | max_width = self._width - indent - allowance |
---|
163 | n/a | if len(rep) > max_width: |
---|
164 | n/a | p = self._dispatch.get(type(object).__repr__, None) |
---|
165 | n/a | if p is not None: |
---|
166 | n/a | context[objid] = 1 |
---|
167 | n/a | p(self, object, stream, indent, allowance, context, level + 1) |
---|
168 | n/a | del context[objid] |
---|
169 | n/a | return |
---|
170 | n/a | elif isinstance(object, dict): |
---|
171 | n/a | context[objid] = 1 |
---|
172 | n/a | self._pprint_dict(object, stream, indent, allowance, |
---|
173 | n/a | context, level + 1) |
---|
174 | n/a | del context[objid] |
---|
175 | n/a | return |
---|
176 | n/a | stream.write(rep) |
---|
177 | n/a | |
---|
178 | n/a | _dispatch = {} |
---|
179 | n/a | |
---|
180 | n/a | def _pprint_dict(self, object, stream, indent, allowance, context, level): |
---|
181 | n/a | write = stream.write |
---|
182 | n/a | write('{') |
---|
183 | n/a | if self._indent_per_level > 1: |
---|
184 | n/a | write((self._indent_per_level - 1) * ' ') |
---|
185 | n/a | length = len(object) |
---|
186 | n/a | if length: |
---|
187 | n/a | items = sorted(object.items(), key=_safe_tuple) |
---|
188 | n/a | self._format_dict_items(items, stream, indent, allowance + 1, |
---|
189 | n/a | context, level) |
---|
190 | n/a | write('}') |
---|
191 | n/a | |
---|
192 | n/a | _dispatch[dict.__repr__] = _pprint_dict |
---|
193 | n/a | |
---|
194 | n/a | def _pprint_ordered_dict(self, object, stream, indent, allowance, context, level): |
---|
195 | n/a | if not len(object): |
---|
196 | n/a | stream.write(repr(object)) |
---|
197 | n/a | return |
---|
198 | n/a | cls = object.__class__ |
---|
199 | n/a | stream.write(cls.__name__ + '(') |
---|
200 | n/a | self._format(list(object.items()), stream, |
---|
201 | n/a | indent + len(cls.__name__) + 1, allowance + 1, |
---|
202 | n/a | context, level) |
---|
203 | n/a | stream.write(')') |
---|
204 | n/a | |
---|
205 | n/a | _dispatch[_collections.OrderedDict.__repr__] = _pprint_ordered_dict |
---|
206 | n/a | |
---|
207 | n/a | def _pprint_list(self, object, stream, indent, allowance, context, level): |
---|
208 | n/a | stream.write('[') |
---|
209 | n/a | self._format_items(object, stream, indent, allowance + 1, |
---|
210 | n/a | context, level) |
---|
211 | n/a | stream.write(']') |
---|
212 | n/a | |
---|
213 | n/a | _dispatch[list.__repr__] = _pprint_list |
---|
214 | n/a | |
---|
215 | n/a | def _pprint_tuple(self, object, stream, indent, allowance, context, level): |
---|
216 | n/a | stream.write('(') |
---|
217 | n/a | endchar = ',)' if len(object) == 1 else ')' |
---|
218 | n/a | self._format_items(object, stream, indent, allowance + len(endchar), |
---|
219 | n/a | context, level) |
---|
220 | n/a | stream.write(endchar) |
---|
221 | n/a | |
---|
222 | n/a | _dispatch[tuple.__repr__] = _pprint_tuple |
---|
223 | n/a | |
---|
224 | n/a | def _pprint_set(self, object, stream, indent, allowance, context, level): |
---|
225 | n/a | if not len(object): |
---|
226 | n/a | stream.write(repr(object)) |
---|
227 | n/a | return |
---|
228 | n/a | typ = object.__class__ |
---|
229 | n/a | if typ is set: |
---|
230 | n/a | stream.write('{') |
---|
231 | n/a | endchar = '}' |
---|
232 | n/a | else: |
---|
233 | n/a | stream.write(typ.__name__ + '({') |
---|
234 | n/a | endchar = '})' |
---|
235 | n/a | indent += len(typ.__name__) + 1 |
---|
236 | n/a | object = sorted(object, key=_safe_key) |
---|
237 | n/a | self._format_items(object, stream, indent, allowance + len(endchar), |
---|
238 | n/a | context, level) |
---|
239 | n/a | stream.write(endchar) |
---|
240 | n/a | |
---|
241 | n/a | _dispatch[set.__repr__] = _pprint_set |
---|
242 | n/a | _dispatch[frozenset.__repr__] = _pprint_set |
---|
243 | n/a | |
---|
244 | n/a | def _pprint_str(self, object, stream, indent, allowance, context, level): |
---|
245 | n/a | write = stream.write |
---|
246 | n/a | if not len(object): |
---|
247 | n/a | write(repr(object)) |
---|
248 | n/a | return |
---|
249 | n/a | chunks = [] |
---|
250 | n/a | lines = object.splitlines(True) |
---|
251 | n/a | if level == 1: |
---|
252 | n/a | indent += 1 |
---|
253 | n/a | allowance += 1 |
---|
254 | n/a | max_width1 = max_width = self._width - indent |
---|
255 | n/a | for i, line in enumerate(lines): |
---|
256 | n/a | rep = repr(line) |
---|
257 | n/a | if i == len(lines) - 1: |
---|
258 | n/a | max_width1 -= allowance |
---|
259 | n/a | if len(rep) <= max_width1: |
---|
260 | n/a | chunks.append(rep) |
---|
261 | n/a | else: |
---|
262 | n/a | # A list of alternating (non-space, space) strings |
---|
263 | n/a | parts = re.findall(r'\S*\s*', line) |
---|
264 | n/a | assert parts |
---|
265 | n/a | assert not parts[-1] |
---|
266 | n/a | parts.pop() # drop empty last part |
---|
267 | n/a | max_width2 = max_width |
---|
268 | n/a | current = '' |
---|
269 | n/a | for j, part in enumerate(parts): |
---|
270 | n/a | candidate = current + part |
---|
271 | n/a | if j == len(parts) - 1 and i == len(lines) - 1: |
---|
272 | n/a | max_width2 -= allowance |
---|
273 | n/a | if len(repr(candidate)) > max_width2: |
---|
274 | n/a | if current: |
---|
275 | n/a | chunks.append(repr(current)) |
---|
276 | n/a | current = part |
---|
277 | n/a | else: |
---|
278 | n/a | current = candidate |
---|
279 | n/a | if current: |
---|
280 | n/a | chunks.append(repr(current)) |
---|
281 | n/a | if len(chunks) == 1: |
---|
282 | n/a | write(rep) |
---|
283 | n/a | return |
---|
284 | n/a | if level == 1: |
---|
285 | n/a | write('(') |
---|
286 | n/a | for i, rep in enumerate(chunks): |
---|
287 | n/a | if i > 0: |
---|
288 | n/a | write('\n' + ' '*indent) |
---|
289 | n/a | write(rep) |
---|
290 | n/a | if level == 1: |
---|
291 | n/a | write(')') |
---|
292 | n/a | |
---|
293 | n/a | _dispatch[str.__repr__] = _pprint_str |
---|
294 | n/a | |
---|
295 | n/a | def _pprint_bytes(self, object, stream, indent, allowance, context, level): |
---|
296 | n/a | write = stream.write |
---|
297 | n/a | if len(object) <= 4: |
---|
298 | n/a | write(repr(object)) |
---|
299 | n/a | return |
---|
300 | n/a | parens = level == 1 |
---|
301 | n/a | if parens: |
---|
302 | n/a | indent += 1 |
---|
303 | n/a | allowance += 1 |
---|
304 | n/a | write('(') |
---|
305 | n/a | delim = '' |
---|
306 | n/a | for rep in _wrap_bytes_repr(object, self._width - indent, allowance): |
---|
307 | n/a | write(delim) |
---|
308 | n/a | write(rep) |
---|
309 | n/a | if not delim: |
---|
310 | n/a | delim = '\n' + ' '*indent |
---|
311 | n/a | if parens: |
---|
312 | n/a | write(')') |
---|
313 | n/a | |
---|
314 | n/a | _dispatch[bytes.__repr__] = _pprint_bytes |
---|
315 | n/a | |
---|
316 | n/a | def _pprint_bytearray(self, object, stream, indent, allowance, context, level): |
---|
317 | n/a | write = stream.write |
---|
318 | n/a | write('bytearray(') |
---|
319 | n/a | self._pprint_bytes(bytes(object), stream, indent + 10, |
---|
320 | n/a | allowance + 1, context, level + 1) |
---|
321 | n/a | write(')') |
---|
322 | n/a | |
---|
323 | n/a | _dispatch[bytearray.__repr__] = _pprint_bytearray |
---|
324 | n/a | |
---|
325 | n/a | def _pprint_mappingproxy(self, object, stream, indent, allowance, context, level): |
---|
326 | n/a | stream.write('mappingproxy(') |
---|
327 | n/a | self._format(object.copy(), stream, indent + 13, allowance + 1, |
---|
328 | n/a | context, level) |
---|
329 | n/a | stream.write(')') |
---|
330 | n/a | |
---|
331 | n/a | _dispatch[_types.MappingProxyType.__repr__] = _pprint_mappingproxy |
---|
332 | n/a | |
---|
333 | n/a | def _format_dict_items(self, items, stream, indent, allowance, context, |
---|
334 | n/a | level): |
---|
335 | n/a | write = stream.write |
---|
336 | n/a | indent += self._indent_per_level |
---|
337 | n/a | delimnl = ',\n' + ' ' * indent |
---|
338 | n/a | last_index = len(items) - 1 |
---|
339 | n/a | for i, (key, ent) in enumerate(items): |
---|
340 | n/a | last = i == last_index |
---|
341 | n/a | rep = self._repr(key, context, level) |
---|
342 | n/a | write(rep) |
---|
343 | n/a | write(': ') |
---|
344 | n/a | self._format(ent, stream, indent + len(rep) + 2, |
---|
345 | n/a | allowance if last else 1, |
---|
346 | n/a | context, level) |
---|
347 | n/a | if not last: |
---|
348 | n/a | write(delimnl) |
---|
349 | n/a | |
---|
350 | n/a | def _format_items(self, items, stream, indent, allowance, context, level): |
---|
351 | n/a | write = stream.write |
---|
352 | n/a | indent += self._indent_per_level |
---|
353 | n/a | if self._indent_per_level > 1: |
---|
354 | n/a | write((self._indent_per_level - 1) * ' ') |
---|
355 | n/a | delimnl = ',\n' + ' ' * indent |
---|
356 | n/a | delim = '' |
---|
357 | n/a | width = max_width = self._width - indent + 1 |
---|
358 | n/a | it = iter(items) |
---|
359 | n/a | try: |
---|
360 | n/a | next_ent = next(it) |
---|
361 | n/a | except StopIteration: |
---|
362 | n/a | return |
---|
363 | n/a | last = False |
---|
364 | n/a | while not last: |
---|
365 | n/a | ent = next_ent |
---|
366 | n/a | try: |
---|
367 | n/a | next_ent = next(it) |
---|
368 | n/a | except StopIteration: |
---|
369 | n/a | last = True |
---|
370 | n/a | max_width -= allowance |
---|
371 | n/a | width -= allowance |
---|
372 | n/a | if self._compact: |
---|
373 | n/a | rep = self._repr(ent, context, level) |
---|
374 | n/a | w = len(rep) + 2 |
---|
375 | n/a | if width < w: |
---|
376 | n/a | width = max_width |
---|
377 | n/a | if delim: |
---|
378 | n/a | delim = delimnl |
---|
379 | n/a | if width >= w: |
---|
380 | n/a | width -= w |
---|
381 | n/a | write(delim) |
---|
382 | n/a | delim = ', ' |
---|
383 | n/a | write(rep) |
---|
384 | n/a | continue |
---|
385 | n/a | write(delim) |
---|
386 | n/a | delim = delimnl |
---|
387 | n/a | self._format(ent, stream, indent, |
---|
388 | n/a | allowance if last else 1, |
---|
389 | n/a | context, level) |
---|
390 | n/a | |
---|
391 | n/a | def _repr(self, object, context, level): |
---|
392 | n/a | repr, readable, recursive = self.format(object, context.copy(), |
---|
393 | n/a | self._depth, level) |
---|
394 | n/a | if not readable: |
---|
395 | n/a | self._readable = False |
---|
396 | n/a | if recursive: |
---|
397 | n/a | self._recursive = True |
---|
398 | n/a | return repr |
---|
399 | n/a | |
---|
400 | n/a | def format(self, object, context, maxlevels, level): |
---|
401 | n/a | """Format object for a specific context, returning a string |
---|
402 | n/a | and flags indicating whether the representation is 'readable' |
---|
403 | n/a | and whether the object represents a recursive construct. |
---|
404 | n/a | """ |
---|
405 | n/a | return _safe_repr(object, context, maxlevels, level) |
---|
406 | n/a | |
---|
407 | n/a | def _pprint_default_dict(self, object, stream, indent, allowance, context, level): |
---|
408 | n/a | if not len(object): |
---|
409 | n/a | stream.write(repr(object)) |
---|
410 | n/a | return |
---|
411 | n/a | rdf = self._repr(object.default_factory, context, level) |
---|
412 | n/a | cls = object.__class__ |
---|
413 | n/a | indent += len(cls.__name__) + 1 |
---|
414 | n/a | stream.write('%s(%s,\n%s' % (cls.__name__, rdf, ' ' * indent)) |
---|
415 | n/a | self._pprint_dict(object, stream, indent, allowance + 1, context, level) |
---|
416 | n/a | stream.write(')') |
---|
417 | n/a | |
---|
418 | n/a | _dispatch[_collections.defaultdict.__repr__] = _pprint_default_dict |
---|
419 | n/a | |
---|
420 | n/a | def _pprint_counter(self, object, stream, indent, allowance, context, level): |
---|
421 | n/a | if not len(object): |
---|
422 | n/a | stream.write(repr(object)) |
---|
423 | n/a | return |
---|
424 | n/a | cls = object.__class__ |
---|
425 | n/a | stream.write(cls.__name__ + '({') |
---|
426 | n/a | if self._indent_per_level > 1: |
---|
427 | n/a | stream.write((self._indent_per_level - 1) * ' ') |
---|
428 | n/a | items = object.most_common() |
---|
429 | n/a | self._format_dict_items(items, stream, |
---|
430 | n/a | indent + len(cls.__name__) + 1, allowance + 2, |
---|
431 | n/a | context, level) |
---|
432 | n/a | stream.write('})') |
---|
433 | n/a | |
---|
434 | n/a | _dispatch[_collections.Counter.__repr__] = _pprint_counter |
---|
435 | n/a | |
---|
436 | n/a | def _pprint_chain_map(self, object, stream, indent, allowance, context, level): |
---|
437 | n/a | if not len(object.maps): |
---|
438 | n/a | stream.write(repr(object)) |
---|
439 | n/a | return |
---|
440 | n/a | cls = object.__class__ |
---|
441 | n/a | stream.write(cls.__name__ + '(') |
---|
442 | n/a | indent += len(cls.__name__) + 1 |
---|
443 | n/a | for i, m in enumerate(object.maps): |
---|
444 | n/a | if i == len(object.maps) - 1: |
---|
445 | n/a | self._format(m, stream, indent, allowance + 1, context, level) |
---|
446 | n/a | stream.write(')') |
---|
447 | n/a | else: |
---|
448 | n/a | self._format(m, stream, indent, 1, context, level) |
---|
449 | n/a | stream.write(',\n' + ' ' * indent) |
---|
450 | n/a | |
---|
451 | n/a | _dispatch[_collections.ChainMap.__repr__] = _pprint_chain_map |
---|
452 | n/a | |
---|
453 | n/a | def _pprint_deque(self, object, stream, indent, allowance, context, level): |
---|
454 | n/a | if not len(object): |
---|
455 | n/a | stream.write(repr(object)) |
---|
456 | n/a | return |
---|
457 | n/a | cls = object.__class__ |
---|
458 | n/a | stream.write(cls.__name__ + '(') |
---|
459 | n/a | indent += len(cls.__name__) + 1 |
---|
460 | n/a | stream.write('[') |
---|
461 | n/a | if object.maxlen is None: |
---|
462 | n/a | self._format_items(object, stream, indent, allowance + 2, |
---|
463 | n/a | context, level) |
---|
464 | n/a | stream.write('])') |
---|
465 | n/a | else: |
---|
466 | n/a | self._format_items(object, stream, indent, 2, |
---|
467 | n/a | context, level) |
---|
468 | n/a | rml = self._repr(object.maxlen, context, level) |
---|
469 | n/a | stream.write('],\n%smaxlen=%s)' % (' ' * indent, rml)) |
---|
470 | n/a | |
---|
471 | n/a | _dispatch[_collections.deque.__repr__] = _pprint_deque |
---|
472 | n/a | |
---|
473 | n/a | def _pprint_user_dict(self, object, stream, indent, allowance, context, level): |
---|
474 | n/a | self._format(object.data, stream, indent, allowance, context, level - 1) |
---|
475 | n/a | |
---|
476 | n/a | _dispatch[_collections.UserDict.__repr__] = _pprint_user_dict |
---|
477 | n/a | |
---|
478 | n/a | def _pprint_user_list(self, object, stream, indent, allowance, context, level): |
---|
479 | n/a | self._format(object.data, stream, indent, allowance, context, level - 1) |
---|
480 | n/a | |
---|
481 | n/a | _dispatch[_collections.UserList.__repr__] = _pprint_user_list |
---|
482 | n/a | |
---|
483 | n/a | def _pprint_user_string(self, object, stream, indent, allowance, context, level): |
---|
484 | n/a | self._format(object.data, stream, indent, allowance, context, level - 1) |
---|
485 | n/a | |
---|
486 | n/a | _dispatch[_collections.UserString.__repr__] = _pprint_user_string |
---|
487 | n/a | |
---|
488 | n/a | # Return triple (repr_string, isreadable, isrecursive). |
---|
489 | n/a | |
---|
490 | n/a | def _safe_repr(object, context, maxlevels, level): |
---|
491 | n/a | typ = type(object) |
---|
492 | n/a | if typ in _builtin_scalars: |
---|
493 | n/a | return repr(object), True, False |
---|
494 | n/a | |
---|
495 | n/a | r = getattr(typ, "__repr__", None) |
---|
496 | n/a | if issubclass(typ, dict) and r is dict.__repr__: |
---|
497 | n/a | if not object: |
---|
498 | n/a | return "{}", True, False |
---|
499 | n/a | objid = id(object) |
---|
500 | n/a | if maxlevels and level >= maxlevels: |
---|
501 | n/a | return "{...}", False, objid in context |
---|
502 | n/a | if objid in context: |
---|
503 | n/a | return _recursion(object), False, True |
---|
504 | n/a | context[objid] = 1 |
---|
505 | n/a | readable = True |
---|
506 | n/a | recursive = False |
---|
507 | n/a | components = [] |
---|
508 | n/a | append = components.append |
---|
509 | n/a | level += 1 |
---|
510 | n/a | saferepr = _safe_repr |
---|
511 | n/a | items = sorted(object.items(), key=_safe_tuple) |
---|
512 | n/a | for k, v in items: |
---|
513 | n/a | krepr, kreadable, krecur = saferepr(k, context, maxlevels, level) |
---|
514 | n/a | vrepr, vreadable, vrecur = saferepr(v, context, maxlevels, level) |
---|
515 | n/a | append("%s: %s" % (krepr, vrepr)) |
---|
516 | n/a | readable = readable and kreadable and vreadable |
---|
517 | n/a | if krecur or vrecur: |
---|
518 | n/a | recursive = True |
---|
519 | n/a | del context[objid] |
---|
520 | n/a | return "{%s}" % ", ".join(components), readable, recursive |
---|
521 | n/a | |
---|
522 | n/a | if (issubclass(typ, list) and r is list.__repr__) or \ |
---|
523 | n/a | (issubclass(typ, tuple) and r is tuple.__repr__): |
---|
524 | n/a | if issubclass(typ, list): |
---|
525 | n/a | if not object: |
---|
526 | n/a | return "[]", True, False |
---|
527 | n/a | format = "[%s]" |
---|
528 | n/a | elif len(object) == 1: |
---|
529 | n/a | format = "(%s,)" |
---|
530 | n/a | else: |
---|
531 | n/a | if not object: |
---|
532 | n/a | return "()", True, False |
---|
533 | n/a | format = "(%s)" |
---|
534 | n/a | objid = id(object) |
---|
535 | n/a | if maxlevels and level >= maxlevels: |
---|
536 | n/a | return format % "...", False, objid in context |
---|
537 | n/a | if objid in context: |
---|
538 | n/a | return _recursion(object), False, True |
---|
539 | n/a | context[objid] = 1 |
---|
540 | n/a | readable = True |
---|
541 | n/a | recursive = False |
---|
542 | n/a | components = [] |
---|
543 | n/a | append = components.append |
---|
544 | n/a | level += 1 |
---|
545 | n/a | for o in object: |
---|
546 | n/a | orepr, oreadable, orecur = _safe_repr(o, context, maxlevels, level) |
---|
547 | n/a | append(orepr) |
---|
548 | n/a | if not oreadable: |
---|
549 | n/a | readable = False |
---|
550 | n/a | if orecur: |
---|
551 | n/a | recursive = True |
---|
552 | n/a | del context[objid] |
---|
553 | n/a | return format % ", ".join(components), readable, recursive |
---|
554 | n/a | |
---|
555 | n/a | rep = repr(object) |
---|
556 | n/a | return rep, (rep and not rep.startswith('<')), False |
---|
557 | n/a | |
---|
558 | n/a | _builtin_scalars = frozenset({str, bytes, bytearray, int, float, complex, |
---|
559 | n/a | bool, type(None)}) |
---|
560 | n/a | |
---|
561 | n/a | def _recursion(object): |
---|
562 | n/a | return ("<Recursion on %s with id=%s>" |
---|
563 | n/a | % (type(object).__name__, id(object))) |
---|
564 | n/a | |
---|
565 | n/a | |
---|
566 | n/a | def _perfcheck(object=None): |
---|
567 | n/a | import time |
---|
568 | n/a | if object is None: |
---|
569 | n/a | object = [("string", (1, 2), [3, 4], {5: 6, 7: 8})] * 100000 |
---|
570 | n/a | p = PrettyPrinter() |
---|
571 | n/a | t1 = time.time() |
---|
572 | n/a | _safe_repr(object, {}, None, 0) |
---|
573 | n/a | t2 = time.time() |
---|
574 | n/a | p.pformat(object) |
---|
575 | n/a | t3 = time.time() |
---|
576 | n/a | print("_safe_repr:", t2 - t1) |
---|
577 | n/a | print("pformat:", t3 - t2) |
---|
578 | n/a | |
---|
579 | n/a | def _wrap_bytes_repr(object, width, allowance): |
---|
580 | n/a | current = b'' |
---|
581 | n/a | last = len(object) // 4 * 4 |
---|
582 | n/a | for i in range(0, len(object), 4): |
---|
583 | n/a | part = object[i: i+4] |
---|
584 | n/a | candidate = current + part |
---|
585 | n/a | if i == last: |
---|
586 | n/a | width -= allowance |
---|
587 | n/a | if len(repr(candidate)) > width: |
---|
588 | n/a | if current: |
---|
589 | n/a | yield repr(current) |
---|
590 | n/a | current = part |
---|
591 | n/a | else: |
---|
592 | n/a | current = candidate |
---|
593 | n/a | if current: |
---|
594 | n/a | yield repr(current) |
---|
595 | n/a | |
---|
596 | n/a | if __name__ == "__main__": |
---|
597 | n/a | _perfcheck() |
---|