diff --git a/jedi/evaluate/compiled/__init__.py b/jedi/evaluate/compiled/__init__.py index ecdb9821..623b52e9 100644 --- a/jedi/evaluate/compiled/__init__.py +++ b/jedi/evaluate/compiled/__init__.py @@ -314,6 +314,20 @@ class CompiledContextName(ContextNameMixin, AbstractNameDefinition): self.parent_context = context.parent_context +class EmptyCompiledName(AbstractNameDefinition): + """ + Accessing some names will raise an exception. To avoid not having any + completions, just give Jedi the option to return this object. It infers to + nothing. + """ + def __init__(self, evaluator, name): + self.parent_context = evaluator.BUILTINS + self.string_name = name + + def infer(self): + return [] + + class CompiledObjectFilter(AbstractFilter): """ A names_dict instance for compiled objects, resembles the parser.tree. @@ -340,7 +354,7 @@ class CompiledObjectFilter(AbstractFilter): # This is a bit ugly. We're basically returning this to make # lookups possible without having the actual attribute. However # this makes proper completion possible. - return [FakeName(name, create(self._evaluator, None), is_definition=True)] + return [EmptyCompiledName(self._evaluator, name)] return [self._create_name(name)] def values(self): diff --git a/jedi/evaluate/flow_analysis.py b/jedi/evaluate/flow_analysis.py index a20843db..6fcc6063 100644 --- a/jedi/evaluate/flow_analysis.py +++ b/jedi/evaluate/flow_analysis.py @@ -83,9 +83,9 @@ def _break_check(context, context_scope, flow_scope, node): break reachable = reachable.invert() else: - node = flow_scope.node_in_which_check_node(node) - if node is not None: - reachable = _check_if(context, node) + flow_node = flow_scope.node_in_which_check_node(node) + if flow_node is not None: + reachable = _check_if(context, flow_node) elif flow_scope.type in ('try_stmt', 'while_stmt'): return UNSURE diff --git a/test/test_api/test_interpreter.py b/test/test_api/test_interpreter.py index 232a008d..b1e56bbb 100644 --- a/test/test_api/test_interpreter.py +++ b/test/test_api/test_interpreter.py @@ -7,6 +7,7 @@ import jedi from jedi._compatibility import is_py33 from jedi.evaluate.compiled import mixed + class _GlobalNameSpace(): class SideEffectContainer(): pass @@ -66,96 +67,104 @@ def test_side_effect_completion(): assert foo.name == 'foo' -class TestInterpreterAPI(TestCase): - def check_interpreter_complete(self, source, namespace, completions, - **kwds): - script = jedi.Interpreter(source, [namespace], **kwds) - cs = script.completions() - actual = [c.name for c in cs] - self.assertEqual(sorted(actual), sorted(completions)) +def _assert_interpreter_complete(source, namespace, completions, + **kwds): + script = jedi.Interpreter(source, [namespace], **kwds) + cs = script.completions() + actual = [c.name for c in cs] + assert sorted(actual) == sorted(completions) - def test_complete_raw_function(self): - from os.path import join - self.check_interpreter_complete('join("").up', - locals(), - ['upper']) - def test_complete_raw_function_different_name(self): - from os.path import join as pjoin - self.check_interpreter_complete('pjoin("").up', - locals(), - ['upper']) +def test_complete_raw_function(): + from os.path import join + _assert_interpreter_complete('join("").up', + locals(), + ['upper']) - def test_complete_raw_module(self): - import os - self.check_interpreter_complete('os.path.join("a").up', - locals(), - ['upper']) - def test_complete_raw_instance(self): - import datetime - dt = datetime.datetime(2013, 1, 1) - completions = ['time', 'timetz', 'timetuple'] - if is_py33: - completions += ['timestamp'] - self.check_interpreter_complete('(dt - dt).ti', - locals(), - completions) +def test_complete_raw_function_different_name(): + from os.path import join as pjoin + _assert_interpreter_complete('pjoin("").up', + locals(), + ['upper']) - def test_list(self): - array = ['haha', 1] - self.check_interpreter_complete('array[0].uppe', - locals(), - ['upper']) - self.check_interpreter_complete('array[0].real', - locals(), - []) - # something different, no index given, still just return the right - self.check_interpreter_complete('array[int].real', - locals(), - ['real']) - self.check_interpreter_complete('array[int()].real', - locals(), - ['real']) - # inexistent index - self.check_interpreter_complete('array[2].upper', - locals(), - ['upper']) +def test_complete_raw_module(): + import os + _assert_interpreter_complete('os.path.join("a").up', + locals(), + ['upper']) - def test_slice(self): - class Foo(): - bar = [] - baz = 'xbarx' - self.check_interpreter_complete('getattr(Foo, baz[1:-1]).append', - locals(), - ['append']) - def test_getitem_side_effects(self): - class Foo(): - def __getitem__(self, index): - # possible side effects here, should therefore not call this. - return index +def test_complete_raw_instance(): + import datetime + dt = datetime.datetime(2013, 1, 1) + completions = ['time', 'timetz', 'timetuple'] + if is_py33: + completions += ['timestamp'] + _assert_interpreter_complete('(dt - dt).ti', + locals(), + completions) - foo = Foo() - self.check_interpreter_complete('foo[0].', locals(), []) - def test_property_error(self): - class Foo(): - @property - def bar(self): - raise ValueError +def test_list(): + array = ['haha', 1] + _assert_interpreter_complete('array[0].uppe', + locals(), + ['upper']) + _assert_interpreter_complete('array[0].real', + locals(), + []) - foo = Foo() - self.check_interpreter_complete('foo.bar', locals(), ['bar']) - self.check_interpreter_complete('foo.bar.baz', locals(), []) + # something different, no index given, still just return the right + _assert_interpreter_complete('array[int].real', + locals(), + ['real']) + _assert_interpreter_complete('array[int()].real', + locals(), + ['real']) + # inexistent index + _assert_interpreter_complete('array[2].upper', + locals(), + ['upper']) - def test_param_completion(self): - def foo(bar): - pass - lambd = lambda xyz: 3 +def test_slice(): + class Foo(): + bar = [] + baz = 'xbarx' + _assert_interpreter_complete('getattr(Foo, baz[1:-1]).append', + locals(), + ['append']) - self.check_interpreter_complete('foo(bar', locals(), ['bar']) - # TODO we're not yet using the Python3.5 inspect.signature, yet. - assert not jedi.Interpreter('lambd(xyz', [locals()]).completions() + +def test_getitem_side_effects(): + class Foo(): + def __getitem__(self, index): + # possible side effects here, should therefore not call this. + return index + + foo = Foo() + _assert_interpreter_complete('foo[0].', locals(), []) + + +def test_property_error(): + class Foo(): + @property + def bar(self): + raise ValueError + + foo = Foo() + _assert_interpreter_complete('foo.bar', locals(), ['bar']) + _assert_interpreter_complete('foo.bar.baz', locals(), []) + + +def test_param_completion(): + def foo(bar): + pass + + lambd = lambda xyz: 3 + + _assert_interpreter_complete('foo(bar', locals(), ['bar']) + # TODO we're not yet using the Python3.5 inspect.signature, yet. + assert not jedi.Interpreter('lambd(xyz', [locals()]).completions()