Skip to content

Commit 2fb2c81

Browse files
bnavigatorFoxboronccordoba12
authored
Update Jedi calls for its 0.17.0+ API (#781)
Co-authored-by: Morten Linderud <morten@linderud.pw> Co-authored-by: Carlos Cordoba <ccordoba12@gmail.com>
1 parent e78ccec commit 2fb2c81

29 files changed

+241
-241
lines changed

pyls/_utils.py

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
# Copyright 2017 Palantir Technologies, Inc.
2-
from distutils.version import LooseVersion
32
import functools
43
import inspect
54
import logging
@@ -140,18 +139,34 @@ def format_docstring(contents):
140139
"""
141140
contents = contents.replace('\t', u'\u00A0' * 4)
142141
contents = contents.replace(' ', u'\u00A0' * 2)
143-
if LooseVersion(JEDI_VERSION) < LooseVersion('0.15.0'):
144-
contents = contents.replace('*', '\\*')
145142
return contents
146143

147144

148145
def clip_column(column, lines, line_number):
149-
# Normalise the position as per the LSP that accepts character positions > line length
150-
# https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md#position
146+
"""
147+
Normalise the position as per the LSP that accepts character positions > line length
148+
149+
https://microsoft.github.io/language-server-protocol/specification#position
150+
"""
151151
max_column = len(lines[line_number].rstrip('\r\n')) if len(lines) > line_number else 0
152152
return min(column, max_column)
153153

154154

155+
def position_to_jedi_linecolumn(document, position):
156+
"""
157+
Convert the LSP format 'line', 'character' to Jedi's 'line', 'column'
158+
159+
https://microsoft.github.io/language-server-protocol/specification#position
160+
"""
161+
code_position = {}
162+
if position:
163+
code_position = {'line': position['line'] + 1,
164+
'column': clip_column(position['character'],
165+
document.lines,
166+
position['line'])}
167+
return code_position
168+
169+
155170
if os.name == 'nt':
156171
import ctypes
157172

pyls/plugins/definition.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
# Copyright 2017 Palantir Technologies, Inc.
22
import logging
3-
from pyls import hookimpl, uris
3+
from pyls import hookimpl, uris, _utils
44

55
log = logging.getLogger(__name__)
66

77

88
@hookimpl
99
def pyls_definitions(config, document, position):
1010
settings = config.plugin_settings('jedi_definition')
11-
definitions = document.jedi_script(position).goto_assignments(
11+
code_position = _utils.position_to_jedi_linecolumn(document, position)
12+
definitions = document.jedi_script().goto(
1213
follow_imports=settings.get('follow_imports', True),
13-
follow_builtin_imports=settings.get('follow_builtin_imports', True))
14+
follow_builtin_imports=settings.get('follow_builtin_imports', True),
15+
**code_position)
1416

1517
return [
1618
{

pyls/plugins/highlight.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
# Copyright 2017 Palantir Technologies, Inc.
22
import logging
3-
from pyls import hookimpl, lsp
3+
from pyls import hookimpl, lsp, _utils
44

55
log = logging.getLogger(__name__)
66

77

88
@hookimpl
99
def pyls_document_highlight(document, position):
10-
usages = document.jedi_script(position).usages()
10+
code_position = _utils.position_to_jedi_linecolumn(document, position)
11+
usages = document.jedi_script().get_references(**code_position)
1112

1213
def is_valid(definition):
1314
return definition.line is not None and definition.column is not None

pyls/plugins/hover.py

Lines changed: 34 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Copyright 2017 Palantir Technologies, Inc.
2-
from distutils.version import LooseVersion
2+
33
import logging
44

55
from pyls import hookimpl, _utils
@@ -9,43 +9,40 @@
99

1010
@hookimpl
1111
def pyls_hover(document, position):
12-
definitions = document.jedi_script(position).goto_definitions()
12+
code_position = _utils.position_to_jedi_linecolumn(document, position)
13+
definitions = document.jedi_script().infer(**code_position)
1314
word = document.word_at_position(position)
1415

15-
if LooseVersion(_utils.JEDI_VERSION) >= LooseVersion('0.15.0'):
16-
# Find first exact matching definition
17-
definition = next((x for x in definitions if x.name == word), None)
18-
19-
# Ensure a definition is used if only one is available
20-
# even if the word doesn't match. An example of this case is 'np'
21-
# where 'numpy' doesn't match with 'np'. Same for NumPy ufuncs
22-
if len(definitions) == 1:
23-
definition = definitions[0]
24-
25-
if not definition:
26-
return {'contents': ''}
27-
28-
# raw docstring returns only doc, without signature
29-
doc = _utils.format_docstring(definition.docstring(raw=True))
30-
31-
# Find first exact matching signature
32-
signature = next((x.to_string() for x in definition.get_signatures() if x.name == word), '')
33-
34-
contents = []
35-
if signature:
36-
contents.append({
37-
'language': 'python',
38-
'value': signature,
39-
})
40-
if doc:
41-
contents.append(doc)
42-
if not contents:
43-
return {'contents': ''}
44-
return {'contents': contents}
45-
else:
46-
# Find an exact match for a completion
47-
for d in definitions:
48-
if d.name == word:
49-
return {'contents': _utils.format_docstring(d.docstring()) or ''}
16+
# Find first exact matching definition
17+
definition = next((x for x in definitions if x.name == word), None)
18+
19+
# Ensure a definition is used if only one is available
20+
# even if the word doesn't match. An example of this case is 'np'
21+
# where 'numpy' doesn't match with 'np'. Same for NumPy ufuncs
22+
if len(definitions) == 1:
23+
definition = definitions[0]
5024

25+
if not definition:
5126
return {'contents': ''}
27+
28+
# raw docstring returns only doc, without signature
29+
doc = _utils.format_docstring(definition.docstring(raw=True))
30+
31+
# Find first exact matching signature
32+
signature = next((x.to_string() for x in definition.get_signatures()
33+
if x.name == word), '')
34+
35+
contents = []
36+
if signature:
37+
contents.append({
38+
'language': 'python',
39+
'value': signature,
40+
})
41+
42+
if doc:
43+
contents.append(doc)
44+
45+
if not contents:
46+
return {'contents': ''}
47+
48+
return {'contents': contents}

pyls/plugins/jedi_completion.py

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -50,17 +50,11 @@
5050

5151
@hookimpl
5252
def pyls_completions(config, document, position):
53-
try:
54-
definitions = document.jedi_script(position).completions()
55-
except AttributeError as e:
56-
if 'CompiledObject' in str(e):
57-
# Needed to handle missing CompiledObject attribute
58-
# 'sub_modules_dict'
59-
definitions = None
60-
else:
61-
raise e
53+
"""Get formatted completions for current code position"""
54+
code_position = _utils.position_to_jedi_linecolumn(document, position)
55+
completions = document.jedi_script().complete(**code_position)
6256

63-
if not definitions:
57+
if not completions:
6458
return None
6559

6660
completion_capabilities = config.capabilities.get('textDocument', {}).get('completion', {})
@@ -69,7 +63,7 @@ def pyls_completions(config, document, position):
6963
settings = config.plugin_settings('jedi_completion', document_path=document.path)
7064
should_include_params = settings.get('include_params')
7165
include_params = snippet_support and should_include_params and use_snippets(document, position)
72-
return [_format_completion(d, include_params) for d in definitions] or None
66+
return [_format_completion(c, include_params) for c in completions] or None
7367

7468

7569
def is_exception_class(name):
@@ -138,9 +132,9 @@ def _format_completion(d, include_params=True):
138132
path = path.replace('/', '\\/')
139133
completion['insertText'] = path
140134

141-
if (include_params and hasattr(d, 'params') and d.params and
142-
not is_exception_class(d.name)):
143-
positional_args = [param for param in d.params
135+
sig = d.get_signatures()
136+
if (include_params and sig and not is_exception_class(d.name)):
137+
positional_args = [param for param in sig[0].params
144138
if '=' not in param.description and
145139
param.name not in {'/', '*'}]
146140

@@ -163,8 +157,9 @@ def _format_completion(d, include_params=True):
163157

164158

165159
def _label(definition):
166-
if definition.type in ('function', 'method') and hasattr(definition, 'params'):
167-
params = ', '.join([param.name for param in definition.params])
160+
sig = definition.get_signatures()
161+
if definition.type in ('function', 'method') and sig:
162+
params = ', '.join([param.name for param in sig[0].params])
168163
return '{}({})'.format(definition.name, params)
169164

170165
return definition.name

pyls/plugins/references.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
# Copyright 2017 Palantir Technologies, Inc.
22
import logging
3-
from pyls import hookimpl, uris
3+
from pyls import hookimpl, uris, _utils
44

55
log = logging.getLogger(__name__)
66

77

88
@hookimpl
99
def pyls_references(document, position, exclude_declaration=False):
10-
# Note that usages is not that great in a lot of cases: https://github.com/davidhalter/jedi/issues/744
11-
usages = document.jedi_script(position).usages()
10+
code_position = _utils.position_to_jedi_linecolumn(document, position)
11+
usages = document.jedi_script().get_references(**code_position)
1212

1313
if exclude_declaration:
1414
# Filter out if the usage is the actual declaration of the thing

pyls/plugins/signature.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414

1515
@hookimpl
1616
def pyls_signature_help(document, position):
17-
signatures = document.jedi_script(position).call_signatures()
17+
code_position = _utils.position_to_jedi_linecolumn(document, position)
18+
signatures = document.jedi_script().get_signatures(**code_position)
1819

1920
if not signatures:
2021
return {'signatures': []}

pyls/workspace.py

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,8 @@ def _create_document(self, doc_uri, source=None, version=None):
112112

113113
class Document(object):
114114

115-
def __init__(self, uri, source=None, version=None, local=True, extra_sys_path=None, rope_project_builder=None,
116-
config=None, workspace=None):
115+
def __init__(self, uri, workspace, source=None, version=None, local=True, extra_sys_path=None,
116+
rope_project_builder=None, config=None):
117117
self.uri = uri
118118
self.version = version
119119
self.path = uris.to_fs_path(uri)
@@ -213,16 +213,9 @@ def word_at_position(self, position):
213213
return m_start[0] + m_end[-1]
214214

215215
def jedi_names(self, all_scopes=False, definitions=True, references=False):
216-
environment_path = None
217-
if self._config:
218-
jedi_settings = self._config.plugin_settings('jedi', document_path=self.path)
219-
environment_path = jedi_settings.get('environment')
220-
environment = self.get_enviroment(environment_path) if environment_path else None
221-
222-
return jedi.api.names(
223-
source=self.source, path=self.path, all_scopes=all_scopes,
224-
definitions=definitions, references=references, environment=environment,
225-
)
216+
script = self.jedi_script()
217+
return script.get_names(all_scopes=all_scopes, definitions=definitions,
218+
references=references)
226219

227220
def jedi_script(self, position=None):
228221
extra_paths = []
@@ -233,19 +226,20 @@ def jedi_script(self, position=None):
233226
environment_path = jedi_settings.get('environment')
234227
extra_paths = jedi_settings.get('extra_paths') or []
235228

236-
sys_path = self.sys_path(environment_path) + extra_paths
237229
environment = self.get_enviroment(environment_path) if environment_path else None
230+
sys_path = self.sys_path(environment_path) + extra_paths
231+
project_path = self._workspace.root_path
238232

239233
kwargs = {
240-
'source': self.source,
234+
'code': self.source,
241235
'path': self.path,
242-
'sys_path': sys_path,
243236
'environment': environment,
237+
'project': jedi.Project(path=project_path, sys_path=sys_path),
244238
}
245239

246240
if position:
247-
kwargs['line'] = position['line'] + 1
248-
kwargs['column'] = _utils.clip_column(position['character'], self.lines, position['line'])
241+
# Deprecated by Jedi to use in Script() constructor
242+
kwargs += _utils.position_to_jedi_linecolumn(self, position)
249243

250244
return jedi.Script(**kwargs)
251245

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
'configparser; python_version<"3.0"',
3636
'future>=0.14.0; python_version<"3"',
3737
'backports.functools_lru_cache; python_version<"3.2"',
38-
'jedi>=0.14.1,<0.16',
38+
'jedi>=0.17.0,<0.18.0',
3939
'python-jsonrpc-server>=0.3.2',
4040
'pluggy',
4141
'ujson<=1.35; platform_system!="Windows"'

test/fixtures.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,5 +48,5 @@ def config(workspace): # pylint: disable=redefined-outer-name
4848

4949

5050
@pytest.fixture
51-
def doc():
52-
return Document(DOC_URI, DOC)
51+
def doc(workspace): # pylint: disable=redefined-outer-name
52+
return Document(DOC_URI, workspace, DOC)

0 commit comments

Comments
 (0)