1
0
forked from VimPlug/jedi

Start using FileIO in modules

This commit is contained in:
Dave Halter
2019-05-31 22:10:43 +02:00
parent 9c40c75136
commit b9e8bff5e2
9 changed files with 56 additions and 41 deletions

View File

@@ -21,6 +21,7 @@ from jedi.parser_utils import get_executable_nodes
from jedi import debug from jedi import debug
from jedi import settings from jedi import settings
from jedi import cache from jedi import cache
from jedi.file_io import KnownContentFileIO
from jedi.api import classes from jedi.api import classes
from jedi.api import interpreter from jedi.api import interpreter
from jedi.api import helpers from jedi.api import helpers
@@ -38,8 +39,7 @@ from jedi.evaluate.syntax_tree import tree_name_to_contexts
from jedi.evaluate.context import ModuleContext from jedi.evaluate.context import ModuleContext
from jedi.evaluate.base_context import ContextSet from jedi.evaluate.base_context import ContextSet
from jedi.evaluate.context.iterable import unpack_tuple_to_dict from jedi.evaluate.context.iterable import unpack_tuple_to_dict
from jedi.evaluate.gradual.conversion import try_stubs_to_actual_context_set, \ from jedi.evaluate.gradual.conversion import try_stub_to_actual_names
try_stub_to_actual_names
from jedi.evaluate.gradual.utils import load_proper_stub_module from jedi.evaluate.gradual.utils import load_proper_stub_module
# Jedi uses lots and lots of recursion. By setting this a little bit higher, we # Jedi uses lots and lots of recursion. By setting this a little bit higher, we
@@ -164,11 +164,12 @@ class Script(object):
names = import_names names = import_names
is_package = is_p is_package = is_p
file_io = KnownContentFileIO(cast_path(self.path), self._code)
if self.path is not None and self.path.endswith('.pyi'): if self.path is not None and self.path.endswith('.pyi'):
# We are in a stub file. Try to load the stub properly. # We are in a stub file. Try to load the stub properly.
stub_module = load_proper_stub_module( stub_module = load_proper_stub_module(
self._evaluator, self._evaluator,
cast_path(self.path), file_io,
names, names,
self._module_node self._module_node
) )
@@ -179,14 +180,11 @@ class Script(object):
names = ('__main__',) names = ('__main__',)
module = ModuleContext( module = ModuleContext(
self._evaluator, self._module_node, cast_path(self.path), self._evaluator, self._module_node, file_io,
string_names=names, string_names=names,
code_lines=self._code_lines, code_lines=self._code_lines,
is_package=is_package, is_package=is_package,
) )
#module, = try_to_merge_with_stub(
# self._evaluator, None, module.string_names, ContextSet([module])
#)
if names[0] not in ('builtins', '__builtin__', 'typing'): if names[0] not in ('builtins', '__builtin__', 'typing'):
# These modules are essential for Jedi, so don't overwrite them. # These modules are essential for Jedi, so don't overwrite them.
self._evaluator.module_cache.add(names, ContextSet([module])) self._evaluator.module_cache.add(names, ContextSet([module]))
@@ -469,7 +467,7 @@ class Interpreter(Script):
self._evaluator, self._evaluator,
self._module_node, self._module_node,
self.namespaces, self.namespaces,
path=self.path, file_io=KnownContentFileIO(self.path, self._code),
code_lines=self._code_lines, code_lines=self._code_lines,
) )

View File

@@ -24,14 +24,14 @@ class MixedModuleContext(Context):
# TODO use ContextWrapper! # TODO use ContextWrapper!
type = 'mixed_module' type = 'mixed_module'
def __init__(self, evaluator, tree_module, namespaces, path, code_lines): def __init__(self, evaluator, tree_module, namespaces, file_io, code_lines):
self.evaluator = evaluator self.evaluator = evaluator
self._namespaces = namespaces self._namespaces = namespaces
self._namespace_objects = [NamespaceObject(n) for n in namespaces] self._namespace_objects = [NamespaceObject(n) for n in namespaces]
self._module_context = ModuleContext( self._module_context = ModuleContext(
evaluator, tree_module, evaluator, tree_module,
path=path, file_io=file_io,
string_names=('__main__',), string_names=('__main__',),
code_lines=code_lines code_lines=code_lines
) )

View File

@@ -11,6 +11,7 @@ from jedi import settings
from jedi.evaluate import compiled from jedi.evaluate import compiled
from jedi.cache import underscore_memoization from jedi.cache import underscore_memoization
from jedi.evaluate import imports from jedi.evaluate import imports
from jedi.file_io import FileIO
from jedi.evaluate.base_context import Context, ContextSet from jedi.evaluate.base_context import Context, ContextSet
from jedi.evaluate.context import ModuleContext from jedi.evaluate.context import ModuleContext
from jedi.evaluate.cache import evaluator_function_cache from jedi.evaluate.cache import evaluator_function_cache
@@ -140,6 +141,7 @@ def _find_syntax_node_name(evaluator, access_handle):
# The path might not exist or be e.g. <stdin>. # The path might not exist or be e.g. <stdin>.
return None return None
file_io = FileIO(path)
module_node = _load_module(evaluator, path) module_node = _load_module(evaluator, path)
if inspect.ismodule(python_object): if inspect.ismodule(python_object):
@@ -147,7 +149,7 @@ def _find_syntax_node_name(evaluator, access_handle):
# a way to write a module in a module in Python (and also __name__ can # a way to write a module in a module in Python (and also __name__ can
# be something like ``email.utils``). # be something like ``email.utils``).
code_lines = get_cached_code_lines(evaluator.grammar, path) code_lines = get_cached_code_lines(evaluator.grammar, path)
return module_node, module_node, path, code_lines return module_node, module_node, file_io, code_lines
try: try:
name_str = python_object.__name__ name_str = python_object.__name__
@@ -186,7 +188,7 @@ def _find_syntax_node_name(evaluator, access_handle):
# completions at some points but will lead to mostly correct type # completions at some points but will lead to mostly correct type
# inference, because people tend to define a public name in a module only # inference, because people tend to define a public name in a module only
# once. # once.
return module_node, names[-1].parent, path, code_lines return module_node, names[-1].parent, file_io, code_lines
@compiled_objects_cache('mixed_cache') @compiled_objects_cache('mixed_cache')
@@ -198,7 +200,7 @@ def _create(evaluator, access_handle, parent_context, *args):
if result is None: if result is None:
return compiled_object return compiled_object
module_node, tree_node, path, code_lines = result module_node, tree_node, file_io, code_lines = result
if parent_context.tree_node.get_root_node() == module_node: if parent_context.tree_node.get_root_node() == module_node:
module_context = parent_context.get_root_context() module_context = parent_context.get_root_context()
@@ -208,7 +210,7 @@ def _create(evaluator, access_handle, parent_context, *args):
string_names = tuple(name.split('.')) string_names = tuple(name.split('.'))
module_context = ModuleContext( module_context = ModuleContext(
evaluator, module_node, evaluator, module_node,
path=path, file_io=file_io,
string_names=string_names, string_names=string_names,
code_lines=code_lines, code_lines=code_lines,
is_package=hasattr(compiled_object, 'py__path__'), is_package=hasattr(compiled_object, 'py__path__'),

View File

@@ -173,13 +173,17 @@ class ModuleContext(ModuleMixin, TreeContext):
api_type = u'module' api_type = u'module'
parent_context = None parent_context = None
def __init__(self, evaluator, module_node, path, string_names, code_lines, is_package=False): def __init__(self, evaluator, module_node, file_io, string_names, code_lines, is_package=False):
super(ModuleContext, self).__init__( super(ModuleContext, self).__init__(
evaluator, evaluator,
parent_context=None, parent_context=None,
tree_node=module_node tree_node=module_node
) )
self._path = path self._file_io = file_io
if self._file_io is None:
self._path = None
else:
self._path = file_io.path
self.string_names = string_names self.string_names = string_names
self.code_lines = code_lines self.code_lines = code_lines
self.is_package = is_package self.is_package = is_package

View File

@@ -4,7 +4,6 @@ import re
from jedi.file_io import FileIO from jedi.file_io import FileIO
from jedi._compatibility import FileNotFoundError, cast_path from jedi._compatibility import FileNotFoundError, cast_path
from jedi.parser_utils import get_cached_code_lines from jedi.parser_utils import get_cached_code_lines
from jedi.evaluate.cache import evaluator_function_cache
from jedi.evaluate.base_context import ContextSet from jedi.evaluate.base_context import ContextSet
from jedi.evaluate.gradual.stub_context import TypingModuleWrapper, StubModuleContext from jedi.evaluate.gradual.stub_context import TypingModuleWrapper, StubModuleContext
@@ -62,11 +61,6 @@ def _get_typeshed_directories(version_info):
yield os.path.join(base, check_version) yield os.path.join(base, check_version)
@evaluator_function_cache()
def _load_stub(evaluator, path):
return evaluator.parse(file_io=FileIO(path), cache=True, use_latest_grammar=True)
_version_cache = {} _version_cache = {}
@@ -149,7 +143,12 @@ def _try_to_load_stub(evaluator, import_names, actual_context_set,
# foo-stubs # foo-stubs
for p in sys_path: for p in sys_path:
init = os.path.join(p, *import_names) + '-stubs' + os.path.sep + '__init__.pyi' init = os.path.join(p, *import_names) + '-stubs' + os.path.sep + '__init__.pyi'
m = _try_to_load_stub_from_file(evaluator, actual_context_set, init, import_names) m = _try_to_load_stub_from_file(
evaluator,
actual_context_set,
file_io=FileIO(init),
import_names=import_names,
)
if m is not None: if m is not None:
return m return m
@@ -172,8 +171,8 @@ def _try_to_load_stub(evaluator, import_names, actual_context_set,
evaluator, evaluator,
actual_context_set, actual_context_set,
# The file path should end with .pyi # The file path should end with .pyi
file_path, file_io=FileIO(file_path),
import_names import_names=import_names,
) )
if m is not None: if m is not None:
return m return m
@@ -202,8 +201,8 @@ def _try_to_load_stub(evaluator, import_names, actual_context_set,
m = _try_to_load_stub_from_file( m = _try_to_load_stub_from_file(
evaluator, evaluator,
actual_context_set, actual_context_set,
os.path.join(p, *names_for_path) + '.pyi', file_io=FileIO(os.path.join(p, *names_for_path) + '.pyi'),
import_names, import_names=import_names,
) )
if m is not None: if m is not None:
return m return m
@@ -229,35 +228,44 @@ def _load_from_typeshed(evaluator, actual_context_set, parent_module_context, im
if map_ is not None: if map_ is not None:
path = map_.get(import_name) path = map_.get(import_name)
if path is not None: if path is not None:
return _try_to_load_stub_from_file(evaluator, actual_context_set, path, import_names) return _try_to_load_stub_from_file(
evaluator,
actual_context_set,
file_io=FileIO(path),
import_names=import_names,
)
def _try_to_load_stub_from_file(evaluator, actual_context_set, path, import_names): def _try_to_load_stub_from_file(evaluator, actual_context_set, file_io, import_names):
try: try:
stub_module_node = _load_stub(evaluator, path) stub_module_node = evaluator.parse(
file_io=file_io,
cache=True,
use_latest_grammar=True
)
except (OSError, IOError): # IOError is Python 2 only except (OSError, IOError): # IOError is Python 2 only
# The file that you're looking for doesn't exist (anymore). # The file that you're looking for doesn't exist (anymore).
return None return None
else: else:
return create_stub_module( return create_stub_module(
evaluator, actual_context_set, stub_module_node, path, evaluator, actual_context_set, stub_module_node, file_io,
import_names import_names
) )
def create_stub_module(evaluator, actual_context_set, stub_module_node, path, import_names): def create_stub_module(evaluator, actual_context_set, stub_module_node, file_io, import_names):
if import_names == ('typing',): if import_names == ('typing',):
module_cls = TypingModuleWrapper module_cls = TypingModuleWrapper
else: else:
module_cls = StubModuleContext module_cls = StubModuleContext
file_name = os.path.basename(path) file_name = os.path.basename(file_io.path)
stub_module_context = module_cls( stub_module_context = module_cls(
actual_context_set, evaluator, stub_module_node, actual_context_set, evaluator, stub_module_node,
path=path, file_io=file_io,
string_names=import_names, string_names=import_names,
# The code was loaded with latest_grammar, so use # The code was loaded with latest_grammar, so use
# that. # that.
code_lines=get_cached_code_lines(evaluator.latest_grammar, path), code_lines=get_cached_code_lines(evaluator.latest_grammar, file_io.path),
is_package=file_name == '__init__.pyi', is_package=file_name == '__init__.pyi',
) )
return stub_module_context return stub_module_context

View File

@@ -3,11 +3,12 @@ import os
from jedi.evaluate.gradual.typeshed import TYPESHED_PATH, create_stub_module from jedi.evaluate.gradual.typeshed import TYPESHED_PATH, create_stub_module
def load_proper_stub_module(evaluator, path, import_names, module_node): def load_proper_stub_module(evaluator, file_io, import_names, module_node):
""" """
This function is given a random .pyi file and should return the proper This function is given a random .pyi file and should return the proper
module. module.
""" """
path = file_io.path
assert path.endswith('.pyi') assert path.endswith('.pyi')
if path.startswith(TYPESHED_PATH): if path.startswith(TYPESHED_PATH):
# /foo/stdlib/3/os/__init__.pyi -> stdlib/3/os/__init__ # /foo/stdlib/3/os/__init__.pyi -> stdlib/3/os/__init__
@@ -24,7 +25,7 @@ def load_proper_stub_module(evaluator, path, import_names, module_node):
return None return None
stub = create_stub_module( stub = create_stub_module(
evaluator, actual_context_set, module_node, path, import_names evaluator, actual_context_set, module_node, file_io, import_names
) )
evaluator.stub_module_cache[import_names] = stub evaluator.stub_module_cache[import_names] = stub
return stub return stub

View File

@@ -464,7 +464,7 @@ def _load_python_module(evaluator, file_io, sys_path=None,
from jedi.evaluate.context import ModuleContext from jedi.evaluate.context import ModuleContext
return ModuleContext( return ModuleContext(
evaluator, module_node, evaluator, module_node,
path=file_io.path, file_io=file_io,
string_names=import_names, string_names=import_names,
code_lines=get_cached_code_lines(evaluator.grammar, file_io.path), code_lines=get_cached_code_lines(evaluator.grammar, file_io.path),
is_package=is_package, is_package=is_package,

View File

@@ -6,6 +6,7 @@ from jedi.evaluate.base_context import ContextualizedNode
from jedi.evaluate.helpers import is_string from jedi.evaluate.helpers import is_string
from jedi.common.utils import traverse_parents from jedi.common.utils import traverse_parents
from jedi.parser_utils import get_cached_code_lines from jedi.parser_utils import get_cached_code_lines
from jedi.file_io import FileIO
from jedi import settings from jedi import settings
from jedi import debug from jedi import debug
@@ -140,9 +141,10 @@ def discover_buildout_paths(evaluator, script_path):
def _get_paths_from_buildout_script(evaluator, buildout_script_path): def _get_paths_from_buildout_script(evaluator, buildout_script_path):
file_io = FileIO(buildout_script_path)
try: try:
module_node = evaluator.parse( module_node = evaluator.parse(
path=buildout_script_path, file_io=file_io,
cache=True, cache=True,
cache_path=settings.cache_directory cache_path=settings.cache_directory
) )
@@ -152,7 +154,7 @@ def _get_paths_from_buildout_script(evaluator, buildout_script_path):
from jedi.evaluate.context import ModuleContext from jedi.evaluate.context import ModuleContext
module = ModuleContext( module = ModuleContext(
evaluator, module_node, buildout_script_path, evaluator, module_node, file_io,
string_names=None, string_names=None,
code_lines=get_cached_code_lines(evaluator.grammar, buildout_script_path), code_lines=get_cached_code_lines(evaluator.grammar, buildout_script_path),
) )

View File

@@ -437,7 +437,7 @@ def collections_namedtuple(obj, arguments):
generated_class = next(module.iter_classdefs()) generated_class = next(module.iter_classdefs())
parent_context = ModuleContext( parent_context = ModuleContext(
evaluator, module, evaluator, module,
path=None, file_io=None,
string_names=None, string_names=None,
code_lines=parso.split_lines(code, keepends=True), code_lines=parso.split_lines(code, keepends=True),
) )