You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

597 lines
20 KiB

Merged revisions 63119-63128,63130-63131,63133,63135-63144,63146-63148,63151-63152,63155-63165,63167-63176,63181-63186,63188-63189 via svnmerge from svn+ssh://pythondev@svn.python.org/python/trunk ........ r63119 | benjamin.peterson | 2008-05-11 20:41:23 -0400 (Sun, 11 May 2008) | 2 lines #2196 hasattr now allows SystemExit and KeyboardInterrupt to propagate ........ r63122 | benjamin.peterson | 2008-05-11 20:46:49 -0400 (Sun, 11 May 2008) | 2 lines make message slightly more informative, so there's no chance of misunderstanding it ........ r63158 | ronald.oussoren | 2008-05-12 07:24:33 -0400 (Mon, 12 May 2008) | 5 lines Remove references to platform 'mac' The 'mac' platform (that is, os.name == 'mac') was used for the MacOS 9 port, which is no longer supported (as of Python 2.4 IIRC). ........ r63159 | ronald.oussoren | 2008-05-12 07:31:05 -0400 (Mon, 12 May 2008) | 8 lines MacOSX: remove dependency on Carbon package for urllib This patch removes the dependency on the Carbon package from urllib. The mac-specific code for getting proxy configuration is now writting in Python using ctypes and uses the SystemConfiguration framework instead of InternetConfig. Also provides a mac-specific implementation of proxy_bypass. ........ r63162 | eric.smith | 2008-05-12 10:00:01 -0400 (Mon, 12 May 2008) | 1 line Added 'n' presentation type for integers. ........ r63164 | georg.brandl | 2008-05-12 12:26:52 -0400 (Mon, 12 May 2008) | 2 lines #1713041: fix pprint's handling of maximum depth. ........ r63170 | georg.brandl | 2008-05-12 12:53:42 -0400 (Mon, 12 May 2008) | 2 lines Fix parameter name for enumerate(). ........ r63173 | georg.brandl | 2008-05-12 13:01:58 -0400 (Mon, 12 May 2008) | 2 lines #2766: remove code without effect. ........ r63174 | georg.brandl | 2008-05-12 13:04:10 -0400 (Mon, 12 May 2008) | 3 lines #2767: don't clear globs in run() call, since they could be needed in tearDown, which clears them at the end. ........ r63175 | georg.brandl | 2008-05-12 13:14:51 -0400 (Mon, 12 May 2008) | 2 lines #1760: try-except-finally is one statement since PEP 341. ........ r63186 | amaury.forgeotdarc | 2008-05-12 17:30:24 -0400 (Mon, 12 May 2008) | 2 lines Sync code with documentation, and remove Win95 support in winsound module. ........ r63189 | amaury.forgeotdarc | 2008-05-12 18:21:39 -0400 (Mon, 12 May 2008) | 3 lines Adapt test_pyclbr to the new version of urllib.py: The new mac-specific functions must be ignored. ........
18 years ago
Restructure comparison dramatically. There is no longer a default *ordering* between objects; there is only a default equality test (defined by an object being equal to itself only). Read the comment in object.c. The current implementation never uses a three-way comparison to compute a rich comparison, but it does use a rich comparison to compute a three-way comparison. I'm not quite done ripping out all the calls to PyObject_Compare/Cmp, or replacing tp_compare implementations with tp_richcompare implementations; but much of that has happened (to make most unit tests pass). The following tests still fail, because I need help deciding or understanding: test_codeop -- depends on comparing code objects test_datetime -- need Tim Peters' opinion test_marshal -- depends on comparing code objects test_mutants -- need help understanding it The problem with test_codeop and test_marshal is this: these tests compare two different code objects and expect them to be equal. Is that still a feature we'd like to support? I've temporarily removed the comparison and hash code from code objects, so they use the default (equality by pointer only) comparison. For the other two tests, run them to see for yourself. (There may be more failing test with "-u all".) A general problem with getting lots of these tests to pass is the reality that for object types that have a natural total ordering, implementing __cmp__ is much more convenient than implementing __eq__, __ne__, __lt__, and so on. Should we go back to allowing __cmp__ to provide a total ordering? Should we provide some other way to implement rich comparison with a single method override? Alex proposed a __key__() method; I've considered a __richcmp__() method. Or perhaps __cmp__() just shouldn't be killed off...
20 years ago
Merged revisions 63119-63128,63130-63131,63133,63135-63144,63146-63148,63151-63152,63155-63165,63167-63176,63181-63186,63188-63189 via svnmerge from svn+ssh://pythondev@svn.python.org/python/trunk ........ r63119 | benjamin.peterson | 2008-05-11 20:41:23 -0400 (Sun, 11 May 2008) | 2 lines #2196 hasattr now allows SystemExit and KeyboardInterrupt to propagate ........ r63122 | benjamin.peterson | 2008-05-11 20:46:49 -0400 (Sun, 11 May 2008) | 2 lines make message slightly more informative, so there's no chance of misunderstanding it ........ r63158 | ronald.oussoren | 2008-05-12 07:24:33 -0400 (Mon, 12 May 2008) | 5 lines Remove references to platform 'mac' The 'mac' platform (that is, os.name == 'mac') was used for the MacOS 9 port, which is no longer supported (as of Python 2.4 IIRC). ........ r63159 | ronald.oussoren | 2008-05-12 07:31:05 -0400 (Mon, 12 May 2008) | 8 lines MacOSX: remove dependency on Carbon package for urllib This patch removes the dependency on the Carbon package from urllib. The mac-specific code for getting proxy configuration is now writting in Python using ctypes and uses the SystemConfiguration framework instead of InternetConfig. Also provides a mac-specific implementation of proxy_bypass. ........ r63162 | eric.smith | 2008-05-12 10:00:01 -0400 (Mon, 12 May 2008) | 1 line Added 'n' presentation type for integers. ........ r63164 | georg.brandl | 2008-05-12 12:26:52 -0400 (Mon, 12 May 2008) | 2 lines #1713041: fix pprint's handling of maximum depth. ........ r63170 | georg.brandl | 2008-05-12 12:53:42 -0400 (Mon, 12 May 2008) | 2 lines Fix parameter name for enumerate(). ........ r63173 | georg.brandl | 2008-05-12 13:01:58 -0400 (Mon, 12 May 2008) | 2 lines #2766: remove code without effect. ........ r63174 | georg.brandl | 2008-05-12 13:04:10 -0400 (Mon, 12 May 2008) | 3 lines #2767: don't clear globs in run() call, since they could be needed in tearDown, which clears them at the end. ........ r63175 | georg.brandl | 2008-05-12 13:14:51 -0400 (Mon, 12 May 2008) | 2 lines #1760: try-except-finally is one statement since PEP 341. ........ r63186 | amaury.forgeotdarc | 2008-05-12 17:30:24 -0400 (Mon, 12 May 2008) | 2 lines Sync code with documentation, and remove Win95 support in winsound module. ........ r63189 | amaury.forgeotdarc | 2008-05-12 18:21:39 -0400 (Mon, 12 May 2008) | 3 lines Adapt test_pyclbr to the new version of urllib.py: The new mac-specific functions must be ignored. ........
18 years ago
  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. """Support to pretty-print lists, tuples, & dictionaries recursively.
  11. Very simple, but useful, especially in debugging data structures.
  12. Classes
  13. -------
  14. PrettyPrinter()
  15. Handle pretty-printing operations onto a stream using a configured
  16. set of formatting parameters.
  17. Functions
  18. ---------
  19. pformat()
  20. Format a Python object into a pretty-printed representation.
  21. pprint()
  22. Pretty-print a Python object to a stream [default is sys.stdout].
  23. saferepr()
  24. Generate a 'standard' repr()-like value, but protect against recursive
  25. data structures.
  26. """
  27. import collections as _collections
  28. import re
  29. import sys as _sys
  30. import types as _types
  31. from io import StringIO as _StringIO
  32. __all__ = ["pprint","pformat","isreadable","isrecursive","saferepr",
  33. "PrettyPrinter"]
  34. def pprint(object, stream=None, indent=1, width=80, depth=None, *,
  35. compact=False):
  36. """Pretty-print a Python object to a stream [default is sys.stdout]."""
  37. printer = PrettyPrinter(
  38. stream=stream, indent=indent, width=width, depth=depth,
  39. compact=compact)
  40. printer.pprint(object)
  41. def pformat(object, indent=1, width=80, depth=None, *, compact=False):
  42. """Format a Python object into a pretty-printed representation."""
  43. return PrettyPrinter(indent=indent, width=width, depth=depth,
  44. compact=compact).pformat(object)
  45. def saferepr(object):
  46. """Version of repr() which can handle recursive data structures."""
  47. return _safe_repr(object, {}, None, 0)[0]
  48. def isreadable(object):
  49. """Determine if saferepr(object) is readable by eval()."""
  50. return _safe_repr(object, {}, None, 0)[1]
  51. def isrecursive(object):
  52. """Determine if object requires a recursive representation."""
  53. return _safe_repr(object, {}, None, 0)[2]
  54. class _safe_key:
  55. """Helper function for key functions when sorting unorderable objects.
  56. The wrapped-object will fallback to a Py2.x style comparison for
  57. unorderable types (sorting first comparing the type name and then by
  58. the obj ids). Does not work recursively, so dict.items() must have
  59. _safe_key applied to both the key and the value.
  60. """
  61. __slots__ = ['obj']
  62. def __init__(self, obj):
  63. self.obj = obj
  64. def __lt__(self, other):
  65. try:
  66. return self.obj < other.obj
  67. except TypeError:
  68. return ((str(type(self.obj)), id(self.obj)) < \
  69. (str(type(other.obj)), id(other.obj)))
  70. def _safe_tuple(t):
  71. "Helper function for comparing 2-tuples"
  72. return _safe_key(t[0]), _safe_key(t[1])
  73. class PrettyPrinter:
  74. def __init__(self, indent=1, width=80, depth=None, stream=None, *,
  75. compact=False):
  76. """Handle pretty printing operations onto a stream using a set of
  77. configured parameters.
  78. indent
  79. Number of spaces to indent for each level of nesting.
  80. width
  81. Attempted maximum number of columns in the output.
  82. depth
  83. The maximum depth to print out nested structures.
  84. stream
  85. The desired output stream. If omitted (or false), the standard
  86. output stream available at construction will be used.
  87. compact
  88. If true, several items will be combined in one line.
  89. """
  90. indent = int(indent)
  91. width = int(width)
  92. if indent < 0:
  93. raise ValueError('indent must be >= 0')
  94. if depth is not None and depth <= 0:
  95. raise ValueError('depth must be > 0')
  96. if not width:
  97. raise ValueError('width must be != 0')
  98. self._depth = depth
  99. self._indent_per_level = indent
  100. self._width = width
  101. if stream is not None:
  102. self._stream = stream
  103. else:
  104. self._stream = _sys.stdout
  105. self._compact = bool(compact)
  106. def pprint(self, object):
  107. self._format(object, self._stream, 0, 0, {}, 0)
  108. self._stream.write("\n")
  109. def pformat(self, object):
  110. sio = _StringIO()
  111. self._format(object, sio, 0, 0, {}, 0)
  112. return sio.getvalue()
  113. def isrecursive(self, object):
  114. return self.format(object, {}, 0, 0)[2]
  115. def isreadable(self, object):
  116. s, readable, recursive = self.format(object, {}, 0, 0)
  117. return readable and not recursive
  118. def _format(self, object, stream, indent, allowance, context, level):
  119. objid = id(object)
  120. if objid in context:
  121. stream.write(_recursion(object))
  122. self._recursive = True
  123. self._readable = False
  124. return
  125. rep = self._repr(object, context, level)
  126. max_width = self._width - indent - allowance
  127. if len(rep) > max_width:
  128. p = self._dispatch.get(type(object).__repr__, None)
  129. if p is not None:
  130. context[objid] = 1
  131. p(self, object, stream, indent, allowance, context, level + 1)
  132. del context[objid]
  133. return
  134. elif isinstance(object, dict):
  135. context[objid] = 1
  136. self._pprint_dict(object, stream, indent, allowance,
  137. context, level + 1)
  138. del context[objid]
  139. return
  140. stream.write(rep)
  141. _dispatch = {}
  142. def _pprint_dict(self, object, stream, indent, allowance, context, level):
  143. write = stream.write
  144. write('{')
  145. if self._indent_per_level > 1:
  146. write((self._indent_per_level - 1) * ' ')
  147. length = len(object)
  148. if length:
  149. items = sorted(object.items(), key=_safe_tuple)
  150. self._format_dict_items(items, stream, indent, allowance + 1,
  151. context, level)
  152. write('}')
  153. _dispatch[dict.__repr__] = _pprint_dict
  154. def _pprint_ordered_dict(self, object, stream, indent, allowance, context, level):
  155. if not len(object):
  156. stream.write(repr(object))
  157. return
  158. cls = object.__class__
  159. stream.write(cls.__name__ + '(')
  160. self._format(list(object.items()), stream,
  161. indent + len(cls.__name__) + 1, allowance + 1,
  162. context, level)
  163. stream.write(')')
  164. _dispatch[_collections.OrderedDict.__repr__] = _pprint_ordered_dict
  165. def _pprint_list(self, object, stream, indent, allowance, context, level):
  166. stream.write('[')
  167. self._format_items(object, stream, indent, allowance + 1,
  168. context, level)
  169. stream.write(']')
  170. _dispatch[list.__repr__] = _pprint_list
  171. def _pprint_tuple(self, object, stream, indent, allowance, context, level):
  172. stream.write('(')
  173. endchar = ',)' if len(object) == 1 else ')'
  174. self._format_items(object, stream, indent, allowance + len(endchar),
  175. context, level)
  176. stream.write(endchar)
  177. _dispatch[tuple.__repr__] = _pprint_tuple
  178. def _pprint_set(self, object, stream, indent, allowance, context, level):
  179. if not len(object):
  180. stream.write(repr(object))
  181. return
  182. typ = object.__class__
  183. if typ is set:
  184. stream.write('{')
  185. endchar = '}'
  186. else:
  187. stream.write(typ.__name__ + '({')
  188. endchar = '})'
  189. indent += len(typ.__name__) + 1
  190. object = sorted(object, key=_safe_key)
  191. self._format_items(object, stream, indent, allowance + len(endchar),
  192. context, level)
  193. stream.write(endchar)
  194. _dispatch[set.__repr__] = _pprint_set
  195. _dispatch[frozenset.__repr__] = _pprint_set
  196. def _pprint_str(self, object, stream, indent, allowance, context, level):
  197. write = stream.write
  198. if not len(object):
  199. write(repr(object))
  200. return
  201. chunks = []
  202. lines = object.splitlines(True)
  203. if level == 1:
  204. indent += 1
  205. allowance += 1
  206. max_width1 = max_width = self._width - indent
  207. for i, line in enumerate(lines):
  208. rep = repr(line)
  209. if i == len(lines) - 1:
  210. max_width1 -= allowance
  211. if len(rep) <= max_width1:
  212. chunks.append(rep)
  213. else:
  214. # A list of alternating (non-space, space) strings
  215. parts = re.findall(r'\S*\s*', line)
  216. assert parts
  217. assert not parts[-1]
  218. parts.pop() # drop empty last part
  219. max_width2 = max_width
  220. current = ''
  221. for j, part in enumerate(parts):
  222. candidate = current + part
  223. if j == len(parts) - 1 and i == len(lines) - 1:
  224. max_width2 -= allowance
  225. if len(repr(candidate)) > max_width2:
  226. if current:
  227. chunks.append(repr(current))
  228. current = part
  229. else:
  230. current = candidate
  231. if current:
  232. chunks.append(repr(current))
  233. if len(chunks) == 1:
  234. write(rep)
  235. return
  236. if level == 1:
  237. write('(')
  238. for i, rep in enumerate(chunks):
  239. if i > 0:
  240. write('\n' + ' '*indent)
  241. write(rep)
  242. if level == 1:
  243. write(')')
  244. _dispatch[str.__repr__] = _pprint_str
  245. def _pprint_bytes(self, object, stream, indent, allowance, context, level):
  246. write = stream.write
  247. if len(object) <= 4:
  248. write(repr(object))
  249. return
  250. parens = level == 1
  251. if parens:
  252. indent += 1
  253. allowance += 1
  254. write('(')
  255. delim = ''
  256. for rep in _wrap_bytes_repr(object, self._width - indent, allowance):
  257. write(delim)
  258. write(rep)
  259. if not delim:
  260. delim = '\n' + ' '*indent
  261. if parens:
  262. write(')')
  263. _dispatch[bytes.__repr__] = _pprint_bytes
  264. def _pprint_bytearray(self, object, stream, indent, allowance, context, level):
  265. write = stream.write
  266. write('bytearray(')
  267. self._pprint_bytes(bytes(object), stream, indent + 10,
  268. allowance + 1, context, level + 1)
  269. write(')')
  270. _dispatch[bytearray.__repr__] = _pprint_bytearray
  271. def _pprint_mappingproxy(self, object, stream, indent, allowance, context, level):
  272. stream.write('mappingproxy(')
  273. self._format(object.copy(), stream, indent + 13, allowance + 1,
  274. context, level)
  275. stream.write(')')
  276. _dispatch[_types.MappingProxyType.__repr__] = _pprint_mappingproxy
  277. def _format_dict_items(self, items, stream, indent, allowance, context,
  278. level):
  279. write = stream.write
  280. indent += self._indent_per_level
  281. delimnl = ',\n' + ' ' * indent
  282. last_index = len(items) - 1
  283. for i, (key, ent) in enumerate(items):
  284. last = i == last_index
  285. rep = self._repr(key, context, level)
  286. write(rep)
  287. write(': ')
  288. self._format(ent, stream, indent + len(rep) + 2,
  289. allowance if last else 1,
  290. context, level)
  291. if not last:
  292. write(delimnl)
  293. def _format_items(self, items, stream, indent, allowance, context, level):
  294. write = stream.write
  295. indent += self._indent_per_level
  296. if self._indent_per_level > 1:
  297. write((self._indent_per_level - 1) * ' ')
  298. delimnl = ',\n' + ' ' * indent
  299. delim = ''
  300. width = max_width = self._width - indent + 1
  301. it = iter(items)
  302. try:
  303. next_ent = next(it)
  304. except StopIteration:
  305. return
  306. last = False
  307. while not last:
  308. ent = next_ent
  309. try:
  310. next_ent = next(it)
  311. except StopIteration:
  312. last = True
  313. max_width -= allowance
  314. width -= allowance
  315. if self._compact:
  316. rep = self._repr(ent, context, level)
  317. w = len(rep) + 2
  318. if width < w:
  319. width = max_width
  320. if delim:
  321. delim = delimnl
  322. if width >= w:
  323. width -= w
  324. write(delim)
  325. delim = ', '
  326. write(rep)
  327. continue
  328. write(delim)
  329. delim = delimnl
  330. self._format(ent, stream, indent,
  331. allowance if last else 1,
  332. context, level)
  333. def _repr(self, object, context, level):
  334. repr, readable, recursive = self.format(object, context.copy(),
  335. self._depth, level)
  336. if not readable:
  337. self._readable = False
  338. if recursive:
  339. self._recursive = True
  340. return repr
  341. def format(self, object, context, maxlevels, level):
  342. """Format object for a specific context, returning a string
  343. and flags indicating whether the representation is 'readable'
  344. and whether the object represents a recursive construct.
  345. """
  346. return _safe_repr(object, context, maxlevels, level)
  347. def _pprint_default_dict(self, object, stream, indent, allowance, context, level):
  348. if not len(object):
  349. stream.write(repr(object))
  350. return
  351. rdf = self._repr(object.default_factory, context, level)
  352. cls = object.__class__
  353. indent += len(cls.__name__) + 1
  354. stream.write('%s(%s,\n%s' % (cls.__name__, rdf, ' ' * indent))
  355. self._pprint_dict(object, stream, indent, allowance + 1, context, level)
  356. stream.write(')')
  357. _dispatch[_collections.defaultdict.__repr__] = _pprint_default_dict
  358. def _pprint_counter(self, object, stream, indent, allowance, context, level):
  359. if not len(object):
  360. stream.write(repr(object))
  361. return
  362. cls = object.__class__
  363. stream.write(cls.__name__ + '({')
  364. if self._indent_per_level > 1:
  365. stream.write((self._indent_per_level - 1) * ' ')
  366. items = object.most_common()
  367. self._format_dict_items(items, stream,
  368. indent + len(cls.__name__) + 1, allowance + 2,
  369. context, level)
  370. stream.write('})')
  371. _dispatch[_collections.Counter.__repr__] = _pprint_counter
  372. def _pprint_chain_map(self, object, stream, indent, allowance, context, level):
  373. if not len(object.maps):
  374. stream.write(repr(object))
  375. return
  376. cls = object.__class__
  377. stream.write(cls.__name__ + '(')
  378. indent += len(cls.__name__) + 1
  379. for i, m in enumerate(object.maps):
  380. if i == len(object.maps) - 1:
  381. self._format(m, stream, indent, allowance + 1, context, level)
  382. stream.write(')')
  383. else:
  384. self._format(m, stream, indent, 1, context, level)
  385. stream.write(',\n' + ' ' * indent)
  386. _dispatch[_collections.ChainMap.__repr__] = _pprint_chain_map
  387. def _pprint_deque(self, object, stream, indent, allowance, context, level):
  388. if not len(object):
  389. stream.write(repr(object))
  390. return
  391. cls = object.__class__
  392. stream.write(cls.__name__ + '(')
  393. indent += len(cls.__name__) + 1
  394. stream.write('[')
  395. if object.maxlen is None:
  396. self._format_items(object, stream, indent, allowance + 2,
  397. context, level)
  398. stream.write('])')
  399. else:
  400. self._format_items(object, stream, indent, 2,
  401. context, level)
  402. rml = self._repr(object.maxlen, context, level)
  403. stream.write('],\n%smaxlen=%s)' % (' ' * indent, rml))
  404. _dispatch[_collections.deque.__repr__] = _pprint_deque
  405. def _pprint_user_dict(self, object, stream, indent, allowance, context, level):
  406. self._format(object.data, stream, indent, allowance, context, level - 1)
  407. _dispatch[_collections.UserDict.__repr__] = _pprint_user_dict
  408. def _pprint_user_list(self, object, stream, indent, allowance, context, level):
  409. self._format(object.data, stream, indent, allowance, context, level - 1)
  410. _dispatch[_collections.UserList.__repr__] = _pprint_user_list
  411. def _pprint_user_string(self, object, stream, indent, allowance, context, level):
  412. self._format(object.data, stream, indent, allowance, context, level - 1)
  413. _dispatch[_collections.UserString.__repr__] = _pprint_user_string
  414. # Return triple (repr_string, isreadable, isrecursive).
  415. def _safe_repr(object, context, maxlevels, level):
  416. typ = type(object)
  417. if typ in _builtin_scalars:
  418. return repr(object), True, False
  419. r = getattr(typ, "__repr__", None)
  420. if issubclass(typ, dict) and r is dict.__repr__:
  421. if not object:
  422. return "{}", True, False
  423. objid = id(object)
  424. if maxlevels and level >= maxlevels:
  425. return "{...}", False, objid in context
  426. if objid in context:
  427. return _recursion(object), False, True
  428. context[objid] = 1
  429. readable = True
  430. recursive = False
  431. components = []
  432. append = components.append
  433. level += 1
  434. saferepr = _safe_repr
  435. items = sorted(object.items(), key=_safe_tuple)
  436. for k, v in items:
  437. krepr, kreadable, krecur = saferepr(k, context, maxlevels, level)
  438. vrepr, vreadable, vrecur = saferepr(v, context, maxlevels, level)
  439. append("%s: %s" % (krepr, vrepr))
  440. readable = readable and kreadable and vreadable
  441. if krecur or vrecur:
  442. recursive = True
  443. del context[objid]
  444. return "{%s}" % ", ".join(components), readable, recursive
  445. if (issubclass(typ, list) and r is list.__repr__) or \
  446. (issubclass(typ, tuple) and r is tuple.__repr__):
  447. if issubclass(typ, list):
  448. if not object:
  449. return "[]", True, False
  450. format = "[%s]"
  451. elif len(object) == 1:
  452. format = "(%s,)"
  453. else:
  454. if not object:
  455. return "()", True, False
  456. format = "(%s)"
  457. objid = id(object)
  458. if maxlevels and level >= maxlevels:
  459. return format % "...", False, objid in context
  460. if objid in context:
  461. return _recursion(object), False, True
  462. context[objid] = 1
  463. readable = True
  464. recursive = False
  465. components = []
  466. append = components.append
  467. level += 1
  468. for o in object:
  469. orepr, oreadable, orecur = _safe_repr(o, context, maxlevels, level)
  470. append(orepr)
  471. if not oreadable:
  472. readable = False
  473. if orecur:
  474. recursive = True
  475. del context[objid]
  476. return format % ", ".join(components), readable, recursive
  477. rep = repr(object)
  478. return rep, (rep and not rep.startswith('<')), False
  479. _builtin_scalars = frozenset({str, bytes, bytearray, int, float, complex,
  480. bool, type(None)})
  481. def _recursion(object):
  482. return ("<Recursion on %s with id=%s>"
  483. % (type(object).__name__, id(object)))
  484. def _perfcheck(object=None):
  485. import time
  486. if object is None:
  487. object = [("string", (1, 2), [3, 4], {5: 6, 7: 8})] * 100000
  488. p = PrettyPrinter()
  489. t1 = time.time()
  490. _safe_repr(object, {}, None, 0)
  491. t2 = time.time()
  492. p.pformat(object)
  493. t3 = time.time()
  494. print("_safe_repr:", t2 - t1)
  495. print("pformat:", t3 - t2)
  496. def _wrap_bytes_repr(object, width, allowance):
  497. current = b''
  498. last = len(object) // 4 * 4
  499. for i in range(0, len(object), 4):
  500. part = object[i: i+4]
  501. candidate = current + part
  502. if i == last:
  503. width -= allowance
  504. if len(repr(candidate)) > width:
  505. if current:
  506. yield repr(current)
  507. current = part
  508. else:
  509. current = candidate
  510. if current:
  511. yield repr(current)
  512. if __name__ == "__main__":
  513. _perfcheck()