123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536 |
- # coding: utf-8
- """Tests for IPython.lib.pretty."""
- # Copyright (c) IPython Development Team.
- # Distributed under the terms of the Modified BSD License.
- from __future__ import print_function
- from collections import Counter, defaultdict, deque, OrderedDict
- import types, string, ctypes
- import nose.tools as nt
- from IPython.lib import pretty
- from IPython.testing.decorators import (skip_without, py2_only, py3_only,
- cpython2_only)
- from IPython.utils.py3compat import PY3, unicode_to_str
- if PY3:
- from io import StringIO
- else:
- from StringIO import StringIO
- class MyList(object):
- def __init__(self, content):
- self.content = content
- def _repr_pretty_(self, p, cycle):
- if cycle:
- p.text("MyList(...)")
- else:
- with p.group(3, "MyList(", ")"):
- for (i, child) in enumerate(self.content):
- if i:
- p.text(",")
- p.breakable()
- else:
- p.breakable("")
- p.pretty(child)
- class MyDict(dict):
- def _repr_pretty_(self, p, cycle):
- p.text("MyDict(...)")
- class MyObj(object):
- def somemethod(self):
- pass
- class Dummy1(object):
- def _repr_pretty_(self, p, cycle):
- p.text("Dummy1(...)")
- class Dummy2(Dummy1):
- _repr_pretty_ = None
- class NoModule(object):
- pass
- NoModule.__module__ = None
- class Breaking(object):
- def _repr_pretty_(self, p, cycle):
- with p.group(4,"TG: ",":"):
- p.text("Breaking(")
- p.break_()
- p.text(")")
- class BreakingRepr(object):
- def __repr__(self):
- return "Breaking(\n)"
- class BreakingReprParent(object):
- def _repr_pretty_(self, p, cycle):
- with p.group(4,"TG: ",":"):
- p.pretty(BreakingRepr())
- class BadRepr(object):
-
- def __repr__(self):
- return 1/0
- def test_indentation():
- """Test correct indentation in groups"""
- count = 40
- gotoutput = pretty.pretty(MyList(range(count)))
- expectedoutput = "MyList(\n" + ",\n".join(" %d" % i for i in range(count)) + ")"
- nt.assert_equal(gotoutput, expectedoutput)
- def test_dispatch():
- """
- Test correct dispatching: The _repr_pretty_ method for MyDict
- must be found before the registered printer for dict.
- """
- gotoutput = pretty.pretty(MyDict())
- expectedoutput = "MyDict(...)"
- nt.assert_equal(gotoutput, expectedoutput)
- def test_callability_checking():
- """
- Test that the _repr_pretty_ method is tested for callability and skipped if
- not.
- """
- gotoutput = pretty.pretty(Dummy2())
- expectedoutput = "Dummy1(...)"
- nt.assert_equal(gotoutput, expectedoutput)
- def test_sets():
- """
- Test that set and frozenset use Python 3 formatting.
- """
- objects = [set(), frozenset(), set([1]), frozenset([1]), set([1, 2]),
- frozenset([1, 2]), set([-1, -2, -3])]
- expected = ['set()', 'frozenset()', '{1}', 'frozenset({1})', '{1, 2}',
- 'frozenset({1, 2})', '{-3, -2, -1}']
- for obj, expected_output in zip(objects, expected):
- got_output = pretty.pretty(obj)
- yield nt.assert_equal, got_output, expected_output
- @skip_without('xxlimited')
- def test_pprint_heap_allocated_type():
- """
- Test that pprint works for heap allocated types.
- """
- import xxlimited
- output = pretty.pretty(xxlimited.Null)
- nt.assert_equal(output, 'xxlimited.Null')
- def test_pprint_nomod():
- """
- Test that pprint works for classes with no __module__.
- """
- output = pretty.pretty(NoModule)
- nt.assert_equal(output, 'NoModule')
-
- def test_pprint_break():
- """
- Test that p.break_ produces expected output
- """
- output = pretty.pretty(Breaking())
- expected = "TG: Breaking(\n ):"
- nt.assert_equal(output, expected)
- def test_pprint_break_repr():
- """
- Test that p.break_ is used in repr
- """
- output = pretty.pretty(BreakingReprParent())
- expected = "TG: Breaking(\n ):"
- nt.assert_equal(output, expected)
- def test_bad_repr():
- """Don't catch bad repr errors"""
- with nt.assert_raises(ZeroDivisionError):
- output = pretty.pretty(BadRepr())
- class BadException(Exception):
- def __str__(self):
- return -1
- class ReallyBadRepr(object):
- __module__ = 1
- @property
- def __class__(self):
- raise ValueError("I am horrible")
-
- def __repr__(self):
- raise BadException()
- def test_really_bad_repr():
- with nt.assert_raises(BadException):
- output = pretty.pretty(ReallyBadRepr())
- class SA(object):
- pass
- class SB(SA):
- pass
- def test_super_repr():
- # "<super: module_name.SA, None>"
- output = pretty.pretty(super(SA))
- nt.assert_regexp_matches(output, r"<super: \S+.SA, None>")
- # "<super: module_name.SA, <module_name.SB at 0x...>>"
- sb = SB()
- output = pretty.pretty(super(SA, sb))
- nt.assert_regexp_matches(output, r"<super: \S+.SA,\s+<\S+.SB at 0x\S+>>")
- def test_long_list():
- lis = list(range(10000))
- p = pretty.pretty(lis)
- last2 = p.rsplit('\n', 2)[-2:]
- nt.assert_equal(last2, [' 999,', ' ...]'])
- def test_long_set():
- s = set(range(10000))
- p = pretty.pretty(s)
- last2 = p.rsplit('\n', 2)[-2:]
- nt.assert_equal(last2, [' 999,', ' ...}'])
- def test_long_tuple():
- tup = tuple(range(10000))
- p = pretty.pretty(tup)
- last2 = p.rsplit('\n', 2)[-2:]
- nt.assert_equal(last2, [' 999,', ' ...)'])
- def test_long_dict():
- d = { n:n for n in range(10000) }
- p = pretty.pretty(d)
- last2 = p.rsplit('\n', 2)[-2:]
- nt.assert_equal(last2, [' 999: 999,', ' ...}'])
- def test_unbound_method():
- output = pretty.pretty(MyObj.somemethod)
- nt.assert_in('MyObj.somemethod', output)
- class MetaClass(type):
- def __new__(cls, name):
- return type.__new__(cls, name, (object,), {'name': name})
- def __repr__(self):
- return "[CUSTOM REPR FOR CLASS %s]" % self.name
- ClassWithMeta = MetaClass('ClassWithMeta')
- def test_metaclass_repr():
- output = pretty.pretty(ClassWithMeta)
- nt.assert_equal(output, "[CUSTOM REPR FOR CLASS ClassWithMeta]")
- def test_unicode_repr():
- u = u"üniçodé"
- ustr = unicode_to_str(u)
-
- class C(object):
- def __repr__(self):
- return ustr
-
- c = C()
- p = pretty.pretty(c)
- nt.assert_equal(p, u)
- p = pretty.pretty([c])
- nt.assert_equal(p, u'[%s]' % u)
- def test_basic_class():
- def type_pprint_wrapper(obj, p, cycle):
- if obj is MyObj:
- type_pprint_wrapper.called = True
- return pretty._type_pprint(obj, p, cycle)
- type_pprint_wrapper.called = False
- stream = StringIO()
- printer = pretty.RepresentationPrinter(stream)
- printer.type_pprinters[type] = type_pprint_wrapper
- printer.pretty(MyObj)
- printer.flush()
- output = stream.getvalue()
- nt.assert_equal(output, '%s.MyObj' % __name__)
- nt.assert_true(type_pprint_wrapper.called)
- # This is only run on Python 2 because in Python 3 the language prevents you
- # from setting a non-unicode value for __qualname__ on a metaclass, and it
- # doesn't respect the descriptor protocol if you subclass unicode and implement
- # __get__.
- @py2_only
- def test_fallback_to__name__on_type():
- # Test that we correctly repr types that have non-string values for
- # __qualname__ by falling back to __name__
- class Type(object):
- __qualname__ = 5
- # Test repring of the type.
- stream = StringIO()
- printer = pretty.RepresentationPrinter(stream)
- printer.pretty(Type)
- printer.flush()
- output = stream.getvalue()
- # If __qualname__ is malformed, we should fall back to __name__.
- expected = '.'.join([__name__, Type.__name__])
- nt.assert_equal(output, expected)
- # Clear stream buffer.
- stream.buf = ''
- # Test repring of an instance of the type.
- instance = Type()
- printer.pretty(instance)
- printer.flush()
- output = stream.getvalue()
- # Should look like:
- # <IPython.lib.tests.test_pretty.Type at 0x7f7658ae07d0>
- prefix = '<' + '.'.join([__name__, Type.__name__]) + ' at 0x'
- nt.assert_true(output.startswith(prefix))
- @py2_only
- def test_fail_gracefully_on_bogus__qualname__and__name__():
- # Test that we correctly repr types that have non-string values for both
- # __qualname__ and __name__
- class Meta(type):
- __name__ = 5
- class Type(object):
- __metaclass__ = Meta
- __qualname__ = 5
- stream = StringIO()
- printer = pretty.RepresentationPrinter(stream)
- printer.pretty(Type)
- printer.flush()
- output = stream.getvalue()
- # If we can't find __name__ or __qualname__ just use a sentinel string.
- expected = '.'.join([__name__, '<unknown type>'])
- nt.assert_equal(output, expected)
- # Clear stream buffer.
- stream.buf = ''
- # Test repring of an instance of the type.
- instance = Type()
- printer.pretty(instance)
- printer.flush()
- output = stream.getvalue()
- # Should look like:
- # <IPython.lib.tests.test_pretty.<unknown type> at 0x7f7658ae07d0>
- prefix = '<' + '.'.join([__name__, '<unknown type>']) + ' at 0x'
- nt.assert_true(output.startswith(prefix))
- def test_collections_defaultdict():
- # Create defaultdicts with cycles
- a = defaultdict()
- a.default_factory = a
- b = defaultdict(list)
- b['key'] = b
- # Dictionary order cannot be relied on, test against single keys.
- cases = [
- (defaultdict(list), 'defaultdict(list, {})'),
- (defaultdict(list, {'key': '-' * 50}),
- "defaultdict(list,\n"
- " {'key': '--------------------------------------------------'})"),
- (a, 'defaultdict(defaultdict(...), {})'),
- (b, "defaultdict(list, {'key': defaultdict(...)})"),
- ]
- for obj, expected in cases:
- nt.assert_equal(pretty.pretty(obj), expected)
- def test_collections_ordereddict():
- # Create OrderedDict with cycle
- a = OrderedDict()
- a['key'] = a
- cases = [
- (OrderedDict(), 'OrderedDict()'),
- (OrderedDict((i, i) for i in range(1000, 1010)),
- 'OrderedDict([(1000, 1000),\n'
- ' (1001, 1001),\n'
- ' (1002, 1002),\n'
- ' (1003, 1003),\n'
- ' (1004, 1004),\n'
- ' (1005, 1005),\n'
- ' (1006, 1006),\n'
- ' (1007, 1007),\n'
- ' (1008, 1008),\n'
- ' (1009, 1009)])'),
- (a, "OrderedDict([('key', OrderedDict(...))])"),
- ]
- for obj, expected in cases:
- nt.assert_equal(pretty.pretty(obj), expected)
- def test_collections_deque():
- # Create deque with cycle
- a = deque()
- a.append(a)
- cases = [
- (deque(), 'deque([])'),
- (deque(i for i in range(1000, 1020)),
- 'deque([1000,\n'
- ' 1001,\n'
- ' 1002,\n'
- ' 1003,\n'
- ' 1004,\n'
- ' 1005,\n'
- ' 1006,\n'
- ' 1007,\n'
- ' 1008,\n'
- ' 1009,\n'
- ' 1010,\n'
- ' 1011,\n'
- ' 1012,\n'
- ' 1013,\n'
- ' 1014,\n'
- ' 1015,\n'
- ' 1016,\n'
- ' 1017,\n'
- ' 1018,\n'
- ' 1019])'),
- (a, 'deque([deque(...)])'),
- ]
- for obj, expected in cases:
- nt.assert_equal(pretty.pretty(obj), expected)
- def test_collections_counter():
- class MyCounter(Counter):
- pass
- cases = [
- (Counter(), 'Counter()'),
- (Counter(a=1), "Counter({'a': 1})"),
- (MyCounter(a=1), "MyCounter({'a': 1})"),
- ]
- for obj, expected in cases:
- nt.assert_equal(pretty.pretty(obj), expected)
- @py3_only
- def test_mappingproxy():
- MP = types.MappingProxyType
- underlying_dict = {}
- mp_recursive = MP(underlying_dict)
- underlying_dict[2] = mp_recursive
- underlying_dict[3] = underlying_dict
- cases = [
- (MP({}), "mappingproxy({})"),
- (MP({None: MP({})}), "mappingproxy({None: mappingproxy({})})"),
- (MP({k: k.upper() for k in string.ascii_lowercase}),
- "mappingproxy({'a': 'A',\n"
- " 'b': 'B',\n"
- " 'c': 'C',\n"
- " 'd': 'D',\n"
- " 'e': 'E',\n"
- " 'f': 'F',\n"
- " 'g': 'G',\n"
- " 'h': 'H',\n"
- " 'i': 'I',\n"
- " 'j': 'J',\n"
- " 'k': 'K',\n"
- " 'l': 'L',\n"
- " 'm': 'M',\n"
- " 'n': 'N',\n"
- " 'o': 'O',\n"
- " 'p': 'P',\n"
- " 'q': 'Q',\n"
- " 'r': 'R',\n"
- " 's': 'S',\n"
- " 't': 'T',\n"
- " 'u': 'U',\n"
- " 'v': 'V',\n"
- " 'w': 'W',\n"
- " 'x': 'X',\n"
- " 'y': 'Y',\n"
- " 'z': 'Z'})"),
- (mp_recursive, "mappingproxy({2: {...}, 3: {2: {...}, 3: {...}}})"),
- (underlying_dict,
- "{2: mappingproxy({2: {...}, 3: {...}}), 3: {...}}"),
- ]
- for obj, expected in cases:
- nt.assert_equal(pretty.pretty(obj), expected)
- @cpython2_only # In PyPy, types.DictProxyType is dict
- def test_dictproxy():
- # This is the dictproxy constructor itself from the Python API,
- DP = ctypes.pythonapi.PyDictProxy_New
- DP.argtypes, DP.restype = (ctypes.py_object,), ctypes.py_object
- underlying_dict = {}
- mp_recursive = DP(underlying_dict)
- underlying_dict[0] = mp_recursive
- underlying_dict[-3] = underlying_dict
- cases = [
- (DP({}), "dict_proxy({})"),
- (DP({None: DP({})}), "dict_proxy({None: dict_proxy({})})"),
- (DP({k: k.lower() for k in string.ascii_uppercase}),
- "dict_proxy({'A': 'a',\n"
- " 'B': 'b',\n"
- " 'C': 'c',\n"
- " 'D': 'd',\n"
- " 'E': 'e',\n"
- " 'F': 'f',\n"
- " 'G': 'g',\n"
- " 'H': 'h',\n"
- " 'I': 'i',\n"
- " 'J': 'j',\n"
- " 'K': 'k',\n"
- " 'L': 'l',\n"
- " 'M': 'm',\n"
- " 'N': 'n',\n"
- " 'O': 'o',\n"
- " 'P': 'p',\n"
- " 'Q': 'q',\n"
- " 'R': 'r',\n"
- " 'S': 's',\n"
- " 'T': 't',\n"
- " 'U': 'u',\n"
- " 'V': 'v',\n"
- " 'W': 'w',\n"
- " 'X': 'x',\n"
- " 'Y': 'y',\n"
- " 'Z': 'z'})"),
- (mp_recursive, "dict_proxy({-3: {-3: {...}, 0: {...}}, 0: {...}})"),
- ]
- for obj, expected in cases:
- nt.assert_is_instance(obj, types.DictProxyType) # Meta-test
- nt.assert_equal(pretty.pretty(obj), expected)
- nt.assert_equal(pretty.pretty(underlying_dict),
- "{-3: {...}, 0: dict_proxy({-3: {...}, 0: {...}})}")
|