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