diff --git a/jedi/__init__.py b/jedi/__init__.py index 3526e370..2eebb4fc 100644 --- a/jedi/__init__.py +++ b/jedi/__init__.py @@ -41,4 +41,4 @@ __version__ = '0.11.0' from jedi.api import Script, Interpreter, set_debug_function, \ preload_module, names from jedi import settings -from jedi.api.environment import find_virtualenvs, create_environment +from jedi.api.environment import find_virtualenvs, find_python_environments diff --git a/jedi/api/__init__.py b/jedi/api/__init__.py index e2919dfc..44c4e1e5 100644 --- a/jedi/api/__init__.py +++ b/jedi/api/__init__.py @@ -24,7 +24,7 @@ from jedi.api import classes from jedi.api import interpreter from jedi.api import helpers from jedi.api.completion import Completion -from jedi.api.environment import get_default_environment +from jedi.api.environment import InterpreterEnvironment from jedi.evaluate import Evaluator from jedi.evaluate import imports from jedi.evaluate import usages @@ -115,14 +115,7 @@ class Script(object): # Load the Python grammar of the current interpreter. self._grammar = parso.load_grammar() project = Project(sys_path=sys_path) - if isinstance(self, Interpreter): - # It's not possible to use a subprocess for the interpreter. - compiled_subprocess = None - else: - if environment is None: - environment = get_default_environment() - compiled_subprocess = environment.get_subprocess() - self._evaluator = Evaluator(self._grammar, project, compiled_subprocess) + self._evaluator = Evaluator(self._grammar, project, environment) project.add_script_path(self.path) debug.speed('init') @@ -366,10 +359,14 @@ class Interpreter(Script): except Exception: raise TypeError("namespaces must be a non-empty list of dicts.") - if 'environment' in kwds: - raise TypeError("Environments are not allowed when using an interpreter.") + environment = kwds.get('environment', None) + if environment is None: + environment = InterpreterEnvironment() + else: + if not isinstance(environment, InterpreterEnvironment): + raise TypeError("The environment needs to be an InterpreterEnvironment subclass.") - super(Interpreter, self).__init__(source, **kwds) + super(Interpreter, self).__init__(source, environment=environment, **kwds) self.namespaces = namespaces def _get_module(self): diff --git a/jedi/api/environment.py b/jedi/api/environment.py index 93d957fb..d01ba1f4 100644 --- a/jedi/api/environment.py +++ b/jedi/api/environment.py @@ -9,7 +9,8 @@ from distutils.spawn import find_executable from jedi.evaluate.project import Project from jedi.cache import memoize_method -from jedi.evaluate.compiled.subprocess import get_subprocess +from jedi.evaluate.compiled.subprocess import get_subprocess, \ + EvaluatorSameProcess, EvaluatorSubprocess import parso @@ -22,7 +23,17 @@ class InvalidPythonEnvironment(Exception): pass -class Environment(object): +class _BaseEnvironment(object): + def get_project(self): + return Project(self.get_sys_path()) + + @memoize_method + def get_parser(self): + version_string = '%s.%s' % (self.version_info.major, self.version_info.minor) + return parso.load_grammar(version=version_string) + + +class Environment(_BaseEnvironment): def __init__(self, path, executable): self._base_path = path self._executable = executable @@ -31,17 +42,12 @@ class Environment(object): def __repr__(self): return '<%s: %s>' % (self.__class__.__name__, self._base_path) - def get_project(self): - return Project(self.get_sys_path()) + def get_evaluator_subprocess(self, evaluator): + return EvaluatorSubprocess(evaluator, self._get_subprocess()) - def get_subprocess(self): + def _get_subprocess(self): return get_subprocess(self._executable) - @memoize_method - def get_parser(self): - version_string = '%s.%s' % (self.version_info.major, self.version_info.minor) - return parso.load_grammar(version=version_string) - @memoize_method def get_sys_path(self): # It's pretty much impossible to generate the sys path without actually @@ -49,7 +55,18 @@ class Environment(object): # on how the Python version was compiled (ENV variables). # If you omit -S when starting Python (normal case), additionally # site.py gets executed. - return self.get_subprocess().get_sys_path() + return self._get_subprocess().get_sys_path() + + +class InterpreterEnvironment(_BaseEnvironment): + def __init__(self): + self.version_info = _VersionInfo(*sys.version_info[:3]) + + def get_evaluator_subprocess(self, evaluator): + return EvaluatorSameProcess(evaluator) + + def get_sys_path(self): + return sys.sys_path def get_default_environment(): diff --git a/jedi/evaluate/__init__.py b/jedi/evaluate/__init__.py index 939d5fde..33d88f34 100644 --- a/jedi/evaluate/__init__.py +++ b/jedi/evaluate/__init__.py @@ -69,6 +69,7 @@ import parso from jedi import debug from jedi import parser_utils +from jedi.api.environment import get_default_environment from jedi.evaluate.utils import unite from jedi.evaluate import imports from jedi.evaluate import recursion @@ -83,11 +84,10 @@ from jedi.evaluate.context import ClassContext, FunctionContext, \ from jedi.evaluate.context.iterable import CompForContext from jedi.evaluate.syntax_tree import eval_trailer, eval_expr_stmt, \ eval_node, check_tuple_assignments -from jedi.evaluate.compiled.subprocess import EvaluatorSubprocess, EvaluatorSameProcess class Evaluator(object): - def __init__(self, grammar, project, compiled_sub_process=None): + def __init__(self, grammar, project, environment=None): self.grammar = grammar self.latest_grammar = parso.load_grammar(version='3.6') self.memoize_cache = {} # for memoize decorators @@ -104,10 +104,10 @@ class Evaluator(object): self.access_cache = {} project.add_evaluator(self) - if compiled_sub_process is None: - self.compiled_subprocess = EvaluatorSameProcess(self) - else: - self.compiled_subprocess = EvaluatorSubprocess(self, compiled_sub_process) + if environment is None: + environment = get_default_environment() + self.environment = environment + self.compiled_subprocess = environment.get_evaluator_subprocess(self) self.reset_recursion_limitations() diff --git a/jedi/evaluate/compiled/subprocess/__init__.py b/jedi/evaluate/compiled/subprocess/__init__.py index 37e3f250..9e0e4da1 100644 --- a/jedi/evaluate/compiled/subprocess/__init__.py +++ b/jedi/evaluate/compiled/subprocess/__init__.py @@ -201,7 +201,12 @@ class Listener(object): try: evaluator = self._evaluators[evaluator_id] except KeyError: - evaluator = Evaluator(None, project=project.Project()) + from jedi.api.environment import InterpreterEnvironment + evaluator = Evaluator( + grammar=None, + project=project.Project(), + environment=InterpreterEnvironment() + ) self._evaluators[evaluator_id] = evaluator return evaluator