Show More
@@ -71,7 +71,7 b' from IPython.core.latex_symbols import latex_symbols, reverse_latex_symbol' | |||
|
71 | 71 | from IPython.utils import generics |
|
72 | 72 | from IPython.utils import io |
|
73 | 73 | from IPython.utils.decorators import undoc |
|
74 |
from IPython.utils.dir2 import dir2, |
|
|
74 | from IPython.utils.dir2 import dir2, get_real_method | |
|
75 | 75 | from IPython.utils.process import arg_split |
|
76 | 76 | from IPython.utils.py3compat import builtin_mod, string_types, PY3 |
|
77 | 77 | from traitlets import CBool, Enum |
@@ -472,19 +472,6 b' def _safe_isinstance(obj, module, class_name):' | |||
|
472 | 472 | return (module in sys.modules and |
|
473 | 473 | isinstance(obj, getattr(__import__(module), class_name))) |
|
474 | 474 | |
|
475 | def _safe_really_hasattr(obj, name): | |
|
476 | """Checks that an object genuinely has a given attribute. | |
|
477 | ||
|
478 | Some objects claim to have any attribute that's requested, to act as a lazy | |
|
479 | proxy for something else. We want to catch these cases and ignore their | |
|
480 | claim to have the attribute we're interested in. | |
|
481 | """ | |
|
482 | if safe_hasattr(obj, '_ipy_proxy_check_dont_define_this_'): | |
|
483 | # If it claims this exists, don't trust it | |
|
484 | return False | |
|
485 | ||
|
486 | return safe_hasattr(obj, name) | |
|
487 | ||
|
488 | 475 | |
|
489 | 476 | def back_unicode_name_matches(text): |
|
490 | 477 | u"""Match unicode characters back to unicode name |
@@ -937,8 +924,9 b' class IPCompleter(Completer):' | |||
|
937 | 924 | def get_keys(obj): |
|
938 | 925 | # Objects can define their own completions by defining an |
|
939 | 926 | # _ipy_key_completions_() method. |
|
940 |
|
|
|
941 | return obj._ipython_key_completions_() | |
|
927 | method = get_real_method(obj, '_ipython_key_completions_') | |
|
928 | if method is not None: | |
|
929 | return method() | |
|
942 | 930 | |
|
943 | 931 | # Special case some common in-memory dict-like types |
|
944 | 932 | if isinstance(obj, dict) or\ |
@@ -13,7 +13,6 b' import sys' | |||
|
13 | 13 | import io as _io |
|
14 | 14 | import tokenize |
|
15 | 15 | |
|
16 | from IPython.core.formatters import _safe_get_formatter_method | |
|
17 | 16 | from traitlets.config.configurable import Configurable |
|
18 | 17 | from IPython.utils import io |
|
19 | 18 | from IPython.utils.py3compat import builtin_mod, cast_unicode_py2 |
@@ -22,6 +22,7 b' from decorator import decorator' | |||
|
22 | 22 | from traitlets.config.configurable import Configurable |
|
23 | 23 | from IPython.core.getipython import get_ipython |
|
24 | 24 | from IPython.utils.sentinel import Sentinel |
|
25 | from IPython.utils.dir2 import get_real_method | |
|
25 | 26 | from IPython.lib import pretty |
|
26 | 27 | from traitlets import ( |
|
27 | 28 | Bool, Dict, Integer, Unicode, CUnicode, ObjectName, List, |
@@ -32,29 +33,6 b' from IPython.utils.py3compat import (' | |||
|
32 | 33 | ) |
|
33 | 34 | |
|
34 | 35 | |
|
35 | #----------------------------------------------------------------------------- | |
|
36 | # The main DisplayFormatter class | |
|
37 | #----------------------------------------------------------------------------- | |
|
38 | ||
|
39 | ||
|
40 | def _safe_get_formatter_method(obj, name): | |
|
41 | """Safely get a formatter method | |
|
42 | ||
|
43 | - Classes cannot have formatter methods, only instance | |
|
44 | - protect against proxy objects that claim to have everything | |
|
45 | """ | |
|
46 | if inspect.isclass(obj): | |
|
47 | # repr methods only make sense on instances, not classes | |
|
48 | return None | |
|
49 | method = pretty._safe_getattr(obj, name, None) | |
|
50 | if callable(method): | |
|
51 | # obj claims to have repr method... | |
|
52 | if callable(pretty._safe_getattr(obj, '_ipython_canary_method_should_not_exist_', None)): | |
|
53 | # ...but don't trust proxy objects that claim to have everything | |
|
54 | return None | |
|
55 | return method | |
|
56 | ||
|
57 | ||
|
58 | 36 | class DisplayFormatter(Configurable): |
|
59 | 37 | |
|
60 | 38 | # When set to true only the default plain text formatter will be used. |
@@ -338,7 +316,7 b' class BaseFormatter(Configurable):' | |||
|
338 | 316 | else: |
|
339 | 317 | return printer(obj) |
|
340 | 318 | # Finally look for special method names |
|
341 |
method = |
|
|
319 | method = get_real_method(obj, self.print_method) | |
|
342 | 320 | if method is not None: |
|
343 | 321 | return method() |
|
344 | 322 | return None |
@@ -904,7 +882,7 b' class IPythonDisplayFormatter(BaseFormatter):' | |||
|
904 | 882 | printer(obj) |
|
905 | 883 | return True |
|
906 | 884 | # Finally look for special method names |
|
907 |
method = |
|
|
885 | method = get_real_method(obj, self.print_method) | |
|
908 | 886 | if method is not None: |
|
909 | 887 | method() |
|
910 | 888 | return True |
@@ -2,21 +2,11 b'' | |||
|
2 | 2 | """A fancy version of Python's builtin :func:`dir` function. |
|
3 | 3 | """ |
|
4 | 4 | |
|
5 | #----------------------------------------------------------------------------- | |
|
6 | # Copyright (C) 2008-2011 The IPython Development Team | |
|
7 | # | |
|
8 | # Distributed under the terms of the BSD License. The full license is in | |
|
9 | # the file COPYING, distributed as part of this software. | |
|
10 | #----------------------------------------------------------------------------- | |
|
11 | ||
|
12 | #----------------------------------------------------------------------------- | |
|
13 | # Imports | |
|
14 | #----------------------------------------------------------------------------- | |
|
15 | from .py3compat import string_types | |
|
5 | # Copyright (c) IPython Development Team. | |
|
6 | # Distributed under the terms of the Modified BSD License. | |
|
16 | 7 | |
|
17 | #----------------------------------------------------------------------------- | |
|
18 | # Code | |
|
19 | #----------------------------------------------------------------------------- | |
|
8 | import inspect | |
|
9 | from .py3compat import string_types | |
|
20 | 10 | |
|
21 | 11 | |
|
22 | 12 | def safe_hasattr(obj, attr): |
@@ -56,3 +46,36 b' def dir2(obj):' | |||
|
56 | 46 | |
|
57 | 47 | words = [w for w in words if isinstance(w, string_types)] |
|
58 | 48 | return sorted(words) |
|
49 | ||
|
50 | ||
|
51 | def get_real_method(obj, name): | |
|
52 | """Like getattr, but with a few extra sanity checks: | |
|
53 | ||
|
54 | - If obj is a class, ignore its methods | |
|
55 | - Check if obj is a proxy that claims to have all attributes | |
|
56 | - Catch attribute access failing with any exception | |
|
57 | - Check that the attribute is a callable object | |
|
58 | ||
|
59 | Returns the method or None. | |
|
60 | """ | |
|
61 | if inspect.isclass(obj): | |
|
62 | return None | |
|
63 | ||
|
64 | try: | |
|
65 | canary = getattr(obj, '_ipython_canary_method_should_not_exist_', None) | |
|
66 | except Exception: | |
|
67 | return None | |
|
68 | ||
|
69 | if canary is not None: | |
|
70 | # It claimed to have an attribute it should never have | |
|
71 | return None | |
|
72 | ||
|
73 | try: | |
|
74 | m = getattr(obj, name, None) | |
|
75 | except Exception: | |
|
76 | return None | |
|
77 | ||
|
78 | if callable(m): | |
|
79 | return m | |
|
80 | ||
|
81 | return None |
General Comments 0
You need to be logged in to leave comments.
Login now