diff --git a/_compatibility.py b/_compatibility.py index 91b8f424..0ce7ee8a 100644 --- a/_compatibility.py +++ b/_compatibility.py @@ -1,5 +1,9 @@ - -# python2.5 compatibility +""" +This is a compatibility module, to make it possible to use jedi also with older +python versions. +""" +# next was defined in python 2.6, in python 3 obj.next won't be possible +# anymore try: next = next except NameError: @@ -14,3 +18,9 @@ except NameError: raise else: return default + +# ast module was defined in python 2.6 +try: + from ast import literal_eval +except ImportError: + literal_eval = eval diff --git a/evaluate.py b/evaluate.py index 68a43f82..87b51d0e 100644 --- a/evaluate.py +++ b/evaluate.py @@ -11,7 +11,7 @@ TODO list comprehensions, priority? TODO care for *args **kwargs TODO annotations """ -from _compatibility import next +from _compatibility import next, literal_eval import itertools import copy @@ -401,16 +401,35 @@ class Array(object): if index is not None: # This is indexing only one element, with a fixed index number, # otherwise it just ignores the index (e.g. [1+1]) + i = index.get_only_subelement().name try: - index_nr = int(index.get_only_subelement().name) - values = [self._array[index_nr]] - except: + print 'index', i + return self.get_exact_index_types(i) + except (IndexError, KeyError): pass - scope = self._array.parent_stmt.parent - return follow_call_list(scope, values) + return self.follow_values(values) def get_exact_index_types(self, index): + if self._array.type == parsing.Array.DICT: + old_index = index + index = None + for key_elements in self._array.keys: + # because we only want the key to be a string + if len(key_elements) == 1: + try: + str_key = key_elements[0].name + if old_index == str_key: + index = str_key.name + break + except AttributeError: + pass + if index is None: + raise KeyError('No key found in dictionary') values = [self._array[index]] + return self.follow_values(values) + + def follow_values(self, values): + """ helper function for the index getters """ scope = self._array.parent_stmt.parent return follow_call_list(scope, values) diff --git a/parsetest.py b/parsetest.py index a894d1c2..7d32da33 100644 --- a/parsetest.py +++ b/parsetest.py @@ -167,14 +167,16 @@ class C(object): test = [1,2] -def args_func(arg1, arg2=1, *args, **kwargs): - return arg1, arg2, args, kwargs +def fu(a=1, b="", *args, **kwargs): + return a, b, args, kwargs -exe = args_func(arg2=1,arg1=set) +exe = fu(arg2=1,arg1=set) +exe = fu(list, 1, "", c=set) args_func() #1,"", a=list)[0]. args_func(arg1=0, *test + [3], *[4,5], **{'a': 'b'}). - +exe[2][0]. +exe[3]['c'].union exe[0]. diff --git a/parsing.py b/parsing.py index ca0f1330..1bdc1c3e 100644 --- a/parsing.py +++ b/parsing.py @@ -31,7 +31,7 @@ Ignored statements: TODO take special care for future imports TODO check meta classes """ -from _compatibility import next +from _compatibility import next, literal_eval import tokenize import cStringIO @@ -326,7 +326,7 @@ class Function(Scope): def get_set_vars(self): n = super(Function, self).get_set_vars() if self.param_cb: - # this is the really ugly part, where the functional style of this + # This is the really ugly part, where the functional style of this # get methods is broken, it executes a callback. # This is important, because something has to inject the params # into the functions, with the right values. @@ -614,13 +614,15 @@ class Statement(Simple): is_call = lambda: result.__class__ == Call is_call_or_close = lambda: is_call() or close_brackets - if isinstance(tok, Name) or token_type in [tokenize.STRING, - tokenize.NUMBER]: # names + is_literal = token_type in [tokenize.STRING, tokenize.NUMBER] + if isinstance(tok, Name) or is_literal: c_type = Call.NAME - if token_type == tokenize.STRING: - c_type = Call.STRING - elif token_type == tokenize.NUMBER: - c_type = Call.NUMBER + if is_literal: + tok = literal_eval(tok) + if token_type == tokenize.STRING: + c_type = Call.STRING + elif token_type == tokenize.NUMBER: + c_type = Call.NUMBER if is_chain: call = Call(tok, c_type, self, result) diff --git a/test/completion/arrays.py b/test/completion/arrays.py index 4cd7f0fd..2dede46b 100644 --- a/test/completion/arrays.py +++ b/test/completion/arrays.py @@ -119,6 +119,12 @@ g1. # ----------------- # dicts # ----------------- -dic2 = {'asdf': 3} +dic2 = {'asdf': 3, 'b': 'str'} #? ['real'] dic2['asdf'].real +#? [] +dic2['asdf'].upper +#? ['real'] +dic2[r'asdf'].real +#? [] +dic2[r'asdf'].upper diff --git a/test/completion/functions.py b/test/completion/functions.py index 6e829758..3a86f505 100644 --- a/test/completion/functions.py +++ b/test/completion/functions.py @@ -151,7 +151,7 @@ exe.items # ----------------- def fu(a=1, b="", *args, **kwargs): - return a,b,args,kwargs + return a, b, args, kwargs exe = fu(list, 1, "", c=set) diff --git a/test/run.py b/test/run.py index 26a62cc9..e64c1db1 100755 --- a/test/run.py +++ b/test/run.py @@ -34,7 +34,7 @@ def completion_test(source): try: completions = functions.complete(source, line_nr, 999, completion_test_dir) - except: + except Exception: print 'test @%s: %s' % (line_nr-1, line) print traceback.format_exc() fails += 1