@@ -58,34 +58,34 @@ def attr_complete(text, namespace=None, config=None):
5858 else :
5959 autocomplete_mode = SUBSTRING
6060
61- dictpattern = re .compile ('[^\[\]]+\[$' )
62- def complete_dict (text ):
63- lastbracket_index = text .rindex ('[' )
64- dexpr = text [:lastbracket_index ].lstrip ()
65- obj = eval (dexpr , namespace )
66- if obj and isinstance (obj , type ({})) and obj .keys ():
67- return [dexpr + "[{!r}]" .format (k ) for k in obj .keys ()]
68- else :
69- # empty dictionary
70- return []
71-
7261 if "." in text :
73- if dictpattern .match (text ):
74- return complete_dict (text )
75- else :
76- # Examples: 'foo.b' or 'foo[bar.'
77- for i in range (1 , len (text ) + 1 ):
78- if text [- i ] == '[' :
79- i -= 1
80- break
81- methodtext = text [- i :]
82- return ['' .join ([text [:- i ], m ]) for m in
83- attr_matches (methodtext , namespace , autocomplete_mode )]
84- elif dictpattern .match (text ):
85- return complete_dict (text )
62+ # Examples: 'foo.b' or 'foo[bar.'
63+ for i in range (1 , len (text ) + 1 ):
64+ if text [- i ] == '[' :
65+ i -= 1
66+ break
67+ methodtext = text [- i :]
68+ return ['' .join ([text [:- i ], m ]) for m in
69+ attr_matches (methodtext , namespace , autocomplete_mode )]
8670 else :
8771 return global_matches (text , namespace , autocomplete_mode )
8872
73+ class SafeEvalFailed (Exception ):
74+ """If this object is returned, safe_eval failed"""
75+ # Because every normal Python value is a possible return value of safe_eval
76+
77+ def safe_eval (expr , namespace ):
78+ """Not all that safe, just catches some errors"""
79+ if expr .isdigit ():
80+ # Special case: float literal, using attrs here will result in
81+ # a SyntaxError
82+ return SafeEvalFailed
83+ try :
84+ obj = eval (expr , namespace )
85+ return obj
86+ except (NameError ,):
87+ return SafeEvalFailed
88+
8989def attr_matches (text , namespace , autocomplete_mode ):
9090 """Taken from rlcompleter.py and bent to my will.
9191 """
@@ -98,11 +98,9 @@ def attr_matches(text, namespace, autocomplete_mode):
9898 return []
9999
100100 expr , attr = m .group (1 , 3 )
101- if expr .isdigit ():
102- # Special case: float literal, using attrs here will result in
103- # a SyntaxError
101+ obj = safe_eval (expr , namespace )
102+ if obj is SafeEvalFailed :
104103 return []
105- obj = eval (expr , namespace )
106104 with inspection .AttrCleaner (obj ):
107105 matches = attr_lookup (obj , expr , attr , autocomplete_mode )
108106 return matches
@@ -211,7 +209,7 @@ def get_completer(cursor_offset, current_line, locals_, argspec, config, magic_m
211209 return sorted (set (matches )), FilenameCompletion
212210
213211 matches = DictKeyCompletion .matches (cursor_offset , current_line , locals_ = locals_ , config = config )
214- if matches is not None :
212+ if matches :
215213 return sorted (set (matches )), DictKeyCompletion
216214
217215 matches = AttrCompletion .matches (cursor_offset , current_line , locals_ = locals_ , config = config )
@@ -289,15 +287,7 @@ def matches(cls, cursor_offset, line, locals_, config):
289287 if r is None :
290288 return None
291289 cw = r [2 ]
292- try :
293- return attr_complete (cw , namespace = locals_ , config = config )
294- except Exception :
295- # This sucks, but it's either that or list all the exceptions that could
296- # possibly be raised here, so if anyone wants to do that, feel free to send me
297- # a patch. XXX: Make sure you raise here if you're debugging the completion
298- # stuff !
299- pass
300- return None
290+ return attr_complete (cw , namespace = locals_ , config = config )
301291 locate = staticmethod (lineparts .current_word )
302292 format = staticmethod (after_last_dot )
303293
@@ -310,7 +300,9 @@ def matches(cls, cursor_offset, line, locals_, config):
310300 return None
311301 start , end , orig = r
312302 _ , _ , dexpr = lineparts .current_dict (cursor_offset , line )
313- obj = eval (dexpr , locals_ )
303+ obj = safe_eval (dexpr , locals_ )
304+ if obj is SafeEvalFailed :
305+ return []
314306 if obj and isinstance (obj , type ({})) and obj .keys ():
315307 return ["{!r}]" .format (k ) for k in obj .keys () if repr (k ).startswith (orig )]
316308 else :
0 commit comments