summaryrefslogtreecommitdiff
blob: 484341ad115563be7389a1d1dda9e1dd00416428 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
From 8bf74c787af082102958de7498a9b4f4248788cc Mon Sep 17 00:00:00 2001
From: Elad Alfassa <elad@fedoraproject.org>
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