[gnome-builder] jedi: adapt to jedi 0.10.0



commit 8bf74c787af082102958de7498a9b4f4248788cc
Author: Elad Alfassa <elad fedoraproject org>
Date:   Wed Aug 9 17:39:07 2017 +0300

    jedi: adapt to jedi 0.10.0
    
    https://bugzilla.gnome.org/show_bug.cgi?id=778708

 plugins/jedi/jedi_plugin.py |   78 +++++++++++++++++++++++++-----------------
 1 files changed, 46 insertions(+), 32 deletions(-)
---
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
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]