forked from VimPlug/jedi
Make it possible to connect to a subprocess to get the sys path
This commit is contained in:
@@ -24,6 +24,7 @@ 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
|
||||||
from jedi.api.completion import Completion
|
from jedi.api.completion import Completion
|
||||||
|
from jedi.api.virtualenv import DefaultEnvironment
|
||||||
from jedi.evaluate import Evaluator
|
from jedi.evaluate import Evaluator
|
||||||
from jedi.evaluate import imports
|
from jedi.evaluate import imports
|
||||||
from jedi.evaluate import usages
|
from jedi.evaluate import usages
|
||||||
@@ -117,22 +118,15 @@ class Script(object):
|
|||||||
project = Project(sys_path=sys_path)
|
project = Project(sys_path=sys_path)
|
||||||
if isinstance(self, Interpreter):
|
if isinstance(self, Interpreter):
|
||||||
# It's not possible to use a subprocess for the interpreter.
|
# It's not possible to use a subprocess for the interpreter.
|
||||||
self._compiled_subprocess = None
|
compiled_subprocess = None
|
||||||
else:
|
else:
|
||||||
if environment is None:
|
if environment is None:
|
||||||
executable = sys.executable
|
environment = DefaultEnvironment()
|
||||||
else:
|
compiled_subprocess = environment.get_subprocess()
|
||||||
executable = environment.executable
|
self._evaluator = Evaluator(self._grammar, project, compiled_subprocess)
|
||||||
self._compiled_subprocess = get_subprocess(executable)
|
|
||||||
self._evaluator = Evaluator(self._grammar, project, self._compiled_subprocess)
|
|
||||||
project.add_script_path(self.path)
|
project.add_script_path(self.path)
|
||||||
debug.speed('init')
|
debug.speed('init')
|
||||||
|
|
||||||
def __del__(self):
|
|
||||||
if self._compiled_subprocess is not None:
|
|
||||||
self._compiled_subprocess.delete_evaluator(evaluator)
|
|
||||||
self._evaluator.cleanup_evaluator
|
|
||||||
|
|
||||||
@cache.memoize_method
|
@cache.memoize_method
|
||||||
def _get_module_node(self):
|
def _get_module_node(self):
|
||||||
return self._grammar.parse(
|
return self._grammar.parse(
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
import sys
|
||||||
import sysconfig
|
import sysconfig
|
||||||
from subprocess import CalledProcessError
|
from subprocess import CalledProcessError
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
@@ -7,7 +8,7 @@ from collections import namedtuple
|
|||||||
from jedi._compatibility import check_output
|
from jedi._compatibility import check_output
|
||||||
from jedi.evaluate.project import Project
|
from jedi.evaluate.project import Project
|
||||||
from jedi.cache import memoize_method
|
from jedi.cache import memoize_method
|
||||||
|
from jedi.evaluate.compiled.subprocess import get_subprocess
|
||||||
|
|
||||||
_VersionInfo = namedtuple('VersionInfo', 'major minor micro')
|
_VersionInfo = namedtuple('VersionInfo', 'major minor micro')
|
||||||
|
|
||||||
@@ -28,6 +29,10 @@ class Environment(object):
|
|||||||
def get_project(self):
|
def get_project(self):
|
||||||
return Project(self.get_sys_path())
|
return Project(self.get_sys_path())
|
||||||
|
|
||||||
|
def get_subprocess(self):
|
||||||
|
return get_subprocess(self._executable)
|
||||||
|
|
||||||
|
@memoize_method
|
||||||
def get_sys_path(self):
|
def get_sys_path(self):
|
||||||
vars = {
|
vars = {
|
||||||
'base': self._path
|
'base': self._path
|
||||||
@@ -38,35 +43,15 @@ class Environment(object):
|
|||||||
# on how the Python version was compiled (ENV variables).
|
# on how the Python version was compiled (ENV variables).
|
||||||
# If you omit -S when starting Python (normal case), additionally
|
# If you omit -S when starting Python (normal case), additionally
|
||||||
# site.py gets executed.
|
# site.py gets executed.
|
||||||
write
|
|
||||||
|
|
||||||
# venv
|
return self.get_subprocess().get_sys_path()
|
||||||
['', '/usr/lib/python3.3', '/usr/lib/python3.3/plat-x86_64-linux-gnu',
|
|
||||||
'/usr/lib/python3.3/lib-dynload',
|
|
||||||
'/home/dave/source/python/virtenv/venv3.3/lib/python3.3/site-packages']
|
|
||||||
|
|
||||||
['/usr/lib/python3.4', '/usr/lib/python3.4/plat-x86_64-linux-gnu',
|
|
||||||
'/usr/lib/python3.4/lib-dynload',
|
|
||||||
'/home/dave/source/stuff_cloudscale/rgw-metrics/venv/lib/python3.4/site-packages']
|
|
||||||
|
|
||||||
['', '/usr/lib/python35.zip', '/usr/lib/python3.5',
|
|
||||||
'/usr/lib/python3.5/plat-x86_64-linux-gnu',
|
|
||||||
'/usr/lib/python3.5/lib-dynload',
|
|
||||||
'/home/dave/source/python/virtenv/venv3.5/lib/python3.5/site-packages']
|
|
||||||
|
|
||||||
|
|
||||||
{'purelib': '{base}/local/lib/python{py_version_short}/dist-packages',
|
class DefaultEnvironment(Environment):
|
||||||
'stdlib': '{base}/lib/python{py_version_short}',
|
def __init__(self, script_path):
|
||||||
'scripts': '{base}/local/bin',
|
# TODO make this usable
|
||||||
'platinclude': '{platbase}/local/include/python{py_version_short}',
|
path = script_path
|
||||||
'include': '{base}/local/include/python{py_version_short}',
|
super(DefaultEnvironment, self).__init__(path, sys.executable)
|
||||||
'data': '{base}/local',
|
|
||||||
'platstdlib': '{platbase}/lib/python{py_version_short}',
|
|
||||||
'platlib': '{platbase}/local/lib/python{py_version_short}/dist-packages'}
|
|
||||||
return [] + additional_paths
|
|
||||||
|
|
||||||
def _get_long_running_process(self):
|
|
||||||
return process
|
|
||||||
|
|
||||||
|
|
||||||
def find_virtualenvs(paths=None):
|
def find_virtualenvs(paths=None):
|
||||||
@@ -95,11 +80,11 @@ def _get_executable_path(path):
|
|||||||
|
|
||||||
def _get_version(executable):
|
def _get_version(executable):
|
||||||
try:
|
try:
|
||||||
output = check_output(executable, '--version')
|
output = check_output([executable, '--version'])
|
||||||
except (CalledProcessError, OSError):
|
except (CalledProcessError, OSError):
|
||||||
raise NoVirtualEnv()
|
raise NoVirtualEnv()
|
||||||
|
|
||||||
match = re.match(r'Python (\d+)\.(\d+)\.(\d+)', output)
|
match = re.match(rb'Python (\d+)\.(\d+)\.(\d+)', output)
|
||||||
if match is None:
|
if match is None:
|
||||||
raise NoVirtualEnv()
|
raise NoVirtualEnv()
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import pickle
|
|||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
from jedi.cache import memoize_method
|
from jedi.cache import memoize_method
|
||||||
from jedi.evaluate.compiled.subprocess import commands
|
from jedi.evaluate.compiled.subprocess import functions
|
||||||
|
|
||||||
_PICKLE_PROTOCOL = 2
|
_PICKLE_PROTOCOL = 2
|
||||||
|
|
||||||
@@ -29,6 +29,11 @@ def get_subprocess(executable):
|
|||||||
return sub
|
return sub
|
||||||
|
|
||||||
|
|
||||||
|
def _get_function(evaluator, name):
|
||||||
|
function = getattr(functions, name)
|
||||||
|
return partial(function, evaluator)
|
||||||
|
|
||||||
|
|
||||||
class EvaluatorSameProcess(object):
|
class EvaluatorSameProcess(object):
|
||||||
"""
|
"""
|
||||||
Basically just an easy access to functions.py. It has the same API
|
Basically just an easy access to functions.py. It has the same API
|
||||||
@@ -38,9 +43,8 @@ class EvaluatorSameProcess(object):
|
|||||||
def __init__(self, evaluator):
|
def __init__(self, evaluator):
|
||||||
self._evaluator = evaluator
|
self._evaluator = evaluator
|
||||||
|
|
||||||
def __getattr__(self):
|
def __getattr__(self, name):
|
||||||
function = getattr(commands, name)
|
return _get_function(self._evaluator, name)
|
||||||
return partial(function, self._evaluator)
|
|
||||||
|
|
||||||
|
|
||||||
class EvaluatorSubprocess(object):
|
class EvaluatorSubprocess(object):
|
||||||
@@ -50,11 +54,10 @@ class EvaluatorSubprocess(object):
|
|||||||
self._compiled_subprocess = compiled_subprocess
|
self._compiled_subprocess = compiled_subprocess
|
||||||
|
|
||||||
def __getattr__(self, name):
|
def __getattr__(self, name):
|
||||||
function = getattr(commands, name)
|
return _get_function(self._evaluator_weakref(), name)
|
||||||
return partial(function, self._evaluator_weakref())
|
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
self.delete_evaluator(self._evaluator_weakref()
|
self.delete_evaluator(self._evaluator_weakref())
|
||||||
|
|
||||||
|
|
||||||
class _Subprocess(object):
|
class _Subprocess(object):
|
||||||
@@ -93,6 +96,9 @@ class _CompiledSubprocess(_Subprocess):
|
|||||||
assert callable(function)
|
assert callable(function)
|
||||||
return self._send(id(evaluator), function, args, kwargs)
|
return self._send(id(evaluator), function, args, kwargs)
|
||||||
|
|
||||||
|
def get_sys_path(self):
|
||||||
|
return self._send(None, functions.get_sys_path, (), {})
|
||||||
|
|
||||||
def delete_evaluator(self, evaluator_id):
|
def delete_evaluator(self, evaluator_id):
|
||||||
# With an argument - the evaluator gets deleted.
|
# With an argument - the evaluator gets deleted.
|
||||||
self._send(evaluator_id, None)
|
self._send(evaluator_id, None)
|
||||||
@@ -102,7 +108,7 @@ class Listener():
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._evaluators = {}
|
self._evaluators = {}
|
||||||
|
|
||||||
def _run(self, evaluator_id, function, args, kwargs):
|
def _get_evaluator(self, function, evaluator_id):
|
||||||
from jedi.evaluate import Evaluator
|
from jedi.evaluate import Evaluator
|
||||||
|
|
||||||
if function is None:
|
if function is None:
|
||||||
@@ -116,8 +122,14 @@ class Listener():
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
evaluator = Evaluator(None, None)
|
evaluator = Evaluator(None, None)
|
||||||
self.evaluators[evaluator_id] = evaluator
|
self.evaluators[evaluator_id] = evaluator
|
||||||
|
return evaluator
|
||||||
|
|
||||||
return function(evaluator, *args, **kwargs)
|
def _run(self, evaluator_id, function, args, kwargs):
|
||||||
|
if evaluator_id is None:
|
||||||
|
return function(*args, **kwargs)
|
||||||
|
else:
|
||||||
|
evaluator = self._get_evaluator(evaluator_id)
|
||||||
|
return function(evaluator, *args, **kwargs)
|
||||||
|
|
||||||
def listen(self):
|
def listen(self):
|
||||||
stdout = sys.stdout
|
stdout = sys.stdout
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
from jedi.evaluate.compiled import subprocess
|
from jedi.evaluate.compiled import subprocess
|
||||||
|
|
||||||
subprocess.listen()
|
subprocess.Listener().listen()
|
||||||
|
|||||||
5
jedi/evaluate/compiled/subprocess/functions.py
Normal file
5
jedi/evaluate/compiled/subprocess/functions.py
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def get_sys_path():
|
||||||
|
return sys.path
|
||||||
@@ -3,12 +3,10 @@ import sys
|
|||||||
|
|
||||||
from jedi.evaluate.sys_path import get_venv_path, detect_additional_paths
|
from jedi.evaluate.sys_path import get_venv_path, detect_additional_paths
|
||||||
from jedi.cache import memoize_method
|
from jedi.cache import memoize_method
|
||||||
from jedi.evaluate.compiled.subprocess import CompiledSubProcess
|
|
||||||
|
|
||||||
|
|
||||||
class Project(object):
|
class Project(object):
|
||||||
def __init__(self, sys_path=None):
|
def __init__(self, sys_path=None):
|
||||||
self._compiled_subprocess = CompiledSubProcess()
|
|
||||||
if sys_path is not None:
|
if sys_path is not None:
|
||||||
self._sys_path = sys_path
|
self._sys_path = sys_path
|
||||||
|
|
||||||
|
|||||||
5
test/test_api/test_environment.py
Normal file
5
test/test_api/test_environment.py
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
from jedi.api.virtualenv import Environment, DefaultEnvironment
|
||||||
|
|
||||||
|
|
||||||
|
def test_sys_path():
|
||||||
|
assert DefaultEnvironment('/foo').get_sys_path()
|
||||||
Reference in New Issue
Block a user