diff --git a/jedi/evaluate/compiled/subprocess/__init__.py b/jedi/evaluate/compiled/subprocess/__init__.py index 07e0d279..74afd660 100644 --- a/jedi/evaluate/compiled/subprocess/__init__.py +++ b/jedi/evaluate/compiled/subprocess/__init__.py @@ -50,12 +50,16 @@ class _EvaluatorProcess(object): return self.get_access_handle(id_) except KeyError: access = DirectObjectAccess(self._evaluator_weakref(), obj) - handle = self._handles[id_] = AccessHandle(self, access, id_) - return handle + handle = AccessHandle(self, access, id_) + self.set_access_handle(handle) + return handle def get_access_handle(self, id_): return self._handles[id_] + def set_access_handle(self, handle): + self._handles[handle.id] = handle + class EvaluatorSameProcess(_EvaluatorProcess): """ @@ -84,7 +88,7 @@ class EvaluatorSubprocess(_EvaluatorProcess): func, args=args, kwargs=kwargs, - unpickler=lambda stdout: _ModifiedMasterUnpickler(self, stdout).load() + unpickler=lambda stdout: _ModifiedUnpickler(self, stdout).load() ) if isinstance(result, AccessHandle): result.add_subprocess(self) @@ -211,7 +215,7 @@ class Listener(): while True: try: - payload = pickle.load(file=stdin) + payload = pickle.load(stdin) except EOFError: # It looks like the parent process closed. Don't make a big fuss # here and just exit. @@ -232,17 +236,20 @@ class _ModifiedUnpickler(pickle._Unpickler): super(_ModifiedUnpickler, self).__init__(*args, **kwargs) self._subprocess = subprocess - def load_newobj(self): - super(_ModifiedUnpickler, self).load_newobj() + def load_build(self): + super(_ModifiedUnpickler, self).load_build() tos = self.stack[-1] if isinstance(tos, AccessHandle): self.stack[-1] = self.get_access_handle(tos) - dispatch[pickle.NEWOBJ[0]] = load_newobj + dispatch[pickle.BUILD[0]] = load_build - -class _ModifiedMasterUnpickler(_ModifiedUnpickler): def get_access_handle(self, access_handle): - access_handle.add_subprocess(self._subprocess) + try: + # Rewrite the access handle to one we're already having. + access_handle = self._subprocess.get_access_handle(access_handle.id) + except KeyError: + access_handle.add_subprocess(self._subprocess) + self._subprocess.set_access_handle(access_handle) return access_handle @@ -262,6 +269,9 @@ class AccessHandle(object): self.id = state def __getattr__(self, name): + if name in ('id', '_subprocess', 'access'): + raise AttributeError("Something went wrong with unpickling") + #print('getattr', name, file=sys.stderr) def compiled_method(*args, **kwargs): return self._subprocess.get_compiled_method_return(self.id, name, *args, **kwargs) diff --git a/jedi/evaluate/stdlib.py b/jedi/evaluate/stdlib.py index f9d70298..d973315a 100644 --- a/jedi/evaluate/stdlib.py +++ b/jedi/evaluate/stdlib.py @@ -110,7 +110,7 @@ def argument_clinic(string, want_obj=False, want_context=False, want_arguments=F try: lst = list(arguments.eval_argument_clinic(clinic_args)) except ValueError: - return NO_CONTEXTS + result = NO_CONTEXTS else: kwargs = {} if want_context: @@ -119,9 +119,10 @@ def argument_clinic(string, want_obj=False, want_context=False, want_arguments=F kwargs['obj'] = obj if want_arguments: kwargs['arguments'] = arguments - return func(evaluator, *lst, **kwargs) + result = func(evaluator, *lst, **kwargs) finally: - debug.dbg('builtin end', color='MAGENTA') + debug.dbg('builtin end: %s', result, color='MAGENTA') + return result return wrapper return f diff --git a/test/test_evaluate/test_compiled.py b/test/test_evaluate/test_compiled.py index bf120ac3..cd9027d3 100644 --- a/test/test_evaluate/test_compiled.py +++ b/test/test_evaluate/test_compiled.py @@ -29,7 +29,7 @@ def test_fake_loading(evaluator): def test_fake_docstr(evaluator): - next_ = interpreter._create(evaluator, next) + next_ = compiled.builtin_from_name(evaluator, 'next') assert next_.py__doc__() assert next_.tree_node is not None assert next_.py__doc__() == next.__doc__ @@ -49,7 +49,9 @@ def test_doc(evaluator): Even CompiledObject docs always return empty docstrings - not None, that's just a Jedi API definition. """ - obj = interpreter._create(evaluator, ''.__getnewargs__) + str_ = compiled.create_simple_object(evaluator, '') + # Equals `''.__getnewargs__` + obj = compiled.create_from_name(evaluator, str_, '__getnewargs__') assert obj.py__doc__() == ''