forked from VimPlug/jedi
Add Script().get_context, fixes #253
This commit is contained in:
@@ -7,6 +7,7 @@ Changelog
|
||||
+++++++++++++++++++
|
||||
|
||||
|
||||
- **Add** ``Script.get_context`` to get information where you currently are.
|
||||
- Big **Script API Changes**:
|
||||
- The line and column parameters of ``jedi.Script`` are now deprecated
|
||||
- ``completions`` deprecated, use ``complete`` instead
|
||||
|
||||
@@ -418,6 +418,30 @@ class Script(object):
|
||||
return [classes.Signature(self._inference_state, signature, call_details)
|
||||
for signature in definitions.get_signatures()]
|
||||
|
||||
@validate_line_column
|
||||
def get_context(self, line=None, column=None):
|
||||
leaf = self._module_node.get_leaf_for_position((line, column), include_prefixes=True)
|
||||
if leaf.start_pos > (line, column) or leaf.type == 'endmarker':
|
||||
previous_leaf = leaf.get_previous_leaf()
|
||||
if previous_leaf is not None:
|
||||
leaf = previous_leaf
|
||||
|
||||
module_context = self._get_module_context()
|
||||
context = module_context.create_context(leaf)
|
||||
while context.name is None:
|
||||
context = context.parent_context # comprehensions
|
||||
|
||||
definition = classes.Definition(self._inference_state, context.name)
|
||||
while definition.type != 'module':
|
||||
name = definition._name # TODO private access
|
||||
tree_name = name.tree_name
|
||||
if tree_name is not None: # Happens with lambdas.
|
||||
scope = tree_name.get_definition()
|
||||
if scope.start_pos[1] < column:
|
||||
break
|
||||
definition = definition.parent()
|
||||
return definition
|
||||
|
||||
def _analysis(self):
|
||||
self._inference_state.is_analysis = True
|
||||
self._inference_state.analysis_modules = [self._module_node]
|
||||
|
||||
113
test/test_api/test_context.py
Normal file
113
test/test_api/test_context.py
Normal file
@@ -0,0 +1,113 @@
|
||||
import pytest
|
||||
|
||||
|
||||
def _iter_hierarchy(context):
|
||||
def iter(context):
|
||||
while context is not None:
|
||||
yield context
|
||||
context = context.parent()
|
||||
|
||||
return reversed(list(iter(context)))
|
||||
|
||||
|
||||
func_code = '''\
|
||||
def func1(x, y):
|
||||
pass
|
||||
|
||||
def func2():
|
||||
what ?
|
||||
i = 3
|
||||
|
||||
def func3():
|
||||
1'''
|
||||
cls_code = '''\
|
||||
class Foo:
|
||||
def x():
|
||||
def y():
|
||||
pass
|
||||
'''
|
||||
cls_nested = '''\
|
||||
class C:
|
||||
class D:
|
||||
def f():
|
||||
pass
|
||||
'''
|
||||
lambda_ = '''\
|
||||
def x():
|
||||
(lambda x:
|
||||
lambda: y
|
||||
)
|
||||
'''
|
||||
comprehension = '''
|
||||
def f(x):
|
||||
[x
|
||||
for
|
||||
x
|
||||
in x
|
||||
]'''
|
||||
|
||||
with_brackets = '''\
|
||||
def x():
|
||||
[
|
||||
|
||||
]
|
||||
'''
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'code, line, column, full_name, expected_parents', [
|
||||
('', None, None, 'myfile', []),
|
||||
(' ', None, 0, 'myfile', []),
|
||||
|
||||
(func_code, 1, 0, 'myfile', []),
|
||||
(func_code, 1, None, 'myfile.func1', ['func1']),
|
||||
#(func_code, 1, 4, 'myfile.func1', ['func1']),
|
||||
#(func_code, 1, 10, 'myfile.func1', ['func1']),
|
||||
|
||||
(func_code, 3, 0, 'myfile', []),
|
||||
(func_code, 5, None, 'myfile.func2', ['func2']),
|
||||
(func_code, 6, None, 'myfile', []),
|
||||
(func_code, 7, None, 'myfile', []),
|
||||
(func_code, 9, None, 'myfile.func3', ['func3']),
|
||||
|
||||
(cls_code, None, None, 'myfile', []),
|
||||
(cls_code + ' ', None, None, 'myfile.Foo', ['Foo']),
|
||||
(cls_code + ' ' * 3, None, None, 'myfile.Foo', ['Foo']),
|
||||
(cls_code + ' ' * 4, None, None, 'myfile.Foo', ['Foo']),
|
||||
(cls_code + ' ' * 5, None, None, 'myfile.Foo.x', ['Foo', 'x']),
|
||||
(cls_code + ' ' * 8, None, None, 'myfile.Foo.x', ['Foo', 'x']),
|
||||
(cls_code + ' ' * 12, None, None, None, ['Foo', 'x', 'y']),
|
||||
|
||||
(cls_code, 4, 0, 'myfile', []),
|
||||
(cls_code, 4, 3, 'myfile.Foo', ['Foo']),
|
||||
(cls_code, 4, 4, 'myfile.Foo', ['Foo']),
|
||||
(cls_code, 4, 5, 'myfile.Foo.x', ['Foo', 'x']),
|
||||
(cls_code, 4, 8, 'myfile.Foo.x', ['Foo', 'x']),
|
||||
(cls_code, 4, 12, None, ['Foo', 'x', 'y']),
|
||||
|
||||
(cls_nested, 4, None, 'myfile.C.D.f', ['C', 'D', 'f']),
|
||||
(cls_nested, 4, 3, 'myfile.C', ['C']),
|
||||
|
||||
(lambda_, 2, 9, 'myfile.x', ['x']), # the lambda keyword
|
||||
(lambda_, 2, 13, 'myfile.x', ['x']), # the lambda param
|
||||
(lambda_, 3, 0, 'myfile', []), # Within brackets, but they are ignored.
|
||||
(lambda_, 3, 8, 'myfile.x', ['x']),
|
||||
(lambda_, 3, None, 'myfile.x', ['x']),
|
||||
|
||||
(comprehension, 2, None, 'myfile.f', ['f']),
|
||||
(comprehension, 3, None, 'myfile.f', ['f']),
|
||||
(comprehension, 4, None, 'myfile.f', ['f']),
|
||||
(comprehension, 5, None, 'myfile.f', ['f']),
|
||||
(comprehension, 6, None, 'myfile.f', ['f']),
|
||||
|
||||
# Brackets are just ignored.
|
||||
(with_brackets, 3, None, 'myfile', []),
|
||||
(with_brackets, 4, 4, 'myfile.x', ['x']),
|
||||
(with_brackets, 4, 5, 'myfile.x', ['x']),
|
||||
]
|
||||
)
|
||||
def test_context(Script, code, line, column, full_name, expected_parents):
|
||||
context = Script(code, path='/foo/myfile.py').get_context(line, column)
|
||||
assert context.full_name == full_name
|
||||
parent_names = [d.name for d in _iter_hierarchy(context)]
|
||||
assert parent_names == ['myfile'] + expected_parents
|
||||
Reference in New Issue
Block a user