mirror of
https://github.com/davidhalter/jedi.git
synced 2025-12-09 23:34:45 +08:00
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 helpers
|
||||
from jedi.api.completion import Completion
|
||||
from jedi.api.virtualenv import DefaultEnvironment
|
||||
from jedi.evaluate import Evaluator
|
||||
from jedi.evaluate import imports
|
||||
from jedi.evaluate import usages
|
||||
@@ -117,22 +118,15 @@ class Script(object):
|
||||
project = Project(sys_path=sys_path)
|
||||
if isinstance(self, Interpreter):
|
||||
# It's not possible to use a subprocess for the interpreter.
|
||||
self._compiled_subprocess = None
|
||||
compiled_subprocess = None
|
||||
else:
|
||||
if environment is None:
|
||||
executable = sys.executable
|
||||
else:
|
||||
executable = environment.executable
|
||||
self._compiled_subprocess = get_subprocess(executable)
|
||||
self._evaluator = Evaluator(self._grammar, project, self._compiled_subprocess)
|
||||
environment = DefaultEnvironment()
|
||||
compiled_subprocess = environment.get_subprocess()
|
||||
self._evaluator = Evaluator(self._grammar, project, compiled_subprocess)
|
||||
project.add_script_path(self.path)
|
||||
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
|
||||
def _get_module_node(self):
|
||||
return self._grammar.parse(
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import sysconfig
|
||||
from subprocess import CalledProcessError
|
||||
from collections import namedtuple
|
||||
@@ -7,7 +8,7 @@ from collections import namedtuple
|
||||
from jedi._compatibility import check_output
|
||||
from jedi.evaluate.project import Project
|
||||
from jedi.cache import memoize_method
|
||||
|
||||
from jedi.evaluate.compiled.subprocess import get_subprocess
|
||||
|
||||
_VersionInfo = namedtuple('VersionInfo', 'major minor micro')
|
||||
|
||||
@@ -28,6 +29,10 @@ class Environment(object):
|
||||
def get_project(self):
|
||||
return Project(self.get_sys_path())
|
||||
|
||||
def get_subprocess(self):
|
||||
return get_subprocess(self._executable)
|
||||
|
||||
@memoize_method
|
||||
def get_sys_path(self):
|
||||
vars = {
|
||||
'base': self._path
|
||||
@@ -38,35 +43,15 @@ 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.
|
||||
write
|
||||
|
||||
# venv
|
||||
['', '/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']
|
||||
return self.get_subprocess().get_sys_path()
|
||||
|
||||
|
||||
{'purelib': '{base}/local/lib/python{py_version_short}/dist-packages',
|
||||
'stdlib': '{base}/lib/python{py_version_short}',
|
||||
'scripts': '{base}/local/bin',
|
||||
'platinclude': '{platbase}/local/include/python{py_version_short}',
|
||||
'include': '{base}/local/include/python{py_version_short}',
|
||||
'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
|
||||
class DefaultEnvironment(Environment):
|
||||
def __init__(self, script_path):
|
||||
# TODO make this usable
|
||||
path = script_path
|
||||
super(DefaultEnvironment, self).__init__(path, sys.executable)
|
||||
|
||||
|
||||
def find_virtualenvs(paths=None):
|
||||
@@ -95,11 +80,11 @@ def _get_executable_path(path):
|
||||
|
||||
def _get_version(executable):
|
||||
try:
|
||||
output = check_output(executable, '--version')
|
||||
output = check_output([executable, '--version'])
|
||||
except (CalledProcessError, OSError):
|
||||
raise NoVirtualEnv()
|
||||
|
||||
match = re.match(r'Python (\d+)\.(\d+)\.(\d+)', output)
|
||||
match = re.match(rb'Python (\d+)\.(\d+)\.(\d+)', output)
|
||||
if match is None:
|
||||
raise NoVirtualEnv()
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import pickle
|
||||
from functools import partial
|
||||
|
||||
from jedi.cache import memoize_method
|
||||
from jedi.evaluate.compiled.subprocess import commands
|
||||
from jedi.evaluate.compiled.subprocess import functions
|
||||
|
||||
_PICKLE_PROTOCOL = 2
|
||||
|
||||
@@ -29,6 +29,11 @@ def get_subprocess(executable):
|
||||
return sub
|
||||
|
||||
|
||||
def _get_function(evaluator, name):
|
||||
function = getattr(functions, name)
|
||||
return partial(function, evaluator)
|
||||
|
||||
|
||||
class EvaluatorSameProcess(object):
|
||||
"""
|
||||
Basically just an easy access to functions.py. It has the same API
|
||||
@@ -38,9 +43,8 @@ class EvaluatorSameProcess(object):
|
||||
def __init__(self, evaluator):
|
||||
self._evaluator = evaluator
|
||||
|
||||
def __getattr__(self):
|
||||
function = getattr(commands, name)
|
||||
return partial(function, self._evaluator)
|
||||
def __getattr__(self, name):
|
||||
return _get_function(self._evaluator, name)
|
||||
|
||||
|
||||
class EvaluatorSubprocess(object):
|
||||
@@ -50,11 +54,10 @@ class EvaluatorSubprocess(object):
|
||||
self._compiled_subprocess = compiled_subprocess
|
||||
|
||||
def __getattr__(self, name):
|
||||
function = getattr(commands, name)
|
||||
return partial(function, self._evaluator_weakref())
|
||||
return _get_function(self._evaluator_weakref(), name)
|
||||
|
||||
def __del__(self):
|
||||
self.delete_evaluator(self._evaluator_weakref()
|
||||
self.delete_evaluator(self._evaluator_weakref())
|
||||
|
||||
|
||||
class _Subprocess(object):
|
||||
@@ -93,6 +96,9 @@ class _CompiledSubprocess(_Subprocess):
|
||||
assert callable(function)
|
||||
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):
|
||||
# With an argument - the evaluator gets deleted.
|
||||
self._send(evaluator_id, None)
|
||||
@@ -102,7 +108,7 @@ class Listener():
|
||||
def __init__(self):
|
||||
self._evaluators = {}
|
||||
|
||||
def _run(self, evaluator_id, function, args, kwargs):
|
||||
def _get_evaluator(self, function, evaluator_id):
|
||||
from jedi.evaluate import Evaluator
|
||||
|
||||
if function is None:
|
||||
@@ -116,7 +122,13 @@ class Listener():
|
||||
except KeyError:
|
||||
evaluator = Evaluator(None, None)
|
||||
self.evaluators[evaluator_id] = evaluator
|
||||
return evaluator
|
||||
|
||||
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):
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
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.cache import memoize_method
|
||||
from jedi.evaluate.compiled.subprocess import CompiledSubProcess
|
||||
|
||||
|
||||
class Project(object):
|
||||
def __init__(self, sys_path=None):
|
||||
self._compiled_subprocess = CompiledSubProcess()
|
||||
if sys_path is not None:
|
||||
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