##// END OF EJS Templates
Fix "super" objects pretty printing in PyPy...
Danilo J. S. Bellini -
Show More
@@ -1,862 +1,866 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 Python advanced pretty printer. This pretty printer is intended to
4 4 replace the old `pprint` python module which does not allow developers
5 5 to provide their own pretty print callbacks.
6 6
7 7 This module is based on ruby's `prettyprint.rb` library by `Tanaka Akira`.
8 8
9 9
10 10 Example Usage
11 11 -------------
12 12
13 13 To directly print the representation of an object use `pprint`::
14 14
15 15 from pretty import pprint
16 16 pprint(complex_object)
17 17
18 18 To get a string of the output use `pretty`::
19 19
20 20 from pretty import pretty
21 21 string = pretty(complex_object)
22 22
23 23
24 24 Extending
25 25 ---------
26 26
27 27 The pretty library allows developers to add pretty printing rules for their
28 28 own objects. This process is straightforward. All you have to do is to
29 29 add a `_repr_pretty_` method to your object and call the methods on the
30 30 pretty printer passed::
31 31
32 32 class MyObject(object):
33 33
34 34 def _repr_pretty_(self, p, cycle):
35 35 ...
36 36
37 37 Here is an example implementation of a `_repr_pretty_` method for a list
38 38 subclass::
39 39
40 40 class MyList(list):
41 41
42 42 def _repr_pretty_(self, p, cycle):
43 43 if cycle:
44 44 p.text('MyList(...)')
45 45 else:
46 46 with p.group(8, 'MyList([', '])'):
47 47 for idx, item in enumerate(self):
48 48 if idx:
49 49 p.text(',')
50 50 p.breakable()
51 51 p.pretty(item)
52 52
53 53 The `cycle` parameter is `True` if pretty detected a cycle. You *have* to
54 54 react to that or the result is an infinite loop. `p.text()` just adds
55 55 non breaking text to the output, `p.breakable()` either adds a whitespace
56 56 or breaks here. If you pass it an argument it's used instead of the
57 57 default space. `p.pretty` prettyprints another object using the pretty print
58 58 method.
59 59
60 60 The first parameter to the `group` function specifies the extra indentation
61 61 of the next line. In this example the next item will either be on the same
62 62 line (if the items are short enough) or aligned with the right edge of the
63 63 opening bracket of `MyList`.
64 64
65 65 If you just want to indent something you can use the group function
66 66 without open / close parameters. You can also use this code::
67 67
68 68 with p.indent(2):
69 69 ...
70 70
71 71 Inheritance diagram:
72 72
73 73 .. inheritance-diagram:: IPython.lib.pretty
74 74 :parts: 3
75 75
76 76 :copyright: 2007 by Armin Ronacher.
77 77 Portions (c) 2009 by Robert Kern.
78 78 :license: BSD License.
79 79 """
80 80 from __future__ import print_function
81 81 from contextlib import contextmanager
82 82 import sys
83 83 import types
84 84 import re
85 85 import datetime
86 86 from collections import deque
87 87
88 from IPython.utils.py3compat import PY3, cast_unicode, string_types
88 from IPython.utils.py3compat import PY3, PYPY, cast_unicode, string_types
89 89 from IPython.utils.encoding import get_stream_enc
90 90
91 91 from io import StringIO
92 92
93 93
94 94 __all__ = ['pretty', 'pprint', 'PrettyPrinter', 'RepresentationPrinter',
95 95 'for_type', 'for_type_by_name']
96 96
97 97
98 98 MAX_SEQ_LENGTH = 1000
99 99 _re_pattern_type = type(re.compile(''))
100 100
101 101 def _safe_getattr(obj, attr, default=None):
102 102 """Safe version of getattr.
103 103
104 104 Same as getattr, but will return ``default`` on any Exception,
105 105 rather than raising.
106 106 """
107 107 try:
108 108 return getattr(obj, attr, default)
109 109 except Exception:
110 110 return default
111 111
112 112 if PY3:
113 113 CUnicodeIO = StringIO
114 114 else:
115 115 class CUnicodeIO(StringIO):
116 116 """StringIO that casts str to unicode on Python 2"""
117 117 def write(self, text):
118 118 return super(CUnicodeIO, self).write(
119 119 cast_unicode(text, encoding=get_stream_enc(sys.stdout)))
120 120
121 121
122 122 def pretty(obj, verbose=False, max_width=79, newline='\n', max_seq_length=MAX_SEQ_LENGTH):
123 123 """
124 124 Pretty print the object's representation.
125 125 """
126 126 stream = CUnicodeIO()
127 127 printer = RepresentationPrinter(stream, verbose, max_width, newline, max_seq_length=max_seq_length)
128 128 printer.pretty(obj)
129 129 printer.flush()
130 130 return stream.getvalue()
131 131
132 132
133 133 def pprint(obj, verbose=False, max_width=79, newline='\n', max_seq_length=MAX_SEQ_LENGTH):
134 134 """
135 135 Like `pretty` but print to stdout.
136 136 """
137 137 printer = RepresentationPrinter(sys.stdout, verbose, max_width, newline, max_seq_length=max_seq_length)
138 138 printer.pretty(obj)
139 139 printer.flush()
140 140 sys.stdout.write(newline)
141 141 sys.stdout.flush()
142 142
143 143 class _PrettyPrinterBase(object):
144 144
145 145 @contextmanager
146 146 def indent(self, indent):
147 147 """with statement support for indenting/dedenting."""
148 148 self.indentation += indent
149 149 try:
150 150 yield
151 151 finally:
152 152 self.indentation -= indent
153 153
154 154 @contextmanager
155 155 def group(self, indent=0, open='', close=''):
156 156 """like begin_group / end_group but for the with statement."""
157 157 self.begin_group(indent, open)
158 158 try:
159 159 yield
160 160 finally:
161 161 self.end_group(indent, close)
162 162
163 163 class PrettyPrinter(_PrettyPrinterBase):
164 164 """
165 165 Baseclass for the `RepresentationPrinter` prettyprinter that is used to
166 166 generate pretty reprs of objects. Contrary to the `RepresentationPrinter`
167 167 this printer knows nothing about the default pprinters or the `_repr_pretty_`
168 168 callback method.
169 169 """
170 170
171 171 def __init__(self, output, max_width=79, newline='\n', max_seq_length=MAX_SEQ_LENGTH):
172 172 self.output = output
173 173 self.max_width = max_width
174 174 self.newline = newline
175 175 self.max_seq_length = max_seq_length
176 176 self.output_width = 0
177 177 self.buffer_width = 0
178 178 self.buffer = deque()
179 179
180 180 root_group = Group(0)
181 181 self.group_stack = [root_group]
182 182 self.group_queue = GroupQueue(root_group)
183 183 self.indentation = 0
184 184
185 185 def _break_outer_groups(self):
186 186 while self.max_width < self.output_width + self.buffer_width:
187 187 group = self.group_queue.deq()
188 188 if not group:
189 189 return
190 190 while group.breakables:
191 191 x = self.buffer.popleft()
192 192 self.output_width = x.output(self.output, self.output_width)
193 193 self.buffer_width -= x.width
194 194 while self.buffer and isinstance(self.buffer[0], Text):
195 195 x = self.buffer.popleft()
196 196 self.output_width = x.output(self.output, self.output_width)
197 197 self.buffer_width -= x.width
198 198
199 199 def text(self, obj):
200 200 """Add literal text to the output."""
201 201 width = len(obj)
202 202 if self.buffer:
203 203 text = self.buffer[-1]
204 204 if not isinstance(text, Text):
205 205 text = Text()
206 206 self.buffer.append(text)
207 207 text.add(obj, width)
208 208 self.buffer_width += width
209 209 self._break_outer_groups()
210 210 else:
211 211 self.output.write(obj)
212 212 self.output_width += width
213 213
214 214 def breakable(self, sep=' '):
215 215 """
216 216 Add a breakable separator to the output. This does not mean that it
217 217 will automatically break here. If no breaking on this position takes
218 218 place the `sep` is inserted which default to one space.
219 219 """
220 220 width = len(sep)
221 221 group = self.group_stack[-1]
222 222 if group.want_break:
223 223 self.flush()
224 224 self.output.write(self.newline)
225 225 self.output.write(' ' * self.indentation)
226 226 self.output_width = self.indentation
227 227 self.buffer_width = 0
228 228 else:
229 229 self.buffer.append(Breakable(sep, width, self))
230 230 self.buffer_width += width
231 231 self._break_outer_groups()
232 232
233 233 def break_(self):
234 234 """
235 235 Explicitly insert a newline into the output, maintaining correct indentation.
236 236 """
237 237 self.flush()
238 238 self.output.write(self.newline)
239 239 self.output.write(' ' * self.indentation)
240 240 self.output_width = self.indentation
241 241 self.buffer_width = 0
242 242
243 243
244 244 def begin_group(self, indent=0, open=''):
245 245 """
246 246 Begin a group. If you want support for python < 2.5 which doesn't has
247 247 the with statement this is the preferred way:
248 248
249 249 p.begin_group(1, '{')
250 250 ...
251 251 p.end_group(1, '}')
252 252
253 253 The python 2.5 expression would be this:
254 254
255 255 with p.group(1, '{', '}'):
256 256 ...
257 257
258 258 The first parameter specifies the indentation for the next line (usually
259 259 the width of the opening text), the second the opening text. All
260 260 parameters are optional.
261 261 """
262 262 if open:
263 263 self.text(open)
264 264 group = Group(self.group_stack[-1].depth + 1)
265 265 self.group_stack.append(group)
266 266 self.group_queue.enq(group)
267 267 self.indentation += indent
268 268
269 269 def _enumerate(self, seq):
270 270 """like enumerate, but with an upper limit on the number of items"""
271 271 for idx, x in enumerate(seq):
272 272 if self.max_seq_length and idx >= self.max_seq_length:
273 273 self.text(',')
274 274 self.breakable()
275 275 self.text('...')
276 276 return
277 277 yield idx, x
278 278
279 279 def end_group(self, dedent=0, close=''):
280 280 """End a group. See `begin_group` for more details."""
281 281 self.indentation -= dedent
282 282 group = self.group_stack.pop()
283 283 if not group.breakables:
284 284 self.group_queue.remove(group)
285 285 if close:
286 286 self.text(close)
287 287
288 288 def flush(self):
289 289 """Flush data that is left in the buffer."""
290 290 for data in self.buffer:
291 291 self.output_width += data.output(self.output, self.output_width)
292 292 self.buffer.clear()
293 293 self.buffer_width = 0
294 294
295 295
296 296 def _get_mro(obj_class):
297 297 """ Get a reasonable method resolution order of a class and its superclasses
298 298 for both old-style and new-style classes.
299 299 """
300 300 if not hasattr(obj_class, '__mro__'):
301 301 # Old-style class. Mix in object to make a fake new-style class.
302 302 try:
303 303 obj_class = type(obj_class.__name__, (obj_class, object), {})
304 304 except TypeError:
305 305 # Old-style extension type that does not descend from object.
306 306 # FIXME: try to construct a more thorough MRO.
307 307 mro = [obj_class]
308 308 else:
309 309 mro = obj_class.__mro__[1:-1]
310 310 else:
311 311 mro = obj_class.__mro__
312 312 return mro
313 313
314 314
315 315 class RepresentationPrinter(PrettyPrinter):
316 316 """
317 317 Special pretty printer that has a `pretty` method that calls the pretty
318 318 printer for a python object.
319 319
320 320 This class stores processing data on `self` so you must *never* use
321 321 this class in a threaded environment. Always lock it or reinstanciate
322 322 it.
323 323
324 324 Instances also have a verbose flag callbacks can access to control their
325 325 output. For example the default instance repr prints all attributes and
326 326 methods that are not prefixed by an underscore if the printer is in
327 327 verbose mode.
328 328 """
329 329
330 330 def __init__(self, output, verbose=False, max_width=79, newline='\n',
331 331 singleton_pprinters=None, type_pprinters=None, deferred_pprinters=None,
332 332 max_seq_length=MAX_SEQ_LENGTH):
333 333
334 334 PrettyPrinter.__init__(self, output, max_width, newline, max_seq_length=max_seq_length)
335 335 self.verbose = verbose
336 336 self.stack = []
337 337 if singleton_pprinters is None:
338 338 singleton_pprinters = _singleton_pprinters.copy()
339 339 self.singleton_pprinters = singleton_pprinters
340 340 if type_pprinters is None:
341 341 type_pprinters = _type_pprinters.copy()
342 342 self.type_pprinters = type_pprinters
343 343 if deferred_pprinters is None:
344 344 deferred_pprinters = _deferred_type_pprinters.copy()
345 345 self.deferred_pprinters = deferred_pprinters
346 346
347 347 def pretty(self, obj):
348 348 """Pretty print the given object."""
349 349 obj_id = id(obj)
350 350 cycle = obj_id in self.stack
351 351 self.stack.append(obj_id)
352 352 self.begin_group()
353 353 try:
354 354 obj_class = _safe_getattr(obj, '__class__', None) or type(obj)
355 355 # First try to find registered singleton printers for the type.
356 356 try:
357 357 printer = self.singleton_pprinters[obj_id]
358 358 except (TypeError, KeyError):
359 359 pass
360 360 else:
361 361 return printer(obj, self, cycle)
362 362 # Next walk the mro and check for either:
363 363 # 1) a registered printer
364 364 # 2) a _repr_pretty_ method
365 365 for cls in _get_mro(obj_class):
366 366 if cls in self.type_pprinters:
367 367 # printer registered in self.type_pprinters
368 368 return self.type_pprinters[cls](obj, self, cycle)
369 369 else:
370 370 # deferred printer
371 371 printer = self._in_deferred_types(cls)
372 372 if printer is not None:
373 373 return printer(obj, self, cycle)
374 374 else:
375 375 # Finally look for special method names.
376 376 # Some objects automatically create any requested
377 377 # attribute. Try to ignore most of them by checking for
378 378 # callability.
379 379 if '_repr_pretty_' in cls.__dict__:
380 380 meth = cls._repr_pretty_
381 381 if callable(meth):
382 382 return meth(obj, self, cycle)
383 383 return _default_pprint(obj, self, cycle)
384 384 finally:
385 385 self.end_group()
386 386 self.stack.pop()
387 387
388 388 def _in_deferred_types(self, cls):
389 389 """
390 390 Check if the given class is specified in the deferred type registry.
391 391
392 392 Returns the printer from the registry if it exists, and None if the
393 393 class is not in the registry. Successful matches will be moved to the
394 394 regular type registry for future use.
395 395 """
396 396 mod = _safe_getattr(cls, '__module__', None)
397 397 name = _safe_getattr(cls, '__name__', None)
398 398 key = (mod, name)
399 399 printer = None
400 400 if key in self.deferred_pprinters:
401 401 # Move the printer over to the regular registry.
402 402 printer = self.deferred_pprinters.pop(key)
403 403 self.type_pprinters[cls] = printer
404 404 return printer
405 405
406 406
407 407 class Printable(object):
408 408
409 409 def output(self, stream, output_width):
410 410 return output_width
411 411
412 412
413 413 class Text(Printable):
414 414
415 415 def __init__(self):
416 416 self.objs = []
417 417 self.width = 0
418 418
419 419 def output(self, stream, output_width):
420 420 for obj in self.objs:
421 421 stream.write(obj)
422 422 return output_width + self.width
423 423
424 424 def add(self, obj, width):
425 425 self.objs.append(obj)
426 426 self.width += width
427 427
428 428
429 429 class Breakable(Printable):
430 430
431 431 def __init__(self, seq, width, pretty):
432 432 self.obj = seq
433 433 self.width = width
434 434 self.pretty = pretty
435 435 self.indentation = pretty.indentation
436 436 self.group = pretty.group_stack[-1]
437 437 self.group.breakables.append(self)
438 438
439 439 def output(self, stream, output_width):
440 440 self.group.breakables.popleft()
441 441 if self.group.want_break:
442 442 stream.write(self.pretty.newline)
443 443 stream.write(' ' * self.indentation)
444 444 return self.indentation
445 445 if not self.group.breakables:
446 446 self.pretty.group_queue.remove(self.group)
447 447 stream.write(self.obj)
448 448 return output_width + self.width
449 449
450 450
451 451 class Group(Printable):
452 452
453 453 def __init__(self, depth):
454 454 self.depth = depth
455 455 self.breakables = deque()
456 456 self.want_break = False
457 457
458 458
459 459 class GroupQueue(object):
460 460
461 461 def __init__(self, *groups):
462 462 self.queue = []
463 463 for group in groups:
464 464 self.enq(group)
465 465
466 466 def enq(self, group):
467 467 depth = group.depth
468 468 while depth > len(self.queue) - 1:
469 469 self.queue.append([])
470 470 self.queue[depth].append(group)
471 471
472 472 def deq(self):
473 473 for stack in self.queue:
474 474 for idx, group in enumerate(reversed(stack)):
475 475 if group.breakables:
476 476 del stack[idx]
477 477 group.want_break = True
478 478 return group
479 479 for group in stack:
480 480 group.want_break = True
481 481 del stack[:]
482 482
483 483 def remove(self, group):
484 484 try:
485 485 self.queue[group.depth].remove(group)
486 486 except ValueError:
487 487 pass
488 488
489 489 try:
490 490 _baseclass_reprs = (object.__repr__, types.InstanceType.__repr__)
491 491 except AttributeError: # Python 3
492 492 _baseclass_reprs = (object.__repr__,)
493 493
494 494
495 495 def _default_pprint(obj, p, cycle):
496 496 """
497 497 The default print function. Used if an object does not provide one and
498 498 it's none of the builtin objects.
499 499 """
500 500 klass = _safe_getattr(obj, '__class__', None) or type(obj)
501 501 if _safe_getattr(klass, '__repr__', None) not in _baseclass_reprs:
502 502 # A user-provided repr. Find newlines and replace them with p.break_()
503 503 _repr_pprint(obj, p, cycle)
504 504 return
505 505 p.begin_group(1, '<')
506 506 p.pretty(klass)
507 507 p.text(' at 0x%x' % id(obj))
508 508 if cycle:
509 509 p.text(' ...')
510 510 elif p.verbose:
511 511 first = True
512 512 for key in dir(obj):
513 513 if not key.startswith('_'):
514 514 try:
515 515 value = getattr(obj, key)
516 516 except AttributeError:
517 517 continue
518 518 if isinstance(value, types.MethodType):
519 519 continue
520 520 if not first:
521 521 p.text(',')
522 522 p.breakable()
523 523 p.text(key)
524 524 p.text('=')
525 525 step = len(key) + 1
526 526 p.indentation += step
527 527 p.pretty(value)
528 528 p.indentation -= step
529 529 first = False
530 530 p.end_group(1, '>')
531 531
532 532
533 533 def _seq_pprinter_factory(start, end, basetype):
534 534 """
535 535 Factory that returns a pprint function useful for sequences. Used by
536 536 the default pprint for tuples, dicts, and lists.
537 537 """
538 538 def inner(obj, p, cycle):
539 539 typ = type(obj)
540 540 if basetype is not None and typ is not basetype and typ.__repr__ != basetype.__repr__:
541 541 # If the subclass provides its own repr, use it instead.
542 542 return p.text(typ.__repr__(obj))
543 543
544 544 if cycle:
545 545 return p.text(start + '...' + end)
546 546 step = len(start)
547 547 p.begin_group(step, start)
548 548 for idx, x in p._enumerate(obj):
549 549 if idx:
550 550 p.text(',')
551 551 p.breakable()
552 552 p.pretty(x)
553 553 if len(obj) == 1 and type(obj) is tuple:
554 554 # Special case for 1-item tuples.
555 555 p.text(',')
556 556 p.end_group(step, end)
557 557 return inner
558 558
559 559
560 560 def _set_pprinter_factory(start, end, basetype):
561 561 """
562 562 Factory that returns a pprint function useful for sets and frozensets.
563 563 """
564 564 def inner(obj, p, cycle):
565 565 typ = type(obj)
566 566 if basetype is not None and typ is not basetype and typ.__repr__ != basetype.__repr__:
567 567 # If the subclass provides its own repr, use it instead.
568 568 return p.text(typ.__repr__(obj))
569 569
570 570 if cycle:
571 571 return p.text(start + '...' + end)
572 572 if len(obj) == 0:
573 573 # Special case.
574 574 p.text(basetype.__name__ + '()')
575 575 else:
576 576 step = len(start)
577 577 p.begin_group(step, start)
578 578 # Like dictionary keys, we will try to sort the items if there aren't too many
579 579 items = obj
580 580 if not (p.max_seq_length and len(obj) >= p.max_seq_length):
581 581 try:
582 582 items = sorted(obj)
583 583 except Exception:
584 584 # Sometimes the items don't sort.
585 585 pass
586 586 for idx, x in p._enumerate(items):
587 587 if idx:
588 588 p.text(',')
589 589 p.breakable()
590 590 p.pretty(x)
591 591 p.end_group(step, end)
592 592 return inner
593 593
594 594
595 595 def _dict_pprinter_factory(start, end, basetype=None):
596 596 """
597 597 Factory that returns a pprint function used by the default pprint of
598 598 dicts and dict proxies.
599 599 """
600 600 def inner(obj, p, cycle):
601 601 typ = type(obj)
602 602 if basetype is not None and typ is not basetype and typ.__repr__ != basetype.__repr__:
603 603 # If the subclass provides its own repr, use it instead.
604 604 return p.text(typ.__repr__(obj))
605 605
606 606 if cycle:
607 607 return p.text('{...}')
608 608 step = len(start)
609 609 p.begin_group(step, start)
610 610 keys = obj.keys()
611 611 # if dict isn't large enough to be truncated, sort keys before displaying
612 612 if not (p.max_seq_length and len(obj) >= p.max_seq_length):
613 613 try:
614 614 keys = sorted(keys)
615 615 except Exception:
616 616 # Sometimes the keys don't sort.
617 617 pass
618 618 for idx, key in p._enumerate(keys):
619 619 if idx:
620 620 p.text(',')
621 621 p.breakable()
622 622 p.pretty(key)
623 623 p.text(': ')
624 624 p.pretty(obj[key])
625 625 p.end_group(step, end)
626 626 return inner
627 627
628 628
629 629 def _super_pprint(obj, p, cycle):
630 630 """The pprint for the super type."""
631 631 p.begin_group(8, '<super: ')
632 632 p.pretty(obj.__thisclass__)
633 633 p.text(',')
634 634 p.breakable()
635 p.pretty(obj.__self__)
635 if PYPY: # In PyPy, super() objects doesn't have __self__ attributes
636 dself = obj.__repr__.__self__
637 p.pretty(None if dself is obj else dself)
638 else:
639 p.pretty(obj.__self__)
636 640 p.end_group(8, '>')
637 641
638 642
639 643 def _re_pattern_pprint(obj, p, cycle):
640 644 """The pprint function for regular expression patterns."""
641 645 p.text('re.compile(')
642 646 pattern = repr(obj.pattern)
643 647 if pattern[:1] in 'uU':
644 648 pattern = pattern[1:]
645 649 prefix = 'ur'
646 650 else:
647 651 prefix = 'r'
648 652 pattern = prefix + pattern.replace('\\\\', '\\')
649 653 p.text(pattern)
650 654 if obj.flags:
651 655 p.text(',')
652 656 p.breakable()
653 657 done_one = False
654 658 for flag in ('TEMPLATE', 'IGNORECASE', 'LOCALE', 'MULTILINE', 'DOTALL',
655 659 'UNICODE', 'VERBOSE', 'DEBUG'):
656 660 if obj.flags & getattr(re, flag):
657 661 if done_one:
658 662 p.text('|')
659 663 p.text('re.' + flag)
660 664 done_one = True
661 665 p.text(')')
662 666
663 667
664 668 def _type_pprint(obj, p, cycle):
665 669 """The pprint for classes and types."""
666 670 # Heap allocated types might not have the module attribute,
667 671 # and others may set it to None.
668 672
669 673 # Checks for a __repr__ override in the metaclass
670 674 if type(obj).__repr__ is not type.__repr__:
671 675 _repr_pprint(obj, p, cycle)
672 676 return
673 677
674 678 mod = _safe_getattr(obj, '__module__', None)
675 679 try:
676 680 name = obj.__qualname__
677 681 if not isinstance(name, string_types):
678 682 # This can happen if the type implements __qualname__ as a property
679 683 # or other descriptor in Python 2.
680 684 raise Exception("Try __name__")
681 685 except Exception:
682 686 name = obj.__name__
683 687 if not isinstance(name, string_types):
684 688 name = '<unknown type>'
685 689
686 690 if mod in (None, '__builtin__', 'builtins', 'exceptions'):
687 691 p.text(name)
688 692 else:
689 693 p.text(mod + '.' + name)
690 694
691 695
692 696 def _repr_pprint(obj, p, cycle):
693 697 """A pprint that just redirects to the normal repr function."""
694 698 # Find newlines and replace them with p.break_()
695 699 output = repr(obj)
696 700 for idx,output_line in enumerate(output.splitlines()):
697 701 if idx:
698 702 p.break_()
699 703 p.text(output_line)
700 704
701 705
702 706 def _function_pprint(obj, p, cycle):
703 707 """Base pprint for all functions and builtin functions."""
704 708 name = _safe_getattr(obj, '__qualname__', obj.__name__)
705 709 mod = obj.__module__
706 710 if mod and mod not in ('__builtin__', 'builtins', 'exceptions'):
707 711 name = mod + '.' + name
708 712 p.text('<function %s>' % name)
709 713
710 714
711 715 def _exception_pprint(obj, p, cycle):
712 716 """Base pprint for all exceptions."""
713 717 name = getattr(obj.__class__, '__qualname__', obj.__class__.__name__)
714 718 if obj.__class__.__module__ not in ('exceptions', 'builtins'):
715 719 name = '%s.%s' % (obj.__class__.__module__, name)
716 720 step = len(name) + 1
717 721 p.begin_group(step, name + '(')
718 722 for idx, arg in enumerate(getattr(obj, 'args', ())):
719 723 if idx:
720 724 p.text(',')
721 725 p.breakable()
722 726 p.pretty(arg)
723 727 p.end_group(step, ')')
724 728
725 729
726 730 #: the exception base
727 731 try:
728 732 _exception_base = BaseException
729 733 except NameError:
730 734 _exception_base = Exception
731 735
732 736
733 737 #: printers for builtin types
734 738 _type_pprinters = {
735 739 int: _repr_pprint,
736 740 float: _repr_pprint,
737 741 str: _repr_pprint,
738 742 tuple: _seq_pprinter_factory('(', ')', tuple),
739 743 list: _seq_pprinter_factory('[', ']', list),
740 744 dict: _dict_pprinter_factory('{', '}', dict),
741 745
742 746 set: _set_pprinter_factory('{', '}', set),
743 747 frozenset: _set_pprinter_factory('frozenset({', '})', frozenset),
744 748 super: _super_pprint,
745 749 _re_pattern_type: _re_pattern_pprint,
746 750 type: _type_pprint,
747 751 types.FunctionType: _function_pprint,
748 752 types.BuiltinFunctionType: _function_pprint,
749 753 types.MethodType: _repr_pprint,
750 754
751 755 datetime.datetime: _repr_pprint,
752 756 datetime.timedelta: _repr_pprint,
753 757 _exception_base: _exception_pprint
754 758 }
755 759
756 760 try:
757 761 # In PyPy, types.DictProxyType is dict, setting the dictproxy printer
758 762 # using dict.setdefault avoids overwritting the dict printer
759 763 _type_pprinters.setdefault(types.DictProxyType,
760 764 _dict_pprinter_factory('dict_proxy({', '})'))
761 765 _type_pprinters[types.ClassType] = _type_pprint
762 766 _type_pprinters[types.SliceType] = _repr_pprint
763 767 except AttributeError: # Python 3
764 768 _type_pprinters[types.MappingProxyType] = \
765 769 _dict_pprinter_factory('mappingproxy({', '})')
766 770 _type_pprinters[slice] = _repr_pprint
767 771
768 772 try:
769 773 _type_pprinters[xrange] = _repr_pprint
770 774 _type_pprinters[long] = _repr_pprint
771 775 _type_pprinters[unicode] = _repr_pprint
772 776 except NameError:
773 777 _type_pprinters[range] = _repr_pprint
774 778 _type_pprinters[bytes] = _repr_pprint
775 779
776 780 #: printers for types specified by name
777 781 _deferred_type_pprinters = {
778 782 }
779 783
780 784 def for_type(typ, func):
781 785 """
782 786 Add a pretty printer for a given type.
783 787 """
784 788 oldfunc = _type_pprinters.get(typ, None)
785 789 if func is not None:
786 790 # To support easy restoration of old pprinters, we need to ignore Nones.
787 791 _type_pprinters[typ] = func
788 792 return oldfunc
789 793
790 794 def for_type_by_name(type_module, type_name, func):
791 795 """
792 796 Add a pretty printer for a type specified by the module and name of a type
793 797 rather than the type object itself.
794 798 """
795 799 key = (type_module, type_name)
796 800 oldfunc = _deferred_type_pprinters.get(key, None)
797 801 if func is not None:
798 802 # To support easy restoration of old pprinters, we need to ignore Nones.
799 803 _deferred_type_pprinters[key] = func
800 804 return oldfunc
801 805
802 806
803 807 #: printers for the default singletons
804 808 _singleton_pprinters = dict.fromkeys(map(id, [None, True, False, Ellipsis,
805 809 NotImplemented]), _repr_pprint)
806 810
807 811
808 812 def _defaultdict_pprint(obj, p, cycle):
809 813 name = obj.__class__.__name__
810 814 with p.group(len(name) + 1, name + '(', ')'):
811 815 if cycle:
812 816 p.text('...')
813 817 else:
814 818 p.pretty(obj.default_factory)
815 819 p.text(',')
816 820 p.breakable()
817 821 p.pretty(dict(obj))
818 822
819 823 def _ordereddict_pprint(obj, p, cycle):
820 824 name = obj.__class__.__name__
821 825 with p.group(len(name) + 1, name + '(', ')'):
822 826 if cycle:
823 827 p.text('...')
824 828 elif len(obj):
825 829 p.pretty(list(obj.items()))
826 830
827 831 def _deque_pprint(obj, p, cycle):
828 832 name = obj.__class__.__name__
829 833 with p.group(len(name) + 1, name + '(', ')'):
830 834 if cycle:
831 835 p.text('...')
832 836 else:
833 837 p.pretty(list(obj))
834 838
835 839
836 840 def _counter_pprint(obj, p, cycle):
837 841 name = obj.__class__.__name__
838 842 with p.group(len(name) + 1, name + '(', ')'):
839 843 if cycle:
840 844 p.text('...')
841 845 elif len(obj):
842 846 p.pretty(dict(obj))
843 847
844 848 for_type_by_name('collections', 'defaultdict', _defaultdict_pprint)
845 849 for_type_by_name('collections', 'OrderedDict', _ordereddict_pprint)
846 850 for_type_by_name('collections', 'deque', _deque_pprint)
847 851 for_type_by_name('collections', 'Counter', _counter_pprint)
848 852
849 853 if __name__ == '__main__':
850 854 from random import randrange
851 855 class Foo(object):
852 856 def __init__(self):
853 857 self.foo = 1
854 858 self.bar = re.compile(r'\s+')
855 859 self.blub = dict.fromkeys(range(30), randrange(1, 40))
856 860 self.hehe = 23424.234234
857 861 self.list = ["blub", "blah", self]
858 862
859 863 def get_foo(self):
860 864 print("foo")
861 865
862 866 pprint(Foo(), verbose=True)
@@ -1,534 +1,536 b''
1 1 # coding: utf-8
2 2 """Tests for IPython.lib.pretty."""
3 3
4 4 # Copyright (c) IPython Development Team.
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 7 from __future__ import print_function
8 8
9 9 from collections import Counter, defaultdict, deque, OrderedDict
10 10 import types, string, ctypes
11 11
12 12 import nose.tools as nt
13 13
14 14 from IPython.lib import pretty
15 15 from IPython.testing.decorators import (skip_without, py2_only, py3_only,
16 16 cpython2_only)
17 17 from IPython.utils.py3compat import PY3, unicode_to_str
18 18
19 19 if PY3:
20 20 from io import StringIO
21 21 else:
22 22 from StringIO import StringIO
23 23
24 24
25 25 class MyList(object):
26 26 def __init__(self, content):
27 27 self.content = content
28 28 def _repr_pretty_(self, p, cycle):
29 29 if cycle:
30 30 p.text("MyList(...)")
31 31 else:
32 32 with p.group(3, "MyList(", ")"):
33 33 for (i, child) in enumerate(self.content):
34 34 if i:
35 35 p.text(",")
36 36 p.breakable()
37 37 else:
38 38 p.breakable("")
39 39 p.pretty(child)
40 40
41 41
42 42 class MyDict(dict):
43 43 def _repr_pretty_(self, p, cycle):
44 44 p.text("MyDict(...)")
45 45
46 46 class MyObj(object):
47 47 def somemethod(self):
48 48 pass
49 49
50 50
51 51 class Dummy1(object):
52 52 def _repr_pretty_(self, p, cycle):
53 53 p.text("Dummy1(...)")
54 54
55 55 class Dummy2(Dummy1):
56 56 _repr_pretty_ = None
57 57
58 58 class NoModule(object):
59 59 pass
60 60
61 61 NoModule.__module__ = None
62 62
63 63 class Breaking(object):
64 64 def _repr_pretty_(self, p, cycle):
65 65 with p.group(4,"TG: ",":"):
66 66 p.text("Breaking(")
67 67 p.break_()
68 68 p.text(")")
69 69
70 70 class BreakingRepr(object):
71 71 def __repr__(self):
72 72 return "Breaking(\n)"
73 73
74 74 class BreakingReprParent(object):
75 75 def _repr_pretty_(self, p, cycle):
76 76 with p.group(4,"TG: ",":"):
77 77 p.pretty(BreakingRepr())
78 78
79 79 class BadRepr(object):
80 80
81 81 def __repr__(self):
82 82 return 1/0
83 83
84 84
85 85 def test_indentation():
86 86 """Test correct indentation in groups"""
87 87 count = 40
88 88 gotoutput = pretty.pretty(MyList(range(count)))
89 89 expectedoutput = "MyList(\n" + ",\n".join(" %d" % i for i in range(count)) + ")"
90 90
91 91 nt.assert_equal(gotoutput, expectedoutput)
92 92
93 93
94 94 def test_dispatch():
95 95 """
96 96 Test correct dispatching: The _repr_pretty_ method for MyDict
97 97 must be found before the registered printer for dict.
98 98 """
99 99 gotoutput = pretty.pretty(MyDict())
100 100 expectedoutput = "MyDict(...)"
101 101
102 102 nt.assert_equal(gotoutput, expectedoutput)
103 103
104 104
105 105 def test_callability_checking():
106 106 """
107 107 Test that the _repr_pretty_ method is tested for callability and skipped if
108 108 not.
109 109 """
110 110 gotoutput = pretty.pretty(Dummy2())
111 111 expectedoutput = "Dummy1(...)"
112 112
113 113 nt.assert_equal(gotoutput, expectedoutput)
114 114
115 115
116 116 def test_sets():
117 117 """
118 118 Test that set and frozenset use Python 3 formatting.
119 119 """
120 120 objects = [set(), frozenset(), set([1]), frozenset([1]), set([1, 2]),
121 121 frozenset([1, 2]), set([-1, -2, -3])]
122 122 expected = ['set()', 'frozenset()', '{1}', 'frozenset({1})', '{1, 2}',
123 123 'frozenset({1, 2})', '{-3, -2, -1}']
124 124 for obj, expected_output in zip(objects, expected):
125 125 got_output = pretty.pretty(obj)
126 126 yield nt.assert_equal, got_output, expected_output
127 127
128 128
129 129 @skip_without('xxlimited')
130 130 def test_pprint_heap_allocated_type():
131 131 """
132 132 Test that pprint works for heap allocated types.
133 133 """
134 134 import xxlimited
135 135 output = pretty.pretty(xxlimited.Null)
136 136 nt.assert_equal(output, 'xxlimited.Null')
137 137
138 138 def test_pprint_nomod():
139 139 """
140 140 Test that pprint works for classes with no __module__.
141 141 """
142 142 output = pretty.pretty(NoModule)
143 143 nt.assert_equal(output, 'NoModule')
144 144
145 145 def test_pprint_break():
146 146 """
147 147 Test that p.break_ produces expected output
148 148 """
149 149 output = pretty.pretty(Breaking())
150 150 expected = "TG: Breaking(\n ):"
151 151 nt.assert_equal(output, expected)
152 152
153 153 def test_pprint_break_repr():
154 154 """
155 155 Test that p.break_ is used in repr
156 156 """
157 157 output = pretty.pretty(BreakingReprParent())
158 158 expected = "TG: Breaking(\n ):"
159 159 nt.assert_equal(output, expected)
160 160
161 161 def test_bad_repr():
162 162 """Don't catch bad repr errors"""
163 163 with nt.assert_raises(ZeroDivisionError):
164 164 output = pretty.pretty(BadRepr())
165 165
166 166 class BadException(Exception):
167 167 def __str__(self):
168 168 return -1
169 169
170 170 class ReallyBadRepr(object):
171 171 __module__ = 1
172 172 @property
173 173 def __class__(self):
174 174 raise ValueError("I am horrible")
175 175
176 176 def __repr__(self):
177 177 raise BadException()
178 178
179 179 def test_really_bad_repr():
180 180 with nt.assert_raises(BadException):
181 181 output = pretty.pretty(ReallyBadRepr())
182 182
183 183
184 184 class SA(object):
185 185 pass
186 186
187 187 class SB(SA):
188 188 pass
189 189
190 190 def test_super_repr():
191 # "<super: module_name.SA, None>"
191 192 output = pretty.pretty(super(SA))
192 nt.assert_in("SA", output)
193 nt.assert_regexp_matches(output, r"<super: \S+.SA, None>")
193 194
195 # "<super: module_name.SA, <module_name.SB at 0x...>>"
194 196 sb = SB()
195 197 output = pretty.pretty(super(SA, sb))
196 nt.assert_in("SA", output)
198 nt.assert_regexp_matches(output, r"<super: \S+.SA,\s+<\S+.SB at 0x\S+>>")
197 199
198 200
199 201 def test_long_list():
200 202 lis = list(range(10000))
201 203 p = pretty.pretty(lis)
202 204 last2 = p.rsplit('\n', 2)[-2:]
203 205 nt.assert_equal(last2, [' 999,', ' ...]'])
204 206
205 207 def test_long_set():
206 208 s = set(range(10000))
207 209 p = pretty.pretty(s)
208 210 last2 = p.rsplit('\n', 2)[-2:]
209 211 nt.assert_equal(last2, [' 999,', ' ...}'])
210 212
211 213 def test_long_tuple():
212 214 tup = tuple(range(10000))
213 215 p = pretty.pretty(tup)
214 216 last2 = p.rsplit('\n', 2)[-2:]
215 217 nt.assert_equal(last2, [' 999,', ' ...)'])
216 218
217 219 def test_long_dict():
218 220 d = { n:n for n in range(10000) }
219 221 p = pretty.pretty(d)
220 222 last2 = p.rsplit('\n', 2)[-2:]
221 223 nt.assert_equal(last2, [' 999: 999,', ' ...}'])
222 224
223 225 def test_unbound_method():
224 226 output = pretty.pretty(MyObj.somemethod)
225 227 nt.assert_in('MyObj.somemethod', output)
226 228
227 229
228 230 class MetaClass(type):
229 231 def __new__(cls, name):
230 232 return type.__new__(cls, name, (object,), {'name': name})
231 233
232 234 def __repr__(self):
233 235 return "[CUSTOM REPR FOR CLASS %s]" % self.name
234 236
235 237
236 238 ClassWithMeta = MetaClass('ClassWithMeta')
237 239
238 240
239 241 def test_metaclass_repr():
240 242 output = pretty.pretty(ClassWithMeta)
241 243 nt.assert_equal(output, "[CUSTOM REPR FOR CLASS ClassWithMeta]")
242 244
243 245
244 246 def test_unicode_repr():
245 247 u = u"üniçodé"
246 248 ustr = unicode_to_str(u)
247 249
248 250 class C(object):
249 251 def __repr__(self):
250 252 return ustr
251 253
252 254 c = C()
253 255 p = pretty.pretty(c)
254 256 nt.assert_equal(p, u)
255 257 p = pretty.pretty([c])
256 258 nt.assert_equal(p, u'[%s]' % u)
257 259
258 260
259 261 def test_basic_class():
260 262 def type_pprint_wrapper(obj, p, cycle):
261 263 if obj is MyObj:
262 264 type_pprint_wrapper.called = True
263 265 return pretty._type_pprint(obj, p, cycle)
264 266 type_pprint_wrapper.called = False
265 267
266 268 stream = StringIO()
267 269 printer = pretty.RepresentationPrinter(stream)
268 270 printer.type_pprinters[type] = type_pprint_wrapper
269 271 printer.pretty(MyObj)
270 272 printer.flush()
271 273 output = stream.getvalue()
272 274
273 275 nt.assert_equal(output, '%s.MyObj' % __name__)
274 276 nt.assert_true(type_pprint_wrapper.called)
275 277
276 278
277 279 # This is only run on Python 2 because in Python 3 the language prevents you
278 280 # from setting a non-unicode value for __qualname__ on a metaclass, and it
279 281 # doesn't respect the descriptor protocol if you subclass unicode and implement
280 282 # __get__.
281 283 @py2_only
282 284 def test_fallback_to__name__on_type():
283 285 # Test that we correctly repr types that have non-string values for
284 286 # __qualname__ by falling back to __name__
285 287
286 288 class Type(object):
287 289 __qualname__ = 5
288 290
289 291 # Test repring of the type.
290 292 stream = StringIO()
291 293 printer = pretty.RepresentationPrinter(stream)
292 294
293 295 printer.pretty(Type)
294 296 printer.flush()
295 297 output = stream.getvalue()
296 298
297 299 # If __qualname__ is malformed, we should fall back to __name__.
298 300 expected = '.'.join([__name__, Type.__name__])
299 301 nt.assert_equal(output, expected)
300 302
301 303 # Clear stream buffer.
302 304 stream.buf = ''
303 305
304 306 # Test repring of an instance of the type.
305 307 instance = Type()
306 308 printer.pretty(instance)
307 309 printer.flush()
308 310 output = stream.getvalue()
309 311
310 312 # Should look like:
311 313 # <IPython.lib.tests.test_pretty.Type at 0x7f7658ae07d0>
312 314 prefix = '<' + '.'.join([__name__, Type.__name__]) + ' at 0x'
313 315 nt.assert_true(output.startswith(prefix))
314 316
315 317
316 318 @py2_only
317 319 def test_fail_gracefully_on_bogus__qualname__and__name__():
318 320 # Test that we correctly repr types that have non-string values for both
319 321 # __qualname__ and __name__
320 322
321 323 class Meta(type):
322 324 __name__ = 5
323 325
324 326 class Type(object):
325 327 __metaclass__ = Meta
326 328 __qualname__ = 5
327 329
328 330 stream = StringIO()
329 331 printer = pretty.RepresentationPrinter(stream)
330 332
331 333 printer.pretty(Type)
332 334 printer.flush()
333 335 output = stream.getvalue()
334 336
335 337 # If we can't find __name__ or __qualname__ just use a sentinel string.
336 338 expected = '.'.join([__name__, '<unknown type>'])
337 339 nt.assert_equal(output, expected)
338 340
339 341 # Clear stream buffer.
340 342 stream.buf = ''
341 343
342 344 # Test repring of an instance of the type.
343 345 instance = Type()
344 346 printer.pretty(instance)
345 347 printer.flush()
346 348 output = stream.getvalue()
347 349
348 350 # Should look like:
349 351 # <IPython.lib.tests.test_pretty.<unknown type> at 0x7f7658ae07d0>
350 352 prefix = '<' + '.'.join([__name__, '<unknown type>']) + ' at 0x'
351 353 nt.assert_true(output.startswith(prefix))
352 354
353 355
354 356 def test_collections_defaultdict():
355 357 # Create defaultdicts with cycles
356 358 a = defaultdict()
357 359 a.default_factory = a
358 360 b = defaultdict(list)
359 361 b['key'] = b
360 362
361 363 # Dictionary order cannot be relied on, test against single keys.
362 364 cases = [
363 365 (defaultdict(list), 'defaultdict(list, {})'),
364 366 (defaultdict(list, {'key': '-' * 50}),
365 367 "defaultdict(list,\n"
366 368 " {'key': '--------------------------------------------------'})"),
367 369 (a, 'defaultdict(defaultdict(...), {})'),
368 370 (b, "defaultdict(list, {'key': defaultdict(...)})"),
369 371 ]
370 372 for obj, expected in cases:
371 373 nt.assert_equal(pretty.pretty(obj), expected)
372 374
373 375
374 376 def test_collections_ordereddict():
375 377 # Create OrderedDict with cycle
376 378 a = OrderedDict()
377 379 a['key'] = a
378 380
379 381 cases = [
380 382 (OrderedDict(), 'OrderedDict()'),
381 383 (OrderedDict((i, i) for i in range(1000, 1010)),
382 384 'OrderedDict([(1000, 1000),\n'
383 385 ' (1001, 1001),\n'
384 386 ' (1002, 1002),\n'
385 387 ' (1003, 1003),\n'
386 388 ' (1004, 1004),\n'
387 389 ' (1005, 1005),\n'
388 390 ' (1006, 1006),\n'
389 391 ' (1007, 1007),\n'
390 392 ' (1008, 1008),\n'
391 393 ' (1009, 1009)])'),
392 394 (a, "OrderedDict([('key', OrderedDict(...))])"),
393 395 ]
394 396 for obj, expected in cases:
395 397 nt.assert_equal(pretty.pretty(obj), expected)
396 398
397 399
398 400 def test_collections_deque():
399 401 # Create deque with cycle
400 402 a = deque()
401 403 a.append(a)
402 404
403 405 cases = [
404 406 (deque(), 'deque([])'),
405 407 (deque(i for i in range(1000, 1020)),
406 408 'deque([1000,\n'
407 409 ' 1001,\n'
408 410 ' 1002,\n'
409 411 ' 1003,\n'
410 412 ' 1004,\n'
411 413 ' 1005,\n'
412 414 ' 1006,\n'
413 415 ' 1007,\n'
414 416 ' 1008,\n'
415 417 ' 1009,\n'
416 418 ' 1010,\n'
417 419 ' 1011,\n'
418 420 ' 1012,\n'
419 421 ' 1013,\n'
420 422 ' 1014,\n'
421 423 ' 1015,\n'
422 424 ' 1016,\n'
423 425 ' 1017,\n'
424 426 ' 1018,\n'
425 427 ' 1019])'),
426 428 (a, 'deque([deque(...)])'),
427 429 ]
428 430 for obj, expected in cases:
429 431 nt.assert_equal(pretty.pretty(obj), expected)
430 432
431 433 def test_collections_counter():
432 434 class MyCounter(Counter):
433 435 pass
434 436 cases = [
435 437 (Counter(), 'Counter()'),
436 438 (Counter(a=1), "Counter({'a': 1})"),
437 439 (MyCounter(a=1), "MyCounter({'a': 1})"),
438 440 ]
439 441 for obj, expected in cases:
440 442 nt.assert_equal(pretty.pretty(obj), expected)
441 443
442 444 @py3_only
443 445 def test_mappingproxy():
444 446 MP = types.MappingProxyType
445 447 underlying_dict = {}
446 448 mp_recursive = MP(underlying_dict)
447 449 underlying_dict[2] = mp_recursive
448 450 underlying_dict[3] = underlying_dict
449 451
450 452 cases = [
451 453 (MP({}), "mappingproxy({})"),
452 454 (MP({None: MP({})}), "mappingproxy({None: mappingproxy({})})"),
453 455 (MP({k: k.upper() for k in string.ascii_lowercase}),
454 456 "mappingproxy({'a': 'A',\n"
455 457 " 'b': 'B',\n"
456 458 " 'c': 'C',\n"
457 459 " 'd': 'D',\n"
458 460 " 'e': 'E',\n"
459 461 " 'f': 'F',\n"
460 462 " 'g': 'G',\n"
461 463 " 'h': 'H',\n"
462 464 " 'i': 'I',\n"
463 465 " 'j': 'J',\n"
464 466 " 'k': 'K',\n"
465 467 " 'l': 'L',\n"
466 468 " 'm': 'M',\n"
467 469 " 'n': 'N',\n"
468 470 " 'o': 'O',\n"
469 471 " 'p': 'P',\n"
470 472 " 'q': 'Q',\n"
471 473 " 'r': 'R',\n"
472 474 " 's': 'S',\n"
473 475 " 't': 'T',\n"
474 476 " 'u': 'U',\n"
475 477 " 'v': 'V',\n"
476 478 " 'w': 'W',\n"
477 479 " 'x': 'X',\n"
478 480 " 'y': 'Y',\n"
479 481 " 'z': 'Z'})"),
480 482 (mp_recursive, "mappingproxy({2: {...}, 3: {2: {...}, 3: {...}}})"),
481 483 (underlying_dict,
482 484 "{2: mappingproxy({2: {...}, 3: {...}}), 3: {...}}"),
483 485 ]
484 486 for obj, expected in cases:
485 487 nt.assert_equal(pretty.pretty(obj), expected)
486 488
487 489 @cpython2_only # In PyPy, types.DictProxyType is dict
488 490 def test_dictproxy():
489 491 # This is the dictproxy constructor itself from the Python API,
490 492 DP = ctypes.pythonapi.PyDictProxy_New
491 493 DP.argtypes, DP.restype = (ctypes.py_object,), ctypes.py_object
492 494
493 495 underlying_dict = {}
494 496 mp_recursive = DP(underlying_dict)
495 497 underlying_dict[0] = mp_recursive
496 498 underlying_dict[-3] = underlying_dict
497 499
498 500 cases = [
499 501 (DP({}), "dict_proxy({})"),
500 502 (DP({None: DP({})}), "dict_proxy({None: dict_proxy({})})"),
501 503 (DP({k: k.lower() for k in string.ascii_uppercase}),
502 504 "dict_proxy({'A': 'a',\n"
503 505 " 'B': 'b',\n"
504 506 " 'C': 'c',\n"
505 507 " 'D': 'd',\n"
506 508 " 'E': 'e',\n"
507 509 " 'F': 'f',\n"
508 510 " 'G': 'g',\n"
509 511 " 'H': 'h',\n"
510 512 " 'I': 'i',\n"
511 513 " 'J': 'j',\n"
512 514 " 'K': 'k',\n"
513 515 " 'L': 'l',\n"
514 516 " 'M': 'm',\n"
515 517 " 'N': 'n',\n"
516 518 " 'O': 'o',\n"
517 519 " 'P': 'p',\n"
518 520 " 'Q': 'q',\n"
519 521 " 'R': 'r',\n"
520 522 " 'S': 's',\n"
521 523 " 'T': 't',\n"
522 524 " 'U': 'u',\n"
523 525 " 'V': 'v',\n"
524 526 " 'W': 'w',\n"
525 527 " 'X': 'x',\n"
526 528 " 'Y': 'y',\n"
527 529 " 'Z': 'z'})"),
528 530 (mp_recursive, "dict_proxy({-3: {-3: {...}, 0: {...}}, 0: {...}})"),
529 531 ]
530 532 for obj, expected in cases:
531 533 nt.assert_is_instance(obj, types.DictProxyType) # Meta-test
532 534 nt.assert_equal(pretty.pretty(obj), expected)
533 535 nt.assert_equal(pretty.pretty(underlying_dict),
534 536 "{-3: {...}, 0: dict_proxy({-3: {...}, 0: {...}})}")
General Comments 0
You need to be logged in to leave comments. Login now