Commit 628760c7 authored by Tzer-jen Wei's avatar Tzer-jen Wei

Experimental support for jedi 0.9.0

parent 19fa1c98
...@@ -6,9 +6,18 @@ from __future__ import absolute_import ...@@ -6,9 +6,18 @@ from __future__ import absolute_import
from io import open from io import open
from collections import defaultdict from collections import defaultdict
from itertools import chain
from jedi import Script import re
from jedi.parser.representation import Function, Module, Import
import jedi
if list(map(int, re.findall('[0-9]+', jedi.__version__ or '0'))) >= [0, 9, 0]:
__jedi_version__ = 9
from jedi.parser.tree import Module, Module as Import
from jedi.evaluate.representation import Function, Instance
else:
__jedi_version__ = 8
from jedi import Script
from jedi.parser.representation import Function, Module, Import
from Cython.Utils import open_source_file from Cython.Utils import open_source_file
...@@ -26,33 +35,54 @@ def analyse(source_path=None, code=None): ...@@ -26,33 +35,54 @@ def analyse(source_path=None, code=None):
""" """
if not source_path and code is None: if not source_path and code is None:
raise ValueError("Either 'source_path' or 'code' is required.") raise ValueError("Either 'source_path' or 'code' is required.")
script = Script(source=code, path=source_path)
evaluator = script._evaluator
scoped_names = {} scoped_names = {}
for statements in script._parser.module().used_names.values(): if __jedi_version__ == 8:
for statement in statements: script = Script(source=code, path=source_path)
scope = statement.parent evaluator = script._evaluator
statement_iter = chain.from_iterable(script._parser.module().used_names.values())
else:
statement_iter = jedi.names(source=code, path=source_path, all_scopes=True)
for statement in statement_iter:
if __jedi_version__ == 8:
parent = scope = statement.parent
while not isinstance(scope, (Function, Module)): while not isinstance(scope, (Function, Module)):
scope = scope.parent parent = scope = scope.parent
# hack: work around current Jedi problem with global module variables # hack: work around current Jedi problem with global module variables
if not hasattr(scope, 'scope_names_generator'): if not hasattr(scope, 'scope_names_generator'):
continue continue
statement_names = statement.get_defined_names() statement_names = statement.get_defined_names()
if not statement_names: if not statement_names:
continue continue
key = (None if isinstance(scope, Module) else str(scope.name), scope.start_pos) else:
try: parent = statement.parent()
names = scoped_names[key] scope = parent._definition
except KeyError: evaluator = statement._evaluator
names = scoped_names[key] = defaultdict(set) # original jedi-typer does not handle function definitions, so skip here as well
for name in statement_names: if isinstance(statement._definition, Function):
for name_type in evaluator.find_types(scope, name): continue
if isinstance(name_type, Import): statement_names = [statement.name]
key = (None if isinstance(scope, Module) else str(parent.name), scope.start_pos)
try:
names = scoped_names[key]
except KeyError:
names = scoped_names[key] = defaultdict(set)
for name in statement_names:
for name_type in evaluator.find_types(scope, name, search_global=True):
if isinstance(name_type, Import):
type_name = 'object'
else:
try:
if __jedi_version__ == 8:
type_name = name_type.name
else:
if isinstance(name_type, Instance):
type_name = name_type.base.obj.__name__
else:
type_name = type(name_type.obj).__name__
except AttributeError as error:
print(error)
type_name = 'object' type_name = 'object'
else: names[str(name)].add(type_name)
type_name = name_type.name
names[str(name)].add(type_name)
return scoped_names return scoped_names
...@@ -72,13 +102,14 @@ def inject_types(source_path, types, type_map=default_type_map, mode='python'): ...@@ -72,13 +102,14 @@ def inject_types(source_path, types, type_map=default_type_map, mode='python'):
for line_no, line in enumerate(f, 1): for line_no, line in enumerate(f, 1):
if line_no in col_and_types_by_line: if line_no in col_and_types_by_line:
col, scope, types = col_and_types_by_line[line_no] col, scope, types = col_and_types_by_line[line_no]
types = ', '.join("%s='%s'" % (name, type_map.get(type_name, type_name)) if types:
for name, type_name in types) types = ', '.join("%s='%s'" % (name, type_map.get(type_name, type_name))
if scope is None: for name, type_name in types)
type_decl = u'{indent}cython.declare({types})\n' if scope is None:
else: type_decl = u'{indent}cython.declare({types})\n'
type_decl = u'{indent}@cython.locals({types})\n' else:
lines.append(type_decl.format(indent=' '*col, types=types)) type_decl = u'{indent}@cython.locals({types})\n'
lines.append(type_decl.format(indent=' '*col, types=types))
lines.append(line) lines.append(line)
return lines return lines
......
...@@ -1943,7 +1943,7 @@ def runtests(options, cmd_args, coverage=None): ...@@ -1943,7 +1943,7 @@ def runtests(options, cmd_args, coverage=None):
try: try:
import jedi import jedi
if not ([0, 8, 1] <= list(map(int, re.findall('[0-9]+', jedi.__version__ or '0'))) < [0, 9]): if not ([0, 8, 1] <= list(map(int, re.findall('[0-9]+', jedi.__version__ or '0'))) <= [0, 9, 0]):
raise ImportError raise ImportError
except (ImportError, AttributeError, TypeError): except (ImportError, AttributeError, TypeError):
exclude_selectors.append(RegExSelector('Jedi')) exclude_selectors.append(RegExSelector('Jedi'))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment