diff --git a/evaluate.py b/evaluate.py index 1c1d7bc1..97a9542e 100644 --- a/evaluate.py +++ b/evaluate.py @@ -34,7 +34,17 @@ import builtin memoize_caches = [] +class DecoratorNotFound(LookupError): + """ + Decorators are sometimes not found, if that happens, that error is raised. + """ + pass + + class MultiLevelStopIteration(Exception): + """ + StopIteration's get catched pretty easy by for loops, let errors propagate. + """ pass @@ -56,6 +66,7 @@ class MultiLevelAttributeError(BaseException): return 'Original:\n\n' + ''.join(tb) + def clear_caches(): for m in memoize_caches: m.clear() @@ -339,6 +350,8 @@ class Function(object): return f def __getattr__(self, name): + if self.decorated_func == None: + raise DecoratorNotFound() return getattr(self.decorated_func, name) def __repr__(self): @@ -379,7 +392,7 @@ class Execution(Executable): try: # if it is an instance, we try to execute the __call__(). call_method = self.base.get_subscope_by_name('__call__') - except (AttributeError, KeyError): + except (AttributeError, KeyError, DecoratorNotFound): debug.warning("no execution possible", self.base) else: debug.dbg('__call__', call_method, self.base) @@ -886,7 +899,12 @@ def get_scopes_for_name(scope, name_str, position=None, search_global=False): break_scopes = [] # here is the position stuff happening (sorting of variables) for name in sorted(name_list, key=comparison_func, reverse=True): - p = name.parent.parent if name.parent else None + try: + p = name.parent.parent if name.parent else None + except DecoratorNotFound: + debug.warning('catched DecoratorNotFound: %s in %s' \ + % (name, scope)) + continue if name_str == name.get_code() and p not in break_scopes: result += handle_non_arrays(name) # for comparison we need the raw class diff --git a/test/completion/classes.py b/test/completion/classes.py index 0aa083e5..22aa9f87 100644 --- a/test/completion/classes.py +++ b/test/completion/classes.py @@ -151,6 +151,31 @@ CallClass()() # properties # ----------------- + + + + + + + + + + + + + + + + + + + + + + + + + class B(): @property def r(self): @@ -172,6 +197,8 @@ B().p ##? [] B().p() +property2 = property + # ----------------- # class decorators # ----------------- diff --git a/test/completion/decorators.py b/test/completion/decorators.py new file mode 100644 index 00000000..f7ee4540 --- /dev/null +++ b/test/completion/decorators.py @@ -0,0 +1,27 @@ +# ----------------- +# not found decorators +# ----------------- +@not_found_decorator +def just_a_func(): + return 1 + +#? [] +just_a_func() + +#? [] +just_a_func. + + +class JustAClass: + @not_found_decorator2 + def a(self): + return 1 + +#? [] +JustAClass().a. +#? [] +JustAClass().a() +#? [] +JustAClass.a. +#? [] +JustAClass().a() diff --git a/test/completion/functions.py b/test/completion/functions.py index 577b3b5f..f7fa56d5 100644 --- a/test/completion/functions.py +++ b/test/completion/functions.py @@ -222,7 +222,6 @@ exe = fu(list, set, 3, '', d='') #? str() exe[3][0] - # ----------------- # generators # -----------------