ยปCore Development>Code coverage>Lib/pprint.py

Python code coverage for Lib/pprint.py

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