1# coding: utf-8 2"""Tests for IPython.lib.pretty.""" 3 4# Copyright (c) IPython Development Team. 5# Distributed under the terms of the Modified BSD License. 6 7from __future__ import print_function 8 9from collections import Counter, defaultdict, deque, OrderedDict 10import types, string, ctypes 11 12import nose.tools as nt 13 14from IPython.lib import pretty 15from IPython.testing.decorators import (skip_without, py2_only, py3_only, 16 cpython2_only) 17from IPython.utils.py3compat import PY3, unicode_to_str 18 19if PY3: 20 from io import StringIO 21else: 22 from StringIO import StringIO 23 24 25class MyList(object): 26 def __init__(self, content): 27 self.content = content 28 def _repr_pretty_(self, p, cycle): 29 if cycle: 30 p.text("MyList(...)") 31 else: 32 with p.group(3, "MyList(", ")"): 33 for (i, child) in enumerate(self.content): 34 if i: 35 p.text(",") 36 p.breakable() 37 else: 38 p.breakable("") 39 p.pretty(child) 40 41 42class MyDict(dict): 43 def _repr_pretty_(self, p, cycle): 44 p.text("MyDict(...)") 45 46class MyObj(object): 47 def somemethod(self): 48 pass 49 50 51class Dummy1(object): 52 def _repr_pretty_(self, p, cycle): 53 p.text("Dummy1(...)") 54 55class Dummy2(Dummy1): 56 _repr_pretty_ = None 57 58class NoModule(object): 59 pass 60 61NoModule.__module__ = None 62 63class Breaking(object): 64 def _repr_pretty_(self, p, cycle): 65 with p.group(4,"TG: ",":"): 66 p.text("Breaking(") 67 p.break_() 68 p.text(")") 69 70class BreakingRepr(object): 71 def __repr__(self): 72 return "Breaking(\n)" 73 74class BreakingReprParent(object): 75 def _repr_pretty_(self, p, cycle): 76 with p.group(4,"TG: ",":"): 77 p.pretty(BreakingRepr()) 78 79class BadRepr(object): 80 81 def __repr__(self): 82 return 1/0 83 84 85def test_indentation(): 86 """Test correct indentation in groups""" 87 count = 40 88 gotoutput = pretty.pretty(MyList(range(count))) 89 expectedoutput = "MyList(\n" + ",\n".join(" %d" % i for i in range(count)) + ")" 90 91 nt.assert_equal(gotoutput, expectedoutput) 92 93 94def test_dispatch(): 95 """ 96 Test correct dispatching: The _repr_pretty_ method for MyDict 97 must be found before the registered printer for dict. 98 """ 99 gotoutput = pretty.pretty(MyDict()) 100 expectedoutput = "MyDict(...)" 101 102 nt.assert_equal(gotoutput, expectedoutput) 103 104 105def test_callability_checking(): 106 """ 107 Test that the _repr_pretty_ method is tested for callability and skipped if 108 not. 109 """ 110 gotoutput = pretty.pretty(Dummy2()) 111 expectedoutput = "Dummy1(...)" 112 113 nt.assert_equal(gotoutput, expectedoutput) 114 115 116def test_sets(): 117 """ 118 Test that set and frozenset use Python 3 formatting. 119 """ 120 objects = [set(), frozenset(), set([1]), frozenset([1]), set([1, 2]), 121 frozenset([1, 2]), set([-1, -2, -3])] 122 expected = ['set()', 'frozenset()', '{1}', 'frozenset({1})', '{1, 2}', 123 'frozenset({1, 2})', '{-3, -2, -1}'] 124 for obj, expected_output in zip(objects, expected): 125 got_output = pretty.pretty(obj) 126 yield nt.assert_equal, got_output, expected_output 127 128 129@skip_without('xxlimited') 130def test_pprint_heap_allocated_type(): 131 """ 132 Test that pprint works for heap allocated types. 133 """ 134 import xxlimited 135 output = pretty.pretty(xxlimited.Null) 136 nt.assert_equal(output, 'xxlimited.Null') 137 138def test_pprint_nomod(): 139 """ 140 Test that pprint works for classes with no __module__. 141 """ 142 output = pretty.pretty(NoModule) 143 nt.assert_equal(output, 'NoModule') 144 145def test_pprint_break(): 146 """ 147 Test that p.break_ produces expected output 148 """ 149 output = pretty.pretty(Breaking()) 150 expected = "TG: Breaking(\n ):" 151 nt.assert_equal(output, expected) 152 153def test_pprint_break_repr(): 154 """ 155 Test that p.break_ is used in repr 156 """ 157 output = pretty.pretty(BreakingReprParent()) 158 expected = "TG: Breaking(\n ):" 159 nt.assert_equal(output, expected) 160 161def test_bad_repr(): 162 """Don't catch bad repr errors""" 163 with nt.assert_raises(ZeroDivisionError): 164 output = pretty.pretty(BadRepr()) 165 166class BadException(Exception): 167 def __str__(self): 168 return -1 169 170class ReallyBadRepr(object): 171 __module__ = 1 172 @property 173 def __class__(self): 174 raise ValueError("I am horrible") 175 176 def __repr__(self): 177 raise BadException() 178 179def test_really_bad_repr(): 180 with nt.assert_raises(BadException): 181 output = pretty.pretty(ReallyBadRepr()) 182 183 184class SA(object): 185 pass 186 187class SB(SA): 188 pass 189 190def test_super_repr(): 191 # "<super: module_name.SA, None>" 192 output = pretty.pretty(super(SA)) 193 nt.assert_regexp_matches(output, r"<super: \S+.SA, None>") 194 195 # "<super: module_name.SA, <module_name.SB at 0x...>>" 196 sb = SB() 197 output = pretty.pretty(super(SA, sb)) 198 nt.assert_regexp_matches(output, r"<super: \S+.SA,\s+<\S+.SB at 0x\S+>>") 199 200 201def test_long_list(): 202 lis = list(range(10000)) 203 p = pretty.pretty(lis) 204 last2 = p.rsplit('\n', 2)[-2:] 205 nt.assert_equal(last2, [' 999,', ' ...]']) 206 207def test_long_set(): 208 s = set(range(10000)) 209 p = pretty.pretty(s) 210 last2 = p.rsplit('\n', 2)[-2:] 211 nt.assert_equal(last2, [' 999,', ' ...}']) 212 213def test_long_tuple(): 214 tup = tuple(range(10000)) 215 p = pretty.pretty(tup) 216 last2 = p.rsplit('\n', 2)[-2:] 217 nt.assert_equal(last2, [' 999,', ' ...)']) 218 219def test_long_dict(): 220 d = { n:n for n in range(10000) } 221 p = pretty.pretty(d) 222 last2 = p.rsplit('\n', 2)[-2:] 223 nt.assert_equal(last2, [' 999: 999,', ' ...}']) 224 225def test_unbound_method(): 226 output = pretty.pretty(MyObj.somemethod) 227 nt.assert_in('MyObj.somemethod', output) 228 229 230class MetaClass(type): 231 def __new__(cls, name): 232 return type.__new__(cls, name, (object,), {'name': name}) 233 234 def __repr__(self): 235 return "[CUSTOM REPR FOR CLASS %s]" % self.name 236 237 238ClassWithMeta = MetaClass('ClassWithMeta') 239 240 241def test_metaclass_repr(): 242 output = pretty.pretty(ClassWithMeta) 243 nt.assert_equal(output, "[CUSTOM REPR FOR CLASS ClassWithMeta]") 244 245 246def test_unicode_repr(): 247 u = u"üniçodé" 248 ustr = unicode_to_str(u) 249 250 class C(object): 251 def __repr__(self): 252 return ustr 253 254 c = C() 255 p = pretty.pretty(c) 256 nt.assert_equal(p, u) 257 p = pretty.pretty([c]) 258 nt.assert_equal(p, u'[%s]' % u) 259 260 261def test_basic_class(): 262 def type_pprint_wrapper(obj, p, cycle): 263 if obj is MyObj: 264 type_pprint_wrapper.called = True 265 return pretty._type_pprint(obj, p, cycle) 266 type_pprint_wrapper.called = False 267 268 stream = StringIO() 269 printer = pretty.RepresentationPrinter(stream) 270 printer.type_pprinters[type] = type_pprint_wrapper 271 printer.pretty(MyObj) 272 printer.flush() 273 output = stream.getvalue() 274 275 nt.assert_equal(output, '%s.MyObj' % __name__) 276 nt.assert_true(type_pprint_wrapper.called) 277 278 279# This is only run on Python 2 because in Python 3 the language prevents you 280# from setting a non-unicode value for __qualname__ on a metaclass, and it 281# doesn't respect the descriptor protocol if you subclass unicode and implement 282# __get__. 283@py2_only 284def test_fallback_to__name__on_type(): 285 # Test that we correctly repr types that have non-string values for 286 # __qualname__ by falling back to __name__ 287 288 class Type(object): 289 __qualname__ = 5 290 291 # Test repring of the type. 292 stream = StringIO() 293 printer = pretty.RepresentationPrinter(stream) 294 295 printer.pretty(Type) 296 printer.flush() 297 output = stream.getvalue() 298 299 # If __qualname__ is malformed, we should fall back to __name__. 300 expected = '.'.join([__name__, Type.__name__]) 301 nt.assert_equal(output, expected) 302 303 # Clear stream buffer. 304 stream.buf = '' 305 306 # Test repring of an instance of the type. 307 instance = Type() 308 printer.pretty(instance) 309 printer.flush() 310 output = stream.getvalue() 311 312 # Should look like: 313 # <IPython.lib.tests.test_pretty.Type at 0x7f7658ae07d0> 314 prefix = '<' + '.'.join([__name__, Type.__name__]) + ' at 0x' 315 nt.assert_true(output.startswith(prefix)) 316 317 318@py2_only 319def test_fail_gracefully_on_bogus__qualname__and__name__(): 320 # Test that we correctly repr types that have non-string values for both 321 # __qualname__ and __name__ 322 323 class Meta(type): 324 __name__ = 5 325 326 class Type(object): 327 __metaclass__ = Meta 328 __qualname__ = 5 329 330 stream = StringIO() 331 printer = pretty.RepresentationPrinter(stream) 332 333 printer.pretty(Type) 334 printer.flush() 335 output = stream.getvalue() 336 337 # If we can't find __name__ or __qualname__ just use a sentinel string. 338 expected = '.'.join([__name__, '<unknown type>']) 339 nt.assert_equal(output, expected) 340 341 # Clear stream buffer. 342 stream.buf = '' 343 344 # Test repring of an instance of the type. 345 instance = Type() 346 printer.pretty(instance) 347 printer.flush() 348 output = stream.getvalue() 349 350 # Should look like: 351 # <IPython.lib.tests.test_pretty.<unknown type> at 0x7f7658ae07d0> 352 prefix = '<' + '.'.join([__name__, '<unknown type>']) + ' at 0x' 353 nt.assert_true(output.startswith(prefix)) 354 355 356def test_collections_defaultdict(): 357 # Create defaultdicts with cycles 358 a = defaultdict() 359 a.default_factory = a 360 b = defaultdict(list) 361 b['key'] = b 362 363 # Dictionary order cannot be relied on, test against single keys. 364 cases = [ 365 (defaultdict(list), 'defaultdict(list, {})'), 366 (defaultdict(list, {'key': '-' * 50}), 367 "defaultdict(list,\n" 368 " {'key': '--------------------------------------------------'})"), 369 (a, 'defaultdict(defaultdict(...), {})'), 370 (b, "defaultdict(list, {'key': defaultdict(...)})"), 371 ] 372 for obj, expected in cases: 373 nt.assert_equal(pretty.pretty(obj), expected) 374 375 376def test_collections_ordereddict(): 377 # Create OrderedDict with cycle 378 a = OrderedDict() 379 a['key'] = a 380 381 cases = [ 382 (OrderedDict(), 'OrderedDict()'), 383 (OrderedDict((i, i) for i in range(1000, 1010)), 384 'OrderedDict([(1000, 1000),\n' 385 ' (1001, 1001),\n' 386 ' (1002, 1002),\n' 387 ' (1003, 1003),\n' 388 ' (1004, 1004),\n' 389 ' (1005, 1005),\n' 390 ' (1006, 1006),\n' 391 ' (1007, 1007),\n' 392 ' (1008, 1008),\n' 393 ' (1009, 1009)])'), 394 (a, "OrderedDict([('key', OrderedDict(...))])"), 395 ] 396 for obj, expected in cases: 397 nt.assert_equal(pretty.pretty(obj), expected) 398 399 400def test_collections_deque(): 401 # Create deque with cycle 402 a = deque() 403 a.append(a) 404 405 cases = [ 406 (deque(), 'deque([])'), 407 (deque(i for i in range(1000, 1020)), 408 'deque([1000,\n' 409 ' 1001,\n' 410 ' 1002,\n' 411 ' 1003,\n' 412 ' 1004,\n' 413 ' 1005,\n' 414 ' 1006,\n' 415 ' 1007,\n' 416 ' 1008,\n' 417 ' 1009,\n' 418 ' 1010,\n' 419 ' 1011,\n' 420 ' 1012,\n' 421 ' 1013,\n' 422 ' 1014,\n' 423 ' 1015,\n' 424 ' 1016,\n' 425 ' 1017,\n' 426 ' 1018,\n' 427 ' 1019])'), 428 (a, 'deque([deque(...)])'), 429 ] 430 for obj, expected in cases: 431 nt.assert_equal(pretty.pretty(obj), expected) 432 433def test_collections_counter(): 434 class MyCounter(Counter): 435 pass 436 cases = [ 437 (Counter(), 'Counter()'), 438 (Counter(a=1), "Counter({'a': 1})"), 439 (MyCounter(a=1), "MyCounter({'a': 1})"), 440 ] 441 for obj, expected in cases: 442 nt.assert_equal(pretty.pretty(obj), expected) 443 444@py3_only 445def test_mappingproxy(): 446 MP = types.MappingProxyType 447 underlying_dict = {} 448 mp_recursive = MP(underlying_dict) 449 underlying_dict[2] = mp_recursive 450 underlying_dict[3] = underlying_dict 451 452 cases = [ 453 (MP({}), "mappingproxy({})"), 454 (MP({None: MP({})}), "mappingproxy({None: mappingproxy({})})"), 455 (MP({k: k.upper() for k in string.ascii_lowercase}), 456 "mappingproxy({'a': 'A',\n" 457 " 'b': 'B',\n" 458 " 'c': 'C',\n" 459 " 'd': 'D',\n" 460 " 'e': 'E',\n" 461 " 'f': 'F',\n" 462 " 'g': 'G',\n" 463 " 'h': 'H',\n" 464 " 'i': 'I',\n" 465 " 'j': 'J',\n" 466 " 'k': 'K',\n" 467 " 'l': 'L',\n" 468 " 'm': 'M',\n" 469 " 'n': 'N',\n" 470 " 'o': 'O',\n" 471 " 'p': 'P',\n" 472 " 'q': 'Q',\n" 473 " 'r': 'R',\n" 474 " 's': 'S',\n" 475 " 't': 'T',\n" 476 " 'u': 'U',\n" 477 " 'v': 'V',\n" 478 " 'w': 'W',\n" 479 " 'x': 'X',\n" 480 " 'y': 'Y',\n" 481 " 'z': 'Z'})"), 482 (mp_recursive, "mappingproxy({2: {...}, 3: {2: {...}, 3: {...}}})"), 483 (underlying_dict, 484 "{2: mappingproxy({2: {...}, 3: {...}}), 3: {...}}"), 485 ] 486 for obj, expected in cases: 487 nt.assert_equal(pretty.pretty(obj), expected) 488 489@cpython2_only # In PyPy, types.DictProxyType is dict 490def test_dictproxy(): 491 # This is the dictproxy constructor itself from the Python API, 492 DP = ctypes.pythonapi.PyDictProxy_New 493 DP.argtypes, DP.restype = (ctypes.py_object,), ctypes.py_object 494 495 underlying_dict = {} 496 mp_recursive = DP(underlying_dict) 497 underlying_dict[0] = mp_recursive 498 underlying_dict[-3] = underlying_dict 499 500 cases = [ 501 (DP({}), "dict_proxy({})"), 502 (DP({None: DP({})}), "dict_proxy({None: dict_proxy({})})"), 503 (DP({k: k.lower() for k in string.ascii_uppercase}), 504 "dict_proxy({'A': 'a',\n" 505 " 'B': 'b',\n" 506 " 'C': 'c',\n" 507 " 'D': 'd',\n" 508 " 'E': 'e',\n" 509 " 'F': 'f',\n" 510 " 'G': 'g',\n" 511 " 'H': 'h',\n" 512 " 'I': 'i',\n" 513 " 'J': 'j',\n" 514 " 'K': 'k',\n" 515 " 'L': 'l',\n" 516 " 'M': 'm',\n" 517 " 'N': 'n',\n" 518 " 'O': 'o',\n" 519 " 'P': 'p',\n" 520 " 'Q': 'q',\n" 521 " 'R': 'r',\n" 522 " 'S': 's',\n" 523 " 'T': 't',\n" 524 " 'U': 'u',\n" 525 " 'V': 'v',\n" 526 " 'W': 'w',\n" 527 " 'X': 'x',\n" 528 " 'Y': 'y',\n" 529 " 'Z': 'z'})"), 530 (mp_recursive, "dict_proxy({-3: {-3: {...}, 0: {...}}, 0: {...}})"), 531 ] 532 for obj, expected in cases: 533 nt.assert_is_instance(obj, types.DictProxyType) # Meta-test 534 nt.assert_equal(pretty.pretty(obj), expected) 535 nt.assert_equal(pretty.pretty(underlying_dict), 536 "{-3: {...}, 0: dict_proxy({-3: {...}, 0: {...}})}") 537 538class OrderedCounter(Counter, OrderedDict): 539 'Counter that remembers the order elements are first encountered' 540 541 def __repr__(self): 542 return '%s(%r)' % (self.__class__.__name__, OrderedDict(self)) 543 544 def __reduce__(self): 545 return self.__class__, (OrderedDict(self),) 546 547class MySet(set): # Override repr of a basic type 548 def __repr__(self): 549 return 'mine' 550 551def test_custom_repr(): 552 """A custom repr should override a pretty printer for a parent type""" 553 oc = OrderedCounter("abracadabra") 554 nt.assert_in("OrderedCounter(OrderedDict", pretty.pretty(oc)) 555 556 nt.assert_equal(pretty.pretty(MySet()), 'mine') 557