1
0
forked from VimPlug/jedi

All modules now have a code_lines attribute, see #1062

This commit is contained in:
Dave Halter
2018-03-16 10:20:14 +01:00
parent 24e1f7e6f0
commit 90a226f898
11 changed files with 102 additions and 33 deletions
+22 -12
View File
@@ -5,6 +5,8 @@ Used only for REPL Completion.
import inspect
import os
from jedi.parser_utils import get_cached_code_lines
from jedi import settings
from jedi.evaluate import compiled
from jedi.cache import underscore_memoization
@@ -140,10 +142,10 @@ def _find_syntax_node_name(evaluator, access_handle):
path = inspect.getsourcefile(python_object)
except TypeError:
# The type might not be known (e.g. class_with_dict.__weakref__)
return None, None, None
return None
if path is None or not os.path.exists(path):
# The path might not exist or be e.g. <stdin>.
return None, None, None
return None
module_node = _load_module(evaluator, path)
@@ -151,22 +153,23 @@ def _find_syntax_node_name(evaluator, access_handle):
# We don't need to check names for modules, because there's not really
# a way to write a module in a module in Python (and also __name__ can
# be something like ``email.utils``).
return module_node, module_node, path
code_lines = get_cached_code_lines(evaluator.grammar, path)
return module_node, module_node, path, code_lines
try:
name_str = python_object.__name__
except AttributeError:
# Stuff like python_function.__code__.
return None, None, None
return None
if name_str == '<lambda>':
return None, None, None # It's too hard to find lambdas.
return None # It's too hard to find lambdas.
# Doesn't always work (e.g. os.stat_result)
try:
names = module_node.get_used_names()[name_str]
except KeyError:
return None, None, None
return None
names = [n for n in names if n.is_definition()]
try:
@@ -183,29 +186,36 @@ def _find_syntax_node_name(evaluator, access_handle):
# There's a chance that the object is not available anymore, because
# the code has changed in the background.
if line_names:
return module_node, line_names[-1].parent, path
names = line_names
code_lines = get_cached_code_lines(evaluator.grammar, path)
# It's really hard to actually get the right definition, here as a last
# resort we just return the last one. This chance might lead to odd
# completions at some points but will lead to mostly correct type
# inference, because people tend to define a public name in a module only
# once.
return module_node, names[-1].parent, path
return module_node, names[-1].parent, path, code_lines
@compiled_objects_cache('mixed_cache')
def _create(evaluator, access_handle, parent_context, *args):
module_node, tree_node, path = _find_syntax_node_name(evaluator, access_handle)
compiled_object = create_cached_compiled_object(
evaluator, access_handle, parent_context=parent_context.compiled_object)
if tree_node is None:
result = _find_syntax_node_name(evaluator, access_handle)
if result is None:
return compiled_object
module_node, tree_node, path, code_lines = result
if parent_context.tree_node.get_root_node() == module_node:
module_context = parent_context.get_root_context()
else:
module_context = ModuleContext(evaluator, module_node, path=path)
module_context = ModuleContext(
evaluator, module_node,
path=path,
code_lines=code_lines,
)
# TODO this __name__ is probably wrong.
name = compiled_object.get_root_context().py__name__()
imports.add_module(evaluator, name, module_context)
+2 -1
View File
@@ -43,10 +43,11 @@ class ModuleContext(TreeContext):
api_type = u'module'
parent_context = None
def __init__(self, evaluator, module_node, path):
def __init__(self, evaluator, module_node, path, code_lines):
super(ModuleContext, self).__init__(evaluator, parent_context=None)
self.tree_node = module_node
self._path = path
self.code_lines = code_lines
def get_filters(self, search_global, until_position=None, origin_scope=None):
yield MergedFilter(
+6 -1
View File
@@ -20,6 +20,7 @@ from parso import python_bytes_to_unicode
from jedi._compatibility import unicode, ImplicitNSInfo, force_unicode
from jedi import debug
from jedi import settings
from jedi.parser_utils import get_cached_code_lines
from jedi.evaluate import sys_path
from jedi.evaluate import helpers
from jedi.evaluate import compiled
@@ -492,7 +493,11 @@ def _load_module(evaluator, path=None, code=None, sys_path=None,
cache_path=settings.cache_directory)
from jedi.evaluate.context import ModuleContext
module = ModuleContext(evaluator, module_node, path=path)
module = ModuleContext(
evaluator, module_node,
path=path,
code_lines=get_cached_code_lines(evaluator.grammar, path),
)
else:
module = compiled.load_module(evaluator, path=path, sys_path=sys_path)
add_module(evaluator, module_name, module, safe=safe_module_name)
+9 -5
View File
@@ -22,7 +22,7 @@ x support for type hint comments for functions, `# type: (int, str) -> int`.
import os
import re
from parso import ParserSyntaxError, parse
from parso import ParserSyntaxError, parse, split_lines
from parso.python import tree
from jedi._compatibility import unicode, force_unicode
@@ -216,6 +216,7 @@ def infer_return_types(function_context):
_typing_module = None
_typing_module_code_lines = None
def _get_typing_replacement_module(grammar):
@@ -223,14 +224,15 @@ def _get_typing_replacement_module(grammar):
The idea is to return our jedi replacement for the PEP-0484 typing module
as discussed at https://github.com/davidhalter/jedi/issues/663
"""
global _typing_module
global _typing_module, _typing_module_code_lines
if _typing_module is None:
typing_path = \
os.path.abspath(os.path.join(__file__, "../jedi_typing.py"))
with open(typing_path) as f:
code = unicode(f.read())
_typing_module = grammar.parse(code)
return _typing_module
_typing_module_code_lines = split_lines(code)
return _typing_module, _typing_module_code_lines
def py__getitem__(context, typ, node):
@@ -260,10 +262,12 @@ def py__getitem__(context, typ, node):
# check for the instance typing._Optional (Python 3.6).
return context.eval_node(nodes[0])
module_node, code_lines = _get_typing_replacement_module(context.evaluator.latest_grammar)
typing = ModuleContext(
context.evaluator,
module_node=_get_typing_replacement_module(context.evaluator.latest_grammar),
path=None
module_node=module_node,
path=None,
code_lines=code_lines,
)
factories = typing.py__getattribute__("factory")
assert len(factories) == 1
+10 -5
View File
@@ -11,6 +11,8 @@ compiled module that returns the types for C-builtins.
"""
import re
import parso
from jedi._compatibility import force_unicode
from jedi import debug
from jedi.evaluate.arguments import ValuesArguments
@@ -293,8 +295,8 @@ def collections_namedtuple(evaluator, obj, arguments):
base = next(iter(_class_template_set)).get_safe_value()
base += _NAMEDTUPLE_INIT
# Build source
source = base.format(
# Build source code
code = base.format(
typename=name,
field_names=tuple(fields),
num_fields=len(fields),
@@ -304,10 +306,13 @@ def collections_namedtuple(evaluator, obj, arguments):
for index, name in enumerate(fields))
)
# Parse source
module = evaluator.grammar.parse(source)
# Parse source code
module = evaluator.grammar.parse(code)
generated_class = next(module.iter_classdefs())
parent_context = ModuleContext(evaluator, module, '')
parent_context = ModuleContext(
evaluator, module, None,
code_lines=parso.split_lines(code),
)
return ContextSet(ClassContext(evaluator, parent_context, generated_class))
+5 -1
View File
@@ -5,6 +5,7 @@ from jedi.evaluate.cache import evaluator_method_cache
from jedi.evaluate.base_context import ContextualizedNode
from jedi.evaluate.helpers import is_string
from jedi.common.utils import traverse_parents
from jedi.parser_utils import get_cached_code_lines
from jedi import settings
from jedi import debug
@@ -150,7 +151,10 @@ def _get_paths_from_buildout_script(evaluator, buildout_script_path):
return
from jedi.evaluate.context import ModuleContext
module = ModuleContext(evaluator, module_node, buildout_script_path)
module = ModuleContext(
evaluator, module_node, buildout_script_path,
code_lines=get_cached_code_lines(evaluator.grammar, buildout_script_path),
)
for path in check_sys_path_modifications(module):
yield path