##// 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 import datetime
85 import datetime
86 from collections import deque
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 from IPython.utils.encoding import get_stream_enc
89 from IPython.utils.encoding import get_stream_enc
90
90
91 from io import StringIO
91 from io import StringIO
@@ -671,7 +671,16 b' def _type_pprint(obj, p, cycle):'
671 return
671 return
672
672
673 mod = _safe_getattr(obj, '__module__', None)
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 if mod in (None, '__builtin__', 'builtins', 'exceptions'):
685 if mod in (None, '__builtin__', 'builtins', 'exceptions'):
677 p.text(name)
686 p.text(name)
@@ -11,7 +11,7 b' from collections import Counter, defaultdict, deque, OrderedDict'
11 import nose.tools as nt
11 import nose.tools as nt
12
12
13 from IPython.lib import pretty
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 from IPython.utils.py3compat import PY3, unicode_to_str
15 from IPython.utils.py3compat import PY3, unicode_to_str
16
16
17 if PY3:
17 if PY3:
@@ -272,6 +272,83 b' def test_basic_class():'
272 nt.assert_true(type_pprint_wrapper.called)
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 def test_collections_defaultdict():
352 def test_collections_defaultdict():
276 # Create defaultdicts with cycles
353 # Create defaultdicts with cycles
277 a = defaultdict()
354 a = defaultdict()
@@ -48,7 +48,7 b' from .ipunittest import ipdoctest, ipdocstring'
48 from IPython.external.decorators import *
48 from IPython.external.decorators import *
49
49
50 # For onlyif_cmd_exists decorator
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 # Classes and functions
54 # Classes and functions
@@ -336,6 +336,9 b" skip_known_failure = knownfailureif(True,'This test is known to fail')"
336 known_failure_py3 = knownfailureif(sys.version_info[0] >= 3,
336 known_failure_py3 = knownfailureif(sys.version_info[0] >= 3,
337 'This test is known to fail on Python 3.')
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 # A null 'decorator', useful to make more readable code that needs to pick
342 # A null 'decorator', useful to make more readable code that needs to pick
340 # between different decorators based on OS or other conditions
343 # between different decorators based on OS or other conditions
341 null_deco = lambda f: f
344 null_deco = lambda f: f
@@ -289,6 +289,9 b' else:'
289 exec(compiler(scripttext, filename, 'exec'), glob, loc)
289 exec(compiler(scripttext, filename, 'exec'), glob, loc)
290
290
291
291
292 PY2 = not PY3
293
294
292 def annotate(**kwargs):
295 def annotate(**kwargs):
293 """Python 3 compatible function annotation for Python 2."""
296 """Python 3 compatible function annotation for Python 2."""
294 if not kwargs:
297 if not kwargs:
General Comments 0
You need to be logged in to leave comments. Login now