From 8bf74c787af082102958de7498a9b4f4248788cc Mon Sep 17 00:00:00 2001 From: Elad Alfassa Date: Wed, 9 Aug 2017 17:39:07 +0300 Subject: [PATCH] jedi: adapt to jedi 0.10.0 https://bugzilla.gnome.org/show_bug.cgi?id=778708 --- diff --git a/plugins/jedi/jedi_plugin.py b/plugins/jedi/jedi_plugin.py index 25ade14..8898b69 100644 --- a/plugins/jedi/jedi_plugin.py +++ b/plugins/jedi/jedi_plugin.py @@ -55,7 +55,6 @@ from gi.repository import GtkSource from gi.repository import Ide from gi.types import GObjectMeta from gi.types import StructMeta - _ = Ide.gettext gi_importer = DynamicImporter('gi.repository') @@ -91,22 +90,31 @@ _ICONS = { try: import jedi from jedi.evaluate.compiled import CompiledObject + from jedi.evaluate.compiled import get_special_object from jedi.evaluate.compiled import _create_from_name - from jedi.evaluate.compiled import builtin + from jedi.evaluate.context import Context from jedi.evaluate.docstrings import _evaluate_for_statement_string from jedi.evaluate.imports import Importer class PatchedJediCompiledObject(CompiledObject): "A modified version of Jedi CompiledObject to work with GObject Introspection modules" + + def __init__(self, evaluator, obj, parent_context=None, faked_class=None): + # we have to override __init__ to change super(CompiledObject, self) + # to Context, in order to prevent an infinite recursion + Context.__init__(self, evaluator, parent_context) + self.obj = obj + self.tree_node = faked_class + def _cls(self): if self.obj.__class__ == IntrospectionModule: return self else: - return super()._cls() + return super()._cls(self) @property def py__call__(self): - def actual(evaluator, params): + def actual(params): # Parse the docstring to find the return type: ret_type = '' if '->' in self.obj.__doc__: @@ -115,18 +123,21 @@ try: if ret_type.startswith('iter:'): ret_type = ret_type[len('iter:'):] # we don't care if it's an iterator - if ret_type in __builtins__: + if hasattr(__builtins__, ret_type): # The function we're inspecting returns a builtin python type, that's easy - obj = _create_from_name(builtin, builtin, ret_type) - return evaluator.execute(obj, params) + # (see test/test_evaluate/test_compiled.py in the jedi source code for usage) + builtins = get_special_object(self.evaluator, 'BUILTINS') + builtin_obj = builtins.py__getattribute__(ret_type) + obj = _create_from_name(self.evaluator, builtins, builtin_obj, "") + return self.evaluator.execute(obj, params) else: # The function we're inspecting returns a GObject type - parent = self.parent.obj.__name__ + parent = self.parent_context.obj.__name__ if parent.startswith('gi.repository'): parent = parent[len('gi.repository.'):] else: # a module with overrides, such as Gtk, behaves differently - parent_module = self.parent.obj.__module__ + parent_module = self.parent_context.obj.__module__ if parent_module.startswith('gi.overrides'): parent_module = parent_module[len('gi.overrides.'):] parent = '%s.%s' % (parent_module, parent) @@ -138,22 +149,28 @@ try: # A pygobject type in a different module return_type_parent = ret_type.split('.', 1)[0] ret_type = 'from gi.repository import %s\n%s' % (return_type_parent, ret_type) - result = _evaluate_for_statement_string(evaluator, ret_type, self.parent) - return result + result = _evaluate_for_statement_string(self.parent_context, ret_type) + return set(result) if type(self.obj) == FunctionInfo: return actual return super().py__call__ + # we need to override CompiledBoundMethod without changing it much, + # just so it'll not get confused due to our overriden CompiledObject + class PatchedCompiledBoundMethod(PatchedJediCompiledObject): + def __init__(self, func): + super().__init__(func.evaluator, func.obj, func.parent_context, func.tree_node) + class PatchedJediImporter(Importer): "A modified version of Jedi Importer to work with GObject Introspection modules" def follow(self): module_list = super().follow() - if module_list == []: + if not module_list: import_path = '.'.join([str(i) for i in self.import_path]) if import_path.startswith('gi.repository'): try: module = gi_importer.load_module(import_path) - module_list = [PatchedJediCompiledObject(module)] + module_list = [PatchedJediCompiledObject(self._evaluator, module)] except ImportError: pass return module_list @@ -169,9 +186,9 @@ try: return original_jedi_get_module('gi._gobject') jedi.evaluate.compiled.fake.get_module = patched_jedi_get_module - - jedi.evaluate.imports.Importer = PatchedJediImporter jedi.evaluate.compiled.CompiledObject = PatchedJediCompiledObject + jedi.evaluate.instance.CompiledBoundMethod = PatchedCompiledBoundMethod + jedi.evaluate.imports.Importer = PatchedJediImporter HAS_JEDI = True except ImportError: print("jedi not found, python auto-completion not possible.") @@ -331,7 +348,6 @@ def update_doc_db_on_startup(): update_doc_db_on_startup() - class JediCompletionProvider(Ide.Object, GtkSource.CompletionProvider, Ide.CompletionProvider): context = None current_word = None @@ -600,6 +616,15 @@ class JediCompletionRequest: script = jedi.Script(self.content, self.line + 1, self.column, self.filename) db = DocumentationDB() + + def get_gi_obj(info): + """ Get a GObject Introspection object from a jedi Completion, or None if the completion is not GObject Introspection related """ + if (type(info._module) == PatchedJediCompiledObject and + info._module.obj.__class__ == IntrospectionModule): + return next(info._name.infer()).obj + else: + return None + for info in script.completions(): if self.cancelled: return @@ -608,10 +633,9 @@ class JediCompletionRequest: # we have to use custom names here because .type and .params can't # be overridden (they are properties) - if type(info._definition) == PatchedJediCompiledObject and \ - type(info._definition.obj) == FunctionInfo: + obj = get_gi_obj(info) + if type(obj) == FunctionInfo: info.real_type = 'function' - obj = info._definition.obj params = [arg_info.get_name() for arg_info in obj.get_arguments()] else: info.real_type = info.type @@ -626,8 +650,8 @@ class JediCompletionRequest: params.append(param.name) doc = info.docstring() - if hasattr(info._definition, 'obj'): - obj = info._definition.obj + if obj is not None: + # get documentation for this GObject Introspection object symbol = None namespace = None @@ -640,17 +664,7 @@ class JediCompletionRequest: namespace = obj.get_namespace() if symbol is not None: - # we need to walk down the path to find the module so we can get the version - parent = info._definition.parent - found = False - while not found: - new_parent = parent.parent - if new_parent is None: - found = True - else: - parent = new_parent - version = parent.obj._version - result = db.query(symbol, version) + result = db.query(symbol, info._module.obj._version) if result is not None: doc = result -- libgit2 0.26.0