mirror of
https://github.com/davidhalter/jedi.git
synced 2025-12-09 23:34:45 +08:00
Replace Scope.subscopes with iter_funcdefs and iter_classdefs.
This commit is contained in:
@@ -7,6 +7,7 @@ mixing in Python code, the autocompletion should work much better for builtins.
|
|||||||
import os
|
import os
|
||||||
import inspect
|
import inspect
|
||||||
import types
|
import types
|
||||||
|
from itertools import chain
|
||||||
|
|
||||||
from jedi._compatibility import is_py3, builtins, unicode, is_py34
|
from jedi._compatibility import is_py3, builtins, unicode, is_py34
|
||||||
from jedi.parser.python import parse
|
from jedi.parser.python import parse
|
||||||
@@ -74,7 +75,7 @@ def _load_faked_module(module):
|
|||||||
|
|
||||||
|
|
||||||
def _search_scope(scope, obj_name):
|
def _search_scope(scope, obj_name):
|
||||||
for s in scope.subscopes:
|
for s in chain(scope.iter_classdefs(), scope.iter_funcdefs()):
|
||||||
if s.name.value == obj_name:
|
if s.name.value == obj_name:
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ def _evaluate_for_statement_string(module_context, string):
|
|||||||
# don't need to conform with the current grammar.
|
# don't need to conform with the current grammar.
|
||||||
module = parse(code.format(indent_block(string)))
|
module = parse(code.format(indent_block(string)))
|
||||||
try:
|
try:
|
||||||
funcdef = module.subscopes[0]
|
funcdef = next(module.iter_funcdefs())
|
||||||
# First pick suite, then simple_stmt and then the node,
|
# First pick suite, then simple_stmt and then the node,
|
||||||
# which is also not the last item, because there's a newline.
|
# which is also not the last item, because there's a newline.
|
||||||
stmt = funcdef.children[-1].children[-1].children[-2]
|
stmt = funcdef.children[-1].children[-1].children[-2]
|
||||||
|
|||||||
@@ -275,7 +275,7 @@ def get_global_filters(evaluator, context, until_position, origin_scope):
|
|||||||
... y = None
|
... y = None
|
||||||
... '''))
|
... '''))
|
||||||
>>> module_node = script._get_module_node()
|
>>> module_node = script._get_module_node()
|
||||||
>>> scope = module_node.subscopes[0]
|
>>> scope = next(module_node.iter_funcdefs())
|
||||||
>>> scope
|
>>> scope
|
||||||
<Function: func@3-5>
|
<Function: func@3-5>
|
||||||
>>> context = script._get_module().create_context(scope)
|
>>> context = script._get_module().create_context(scope)
|
||||||
|
|||||||
@@ -270,7 +270,7 @@ def collections_namedtuple(evaluator, obj, arguments):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Parse source
|
# Parse source
|
||||||
generated_class = parse(source, grammar=evaluator.grammar).subscopes[0]
|
generated_class = next(parse(source, grammar=evaluator.grammar).iter_classdefs())
|
||||||
return set([er.ClassContext(evaluator, generated_class, evaluator.BUILTINS)])
|
return set([er.ClassContext(evaluator, generated_class, evaluator.BUILTINS)])
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -23,8 +23,6 @@ Any subclasses of :class:`Scope`, including :class:`Module` has an attribute
|
|||||||
|
|
||||||
>>> module.imports
|
>>> module.imports
|
||||||
[<ImportName: import os@1,0>]
|
[<ImportName: import os@1,0>]
|
||||||
|
|
||||||
See also :attr:`Scope.subscopes` and :attr:`Scope.statements`.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
@@ -234,12 +232,7 @@ class Scope(PythonBaseNode, DocstringMixin):
|
|||||||
"""
|
"""
|
||||||
Super class for the parser tree, which represents the state of a python
|
Super class for the parser tree, which represents the state of a python
|
||||||
text file.
|
text file.
|
||||||
A Scope manages and owns its subscopes, which are classes and functions, as
|
A Scope is either a function, class or lambda.
|
||||||
well as variables and imports. It is used to access the structure of python
|
|
||||||
files.
|
|
||||||
|
|
||||||
:param start_pos: The position (line and column) of the scope.
|
|
||||||
:type start_pos: tuple(int, int)
|
|
||||||
"""
|
"""
|
||||||
__slots__ = ()
|
__slots__ = ()
|
||||||
|
|
||||||
@@ -250,26 +243,27 @@ class Scope(PythonBaseNode, DocstringMixin):
|
|||||||
def returns(self):
|
def returns(self):
|
||||||
# Needed here for fast_parser, because the fast_parser splits and
|
# Needed here for fast_parser, because the fast_parser splits and
|
||||||
# returns will be in "normal" modules.
|
# returns will be in "normal" modules.
|
||||||
return self._search_in_scope(ReturnStmt)
|
return list(self._search_in_scope(ReturnStmt))
|
||||||
|
|
||||||
@property
|
def iter_funcdefs(self):
|
||||||
def subscopes(self):
|
return self._search_in_scope(Function)
|
||||||
return self._search_in_scope(Scope)
|
|
||||||
|
def iter_classdefs(self):
|
||||||
|
return self._search_in_scope(Class)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def imports(self):
|
def imports(self):
|
||||||
return self._search_in_scope(Import)
|
return list(self._search_in_scope(Import))
|
||||||
|
|
||||||
def _search_in_scope(self, typ):
|
def _search_in_scope(self, typ):
|
||||||
def scan(children):
|
def scan(children):
|
||||||
elements = []
|
|
||||||
for element in children:
|
for element in children:
|
||||||
if isinstance(element, typ):
|
if isinstance(element, typ):
|
||||||
elements.append(element)
|
yield element
|
||||||
if element.type in ('suite', 'simple_stmt', 'decorated') \
|
if element.type in ('suite', 'simple_stmt', 'decorated') \
|
||||||
or isinstance(element, Flow):
|
or isinstance(element, Flow):
|
||||||
elements += scan(element.children)
|
for e in scan(element.children):
|
||||||
return elements
|
yield e
|
||||||
|
|
||||||
return scan(self.children)
|
return scan(self.children)
|
||||||
|
|
||||||
@@ -473,7 +467,7 @@ class Function(ClassOrFunc):
|
|||||||
@property
|
@property
|
||||||
def yields(self):
|
def yields(self):
|
||||||
# TODO This is incorrect, yields are also possible in a statement.
|
# TODO This is incorrect, yields are also possible in a statement.
|
||||||
return self._search_in_scope(YieldExpr)
|
return list(self._search_in_scope(YieldExpr))
|
||||||
|
|
||||||
def is_generator(self):
|
def is_generator(self):
|
||||||
return bool(self.yields)
|
return bool(self.yields)
|
||||||
|
|||||||
@@ -164,10 +164,10 @@ def get_doc_with_call_signature(scope_node):
|
|||||||
"""
|
"""
|
||||||
call_signature = None
|
call_signature = None
|
||||||
if scope_node.type == 'classdef':
|
if scope_node.type == 'classdef':
|
||||||
for sub in scope_node.subscopes:
|
for funcdef in scope_node.iter_funcdefs():
|
||||||
if sub.name.value == '__init__':
|
if funcdef.name.value == '__init__':
|
||||||
call_signature = \
|
call_signature = \
|
||||||
get_call_signature(sub, call_string=scope_node.name.value)
|
get_call_signature(funcdef, call_string=scope_node.name.value)
|
||||||
elif scope_node.type in ('funcdef', 'lambdef'):
|
elif scope_node.type in ('funcdef', 'lambdef'):
|
||||||
call_signature = get_call_signature(scope_node)
|
call_signature = get_call_signature(scope_node)
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ def assert_params(param_string, **wanted_dct):
|
|||||||
''') % param_string
|
''') % param_string
|
||||||
|
|
||||||
module = parse(source)
|
module = parse(source)
|
||||||
funcdef = module.subscopes[0]
|
funcdef = next(module.iter_funcdefs())
|
||||||
dct = dict((p.name.value, p.default and p.default.get_code())
|
dct = dict((p.name.value, p.default and p.default.get_code())
|
||||||
for p in funcdef.params)
|
for p in funcdef.params)
|
||||||
assert dct == wanted_dct
|
assert dct == wanted_dct
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ class TestCallAndName():
|
|||||||
|
|
||||||
class TestSubscopes():
|
class TestSubscopes():
|
||||||
def get_sub(self, source):
|
def get_sub(self, source):
|
||||||
return parse(source).subscopes[0]
|
return parse(source).children[0]
|
||||||
|
|
||||||
def test_subscope_names(self):
|
def test_subscope_names(self):
|
||||||
name = self.get_sub('class Foo: pass').name
|
name = self.get_sub('class Foo: pass').name
|
||||||
@@ -100,7 +100,7 @@ def test_end_pos():
|
|||||||
y = None
|
y = None
|
||||||
''')
|
''')
|
||||||
parser = parse(s)
|
parser = parse(s)
|
||||||
scope = parser.subscopes[0]
|
scope = next(parser.iter_funcdefs())
|
||||||
assert scope.start_pos == (3, 0)
|
assert scope.start_pos == (3, 0)
|
||||||
assert scope.end_pos == (5, 0)
|
assert scope.end_pos == (5, 0)
|
||||||
|
|
||||||
@@ -134,7 +134,7 @@ def test_hex_values_in_docstring():
|
|||||||
return 1
|
return 1
|
||||||
'''
|
'''
|
||||||
|
|
||||||
doc = clean_scope_docstring(parse(source).subscopes[0])
|
doc = clean_scope_docstring(next(parse(source).iter_funcdefs()))
|
||||||
if is_py3:
|
if is_py3:
|
||||||
assert doc == '\xff'
|
assert doc == '\xff'
|
||||||
else:
|
else:
|
||||||
@@ -184,12 +184,12 @@ def test_param_splitting():
|
|||||||
grammar = load_grammar('%s.%s' % sys.version_info[:2])
|
grammar = load_grammar('%s.%s' % sys.version_info[:2])
|
||||||
m = parse(src, grammar=grammar)
|
m = parse(src, grammar=grammar)
|
||||||
if is_py3:
|
if is_py3:
|
||||||
assert not m.subscopes
|
assert not list(m.iter_funcdefs())
|
||||||
else:
|
else:
|
||||||
# We don't want b and c to be a part of the param enumeration. Just
|
# We don't want b and c to be a part of the param enumeration. Just
|
||||||
# ignore them, because it's not what we want to support in the
|
# ignore them, because it's not what we want to support in the
|
||||||
# future.
|
# future.
|
||||||
assert [param.name.value for param in m.subscopes[0].params] == result
|
assert [param.name.value for param in next(m.iter_funcdefs()).params] == result
|
||||||
|
|
||||||
check('def x(a, (b, c)):\n pass', ['a'])
|
check('def x(a, (b, c)):\n pass', ['a'])
|
||||||
check('def x((b, c)):\n pass', [])
|
check('def x((b, c)):\n pass', [])
|
||||||
|
|||||||
@@ -29,7 +29,10 @@ class TestsFunctionAndLambdaParsing(object):
|
|||||||
def node(self, request):
|
def node(self, request):
|
||||||
parsed = parse(dedent(request.param[0]))
|
parsed = parse(dedent(request.param[0]))
|
||||||
request.keywords['expected'] = request.param[1]
|
request.keywords['expected'] = request.param[1]
|
||||||
return parsed.subscopes[0]
|
child = parsed.children[0]
|
||||||
|
if child.type == 'simple_stmt':
|
||||||
|
child = child.children[0]
|
||||||
|
return child
|
||||||
|
|
||||||
@pytest.fixture()
|
@pytest.fixture()
|
||||||
def expected(self, request, node):
|
def expected(self, request, node):
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class TokenTest(unittest.TestCase):
|
|||||||
def testit():
|
def testit():
|
||||||
a = "huhu"
|
a = "huhu"
|
||||||
'''))
|
'''))
|
||||||
simple_stmt = parsed.subscopes[0].get_suite().children[-1]
|
simple_stmt = next(parsed.iter_funcdefs()).get_suite().children[-1]
|
||||||
string = simple_stmt.children[0].get_rhs()
|
string = simple_stmt.children[0].get_rhs()
|
||||||
assert string.end_pos == (3, 14)
|
assert string.end_pos == (3, 14)
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ class TokenTest(unittest.TestCase):
|
|||||||
a = """huhu
|
a = """huhu
|
||||||
asdfasdf""" + "h"
|
asdfasdf""" + "h"
|
||||||
'''))
|
'''))
|
||||||
expr_stmt = parsed.subscopes[0].get_suite().children[1].children[0]
|
expr_stmt = next(parsed.iter_funcdefs()).get_suite().children[1].children[0]
|
||||||
string_leaf = expr_stmt.get_rhs().children[0]
|
string_leaf = expr_stmt.get_rhs().children[0]
|
||||||
assert string_leaf.end_pos == (4, 11)
|
assert string_leaf.end_pos == (4, 11)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user