[gnome-builder: 1/4] change jedi patching so that it works for completion even if patching not possible



commit 465d853cd006efc5a86109f28eece58466bce130
Author: Sagar Chalise <chalisesagar gmail com>
Date:   Sun Jan 26 11:52:22 2020 +0545

    change jedi patching so that it works for completion even if patching not possible

 src/plugins/jedi/jedi_plugin.py | 241 +++++++++++++++++++++-------------------
 1 file changed, 126 insertions(+), 115 deletions(-)
---
diff --git a/src/plugins/jedi/jedi_plugin.py b/src/plugins/jedi/jedi_plugin.py
index 119832e88..a01da9835 100644
--- a/src/plugins/jedi/jedi_plugin.py
+++ b/src/plugins/jedi/jedi_plugin.py
@@ -89,127 +89,136 @@ def return_error(task, error):
     #print(repr(error))
     task.return_error(GLib.Error(message=repr(error)))
 
-try:
-    import jedi
-    from jedi.evaluate.compiled import CompiledObject
-    from jedi.evaluate.compiled import get_special_object
+def patch_jedi():
     try:
-        # 0.12
-        from jedi.evaluate.compiled import create_from_name
-        from jedi.evaluate.base_context import Context
-    except ImportError:
-        # Pre 0.12
-        from jedi.evaluate.compiled import _create_from_name as create_from_name
-        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(self)
-
-        @property
-        def py__call__(self):
-            def actual(params):
-                # Parse the docstring to find the return type:
-                ret_type = ''
-                if '->' in self.obj.__doc__:
-                    ret_type = self.obj.__doc__.split('->')[1].strip()
-                    ret_type = ret_type.replace(' or None', '')
-                if ret_type.startswith('iter:'):
-                    ret_type = ret_type[len('iter:'):]  # we don't care if it's an iterator
-
-                if hasattr(__builtins__, ret_type):
-                    # The function we're inspecting returns a builtin python type, that's easy
-                    # (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)
+        from jedi.evaluate.compiled import CompiledObject
+        from jedi.evaluate.compiled import get_special_object
+        try:
+            # 0.12
+            from jedi.evaluate.compiled import create_from_name
+            from jedi.evaluate.base_context import Context
+        except ImportError:
+            # Pre 0.12
+            from jedi.evaluate.compiled import _create_from_name as create_from_name
+            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:
-                    # The function we're inspecting returns a GObject type
-                    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_context.obj.__module__
-                        if parent_module.startswith('gi.overrides'):
-                            parent_module = parent_module[len('gi.overrides.'):]
-                            parent = '%s.%s' % (parent_module, parent)
-
-                    if ret_type.startswith(parent):
-                        # A pygobject type in the same module
-                        ret_type = ret_type[len(parent):]
+                    return super()._cls(self)
+    
+            @property
+            def py__call__(self):
+                def actual(params):
+                    # Parse the docstring to find the return type:
+                    ret_type = ''
+                    if '->' in self.obj.__doc__:
+                        ret_type = self.obj.__doc__.split('->')[1].strip()
+                        ret_type = ret_type.replace(' or None', '')
+                    if ret_type.startswith('iter:'):
+                        ret_type = ret_type[len('iter:'):]  # we don't care if it's an iterator
+    
+                    if hasattr(__builtins__, ret_type):
+                        # The function we're inspecting returns a builtin python type, that's easy
+                        # (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:
-                        # 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(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 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(self._evaluator, module)]
-                    except ImportError:
-                        pass
-            return module_list
-
-    try:
-        # Pre 0.12 workaround
-        # TODO: What needs to be fixed here for 0.12?
-        original_jedi_get_module = jedi.evaluate.compiled.fake.get_module
-        def patched_jedi_get_module(obj):
-            "Work around a weird bug in jedi"
-            try:
-                return original_jedi_get_module(obj)
-            except ImportError as e:
-                if e.msg == "No module named 'gi._gobject._gobject'":
-                    return original_jedi_get_module('gi._gobject')
-        jedi.evaluate.compiled.fake.get_module = patched_jedi_get_module
-    except:
-        pass
+                        # The function we're inspecting returns a GObject type
+                        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_context.obj.__module__
+                            if parent_module.startswith('gi.overrides'):
+                                parent_module = parent_module[len('gi.overrides.'):]
+                                parent = '%s.%s' % (parent_module, parent)
+    
+                        if ret_type.startswith(parent):
+                            # A pygobject type in the same module
+                            ret_type = ret_type[len(parent):]
+                        else:
+                            # 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(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 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(self._evaluator, module)]
+                        except ImportError:
+                            pass
+                return module_list
+    
+        try:
+            # Pre 0.12 workaround
+            # TODO: What needs to be fixed here for 0.12?
+            original_jedi_get_module = jedi.evaluate.compiled.fake.get_module
+            def patched_jedi_get_module(obj):
+                "Work around a weird bug in jedi"
+                try:
+                    return original_jedi_get_module(obj)
+                except ImportError as e:
+                    if e.msg == "No module named 'gi._gobject._gobject'":
+                        return original_jedi_get_module('gi._gobject')
+            jedi.evaluate.compiled.fake.get_module = patched_jedi_get_module
+        except:
+            pass
+    
+        jedi.evaluate.compiled.CompiledObject = PatchedJediCompiledObject
+        try:
+            jedi.evaluate.instance.CompiledBoundMethod = PatchedCompiledBoundMethod
+        except AttributeError:
+            jedi.evaluate.context.instance.CompiledBoundMethod = PatchedCompiledBoundMethod
+        jedi.evaluate.imports.Importer = PatchedJediImporter
+        return True
+    except ImportError as ex:
+        print("jedi patching not possible. GI completion may not work.")
+        print(ex)
+        return False
 
-    jedi.evaluate.compiled.CompiledObject = PatchedJediCompiledObject
-    try:
-        jedi.evaluate.instance.CompiledBoundMethod = PatchedCompiledBoundMethod
-    except AttributeError:
-        jedi.evaluate.context.instance.CompiledBoundMethod = PatchedCompiledBoundMethod
-    jedi.evaluate.imports.Importer = PatchedJediImporter
-    HAS_JEDI = True
-except ImportError as ex:
+try:
+    import jedi
+except ImportError:
     print("jedi not found, python auto-completion not possible.")
-    print(ex)
+    IS_JEDI_PATCHED = False
     HAS_JEDI = False
-
+else:
+    HAS_JEDI = True
+    IS_JEDI_PATCHED = patch_jedi()
 GIR_PATH_LIST = []
 
 def init_gir_path_list():
@@ -543,6 +552,8 @@ class JediCompletionRequest:
 
         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 not IS_JEDI_PATCHED:
+                return None
             if (type(info._module) == PatchedJediCompiledObject and
                info._module.obj.__class__ == IntrospectionModule):
                 return next(info._name.infer()).obj


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