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
@compiled_objects_cache('compiled_cache')
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):
@@ -329,9 +328,10 @@ class DirectObjectAccess(object):
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]
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):
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.evaluate.compiled.subprocess import functions
from jedi.evaluate.compiled import CompiledObject
from jedi.evaluate.compiled.access import DirectObjectAccess
_PICKLE_PROTOCOL = 2
@@ -37,24 +37,39 @@ def _get_function(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
as EvaluatorSubprocess and does the same thing without using a subprocess.
This is necessary for the Interpreter process.
"""
def __init__(self, evaluator):
self._evaluator = evaluator
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):
super(EvaluatorSubprocess).__init__(evaluator)
self._used = False
self._evaluator_weakref = weakref.ref(evaluator)
self._evaluator_id = id(evaluator)
self._compiled_subprocess = compiled_subprocess
def __getattr__(self, name):
@@ -70,7 +85,7 @@ class EvaluatorSubprocess(object):
kwargs=kwargs,
unpickler=lambda stdout: ModifiedUnpickler(self, stdout).load()
)
if isinstance(result, CompiledHandle):
if isinstance(result, AccessHandle):
result.add_subprocess(self)
return result
@@ -142,12 +157,11 @@ class Listener():
from jedi.evaluate import Evaluator, project
try:
evaluator, handles = self._evaluators[evaluator_id]
evaluator = self._evaluators[evaluator_id]
except KeyError:
evaluator = Evaluator(None, project=project.Project())
handles = Handles()
self._evaluators[evaluator_id] = evaluator, handles
return evaluator, handles
self._evaluators[evaluator_id] = evaluator
return evaluator
def _run(self, evaluator_id, function, args, kwargs):
if evaluator_id is None:
@@ -155,8 +169,8 @@ class Listener():
elif function is None:
del self._evaluators[evaluator_id]
else:
evaluator, handles = self._get_evaluator(function, evaluator_id)
return function(evaluator, handles, *args, **kwargs)
evaluator = self._get_evaluator(function, evaluator_id)
return function(evaluator, *args, **kwargs)
def listen(self):
stdout = sys.stdout
@@ -194,44 +208,26 @@ class ModifiedUnpickler(pickle._Unpickler):
super(ModifiedUnpickler, self).load_newobj()
tos = self.stack[-1]
print('pop', tos, file=sys.stderr)
if isinstance(tos, CompiledHandle):
if isinstance(tos, AccessHandle):
tos.add_subprocess(self._subprocess)
dispatch[pickle.NEWOBJ[0]] = load_newobj
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):
print('s', obj, args, kwargs, file=sys.stderr)
if isinstance(obj, CompiledObject):
obj = CompiledHandle(obj)
return super(ModifiedPickler, self).save(obj, *args, **kwargs)
class Handles(object):
def __init__(self):
self._handles = {}
def create(self, obj):
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
class AccessHandle(object):
def __init__(self, subprocess, access, id_):
self.access = access
self._subprocess = subprocess
self._id = id_
def add_subprocess(self, subprocess):
self._subprocess = subprocess
@@ -244,15 +240,6 @@ class CompiledHandle(object):
def __getattr__(self, name):
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):
return self._subprocess.get_compiled_method_return(self._id, name, *args, **kwargs)
return compiled_method

View File

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

View File

@@ -378,8 +378,7 @@ class Importer(object):
module = ImplicitNamespaceContext(self._evaluator, fullname=fullname)
module.paths = paths
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, module_path)
module = compiled.load_module(self._evaluator, path=module_path)
else:
module = _load_module(self._evaluator, module_path, code, sys_path, parent_module)