Personal emacs config
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

737 lines
30 KiB

  1. """Elpy backend using the Jedi library.
  2. This backend uses the Jedi library:
  3. https://github.com/davidhalter/jedi
  4. """
  5. import sys
  6. import traceback
  7. import re
  8. import jedi
  9. from elpy import rpc
  10. from elpy.rpc import Fault
  11. # in case pkg_resources is not properly installed
  12. # (see https://github.com/jorgenschaefer/elpy/issues/1674).
  13. try:
  14. from pkg_resources import parse_version
  15. except ImportError: # pragma: no cover
  16. def parse_version(*arg, **kwargs):
  17. raise Fault("`pkg_resources` could not be imported, "
  18. "please reinstall Elpy RPC virtualenv with"
  19. " `M-x elpy-rpc-reinstall-virtualenv`", code=400)
  20. JEDISUP17 = parse_version(jedi.__version__) >= parse_version("0.17.0")
  21. class JediBackend(object):
  22. """The Jedi backend class.
  23. Implements the RPC calls we can pass on to Jedi.
  24. Documentation: http://jedi.jedidjah.ch/en/latest/docs/plugin-api.html
  25. """
  26. name = "jedi"
  27. def __init__(self, project_root, environment_binaries_path):
  28. self.project_root = project_root
  29. self.environment = None
  30. if environment_binaries_path is not None:
  31. self.environment = jedi.create_environment(environment_binaries_path,
  32. safe=False)
  33. self.completions = {}
  34. sys.path.append(project_root)
  35. # Backward compatibility to jedi<17
  36. if not JEDISUP17: # pragma: no cover
  37. self.rpc_get_completions = self.rpc_get_completions_jedi16
  38. self.rpc_get_docstring = self.rpc_get_docstring_jedi16
  39. self.rpc_get_definition = self.rpc_get_definition_jedi16
  40. self.rpc_get_assignment = self.rpc_get_assignment_jedi16
  41. self.rpc_get_calltip = self.rpc_get_calltip_jedi16
  42. self.rpc_get_oneline_docstring = self.rpc_get_oneline_docstring_jedi16
  43. self.rpc_get_usages = self.rpc_get_usages_jedi16
  44. self.rpc_get_names = self.rpc_get_names_jedi16
  45. def rpc_get_completions(self, filename, source, offset):
  46. line, column = pos_to_linecol(source, offset)
  47. proposals = run_with_debug(jedi, 'complete', code=source,
  48. path=filename,
  49. environment=self.environment,
  50. fun_kwargs={'line': line, 'column': column})
  51. self.completions = dict((proposal.name, proposal)
  52. for proposal in proposals)
  53. return [{'name': proposal.name.rstrip("="),
  54. 'suffix': proposal.complete.rstrip("="),
  55. 'annotation': proposal.type,
  56. 'meta': proposal.description}
  57. for proposal in proposals]
  58. def rpc_get_completions_jedi16(self, filename, source, offset):
  59. # Backward compatibility to jedi<17
  60. line, column = pos_to_linecol(source, offset)
  61. proposals = run_with_debug(jedi, 'completions',
  62. source=source, line=line, column=column,
  63. path=filename, encoding='utf-8',
  64. environment=self.environment)
  65. if proposals is None:
  66. return []
  67. self.completions = dict((proposal.name, proposal)
  68. for proposal in proposals)
  69. return [{'name': proposal.name.rstrip("="),
  70. 'suffix': proposal.complete.rstrip("="),
  71. 'annotation': proposal.type,
  72. 'meta': proposal.description}
  73. for proposal in proposals]
  74. def rpc_get_completion_docstring(self, completion):
  75. proposal = self.completions.get(completion)
  76. if proposal is None:
  77. return None
  78. else:
  79. return proposal.docstring(fast=False)
  80. def rpc_get_completion_location(self, completion):
  81. proposal = self.completions.get(completion)
  82. if proposal is None:
  83. return None
  84. else:
  85. return (proposal.module_path, proposal.line)
  86. def rpc_get_docstring(self, filename, source, offset):
  87. line, column = pos_to_linecol(source, offset)
  88. locations = run_with_debug(jedi, 'goto',
  89. code=source,
  90. path=filename,
  91. environment=self.environment,
  92. fun_kwargs={'line': line,
  93. 'column': column,
  94. 'follow_imports': True,
  95. 'follow_builtin_imports': True})
  96. if not locations:
  97. return None
  98. # Filter uninteresting things
  99. if locations[-1].name in ["str", "int", "float", "bool", "tuple",
  100. "list", "dict"]:
  101. return None
  102. if locations[-1].docstring():
  103. return ('Documentation for {0}:\n\n'.format(
  104. locations[-1].full_name) + locations[-1].docstring())
  105. else:
  106. return None
  107. def rpc_get_docstring_jedi16(self, filename, source, offset):
  108. # Backward compatibility to jedi<17
  109. line, column = pos_to_linecol(source, offset)
  110. locations = run_with_debug(jedi, 'goto_definitions',
  111. source=source, line=line, column=column,
  112. path=filename, encoding='utf-8',
  113. environment=self.environment)
  114. if not locations:
  115. return None
  116. # Filter uninteresting things
  117. if locations[-1].name in ["str", "int", "float", "bool", "tuple",
  118. "list", "dict"]:
  119. return None
  120. if locations[-1].docstring():
  121. return ('Documentation for {0}:\n\n'.format(
  122. locations[-1].full_name) + locations[-1].docstring())
  123. else:
  124. return None
  125. def rpc_get_definition(self, filename, source, offset):
  126. line, column = pos_to_linecol(source, offset)
  127. locations = run_with_debug(jedi, 'goto',
  128. code=source,
  129. path=filename,
  130. environment=self.environment,
  131. fun_kwargs={'line': line,
  132. 'column': column,
  133. 'follow_imports': True,
  134. 'follow_builtin_imports': True})
  135. if not locations:
  136. return None
  137. # goto_definitions() can return silly stuff like __builtin__
  138. # for int variables, so we remove them. See issue #76.
  139. locations = [
  140. loc for loc in locations
  141. if (loc.module_path is not None
  142. and loc.module_name != 'builtins'
  143. and loc.module_name != '__builtin__')]
  144. if len(locations) == 0:
  145. return None
  146. loc = locations[-1]
  147. try:
  148. if loc.module_path == filename:
  149. offset = linecol_to_pos(source,
  150. loc.line,
  151. loc.column)
  152. else:
  153. with open(loc.module_path) as f:
  154. offset = linecol_to_pos(f.read(),
  155. loc.line,
  156. loc.column)
  157. except IOError: # pragma: no cover
  158. return None
  159. return (loc.module_path, offset)
  160. def rpc_get_definition_jedi16(self, filename, source, offset): # pragma: no cover
  161. # Backward compatibility to jedi<17
  162. line, column = pos_to_linecol(source, offset)
  163. locations = run_with_debug(jedi, 'goto_definitions',
  164. source=source, line=line, column=column,
  165. path=filename, encoding='utf-8',
  166. environment=self.environment)
  167. # goto_definitions() can return silly stuff like __builtin__
  168. # for int variables, so we fall back on goto() in those
  169. # cases. See issue #76.
  170. if (
  171. locations and
  172. (locations[0].module_path is None
  173. or locations[0].module_name == 'builtins'
  174. or locations[0].module_name == '__builtin__')
  175. ):
  176. locations = run_with_debug(jedi, 'goto_assignments',
  177. source=source, line=line,
  178. column=column,
  179. path=filename,
  180. encoding='utf-8',
  181. environment=self.environment)
  182. if not locations:
  183. return None
  184. else:
  185. loc = locations[-1]
  186. try:
  187. if loc.module_path:
  188. if loc.module_path == filename:
  189. offset = linecol_to_pos(source,
  190. loc.line,
  191. loc.column)
  192. else:
  193. with open(loc.module_path) as f:
  194. offset = linecol_to_pos(f.read(),
  195. loc.line,
  196. loc.column)
  197. else:
  198. return None
  199. except IOError:
  200. return None
  201. return (loc.module_path, offset)
  202. def rpc_get_assignment(self, filename, source, offset):
  203. raise Fault("Obsolete since jedi 17.0. Please use 'get_definition'.")
  204. def rpc_get_assignment_jedi16(self, filename, source, offset): # pragma: no cover
  205. # Backward compatibility to jedi<17
  206. line, column = pos_to_linecol(source, offset)
  207. locations = run_with_debug(jedi, 'goto_assignments',
  208. source=source, line=line, column=column,
  209. path=filename, encoding='utf-8',
  210. environment=self.environment)
  211. if not locations:
  212. return None
  213. else:
  214. loc = locations[-1]
  215. try:
  216. if loc.module_path:
  217. if loc.module_path == filename:
  218. offset = linecol_to_pos(source,
  219. loc.line,
  220. loc.column)
  221. else:
  222. with open(loc.module_path) as f:
  223. offset = linecol_to_pos(f.read(),
  224. loc.line,
  225. loc.column)
  226. else:
  227. return None
  228. except IOError:
  229. return None
  230. return (loc.module_path, offset)
  231. def rpc_get_calltip(self, filename, source, offset):
  232. line, column = pos_to_linecol(source, offset)
  233. calls = run_with_debug(jedi, 'get_signatures',
  234. code=source,
  235. path=filename,
  236. environment=self.environment,
  237. fun_kwargs={'line': line,
  238. 'column': column})
  239. if not calls:
  240. return None
  241. params = [re.sub("^param ", '', param.description)
  242. for param in calls[0].params]
  243. return {"name": calls[0].name,
  244. "index": calls[0].index,
  245. "params": params}
  246. def rpc_get_calltip_jedi16(self, filename, source, offset): # pragma: no cover
  247. # Backward compatibility to jedi<17
  248. line, column = pos_to_linecol(source, offset)
  249. calls = run_with_debug(jedi, 'call_signatures',
  250. source=source, line=line, column=column,
  251. path=filename, encoding='utf-8',
  252. environment=self.environment)
  253. if calls:
  254. call = calls[0]
  255. else:
  256. call = None
  257. if not call:
  258. return None
  259. # Strip 'param' added by jedi at the beginning of
  260. # parameter names. Should be unecessary for jedi > 0.13.0
  261. params = [re.sub("^param ", '', param.description)
  262. for param in call.params]
  263. return {"name": call.name,
  264. "index": call.index,
  265. "params": params}
  266. def rpc_get_calltip_or_oneline_docstring(self, filename, source, offset):
  267. """
  268. Return the current function calltip or its oneline docstring.
  269. Meant to be used with eldoc.
  270. """
  271. # Try to get a oneline docstring then
  272. docs = self.rpc_get_oneline_docstring(filename=filename,
  273. source=source,
  274. offset=offset)
  275. if docs is not None:
  276. if docs['doc'] != "No documentation":
  277. docs['kind'] = 'oneline_doc'
  278. return docs
  279. # Try to get a calltip
  280. calltip = self.rpc_get_calltip(filename=filename, source=source,
  281. offset=offset)
  282. if calltip is not None:
  283. calltip['kind'] = 'calltip'
  284. return calltip
  285. # Ok, no calltip, just display the function name
  286. if docs is not None:
  287. docs['kind'] = 'oneline_doc'
  288. return docs
  289. # Giving up...
  290. return None
  291. def rpc_get_oneline_docstring(self, filename, source, offset):
  292. """Return a oneline docstring for the symbol at offset"""
  293. line, column = pos_to_linecol(source, offset)
  294. definitions = run_with_debug(jedi, 'goto',
  295. code=source,
  296. path=filename,
  297. environment=self.environment,
  298. fun_kwargs={'line': line,
  299. 'column': column})
  300. if not definitions:
  301. return None
  302. # avoid unintersting stuff
  303. definitions = [defi for defi in definitions
  304. if defi.name not in
  305. ["str", "int", "float", "bool", "tuple",
  306. "list", "dict"]]
  307. if len(definitions) == 0:
  308. return None
  309. definition = definitions[0]
  310. # Get name
  311. if definition.type in ['function', 'class']:
  312. raw_name = definition.name
  313. name = '{}()'.format(raw_name)
  314. doc = definition.docstring().split('\n')
  315. elif definition.type in ['module']:
  316. raw_name = definition.name
  317. name = '{} {}'.format(raw_name, definition.type)
  318. doc = definition.docstring().split('\n')
  319. elif (definition.type in ['instance']
  320. and hasattr(definition, "name")):
  321. raw_name = definition.name
  322. name = raw_name
  323. doc = definition.docstring().split('\n')
  324. else:
  325. return None
  326. # Keep only the first paragraph that is not a function declaration
  327. lines = []
  328. call = "{}(".format(raw_name)
  329. # last line
  330. doc.append('')
  331. for i in range(len(doc)):
  332. if doc[i] == '' and len(lines) != 0:
  333. paragraph = " ".join(lines)
  334. lines = []
  335. if call != paragraph[0:len(call)]:
  336. break
  337. paragraph = ""
  338. continue
  339. lines.append(doc[i])
  340. # Keep only the first sentence
  341. onelinedoc = paragraph.split('. ', 1)
  342. if len(onelinedoc) == 2:
  343. onelinedoc = onelinedoc[0] + '.'
  344. else:
  345. onelinedoc = onelinedoc[0]
  346. if onelinedoc == '':
  347. onelinedoc = "No documentation"
  348. return {"name": name,
  349. "doc": onelinedoc}
  350. def rpc_get_oneline_docstring_jedi16(self, filename, source, offset): # pragma: no cover
  351. """Return a oneline docstring for the symbol at offset"""
  352. # Backward compatibility to jedi<17
  353. line, column = pos_to_linecol(source, offset)
  354. definitions = run_with_debug(jedi, 'goto_definitions',
  355. source=source, line=line, column=column,
  356. path=filename, encoding='utf-8',
  357. environment=self.environment)
  358. # avoid unintersting stuff
  359. try:
  360. if definitions[0].name in ["str", "int", "float", "bool", "tuple",
  361. "list", "dict"]:
  362. return None
  363. except:
  364. pass
  365. assignments = run_with_debug(jedi, 'goto_assignments',
  366. source=source, line=line, column=column,
  367. path=filename, encoding='utf-8',
  368. environment=self.environment)
  369. if definitions:
  370. definition = definitions[0]
  371. else:
  372. definition = None
  373. if assignments:
  374. assignment = assignments[0]
  375. else:
  376. assignment = None
  377. if definition:
  378. # Get name
  379. if definition.type in ['function', 'class']:
  380. raw_name = definition.name
  381. name = '{}()'.format(raw_name)
  382. doc = definition.docstring().split('\n')
  383. elif definition.type in ['module']:
  384. raw_name = definition.name
  385. name = '{} {}'.format(raw_name, definition.type)
  386. doc = definition.docstring().split('\n')
  387. elif (definition.type in ['instance']
  388. and hasattr(assignment, "name")):
  389. raw_name = assignment.name
  390. name = raw_name
  391. doc = assignment.docstring().split('\n')
  392. else:
  393. return None
  394. # Keep only the first paragraph that is not a function declaration
  395. lines = []
  396. call = "{}(".format(raw_name)
  397. # last line
  398. doc.append('')
  399. for i in range(len(doc)):
  400. if doc[i] == '' and len(lines) != 0:
  401. paragraph = " ".join(lines)
  402. lines = []
  403. if call != paragraph[0:len(call)]:
  404. break
  405. paragraph = ""
  406. continue
  407. lines.append(doc[i])
  408. # Keep only the first sentence
  409. onelinedoc = paragraph.split('. ', 1)
  410. if len(onelinedoc) == 2:
  411. onelinedoc = onelinedoc[0] + '.'
  412. else:
  413. onelinedoc = onelinedoc[0]
  414. if onelinedoc == '':
  415. onelinedoc = "No documentation"
  416. return {"name": name,
  417. "doc": onelinedoc}
  418. return None
  419. def rpc_get_usages(self, filename, source, offset):
  420. """Return the uses of the symbol at offset.
  421. Returns a list of occurrences of the symbol, as dicts with the
  422. fields name, filename, and offset.
  423. """
  424. line, column = pos_to_linecol(source, offset)
  425. uses = run_with_debug(jedi, 'get_references',
  426. code=source,
  427. path=filename,
  428. environment=self.environment,
  429. fun_kwargs={'line': line,
  430. 'column': column})
  431. if uses is None:
  432. return None
  433. result = []
  434. for use in uses:
  435. if use.module_path == filename:
  436. offset = linecol_to_pos(source, use.line, use.column)
  437. elif use.module_path is not None:
  438. with open(use.module_path) as f:
  439. text = f.read()
  440. offset = linecol_to_pos(text, use.line, use.column)
  441. result.append({"name": use.name,
  442. "filename": use.module_path,
  443. "offset": offset})
  444. return result
  445. def rpc_get_usages_jedi16(self, filename, source, offset): # pragma: no cover
  446. """Return the uses of the symbol at offset.
  447. Returns a list of occurrences of the symbol, as dicts with the
  448. fields name, filename, and offset.
  449. """
  450. # Backward compatibility to jedi<17
  451. line, column = pos_to_linecol(source, offset)
  452. uses = run_with_debug(jedi, 'usages',
  453. source=source, line=line, column=column,
  454. path=filename, encoding='utf-8',
  455. environment=self.environment)
  456. if uses is None:
  457. return None
  458. result = []
  459. for use in uses:
  460. if use.module_path == filename:
  461. offset = linecol_to_pos(source, use.line, use.column)
  462. elif use.module_path is not None:
  463. with open(use.module_path) as f:
  464. text = f.read()
  465. offset = linecol_to_pos(text, use.line, use.column)
  466. result.append({"name": use.name,
  467. "filename": use.module_path,
  468. "offset": offset})
  469. return result
  470. def rpc_get_names(self, filename, source, offset):
  471. """Return the list of possible names"""
  472. names = run_with_debug(jedi, 'get_names',
  473. code=source,
  474. path=filename,
  475. environment=self.environment,
  476. fun_kwargs={'all_scopes': True,
  477. 'definitions': True,
  478. 'references': True})
  479. result = []
  480. for name in names:
  481. if name.module_path == filename:
  482. offset = linecol_to_pos(source, name.line, name.column)
  483. elif name.module_path is not None:
  484. with open(name.module_path) as f:
  485. text = f.read()
  486. offset = linecol_to_pos(text, name.line, name.column)
  487. result.append({"name": name.name,
  488. "filename": name.module_path,
  489. "offset": offset})
  490. return result
  491. def rpc_get_names_jedi16(self, filename, source, offset): # pragma: no cover
  492. """Return the list of possible names"""
  493. # Backward compatibility to jedi<17
  494. names = jedi.api.names(source=source,
  495. path=filename, encoding='utf-8',
  496. all_scopes=True,
  497. definitions=True,
  498. references=True)
  499. result = []
  500. for name in names:
  501. if name.module_path == filename:
  502. offset = linecol_to_pos(source, name.line, name.column)
  503. elif name.module_path is not None:
  504. with open(name.module_path) as f:
  505. text = f.read()
  506. offset = linecol_to_pos(text, name.line, name.column)
  507. result.append({"name": name.name,
  508. "filename": name.module_path,
  509. "offset": offset})
  510. return result
  511. def rpc_get_rename_diff(self, filename, source, offset, new_name):
  512. """Get the diff resulting from renaming the thing at point"""
  513. if not hasattr(jedi.Script, "rename"): # pragma: no cover
  514. return {'success': "Not available"}
  515. line, column = pos_to_linecol(source, offset)
  516. ren = run_with_debug(jedi, 'rename', code=source,
  517. path=filename,
  518. environment=self.environment,
  519. fun_kwargs={'line': line,
  520. 'column': column,
  521. 'new_name': new_name})
  522. if ren is None:
  523. return {'success': False}
  524. else:
  525. return {'success': True,
  526. 'project_path': ren._inference_state.project._path,
  527. 'diff': ren.get_diff(),
  528. 'changed_files': list(ren.get_changed_files().keys())}
  529. def rpc_get_extract_variable_diff(self, filename, source, offset, new_name,
  530. line_beg, line_end, col_beg, col_end):
  531. """Get the diff resulting from extracting the selected code"""
  532. if not hasattr(jedi.Script, "extract_variable"): # pragma: no cover
  533. return {'success': "Not available"}
  534. ren = run_with_debug(jedi, 'extract_variable', code=source,
  535. path=filename,
  536. environment=self.environment,
  537. fun_kwargs={'line': line_beg,
  538. 'until_line': line_end,
  539. 'column': col_beg,
  540. 'until_column': col_end,
  541. 'new_name': new_name})
  542. if ren is None:
  543. return {'success': False}
  544. else:
  545. return {'success': True,
  546. 'project_path': ren._inference_state.project._path,
  547. 'diff': ren.get_diff(),
  548. 'changed_files': list(ren.get_changed_files().keys())}
  549. def rpc_get_extract_function_diff(self, filename, source, offset, new_name,
  550. line_beg, line_end, col_beg, col_end):
  551. """Get the diff resulting from extracting the selected code"""
  552. if not hasattr(jedi.Script, "extract_function"): # pragma: no cover
  553. return {'success': "Not available"}
  554. ren = run_with_debug(jedi, 'extract_function', code=source,
  555. path=filename,
  556. environment=self.environment,
  557. fun_kwargs={'line': line_beg,
  558. 'until_line': line_end,
  559. 'column': col_beg,
  560. 'until_column': col_end,
  561. 'new_name': new_name})
  562. if ren is None:
  563. return {'success': False}
  564. else:
  565. return {'success': True,
  566. 'project_path': ren._inference_state.project._path,
  567. 'diff': ren.get_diff(),
  568. 'changed_files': list(ren.get_changed_files().keys())}
  569. def rpc_get_inline_diff(self, filename, source, offset):
  570. """Get the diff resulting from inlining the selected variable"""
  571. if not hasattr(jedi.Script, "inline"): # pragma: no cover
  572. return {'success': "Not available"}
  573. line, column = pos_to_linecol(source, offset)
  574. ren = run_with_debug(jedi, 'inline', code=source,
  575. path=filename,
  576. environment=self.environment,
  577. fun_kwargs={'line': line,
  578. 'column': column})
  579. if ren is None:
  580. return {'success': False}
  581. else:
  582. return {'success': True,
  583. 'project_path': ren._inference_state.project._path,
  584. 'diff': ren.get_diff(),
  585. 'changed_files': list(ren.get_changed_files().keys())}
  586. # From the Jedi documentation:
  587. #
  588. # line is the current line you want to perform actions on (starting
  589. # with line #1 as the first line). column represents the current
  590. # column/indent of the cursor (starting with zero). source_path
  591. # should be the path of your file in the file system.
  592. def pos_to_linecol(text, pos):
  593. """Return a tuple of line and column for offset pos in text.
  594. Lines are one-based, columns zero-based.
  595. This is how Jedi wants it. Don't ask me why.
  596. """
  597. line_start = text.rfind("\n", 0, pos) + 1
  598. line = text.count("\n", 0, line_start) + 1
  599. col = pos - line_start
  600. return line, col
  601. def linecol_to_pos(text, line, col):
  602. """Return the offset of this line and column in text.
  603. Lines are one-based, columns zero-based.
  604. This is how Jedi wants it. Don't ask me why.
  605. """
  606. nth_newline_offset = 0
  607. for i in range(line - 1):
  608. new_offset = text.find("\n", nth_newline_offset)
  609. if new_offset < 0:
  610. raise ValueError("Text does not have {0} lines."
  611. .format(line))
  612. nth_newline_offset = new_offset + 1
  613. offset = nth_newline_offset + col
  614. if offset > len(text):
  615. raise ValueError("Line {0} column {1} is not within the text"
  616. .format(line, col))
  617. return offset
  618. def run_with_debug(jedi, name, fun_kwargs={}, *args, **kwargs):
  619. re_raise = kwargs.pop('re_raise', ())
  620. try:
  621. script = jedi.Script(*args, **kwargs)
  622. return getattr(script, name)(**fun_kwargs)
  623. except Exception as e:
  624. if isinstance(e, re_raise):
  625. raise
  626. if JEDISUP17:
  627. if isinstance(e, jedi.RefactoringError):
  628. return None
  629. # Bug jedi#485
  630. if (
  631. isinstance(e, ValueError) and
  632. "invalid \\x escape" in str(e)
  633. ):
  634. return None
  635. # Bug jedi#485 in Python 3
  636. if (
  637. isinstance(e, SyntaxError) and
  638. "truncated \\xXX escape" in str(e)
  639. ):
  640. return None
  641. from jedi import debug
  642. debug_info = []
  643. def _debug(level, str_out):
  644. if level == debug.NOTICE:
  645. prefix = "[N]"
  646. elif level == debug.WARNING:
  647. prefix = "[W]"
  648. else:
  649. prefix = "[?]"
  650. debug_info.append(u"{0} {1}".format(prefix, str_out))
  651. jedi.set_debug_function(_debug, speed=False)
  652. try:
  653. script = jedi.Script(*args, **kwargs)
  654. return getattr(script, name)()
  655. except Exception as e:
  656. source = kwargs.get('source')
  657. sc_args = []
  658. sc_args.extend(repr(arg) for arg in args)
  659. sc_args.extend("{0}={1}".format(k, "source" if k == "source"
  660. else repr(v))
  661. for (k, v) in kwargs.items())
  662. data = {
  663. "traceback": traceback.format_exc(),
  664. "jedi_debug_info": {'script_args': ", ".join(sc_args),
  665. 'source': source,
  666. 'method': name,
  667. 'debug_info': debug_info}
  668. }
  669. raise rpc.Fault(message=str(e),
  670. code=500,
  671. data=data)
  672. finally:
  673. jedi.set_debug_function(None)