1
0
forked from VimPlug/jedi

Create a way of accessing access objects through a subprocess

This commit is contained in:
Dave Halter
2017-12-06 14:18:10 +01:00
parent 34bd19ee8d
commit 7db6d11c49
4 changed files with 48 additions and 67 deletions

View File

@@ -114,9 +114,8 @@ def compiled_objects_cache(attribute_name):
return decorator return decorator
@compiled_objects_cache('compiled_cache')
def create_access(evaluator, obj): def create_access(evaluator, obj):
return DirectObjectAccess(evaluator, obj) return evaluator.compiled_subprocess.get_or_create_access_handle(obj)
def load_module(evaluator, path=None, name=None): def load_module(evaluator, path=None, name=None):
@@ -329,9 +328,10 @@ class DirectObjectAccess(object):
return list(reversed(list(get()))) return list(reversed(list(get())))
def execute_operation(self, other, operator): def execute_operation(self, other_access_handle, operator):
other_access = other_access_handle.access
op = _OPERATORS[operator] op = _OPERATORS[operator]
return self._create_access_path(op(self._obj, other._obj)) return self._create_access_path(op(self._obj, other_access._obj))
def needs_type_completions(self): def needs_type_completions(self):
return inspect.isclass(self._obj) and self._obj != type return inspect.isclass(self._obj) and self._obj != type

View File

@@ -16,7 +16,7 @@ from functools import partial
from jedi.cache import memoize_method from jedi.cache import memoize_method
from jedi.evaluate.compiled.subprocess import functions from jedi.evaluate.compiled.subprocess import functions
from jedi.evaluate.compiled import CompiledObject from jedi.evaluate.compiled.access import DirectObjectAccess
_PICKLE_PROTOCOL = 2 _PICKLE_PROTOCOL = 2
@@ -37,24 +37,39 @@ def _get_function(name):
return getattr(functions, name) return getattr(functions, name)
class EvaluatorSameProcess(object): class _EvaluatorProcess(object):
def __init__(self, evaluator):
self._evaluator_weakref = weakref.ref(evaluator)
self._evaluator_id = id(evaluator)
self._handles = {}
def get_or_create_access_handle(self, obj):
id_ = id(obj)
try:
return self.get_access_handle(id_)
except KeyError:
access = DirectObjectAccess(self._evaluator_weakref(), obj)
handle = self._handles[id_] = AccessHandle(self, access, id_)
return handle
def get_access_handle(self, id_):
return self._handles[id_]
class EvaluatorSameProcess(_EvaluatorProcess):
""" """
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
as EvaluatorSubprocess and does the same thing without using a subprocess. as EvaluatorSubprocess and does the same thing without using a subprocess.
This is necessary for the Interpreter process. This is necessary for the Interpreter process.
""" """
def __init__(self, evaluator):
self._evaluator = evaluator
def __getattr__(self, name): def __getattr__(self, name):
return partial(_get_function(name), self._evaluator, IgnoreHandles()) return partial(_get_function(name), self._evaluator_weakref())
class EvaluatorSubprocess(object): class EvaluatorSubprocess(_EvaluatorProcess):
def __init__(self, evaluator, compiled_subprocess): def __init__(self, evaluator, compiled_subprocess):
super(EvaluatorSubprocess).__init__(evaluator)
self._used = False self._used = False
self._evaluator_weakref = weakref.ref(evaluator)
self._evaluator_id = id(evaluator)
self._compiled_subprocess = compiled_subprocess self._compiled_subprocess = compiled_subprocess
def __getattr__(self, name): def __getattr__(self, name):
@@ -70,7 +85,7 @@ class EvaluatorSubprocess(object):
kwargs=kwargs, kwargs=kwargs,
unpickler=lambda stdout: ModifiedUnpickler(self, stdout).load() unpickler=lambda stdout: ModifiedUnpickler(self, stdout).load()
) )
if isinstance(result, CompiledHandle): if isinstance(result, AccessHandle):
result.add_subprocess(self) result.add_subprocess(self)
return result return result
@@ -142,12 +157,11 @@ class Listener():
from jedi.evaluate import Evaluator, project from jedi.evaluate import Evaluator, project
try: try:
evaluator, handles = self._evaluators[evaluator_id] evaluator = self._evaluators[evaluator_id]
except KeyError: except KeyError:
evaluator = Evaluator(None, project=project.Project()) evaluator = Evaluator(None, project=project.Project())
handles = Handles() self._evaluators[evaluator_id] = evaluator
self._evaluators[evaluator_id] = evaluator, handles return evaluator
return evaluator, handles
def _run(self, evaluator_id, function, args, kwargs): def _run(self, evaluator_id, function, args, kwargs):
if evaluator_id is None: if evaluator_id is None:
@@ -155,8 +169,8 @@ class Listener():
elif function is None: elif function is None:
del self._evaluators[evaluator_id] del self._evaluators[evaluator_id]
else: else:
evaluator, handles = self._get_evaluator(function, evaluator_id) evaluator = self._get_evaluator(function, evaluator_id)
return function(evaluator, handles, *args, **kwargs) return function(evaluator, *args, **kwargs)
def listen(self): def listen(self):
stdout = sys.stdout stdout = sys.stdout
@@ -194,44 +208,26 @@ class ModifiedUnpickler(pickle._Unpickler):
super(ModifiedUnpickler, self).load_newobj() super(ModifiedUnpickler, self).load_newobj()
tos = self.stack[-1] tos = self.stack[-1]
print('pop', tos, file=sys.stderr) print('pop', tos, file=sys.stderr)
if isinstance(tos, CompiledHandle): if isinstance(tos, AccessHandle):
tos.add_subprocess(self._subprocess) tos.add_subprocess(self._subprocess)
dispatch[pickle.NEWOBJ[0]] = load_newobj dispatch[pickle.NEWOBJ[0]] = load_newobj
class ModifiedPickler(pickle._Pickler): class ModifiedPickler(pickle._Pickler):
def __init__(self, subprocess, *args, **kwargs):
super(ModifiedPickler, self).__init__(*args, **kwargs)
self._subprocess = subprocess
def save(self, obj, *args, **kwargs): def save(self, obj, *args, **kwargs):
print('s', obj, args, kwargs, file=sys.stderr) print('s', obj, args, kwargs, file=sys.stderr)
if isinstance(obj, CompiledObject):
obj = CompiledHandle(obj)
return super(ModifiedPickler, self).save(obj, *args, **kwargs) return super(ModifiedPickler, self).save(obj, *args, **kwargs)
class Handles(object): class AccessHandle(object):
def __init__(self): def __init__(self, subprocess, access, id_):
self._handles = {} self.access = access
self._subprocess = subprocess
def create(self, obj): self._id = id_
handle = self._handles[id(obj)] = CompiledHandle(obj)
return handle
def get_compiled_object(self, id_):
return self._handles[id_].compiled_object
class IgnoreHandles(object):
def create(self, obj):
return obj
class CompiledHandle(object):
def __init__(self, compiled_object):
self.compiled_object = compiled_object
self._id = id(compiled_object)
@property
def obj(self):
raise NotImplementedError
def add_subprocess(self, subprocess): def add_subprocess(self, subprocess):
self._subprocess = subprocess self._subprocess = subprocess
@@ -244,15 +240,6 @@ class CompiledHandle(object):
def __getattr__(self, name): def __getattr__(self, name):
print('getattr', name, file=sys.stderr) print('getattr', name, file=sys.stderr)
from jedi.evaluate import compiled
attr = getattr(compiled.CompiledObject, name)
if isinstance(attr, property):
return self._subprocess.get_compiled_property(self._id, name)
elif isinstance(attr, compiled.CheckAttribute):
# It might raise an AttributeError, however we're interested in the
# function return value.
self._subprocess.get_compiled_property(self._id, name)
def compiled_method(*args, **kwargs): def compiled_method(*args, **kwargs):
return self._subprocess.get_compiled_method_return(self._id, name, *args, **kwargs) return self._subprocess.get_compiled_method_return(self._id, name, *args, **kwargs)
return compiled_method return compiled_method

View File

@@ -13,14 +13,9 @@ def import_module(evaluator, handles, path=None, name=None):
return handles.create(compiled_object) return handles.create(compiled_object)
def get_compiled_property(evaluator, handles, id, attribute): def get_compiled_method_return(evaluator, id, attribute, *args, **kwargs):
compiled_object = handles.get_compiled_object(id) handle = evaluator.compiled_subprocess.get_access_handle(id)
return getattr(compiled_object, attribute) return getattr(handle.access, attribute)(*args, **kwargs)
def get_compiled_method_return(evaluator, handles, id, attribute, *args, **kwargs):
compiled_object = handles.get_compiled_object(id)
return getattr(compiled_object, attribute)(*args, **kwargs)
def get_special_object(evaluator, handles, identifier): def get_special_object(evaluator, handles, identifier):

View File

@@ -378,8 +378,7 @@ class Importer(object):
module = ImplicitNamespaceContext(self._evaluator, fullname=fullname) module = ImplicitNamespaceContext(self._evaluator, fullname=fullname)
module.paths = paths module.paths = paths
elif module_file is None and not module_path.endswith(('.py', '.zip', '.egg')): elif module_file is None and not module_path.endswith(('.py', '.zip', '.egg')):
module = self._evaluator.compiled_subprocess.import_module(module_path) module = compiled.load_module(self._evaluator, path=module_path)
#module = compiled.load_module(self._evaluator, module_path)
else: else:
module = _load_module(self._evaluator, module_path, code, sys_path, parent_module) module = _load_module(self._evaluator, module_path, code, sys_path, parent_module)