blob: ae96dde1e0266c65d0e8f4cc7ce96f5d930ab4ed [file] [log] [blame]
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001# Author: Fred L. Drake, Jr.
Fred Drake3e5e6612001-10-09 20:53:48 +00002# fdrake@acm.org
Guido van Rossum5e92aff1997-04-16 00:49:59 +00003#
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
Thomas Wouters7e474022000-07-16 12:04:32 +00007# tuples with fairly non-descriptive content. This is modeled very much
Guido van Rossum5e92aff1997-04-16 00:49:59 +00008# 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
13Very simple, but useful, especially in debugging data structures.
14
Fred Drakea89fda01997-04-16 16:59:30 +000015Classes
16-------
17
18PrettyPrinter()
19 Handle pretty-printing operations onto a stream using a configured
20 set of formatting parameters.
21
Guido van Rossum5e92aff1997-04-16 00:49:59 +000022Functions
23---------
24
25pformat()
26 Format a Python object into a pretty-printed representation.
27
28pprint()
Skip Montanaro2dc0c132004-05-14 16:31:56 +000029 Pretty-print a Python object to a stream [default is sys.stdout].
Guido van Rossum5e92aff1997-04-16 00:49:59 +000030
Fred Drakea89fda01997-04-16 16:59:30 +000031saferepr()
32 Generate a 'standard' repr()-like value, but protect against recursive
33 data structures.
Guido van Rossum5e92aff1997-04-16 00:49:59 +000034
35"""
36
Fred Drake397b6152002-12-31 07:14:18 +000037import sys as _sys
Raymond Hettingerbad3c882010-09-09 12:31:00 +000038from collections import OrderedDict as _OrderedDict
Guido van Rossum34d19282007-08-09 01:03:29 +000039from io import StringIO as _StringIO
Guido van Rossum5e92aff1997-04-16 00:49:59 +000040
Skip Montanaroc62c81e2001-02-12 02:00:42 +000041__all__ = ["pprint","pformat","isreadable","isrecursive","saferepr",
42 "PrettyPrinter"]
Guido van Rossum5e92aff1997-04-16 00:49:59 +000043
Fred Drake49cc01e2001-11-01 17:50:38 +000044# cache these for faster access:
45_commajoin = ", ".join
Fred Drake49cc01e2001-11-01 17:50:38 +000046_id = id
47_len = len
48_type = type
49
50
Walter Dörwaldc8de4582003-12-03 20:26:05 +000051def pprint(object, stream=None, indent=1, width=80, depth=None):
Skip Montanaro2dc0c132004-05-14 16:31:56 +000052 """Pretty-print a Python object to a stream [default is sys.stdout]."""
Walter Dörwaldc8de4582003-12-03 20:26:05 +000053 printer = PrettyPrinter(
54 stream=stream, indent=indent, width=width, depth=depth)
Fred Drakea89fda01997-04-16 16:59:30 +000055 printer.pprint(object)
Guido van Rossum5e92aff1997-04-16 00:49:59 +000056
Walter Dörwaldc8de4582003-12-03 20:26:05 +000057def pformat(object, indent=1, width=80, depth=None):
Fred Drakea89fda01997-04-16 16:59:30 +000058 """Format a Python object into a pretty-printed representation."""
Walter Dörwaldc8de4582003-12-03 20:26:05 +000059 return PrettyPrinter(indent=indent, width=width, depth=depth).pformat(object)
Guido van Rossum5e92aff1997-04-16 00:49:59 +000060
Fred Drakea89fda01997-04-16 16:59:30 +000061def saferepr(object):
62 """Version of repr() which can handle recursive data structures."""
Fred Drake49cc01e2001-11-01 17:50:38 +000063 return _safe_repr(object, {}, None, 0)[0]
Guido van Rossum5e92aff1997-04-16 00:49:59 +000064
Tim Petersa814db52001-05-14 07:05:58 +000065def isreadable(object):
66 """Determine if saferepr(object) is readable by eval()."""
Fred Drake49cc01e2001-11-01 17:50:38 +000067 return _safe_repr(object, {}, None, 0)[1]
Tim Petersa814db52001-05-14 07:05:58 +000068
69def isrecursive(object):
70 """Determine if object requires a recursive representation."""
Fred Drake49cc01e2001-11-01 17:50:38 +000071 return _safe_repr(object, {}, None, 0)[2]
Guido van Rossum5e92aff1997-04-16 00:49:59 +000072
Raymond Hettingera7da1662009-11-19 01:07:05 +000073class _safe_key:
74 """Helper function for key functions when sorting unorderable objects.
75
76 The wrapped-object will fallback to an Py2.x style comparison for
77 unorderable types (sorting first comparing the type name and then by
78 the obj ids). Does not work recursively, so dict.items() must have
79 _safe_key applied to both the key and the value.
80
81 """
82
83 __slots__ = ['obj']
84
85 def __init__(self, obj):
86 self.obj = obj
87
88 def __lt__(self, other):
Florent Xiclunad6da90f2012-07-21 11:17:38 +020089 try:
90 rv = self.obj.__lt__(other.obj)
91 except TypeError:
92 rv = NotImplemented
93
Raymond Hettingera7da1662009-11-19 01:07:05 +000094 if rv is NotImplemented:
95 rv = (str(type(self.obj)), id(self.obj)) < \
96 (str(type(other.obj)), id(other.obj))
97 return rv
98
99def _safe_tuple(t):
100 "Helper function for comparing 2-tuples"
101 return _safe_key(t[0]), _safe_key(t[1])
102
Fred Drakea89fda01997-04-16 16:59:30 +0000103class PrettyPrinter:
104 def __init__(self, indent=1, width=80, depth=None, stream=None):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000105 """Handle pretty printing operations onto a stream using a set of
106 configured parameters.
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000107
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000108 indent
109 Number of spaces to indent for each level of nesting.
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000110
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000111 width
112 Attempted maximum number of columns in the output.
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000113
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000114 depth
115 The maximum depth to print out nested structures.
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000116
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000117 stream
118 The desired output stream. If omitted (or false), the standard
119 output stream available at construction will be used.
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000120
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000121 """
122 indent = int(indent)
123 width = int(width)
Walter Dörwald7a7ede52003-12-03 20:15:28 +0000124 assert indent >= 0, "indent must be >= 0"
Tim Petersa814db52001-05-14 07:05:58 +0000125 assert depth is None or depth > 0, "depth must be > 0"
Walter Dörwald7a7ede52003-12-03 20:15:28 +0000126 assert width, "width must be != 0"
Fred Drakee6691ef2002-07-08 12:28:06 +0000127 self._depth = depth
128 self._indent_per_level = indent
129 self._width = width
Raymond Hettinger16e3c422002-06-01 16:07:16 +0000130 if stream is not None:
Fred Drakee6691ef2002-07-08 12:28:06 +0000131 self._stream = stream
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000132 else:
Fred Drake397b6152002-12-31 07:14:18 +0000133 self._stream = _sys.stdout
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000134
Fred Drakea89fda01997-04-16 16:59:30 +0000135 def pprint(self, object):
Walter Dörwalde62e9362005-11-11 18:18:51 +0000136 self._format(object, self._stream, 0, 0, {}, 0)
137 self._stream.write("\n")
Fred Drakea89fda01997-04-16 16:59:30 +0000138
139 def pformat(self, object):
Fred Drake397b6152002-12-31 07:14:18 +0000140 sio = _StringIO()
Fred Drakee6691ef2002-07-08 12:28:06 +0000141 self._format(object, sio, 0, 0, {}, 0)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000142 return sio.getvalue()
Fred Drakea89fda01997-04-16 16:59:30 +0000143
Fred Drakee0ffabe1997-07-18 20:42:39 +0000144 def isrecursive(self, object):
Fred Drake397b6152002-12-31 07:14:18 +0000145 return self.format(object, {}, 0, 0)[2]
Fred Drakee0ffabe1997-07-18 20:42:39 +0000146
147 def isreadable(self, object):
Fred Drake397b6152002-12-31 07:14:18 +0000148 s, readable, recursive = self.format(object, {}, 0, 0)
Fred Drakeaee113d2002-04-02 05:08:35 +0000149 return readable and not recursive
Fred Drakee0ffabe1997-07-18 20:42:39 +0000150
Fred Drakee6691ef2002-07-08 12:28:06 +0000151 def _format(self, object, stream, indent, allowance, context, level):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000152 level = level + 1
Fred Drake49cc01e2001-11-01 17:50:38 +0000153 objid = _id(object)
154 if objid in context:
155 stream.write(_recursion(object))
Fred Drakee6691ef2002-07-08 12:28:06 +0000156 self._recursive = True
157 self._readable = False
Fred Drake49cc01e2001-11-01 17:50:38 +0000158 return
Fred Drakee6691ef2002-07-08 12:28:06 +0000159 rep = self._repr(object, context, level - 1)
Fred Drake49cc01e2001-11-01 17:50:38 +0000160 typ = _type(object)
Fred Drakee6691ef2002-07-08 12:28:06 +0000161 sepLines = _len(rep) > (self._width - 1 - indent - allowance)
Fred Drake49cc01e2001-11-01 17:50:38 +0000162 write = stream.write
Fred Drakea89fda01997-04-16 16:59:30 +0000163
Alexandre Vassalottieca20b62008-05-16 02:54:33 +0000164 if self._depth and level > self._depth:
165 write(rep)
166 return
167
Fred Drake49cc01e2001-11-01 17:50:38 +0000168 if sepLines:
Walter Dörwald1b626ca2004-11-15 13:51:41 +0000169 r = getattr(typ, "__repr__", None)
Raymond Hettingerbad3c882010-09-09 12:31:00 +0000170 if issubclass(typ, dict):
Fred Drake49cc01e2001-11-01 17:50:38 +0000171 write('{')
Fred Drakee6691ef2002-07-08 12:28:06 +0000172 if self._indent_per_level > 1:
173 write((self._indent_per_level - 1) * ' ')
Fred Drake49cc01e2001-11-01 17:50:38 +0000174 length = _len(object)
175 if length:
176 context[objid] = 1
Fred Drakee6691ef2002-07-08 12:28:06 +0000177 indent = indent + self._indent_per_level
Raymond Hettingerbad3c882010-09-09 12:31:00 +0000178 if issubclass(typ, _OrderedDict):
179 items = list(object.items())
180 else:
181 items = sorted(object.items(), key=_safe_tuple)
Fred Drake49cc01e2001-11-01 17:50:38 +0000182 key, ent = items[0]
Fred Drakee6691ef2002-07-08 12:28:06 +0000183 rep = self._repr(key, context, level)
Fred Drake49cc01e2001-11-01 17:50:38 +0000184 write(rep)
185 write(': ')
Fred Drakee6691ef2002-07-08 12:28:06 +0000186 self._format(ent, stream, indent + _len(rep) + 2,
Fred Drake49cc01e2001-11-01 17:50:38 +0000187 allowance + 1, context, level)
188 if length > 1:
189 for key, ent in items[1:]:
Fred Drakee6691ef2002-07-08 12:28:06 +0000190 rep = self._repr(key, context, level)
Barry Warsaw00859c02001-11-28 05:49:39 +0000191 write(',\n%s%s: ' % (' '*indent, rep))
Fred Drakee6691ef2002-07-08 12:28:06 +0000192 self._format(ent, stream, indent + _len(rep) + 2,
Fred Drake49cc01e2001-11-01 17:50:38 +0000193 allowance + 1, context, level)
Fred Drakee6691ef2002-07-08 12:28:06 +0000194 indent = indent - self._indent_per_level
Fred Drake49cc01e2001-11-01 17:50:38 +0000195 del context[objid]
196 write('}')
197 return
Fred Drakea89fda01997-04-16 16:59:30 +0000198
Christian Heimes1af737c2008-01-23 08:24:23 +0000199 if ((issubclass(typ, list) and r is list.__repr__) or
200 (issubclass(typ, tuple) and r is tuple.__repr__) or
201 (issubclass(typ, set) and r is set.__repr__) or
202 (issubclass(typ, frozenset) and r is frozenset.__repr__)
203 ):
Christian Heimes969fe572008-01-25 11:23:10 +0000204 length = _len(object)
Walter Dörwald7a7ede52003-12-03 20:15:28 +0000205 if issubclass(typ, list):
Fred Drake49cc01e2001-11-01 17:50:38 +0000206 write('[')
207 endchar = ']'
Christian Heimes1af737c2008-01-23 08:24:23 +0000208 elif issubclass(typ, set):
Christian Heimes969fe572008-01-25 11:23:10 +0000209 if not length:
210 write('set()')
211 return
Christian Heimes1af737c2008-01-23 08:24:23 +0000212 write('{')
213 endchar = '}'
Raymond Hettingera7da1662009-11-19 01:07:05 +0000214 object = sorted(object, key=_safe_key)
Christian Heimes1af737c2008-01-23 08:24:23 +0000215 elif issubclass(typ, frozenset):
Christian Heimes969fe572008-01-25 11:23:10 +0000216 if not length:
217 write('frozenset()')
218 return
Raymond Hettinger4b8db412008-01-31 01:10:03 +0000219 write('frozenset({')
220 endchar = '})'
Raymond Hettingera7da1662009-11-19 01:07:05 +0000221 object = sorted(object, key=_safe_key)
Christian Heimes969fe572008-01-25 11:23:10 +0000222 indent += 10
Fred Drake49cc01e2001-11-01 17:50:38 +0000223 else:
224 write('(')
225 endchar = ')'
Fred Drakee6691ef2002-07-08 12:28:06 +0000226 if self._indent_per_level > 1:
227 write((self._indent_per_level - 1) * ' ')
Fred Drake49cc01e2001-11-01 17:50:38 +0000228 if length:
229 context[objid] = 1
Fred Drakee6691ef2002-07-08 12:28:06 +0000230 indent = indent + self._indent_per_level
231 self._format(object[0], stream, indent, allowance + 1,
232 context, level)
Fred Drake49cc01e2001-11-01 17:50:38 +0000233 if length > 1:
234 for ent in object[1:]:
235 write(',\n' + ' '*indent)
Fred Drakee6691ef2002-07-08 12:28:06 +0000236 self._format(ent, stream, indent,
Fred Drake49cc01e2001-11-01 17:50:38 +0000237 allowance + 1, context, level)
Fred Drakee6691ef2002-07-08 12:28:06 +0000238 indent = indent - self._indent_per_level
Fred Drake49cc01e2001-11-01 17:50:38 +0000239 del context[objid]
Walter Dörwald7a7ede52003-12-03 20:15:28 +0000240 if issubclass(typ, tuple) and length == 1:
Fred Drake49cc01e2001-11-01 17:50:38 +0000241 write(',')
242 write(endchar)
243 return
Fred Drakea89fda01997-04-16 16:59:30 +0000244
Fred Drake49cc01e2001-11-01 17:50:38 +0000245 write(rep)
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000246
Fred Drakee6691ef2002-07-08 12:28:06 +0000247 def _repr(self, object, context, level):
Fred Drakeaee113d2002-04-02 05:08:35 +0000248 repr, readable, recursive = self.format(object, context.copy(),
Fred Drakee6691ef2002-07-08 12:28:06 +0000249 self._depth, level)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000250 if not readable:
Fred Drakee6691ef2002-07-08 12:28:06 +0000251 self._readable = False
Tim Petersa814db52001-05-14 07:05:58 +0000252 if recursive:
Fred Drakee6691ef2002-07-08 12:28:06 +0000253 self._recursive = True
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000254 return repr
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000255
Fred Drakeaee113d2002-04-02 05:08:35 +0000256 def format(self, object, context, maxlevels, level):
257 """Format object for a specific context, returning a string
258 and flags indicating whether the representation is 'readable'
259 and whether the object represents a recursive construct.
260 """
261 return _safe_repr(object, context, maxlevels, level)
262
263
Tim Petersa814db52001-05-14 07:05:58 +0000264# Return triple (repr_string, isreadable, isrecursive).
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000265
Fred Drake49cc01e2001-11-01 17:50:38 +0000266def _safe_repr(object, context, maxlevels, level):
267 typ = _type(object)
Martin v. Löwisd02879d2003-06-07 20:47:37 +0000268 if typ is str:
Fred Drake397b6152002-12-31 07:14:18 +0000269 if 'locale' not in _sys.modules:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000270 return repr(object), True, False
Fred Drake1ef106c2001-09-04 19:43:26 +0000271 if "'" in object and '"' not in object:
272 closure = '"'
273 quotes = {'"': '\\"'}
274 else:
275 closure = "'"
276 quotes = {"'": "\\'"}
Fred Drake49cc01e2001-11-01 17:50:38 +0000277 qget = quotes.get
Fred Drake397b6152002-12-31 07:14:18 +0000278 sio = _StringIO()
Fred Drake49cc01e2001-11-01 17:50:38 +0000279 write = sio.write
Fred Drake1ef106c2001-09-04 19:43:26 +0000280 for char in object:
281 if char.isalpha():
Fred Drake49cc01e2001-11-01 17:50:38 +0000282 write(char)
Fred Drake1ef106c2001-09-04 19:43:26 +0000283 else:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000284 write(qget(char, repr(char)[1:-1]))
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000285 return ("%s%s%s" % (closure, sio.getvalue(), closure)), True, False
Tim Peters95b3f782001-05-14 18:39:41 +0000286
Walter Dörwald1b626ca2004-11-15 13:51:41 +0000287 r = getattr(typ, "__repr__", None)
Walter Dörwald7a7ede52003-12-03 20:15:28 +0000288 if issubclass(typ, dict) and r is dict.__repr__:
Fred Drake49cc01e2001-11-01 17:50:38 +0000289 if not object:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000290 return "{}", True, False
Fred Drake49cc01e2001-11-01 17:50:38 +0000291 objid = _id(object)
Alexandre Vassalottieca20b62008-05-16 02:54:33 +0000292 if maxlevels and level >= maxlevels:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000293 return "{...}", False, objid in context
Fred Drake49cc01e2001-11-01 17:50:38 +0000294 if objid in context:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000295 return _recursion(object), False, True
Fred Drake49cc01e2001-11-01 17:50:38 +0000296 context[objid] = 1
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000297 readable = True
298 recursive = False
Tim Peters95b3f782001-05-14 18:39:41 +0000299 components = []
Fred Drake49cc01e2001-11-01 17:50:38 +0000300 append = components.append
301 level += 1
302 saferepr = _safe_repr
Raymond Hettingera7da1662009-11-19 01:07:05 +0000303 items = sorted(object.items(), key=_safe_tuple)
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000304 for k, v in items:
Fred Drake49cc01e2001-11-01 17:50:38 +0000305 krepr, kreadable, krecur = saferepr(k, context, maxlevels, level)
306 vrepr, vreadable, vrecur = saferepr(v, context, maxlevels, level)
307 append("%s: %s" % (krepr, vrepr))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000308 readable = readable and kreadable and vreadable
Fred Drake49cc01e2001-11-01 17:50:38 +0000309 if krecur or vrecur:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000310 recursive = True
Fred Drake49cc01e2001-11-01 17:50:38 +0000311 del context[objid]
312 return "{%s}" % _commajoin(components), readable, recursive
Tim Peters95b3f782001-05-14 18:39:41 +0000313
Walter Dörwald7a7ede52003-12-03 20:15:28 +0000314 if (issubclass(typ, list) and r is list.__repr__) or \
315 (issubclass(typ, tuple) and r is tuple.__repr__):
316 if issubclass(typ, list):
Fred Drake49cc01e2001-11-01 17:50:38 +0000317 if not object:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000318 return "[]", True, False
Fred Drake49cc01e2001-11-01 17:50:38 +0000319 format = "[%s]"
320 elif _len(object) == 1:
321 format = "(%s,)"
322 else:
323 if not object:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000324 return "()", True, False
Fred Drake49cc01e2001-11-01 17:50:38 +0000325 format = "(%s)"
326 objid = _id(object)
Alexandre Vassalottieca20b62008-05-16 02:54:33 +0000327 if maxlevels and level >= maxlevels:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000328 return format % "...", False, objid in context
Fred Drake49cc01e2001-11-01 17:50:38 +0000329 if objid in context:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000330 return _recursion(object), False, True
Fred Drake49cc01e2001-11-01 17:50:38 +0000331 context[objid] = 1
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000332 readable = True
333 recursive = False
Tim Peters95b3f782001-05-14 18:39:41 +0000334 components = []
Fred Drake49cc01e2001-11-01 17:50:38 +0000335 append = components.append
336 level += 1
337 for o in object:
338 orepr, oreadable, orecur = _safe_repr(o, context, maxlevels, level)
339 append(orepr)
340 if not oreadable:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000341 readable = False
Fred Drake49cc01e2001-11-01 17:50:38 +0000342 if orecur:
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000343 recursive = True
Fred Drake49cc01e2001-11-01 17:50:38 +0000344 del context[objid]
345 return format % _commajoin(components), readable, recursive
Tim Peters88768482001-11-13 21:51:26 +0000346
Walter Dörwald70a6b492004-02-12 17:35:32 +0000347 rep = repr(object)
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000348 return rep, (rep and not rep.startswith('<')), False
Tim Peters95b3f782001-05-14 18:39:41 +0000349
Guido van Rossum5e92aff1997-04-16 00:49:59 +0000350
Fred Drake49cc01e2001-11-01 17:50:38 +0000351def _recursion(object):
352 return ("<Recursion on %s with id=%s>"
353 % (_type(object).__name__, _id(object)))
Fred Drakea89fda01997-04-16 16:59:30 +0000354
Fred Drake49cc01e2001-11-01 17:50:38 +0000355
356def _perfcheck(object=None):
357 import time
358 if object is None:
359 object = [("string", (1, 2), [3, 4], {5: 6, 7: 8})] * 100000
360 p = PrettyPrinter()
361 t1 = time.time()
362 _safe_repr(object, {}, None, 0)
363 t2 = time.time()
364 p.pformat(object)
365 t3 = time.time()
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000366 print("_safe_repr:", t2 - t1)
367 print("pformat:", t3 - t2)
Fred Drake49cc01e2001-11-01 17:50:38 +0000368
369if __name__ == "__main__":
370 _perfcheck()