Mercurial > hg > dotemacs
annotate elpa/elpy-1.26.0/elpy/server.py @ 183:3de719fb264a
elpy: version 1.26
author | Jordi Gutiérrez Hermoso <jordigh@octave.org> |
---|---|
date | Wed, 21 Nov 2018 14:39:16 -0500 |
parents | elpa/elpy-1.25.0/elpy/server.py@c3bd84985977 |
children |
rev | line source |
---|---|
98 | 1 """Method implementations for the Elpy JSON-RPC server. |
2 | |
3 This file implements the methods exported by the JSON-RPC server. It | |
4 handles backend selection and passes methods on to the selected | |
5 backend. | |
6 | |
7 """ | |
8 import io | |
9 import os | |
10 import pydoc | |
11 | |
12 from elpy.pydocutils import get_pydoc_completions | |
13 from elpy.rpc import JSONRPCServer, Fault | |
152
55ceabc58fcc
elpy: upgrade to 1.12
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
126
diff
changeset
|
14 from elpy.auto_pep8 import fix_code |
55ceabc58fcc
elpy: upgrade to 1.12
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
126
diff
changeset
|
15 from elpy.yapfutil import fix_code as fix_code_with_yapf |
182
c3bd84985977
upgrade elpy to 1.25
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
175
diff
changeset
|
16 from elpy.blackutil import fix_code as fix_code_with_black |
126
29cff77e2387
update elpa packges
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
98
diff
changeset
|
17 |
98 | 18 |
19 try: | |
20 from elpy import jedibackend | |
21 except ImportError: # pragma: no cover | |
22 jedibackend = None | |
23 | |
24 | |
25 class ElpyRPCServer(JSONRPCServer): | |
26 """The RPC server for elpy. | |
27 | |
28 See the rpc_* methods for exported method documentation. | |
29 | |
30 """ | |
126
29cff77e2387
update elpa packges
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
98
diff
changeset
|
31 def __init__(self, *args, **kwargs): |
29cff77e2387
update elpa packges
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
98
diff
changeset
|
32 super(ElpyRPCServer, self).__init__(*args, **kwargs) |
98 | 33 self.backend = None |
34 self.project_root = None | |
35 | |
36 def _call_backend(self, method, default, *args, **kwargs): | |
37 """Call the backend method with args. | |
38 | |
39 If there is currently no backend, return default.""" | |
40 meth = getattr(self.backend, method, None) | |
41 if meth is None: | |
42 return default | |
43 else: | |
44 return meth(*args, **kwargs) | |
45 | |
46 def rpc_echo(self, *args): | |
47 """Return the arguments. | |
48 | |
49 This is a simple test method to see if the protocol is | |
50 working. | |
51 | |
52 """ | |
53 return args | |
54 | |
55 def rpc_init(self, options): | |
56 self.project_root = options["project_root"] | |
57 | |
175
56ea66d76309
elpy: version 1.18
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
156
diff
changeset
|
58 if jedibackend: |
98 | 59 self.backend = jedibackend.JediBackend(self.project_root) |
60 else: | |
61 self.backend = None | |
62 | |
63 return { | |
175
56ea66d76309
elpy: version 1.18
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
156
diff
changeset
|
64 'jedi_available': (self.backend is not None) |
98 | 65 } |
66 | |
67 def rpc_get_calltip(self, filename, source, offset): | |
68 """Get the calltip for the function at the offset. | |
69 | |
70 """ | |
71 return self._call_backend("rpc_get_calltip", None, filename, | |
72 get_source(source), offset) | |
73 | |
183
3de719fb264a
elpy: version 1.26
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
182
diff
changeset
|
74 def rpc_get_oneline_docstring(self, filename, source, offset): |
3de719fb264a
elpy: version 1.26
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
182
diff
changeset
|
75 """Get a oneline docstring for the symbol at the offset. |
3de719fb264a
elpy: version 1.26
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
182
diff
changeset
|
76 |
3de719fb264a
elpy: version 1.26
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
182
diff
changeset
|
77 """ |
3de719fb264a
elpy: version 1.26
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
182
diff
changeset
|
78 return self._call_backend("rpc_get_oneline_docstring", None, filename, |
3de719fb264a
elpy: version 1.26
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
182
diff
changeset
|
79 get_source(source), offset) |
3de719fb264a
elpy: version 1.26
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
182
diff
changeset
|
80 |
98 | 81 def rpc_get_completions(self, filename, source, offset): |
82 """Get a list of completion candidates for the symbol at offset. | |
83 | |
84 """ | |
126
29cff77e2387
update elpa packges
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
98
diff
changeset
|
85 results = self._call_backend("rpc_get_completions", [], filename, |
29cff77e2387
update elpa packges
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
98
diff
changeset
|
86 get_source(source), offset) |
29cff77e2387
update elpa packges
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
98
diff
changeset
|
87 # Uniquify by name |
29cff77e2387
update elpa packges
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
98
diff
changeset
|
88 results = list(dict((res['name'], res) for res in results) |
29cff77e2387
update elpa packges
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
98
diff
changeset
|
89 .values()) |
29cff77e2387
update elpa packges
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
98
diff
changeset
|
90 results.sort(key=lambda cand: _pysymbol_key(cand["name"])) |
29cff77e2387
update elpa packges
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
98
diff
changeset
|
91 return results |
98 | 92 |
93 def rpc_get_completion_docstring(self, completion): | |
94 """Return documentation for a previously returned completion. | |
95 | |
96 """ | |
97 return self._call_backend("rpc_get_completion_docstring", | |
98 None, completion) | |
99 | |
100 def rpc_get_completion_location(self, completion): | |
101 """Return the location for a previously returned completion. | |
102 | |
103 This returns a list of [file name, line number]. | |
104 | |
105 """ | |
106 return self._call_backend("rpc_get_completion_location", None, | |
107 completion) | |
108 | |
109 def rpc_get_definition(self, filename, source, offset): | |
110 """Get the location of the definition for the symbol at the offset. | |
111 | |
112 """ | |
113 return self._call_backend("rpc_get_definition", None, filename, | |
114 get_source(source), offset) | |
115 | |
175
56ea66d76309
elpy: version 1.18
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
156
diff
changeset
|
116 def rpc_get_assignment(self, filename, source, offset): |
56ea66d76309
elpy: version 1.18
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
156
diff
changeset
|
117 """Get the location of the assignment for the symbol at the offset. |
56ea66d76309
elpy: version 1.18
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
156
diff
changeset
|
118 |
56ea66d76309
elpy: version 1.18
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
156
diff
changeset
|
119 """ |
56ea66d76309
elpy: version 1.18
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
156
diff
changeset
|
120 return self._call_backend("rpc_get_assignment", None, filename, |
56ea66d76309
elpy: version 1.18
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
156
diff
changeset
|
121 get_source(source), offset) |
56ea66d76309
elpy: version 1.18
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
156
diff
changeset
|
122 |
98 | 123 def rpc_get_docstring(self, filename, source, offset): |
124 """Get the docstring for the symbol at the offset. | |
125 | |
126 """ | |
127 return self._call_backend("rpc_get_docstring", None, filename, | |
128 get_source(source), offset) | |
129 | |
130 def rpc_get_pydoc_completions(self, name=None): | |
131 """Return a list of possible strings to pass to pydoc. | |
132 | |
133 If name is given, the strings are under name. If not, top | |
134 level modules are returned. | |
135 | |
136 """ | |
137 return get_pydoc_completions(name) | |
138 | |
139 def rpc_get_pydoc_documentation(self, symbol): | |
140 """Get the Pydoc documentation for the given symbol. | |
141 | |
142 Uses pydoc and can return a string with backspace characters | |
143 for bold highlighting. | |
144 | |
145 """ | |
146 try: | |
147 docstring = pydoc.render_doc(str(symbol), | |
148 "Elpy Pydoc Documentation for %s", | |
149 False) | |
150 except (ImportError, pydoc.ErrorDuringImport): | |
151 return None | |
152 else: | |
153 if isinstance(docstring, bytes): | |
154 docstring = docstring.decode("utf-8", "replace") | |
155 return docstring | |
156 | |
157 def rpc_get_refactor_options(self, filename, start, end=None): | |
158 """Return a list of possible refactoring options. | |
159 | |
160 This list will be filtered depending on whether it's | |
161 applicable at the point START and possibly the region between | |
162 START and END. | |
163 | |
164 """ | |
165 try: | |
166 from elpy import refactor | |
167 except: | |
168 raise ImportError("Rope not installed, refactorings unavailable") | |
169 ref = refactor.Refactor(self.project_root, filename) | |
170 return ref.get_refactor_options(start, end) | |
171 | |
172 def rpc_refactor(self, filename, method, args): | |
173 """Return a list of changes from the refactoring action. | |
174 | |
175 A change is a dictionary describing the change. See | |
176 elpy.refactor.translate_changes for a description. | |
177 | |
178 """ | |
179 try: | |
180 from elpy import refactor | |
181 except: | |
182 raise ImportError("Rope not installed, refactorings unavailable") | |
183 if args is None: | |
184 args = () | |
185 ref = refactor.Refactor(self.project_root, filename) | |
186 return ref.get_changes(method, *args) | |
187 | |
188 def rpc_get_usages(self, filename, source, offset): | |
189 """Get usages for the symbol at point. | |
190 | |
191 """ | |
192 source = get_source(source) | |
193 if hasattr(self.backend, "rpc_get_usages"): | |
194 return self.backend.rpc_get_usages(filename, source, offset) | |
195 else: | |
196 raise Fault("get_usages not implemented by current backend", | |
197 code=400) | |
198 | |
175
56ea66d76309
elpy: version 1.18
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
156
diff
changeset
|
199 def rpc_get_names(self, filename, source, offset): |
56ea66d76309
elpy: version 1.18
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
156
diff
changeset
|
200 """Get all possible names |
126
29cff77e2387
update elpa packges
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
98
diff
changeset
|
201 |
29cff77e2387
update elpa packges
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
98
diff
changeset
|
202 """ |
29cff77e2387
update elpa packges
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
98
diff
changeset
|
203 source = get_source(source) |
175
56ea66d76309
elpy: version 1.18
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
156
diff
changeset
|
204 if hasattr(self.backend, "rpc_get_names"): |
56ea66d76309
elpy: version 1.18
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
156
diff
changeset
|
205 return self.backend.rpc_get_names(filename, source, offset) |
56ea66d76309
elpy: version 1.18
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
156
diff
changeset
|
206 else: |
56ea66d76309
elpy: version 1.18
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
156
diff
changeset
|
207 raise Fault("get_names not implemented by current backend", |
56ea66d76309
elpy: version 1.18
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
156
diff
changeset
|
208 code=400) |
152
55ceabc58fcc
elpy: upgrade to 1.12
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
126
diff
changeset
|
209 |
182
c3bd84985977
upgrade elpy to 1.25
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
175
diff
changeset
|
210 def rpc_fix_code(self, source, directory): |
152
55ceabc58fcc
elpy: upgrade to 1.12
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
126
diff
changeset
|
211 """Formats Python code to conform to the PEP 8 style guide. |
55ceabc58fcc
elpy: upgrade to 1.12
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
126
diff
changeset
|
212 |
55ceabc58fcc
elpy: upgrade to 1.12
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
126
diff
changeset
|
213 """ |
55ceabc58fcc
elpy: upgrade to 1.12
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
126
diff
changeset
|
214 source = get_source(source) |
182
c3bd84985977
upgrade elpy to 1.25
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
175
diff
changeset
|
215 return fix_code(source, directory) |
152
55ceabc58fcc
elpy: upgrade to 1.12
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
126
diff
changeset
|
216 |
182
c3bd84985977
upgrade elpy to 1.25
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
175
diff
changeset
|
217 def rpc_fix_code_with_yapf(self, source, directory): |
152
55ceabc58fcc
elpy: upgrade to 1.12
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
126
diff
changeset
|
218 """Formats Python code to conform to the PEP 8 style guide. |
55ceabc58fcc
elpy: upgrade to 1.12
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
126
diff
changeset
|
219 |
55ceabc58fcc
elpy: upgrade to 1.12
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
126
diff
changeset
|
220 """ |
55ceabc58fcc
elpy: upgrade to 1.12
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
126
diff
changeset
|
221 source = get_source(source) |
182
c3bd84985977
upgrade elpy to 1.25
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
175
diff
changeset
|
222 return fix_code_with_yapf(source, directory) |
c3bd84985977
upgrade elpy to 1.25
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
175
diff
changeset
|
223 |
c3bd84985977
upgrade elpy to 1.25
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
175
diff
changeset
|
224 def rpc_fix_code_with_black(self, source, directory): |
c3bd84985977
upgrade elpy to 1.25
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
175
diff
changeset
|
225 """Formats Python code to conform to the PEP 8 style guide. |
c3bd84985977
upgrade elpy to 1.25
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
175
diff
changeset
|
226 |
c3bd84985977
upgrade elpy to 1.25
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
175
diff
changeset
|
227 """ |
c3bd84985977
upgrade elpy to 1.25
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
175
diff
changeset
|
228 source = get_source(source) |
c3bd84985977
upgrade elpy to 1.25
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
175
diff
changeset
|
229 return fix_code_with_black(source, directory) |
126
29cff77e2387
update elpa packges
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
98
diff
changeset
|
230 |
98 | 231 |
232 def get_source(fileobj): | |
233 """Translate fileobj into file contents. | |
234 | |
235 fileobj is either a string or a dict. If it's a string, that's the | |
236 file contents. If it's a string, then the filename key contains | |
237 the name of the file whose contents we are to use. | |
238 | |
239 If the dict contains a true value for the key delete_after_use, | |
240 the file should be deleted once read. | |
241 | |
242 """ | |
243 if not isinstance(fileobj, dict): | |
244 return fileobj | |
245 else: | |
246 try: | |
152
55ceabc58fcc
elpy: upgrade to 1.12
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
126
diff
changeset
|
247 with io.open(fileobj["filename"], encoding="utf-8", |
55ceabc58fcc
elpy: upgrade to 1.12
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
126
diff
changeset
|
248 errors="ignore") as f: |
98 | 249 return f.read() |
250 finally: | |
251 if fileobj.get('delete_after_use'): | |
252 try: | |
253 os.remove(fileobj["filename"]) | |
254 except: # pragma: no cover | |
255 pass | |
126
29cff77e2387
update elpa packges
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
98
diff
changeset
|
256 |
29cff77e2387
update elpa packges
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
98
diff
changeset
|
257 |
29cff77e2387
update elpa packges
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
98
diff
changeset
|
258 def _pysymbol_key(name): |
29cff77e2387
update elpa packges
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
98
diff
changeset
|
259 """Return a sortable key index for name. |
29cff77e2387
update elpa packges
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
98
diff
changeset
|
260 |
29cff77e2387
update elpa packges
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
98
diff
changeset
|
261 Sorting is case-insensitive, with the first underscore counting as |
29cff77e2387
update elpa packges
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
98
diff
changeset
|
262 worse than any character, but subsequent underscores do not. This |
29cff77e2387
update elpa packges
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
98
diff
changeset
|
263 means that dunder symbols (like __init__) are sorted after symbols |
29cff77e2387
update elpa packges
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
98
diff
changeset
|
264 that start with an alphabetic character, but before those that |
29cff77e2387
update elpa packges
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
98
diff
changeset
|
265 start with only a single underscore. |
29cff77e2387
update elpa packges
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
98
diff
changeset
|
266 |
29cff77e2387
update elpa packges
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
98
diff
changeset
|
267 """ |
29cff77e2387
update elpa packges
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
98
diff
changeset
|
268 if name.startswith("_"): |
29cff77e2387
update elpa packges
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
98
diff
changeset
|
269 name = "~" + name[1:] |
29cff77e2387
update elpa packges
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents:
98
diff
changeset
|
270 return name.lower() |