From 2b56604f3164d80ac066ea982276438c0601dfeb 2014-04-26 09:32:28 From: Joel Nothman Date: 2014-04-26 09:32:28 Subject: [PATCH] Make dict key completion more conservative Only handle subtypes of dict, struct arrays and DataFrames --- diff --git a/IPython/core/completer.py b/IPython/core/completer.py index 4337dfb..07d1119 100644 --- a/IPython/core/completer.py +++ b/IPython/core/completer.py @@ -97,6 +97,21 @@ if sys.platform == 'win32': else: PROTECTABLES = ' ()[]{}?=\\|;:\'#*"^&' + +# For dict key completion +try: + import numpy +except ImportError: + STRUCT_ARRAY_TYPES = () +else: + STRUCT_ARRAY_TYPES = (numpy.ndarray,) + try: + import pandas + except ImportError: + KEYED_DICT_TYPES = (dict,) + else: + KEYED_DICT_TYPES = (dict, pandas.DataFrame) + #----------------------------------------------------------------------------- # Main functions and classes #----------------------------------------------------------------------------- @@ -856,14 +871,15 @@ class IPCompleter(Completer): def dict_key_matches(self, text): def get_keys(obj): - if not callable(getattr(obj, '__getitem__', None)): - return [] - if hasattr(obj, 'keys'): + # Only allow completion for known in-memory dict-like types + if isinstance(obj, KEYED_DICT_TYPES): try: return list(obj.keys()) except Exception: return [] - return getattr(getattr(obj, 'dtype', None), 'names', []) + elif isinstance(obj, STRUCT_ARRAY_TYPES): + return obj.dtype.names or [] + return [] try: regexps = self.__dict_key_regexps diff --git a/IPython/core/tests/test_completer.py b/IPython/core/tests/test_completer.py index 22acfd8..354a26e 100644 --- a/IPython/core/tests/test_completer.py +++ b/IPython/core/tests/test_completer.py @@ -584,21 +584,6 @@ def test_dict_key_completion_unicode_py3(): nt.assert_in(unicode_type(b"a\xd7\x90']", 'utf8'), matches) -def test_dict_like_key_completion(): - """Test dict key completion applies where __getitem__ and keys exist""" - class D(object): - def __getitem__(self): - pass - def keys(self): - return iter(['hello', 'world']) - ip = get_ipython() - complete = ip.Completer.complete - ip.user_ns['d'] = D() - _, matches = complete(line_buffer="d['") - nt.assert_in("hello']", matches) - nt.assert_in("world']", matches) - - @dec.skip_without('numpy') def test_struct_array_key_completion(): """Test dict key completion applies to numpy struct arrays"""