##// END OF EJS Templates
BUG: Fix pprint failure on non-string __qualname__ or __name__....
Scott Sanderson -
Show More
@@ -85,7 +85,7 b' import re'
85 85 import datetime
86 86 from collections import deque
87 87
88 from IPython.utils.py3compat import PY3, cast_unicode
88 from IPython.utils.py3compat import PY3, cast_unicode, string_types
89 89 from IPython.utils.encoding import get_stream_enc
90 90
91 91 from io import StringIO
@@ -671,7 +671,16 b' def _type_pprint(obj, p, cycle):'
671 671 return
672 672
673 673 mod = _safe_getattr(obj, '__module__', None)
674 name = _safe_getattr(obj, '__qualname__', obj.__name__)
674 try:
675 name = obj.__qualname__
676 if not isinstance(name, string_types):
677 # This can happen if the type implements __qualname__ as a property
678 # or other descriptor in Python 2.
679 raise Exception("Try __name__")
680 except Exception:
681 name = obj.__name__
682 if not isinstance(name, string_types):
683 name = '<unknown type>'
675 684
676 685 if mod in (None, '__builtin__', 'builtins', 'exceptions'):
677 686 p.text(name)
@@ -11,7 +11,7 b' from collections import Counter, defaultdict, deque, OrderedDict'
11 11 import nose.tools as nt
12 12
13 13 from IPython.lib import pretty
14 from IPython.testing.decorators import skip_without
14 from IPython.testing.decorators import skip_without, py2_only
15 15 from IPython.utils.py3compat import PY3, unicode_to_str
16 16
17 17 if PY3:
@@ -272,6 +272,83 b' def test_basic_class():'
272 272 nt.assert_true(type_pprint_wrapper.called)
273 273
274 274
275 # This is only run on Python 2 because in Python 3 the language prevents you
276 # from setting a non-unicode value for __qualname__ on a metaclass, and it
277 # doesn't respect the descriptor protocol if you subclass unicode and implement
278 # __get__.
279 @py2_only
280 def test_fallback_to__name__on_type():
281 # Test that we correctly repr types that have non-string values for
282 # __qualname__ by falling back to __name__
283
284 class Type(object):
285 __qualname__ = 5
286
287 # Test repring of the type.
288 stream = StringIO()
289 printer = pretty.RepresentationPrinter(stream)
290
291 printer.pretty(Type)
292 printer.flush()
293 output = stream.getvalue()
294
295 # If __qualname__ is malformed, we should fall back to __name__.
296 expected = '.'.join([__name__, Type.__name__])
297 nt.assert_equal(output, expected)
298
299 # Clear stream buffer.
300 stream.buf = ''
301
302 # Test repring of an instance of the type.
303 instance = Type()
304 printer.pretty(instance)
305 printer.flush()
306 output = stream.getvalue()
307
308 # Should look like:
309 # <IPython.lib.tests.test_pretty.Type at 0x7f7658ae07d0>
310 prefix = '<' + '.'.join([__name__, Type.__name__]) + ' at 0x'
311 nt.assert_true(output.startswith(prefix))
312
313
314 @py2_only
315 def test_fail_gracefully_on_bogus__qualname__and__name__():
316 # Test that we correctly repr types that have non-string values for both
317 # __qualname__ and __name__
318
319 class Meta(type):
320 __name__ = 5
321
322 class Type(object):
323 __metaclass__ = Meta
324 __qualname__ = 5
325
326 stream = StringIO()
327 printer = pretty.RepresentationPrinter(stream)
328
329 printer.pretty(Type)
330 printer.flush()
331 output = stream.getvalue()
332
333 # If we can't find __name__ or __qualname__ just use a sentinel string.
334 expected = '.'.join([__name__, '<unknown type>'])
335 nt.assert_equal(output, expected)
336
337 # Clear stream buffer.
338 stream.buf = ''
339
340 # Test repring of an instance of the type.
341 instance = Type()
342 printer.pretty(instance)
343 printer.flush()
344 output = stream.getvalue()
345
346 # Should look like:
347 # <IPython.lib.tests.test_pretty.<unknown type> at 0x7f7658ae07d0>
348 prefix = '<' + '.'.join([__name__, '<unknown type>']) + ' at 0x'
349 nt.assert_true(output.startswith(prefix))
350
351
275 352 def test_collections_defaultdict():
276 353 # Create defaultdicts with cycles
277 354 a = defaultdict()
@@ -48,7 +48,7 b' from .ipunittest import ipdoctest, ipdocstring'
48 48 from IPython.external.decorators import *
49 49
50 50 # For onlyif_cmd_exists decorator
51 from IPython.utils.py3compat import string_types, which
51 from IPython.utils.py3compat import string_types, which, PY2, PY3
52 52
53 53 #-----------------------------------------------------------------------------
54 54 # Classes and functions
@@ -336,6 +336,9 b" skip_known_failure = knownfailureif(True,'This test is known to fail')"
336 336 known_failure_py3 = knownfailureif(sys.version_info[0] >= 3,
337 337 'This test is known to fail on Python 3.')
338 338
339 py2_only = skipif(PY3, "This test only runs on Python 2.")
340 py3_only = skipif(PY2, "This test only runs on Python 3.")
341
339 342 # A null 'decorator', useful to make more readable code that needs to pick
340 343 # between different decorators based on OS or other conditions
341 344 null_deco = lambda f: f
@@ -289,6 +289,9 b' else:'
289 289 exec(compiler(scripttext, filename, 'exec'), glob, loc)
290 290
291 291
292 PY2 = not PY3
293
294
292 295 def annotate(**kwargs):
293 296 """Python 3 compatible function annotation for Python 2."""
294 297 if not kwargs:
General Comments 0
You need to be logged in to leave comments. Login now