Skip to content

Commit 7df55fa

Browse files
committed
Merge from 4.x: PR spyder-ide#13146
2 parents e09f8b1 + 1dd07b5 commit 7df55fa

20 files changed

Lines changed: 212 additions & 119 deletions

external-deps/python-language-server/.gitrepo

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
[subrepo]
77
remote = https://github.com/palantir/python-language-server.git
88
branch = develop
9-
commit = c57bf8940411676ccc82c74e8a32227289cda30f
10-
parent = 69bb0c54c9d3c4d44ac0c950bfdc9e2db0d1b0d4
9+
commit = 5fa7ae9154c79ba1f5347e1452bd770a958869b3
10+
parent = b28a55794aa934db3c08c1b533df4d72ae5e6664
1111
method = merge
1212
cmdver = 0.4.1

external-deps/python-language-server/pyls/config/config.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -106,29 +106,31 @@ def settings(self, document_path=None):
106106
settings = {}
107107
sources = self._settings.get('configurationSources', DEFAULT_CONFIG_SOURCES)
108108

109+
# Plugin configuration
110+
settings = _utils.merge_dicts(settings, self._plugin_settings)
111+
112+
# LSP configuration
113+
settings = _utils.merge_dicts(settings, self._settings)
114+
115+
# User configuration
109116
for source_name in reversed(sources):
110117
source = self._config_sources.get(source_name)
111118
if not source:
112119
continue
113120
source_conf = source.user_config()
114121
log.debug("Got user config from %s: %s", source.__class__.__name__, source_conf)
115122
settings = _utils.merge_dicts(settings, source_conf)
116-
log.debug("With user configuration: %s", settings)
117-
118-
settings = _utils.merge_dicts(settings, self._plugin_settings)
119-
log.debug("With plugin configuration: %s", settings)
120-
121-
settings = _utils.merge_dicts(settings, self._settings)
122-
log.debug("With lsp configuration: %s", settings)
123123

124+
# Project configuration
124125
for source_name in reversed(sources):
125126
source = self._config_sources.get(source_name)
126127
if not source:
127128
continue
128129
source_conf = source.project_config(document_path or self._root_path)
129130
log.debug("Got project config from %s: %s", source.__class__.__name__, source_conf)
130131
settings = _utils.merge_dicts(settings, source_conf)
131-
log.debug("With project configuration: %s", settings)
132+
133+
log.debug("With configuration: %s", settings)
132134

133135
return settings
134136

external-deps/python-language-server/pyls/plugins/flake8_lint.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from pyls import hookimpl, lsp
88

99
log = logging.getLogger(__name__)
10+
FIX_IGNORES_RE = re.compile(r'([^a-zA-Z0-9_,]*;.*(\W+||$))')
1011

1112

1213
@hookimpl
@@ -16,7 +17,8 @@ def pyls_settings():
1617

1718

1819
@hookimpl
19-
def pyls_lint(config, document):
20+
def pyls_lint(workspace, document):
21+
config = workspace._config
2022
settings = config.plugin_settings('flake8')
2123
log.debug("Got flake8 settings: %s", settings)
2224

@@ -39,22 +41,28 @@ def pyls_lint(config, document):
3941
log.debug("using flake8 with config: %s", opts['config'])
4042

4143
# Call the flake8 utility then parse diagnostics from stdout
44+
flake8_executable = settings.get('executable', 'flake8')
45+
4246
args = build_args(opts, document.path)
43-
output = run_flake8(args)
47+
output = run_flake8(flake8_executable, args)
4448
return parse_stdout(document, output)
4549

4650

47-
def run_flake8(args):
51+
def run_flake8(flake8_executable, args):
4852
"""Run flake8 with the provided arguments, logs errors
4953
from stderr if any.
5054
"""
51-
log.debug("Calling flake8 with args: '%s'", args)
55+
# a quick temporary fix to deal with Atom
56+
args = [(i if not i.startswith('--ignore=') else FIX_IGNORES_RE.sub('', i))
57+
for i in args if i is not None]
58+
59+
log.debug("Calling %s with args: '%s'", flake8_executable, args)
5260
try:
53-
cmd = ['flake8']
61+
cmd = [flake8_executable]
5462
cmd.extend(args)
5563
p = Popen(cmd, stdout=PIPE, stderr=PIPE)
5664
except IOError:
57-
log.debug("Can't execute flake8. Trying with 'python -m flake8'")
65+
log.debug("Can't execute %s. Trying with 'python -m flake8'", flake8_executable)
5866
cmd = ['python', '-m', 'flake8']
5967
cmd.extend(args)
6068
p = Popen(cmd, stdout=PIPE, stderr=PIPE)

external-deps/python-language-server/pyls/plugins/pycodestyle_lint.py

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

2020

2121
@hookimpl
22-
def pyls_lint(config, document):
22+
def pyls_lint(workspace, document):
23+
config = workspace._config
2324
settings = config.plugin_settings('pycodestyle')
2425
log.debug("Got pycodestyle settings: %s", settings)
2526

external-deps/python-language-server/pyls/python_ls.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ def m_workspace__did_change_configuration(self, settings=None):
358358
self.config.update((settings or {}).get('pyls', {}))
359359
for workspace_uri in self.workspaces:
360360
workspace = self.workspaces[workspace_uri]
361-
workspace.update_config(self.config)
361+
workspace.update_config(settings)
362362
for doc_uri in workspace.documents:
363363
self.lint(doc_uri, is_saved=False)
364364

@@ -376,23 +376,31 @@ def m_workspace__did_change_workspace_folders(self, event=None, **_kwargs): # p
376376
for added_info in added:
377377
if 'uri' in added_info:
378378
added_uri = added_info['uri']
379-
self.workspaces[added_uri] = Workspace(added_uri, self._endpoint, self.config)
379+
workspace_config = config.Config(
380+
added_uri, self.config._init_opts,
381+
self.config._process_id, self.config._capabilities)
382+
self.workspaces[added_uri] = Workspace(
383+
added_uri, self._endpoint, workspace_config)
380384

381385
root_workspace_removed = any(removed_info['uri'] == self.root_uri for removed_info in removed)
382386
workspace_added = len(added) > 0 and 'uri' in added[0]
383387
if root_workspace_removed and workspace_added:
384388
added_uri = added[0]['uri']
385389
self.root_uri = added_uri
386-
self.workspace = self.workspaces[added_uri]
390+
new_root_workspace = self.workspaces[added_uri]
391+
self.config = new_root_workspace._config
392+
self.workspace = new_root_workspace
387393
elif root_workspace_removed:
388394
# NOTE: Removing the root workspace can only happen when the server
389395
# is closed, thus the else condition of this if can never happen.
390396
if self.workspaces:
391397
log.debug('Root workspace deleted!')
392398
available_workspaces = sorted(self.workspaces)
393399
first_workspace = available_workspaces[0]
400+
new_root_workspace = self.workspaces[first_workspace]
394401
self.root_uri = first_workspace
395-
self.workspace = self.workspaces[first_workspace]
402+
self.config = new_root_workspace._config
403+
self.workspace = new_root_workspace
396404

397405
# Migrate documents that are on the root workspace and have a better
398406
# match now

external-deps/python-language-server/pyls/workspace.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,10 @@ def update_document(self, doc_uri, change, version=None):
8484
self._docs[doc_uri].apply_change(change)
8585
self._docs[doc_uri].version = version
8686

87-
def update_config(self, config):
88-
self._config = config
87+
def update_config(self, settings):
88+
self._config.update((settings or {}).get('pyls', {}))
8989
for doc_uri in self.documents:
90-
self.get_document(doc_uri).update_config(config)
90+
self.get_document(doc_uri).update_config(settings)
9191

9292
def apply_edit(self, edit):
9393
return self._endpoint.request(self.M_APPLY_EDIT, {'edit': edit})
@@ -106,23 +106,25 @@ def source_roots(self, document_path):
106106
def _create_document(self, doc_uri, source=None, version=None):
107107
path = uris.to_fs_path(doc_uri)
108108
return Document(
109-
doc_uri, self, source=source, version=version,
109+
doc_uri,
110+
self,
111+
source=source,
112+
version=version,
110113
extra_sys_path=self.source_roots(path),
111114
rope_project_builder=self._rope_project_builder,
112-
config=self._config,
113115
)
114116

115117

116118
class Document(object):
117119

118120
def __init__(self, uri, workspace, source=None, version=None, local=True, extra_sys_path=None,
119-
rope_project_builder=None, config=None):
121+
rope_project_builder=None):
120122
self.uri = uri
121123
self.version = version
122124
self.path = uris.to_fs_path(uri)
123125
self.filename = os.path.basename(self.path)
124126

125-
self._config = config
127+
self._config = workspace._config
126128
self._workspace = workspace
127129
self._local = local
128130
self._source = source
@@ -147,8 +149,8 @@ def source(self):
147149
return f.read()
148150
return self._source
149151

150-
def update_config(self, config):
151-
self._config = config
152+
def update_config(self, settings):
153+
self._config.update((settings or {}).get('pyls', {}))
152154

153155
def apply_change(self, change):
154156
"""Apply a change to the document."""

external-deps/python-language-server/test/fixtures.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ def pyls(tmpdir):
3939
@pytest.fixture
4040
def workspace(tmpdir):
4141
"""Return a workspace."""
42-
return Workspace(uris.from_fs_path(str(tmpdir)), Mock())
42+
ws = Workspace(uris.from_fs_path(str(tmpdir)), Mock())
43+
ws._config = Config(ws.root_uri, {}, 0, {})
44+
return ws
4345

4446

4547
@pytest.fixture

external-deps/python-language-server/test/plugins/test_completion.py

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
import os
33
import sys
44

5-
from test.test_utils import MockWorkspace
65
import pytest
76

87
from pyls import uris, lsp
@@ -278,7 +277,7 @@ def test_multistatement_snippet(config, workspace):
278277
assert completions[0]['insertText'] == 'date(${1:year}, ${2:month}, ${3:day})$0'
279278

280279

281-
def test_jedi_completion_extra_paths(config, tmpdir, workspace):
280+
def test_jedi_completion_extra_paths(tmpdir, workspace):
282281
# Create a tempfile with some content and pass to extra_paths
283282
temp_doc_content = '''
284283
def spam():
@@ -296,42 +295,42 @@ def spam():
296295

297296
# After 'foo.s' without extra paths
298297
com_position = {'line': 1, 'character': 5}
299-
completions = pyls_jedi_completions(config, doc, com_position)
298+
completions = pyls_jedi_completions(doc._config, doc, com_position)
300299
assert completions is None
301300

302301
# Update config extra paths
303-
config.update({'plugins': {'jedi': {'extra_paths': extra_paths}}})
304-
doc.update_config(config)
302+
settings = {'pyls': {'plugins': {'jedi': {'extra_paths': extra_paths}}}}
303+
doc.update_config(settings)
305304

306305
# After 'foo.s' with extra paths
307306
com_position = {'line': 1, 'character': 5}
308-
completions = pyls_jedi_completions(config, doc, com_position)
307+
completions = pyls_jedi_completions(doc._config, doc, com_position)
309308
assert completions[0]['label'] == 'spam()'
310309

311310

312311
@pytest.mark.skipif(PY2 or not LINUX or not CI, reason="tested on linux and python 3 only")
313-
def test_jedi_completion_environment(config):
312+
def test_jedi_completion_environment(workspace):
314313
# Content of doc to test completion
315314
doc_content = '''import logh
316315
'''
317-
doc = Document(DOC_URI, MockWorkspace(), doc_content)
316+
doc = Document(DOC_URI, workspace, doc_content)
318317

319318
# After 'import logh' with default environment
320319
com_position = {'line': 0, 'character': 11}
321320

322321
assert os.path.isdir('/tmp/pyenv/')
323322

324-
config.update({'plugins': {'jedi': {'environment': None}}})
325-
doc.update_config(config)
326-
completions = pyls_jedi_completions(config, doc, com_position)
323+
settings = {'pyls': {'plugins': {'jedi': {'environment': None}}}}
324+
doc.update_config(settings)
325+
completions = pyls_jedi_completions(doc._config, doc, com_position)
327326
assert completions is None
328327

329328
# Update config extra environment
330329
env_path = '/tmp/pyenv/bin/python'
331-
config.update({'plugins': {'jedi': {'environment': env_path}}})
332-
doc.update_config(config)
330+
settings = {'pyls': {'plugins': {'jedi': {'environment': env_path}}}}
331+
doc.update_config(settings)
333332

334333
# After 'import logh' with new environment
335-
completions = pyls_jedi_completions(config, doc, com_position)
334+
completions = pyls_jedi_completions(doc._config, doc, com_position)
336335
assert completions[0]['label'] == 'loghub'
337336
assert 'changelog generator' in completions[0]['documentation'].lower()

external-deps/python-language-server/test/plugins/test_flake8_lint.py

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
# Copyright 2019 Palantir Technologies, Inc.
22
import tempfile
33
import os
4-
from test.test_utils import MockWorkspace
54
from mock import patch
65
from pyls import lsp, uris
76
from pyls.plugins import flake8_lint
@@ -19,29 +18,29 @@ def using_const():
1918
"""
2019

2120

22-
def temp_document(doc_text):
21+
def temp_document(doc_text, workspace):
2322
temp_file = tempfile.NamedTemporaryFile(mode='w', delete=False)
2423
name = temp_file.name
2524
temp_file.write(doc_text)
2625
temp_file.close()
27-
doc = Document(uris.from_fs_path(name), MockWorkspace())
26+
doc = Document(uris.from_fs_path(name), workspace)
2827

2928
return name, doc
3029

3130

32-
def test_flake8_no_checked_file(config, workspace):
31+
def test_flake8_no_checked_file(workspace):
3332
# A bad uri or a non-saved file may cause the flake8 linter to do nothing.
3433
# In this situtation, the linter will return an empty list.
3534

3635
doc = Document('', workspace, DOC)
37-
diags = flake8_lint.pyls_lint(config, doc)
36+
diags = flake8_lint.pyls_lint(workspace, doc)
3837
assert 'Error' in diags[0]['message']
3938

4039

41-
def test_flake8_lint(config):
40+
def test_flake8_lint(workspace):
4241
try:
43-
name, doc = temp_document(DOC)
44-
diags = flake8_lint.pyls_lint(config, doc)
42+
name, doc = temp_document(DOC, workspace)
43+
diags = flake8_lint.pyls_lint(workspace, doc)
4544
msg = 'local variable \'a\' is assigned to but never used'
4645
unused_var = [d for d in diags if d['message'] == msg][0]
4746

@@ -55,14 +54,29 @@ def test_flake8_lint(config):
5554
os.remove(name)
5655

5756

58-
def test_flake8_config_param(config):
57+
def test_flake8_config_param(workspace):
5958
with patch('pyls.plugins.flake8_lint.Popen') as popen_mock:
6059
mock_instance = popen_mock.return_value
6160
mock_instance.communicate.return_value = [bytes(), bytes()]
6261
flake8_conf = '/tmp/some.cfg'
63-
config.update({'plugins': {'flake8': {'config': flake8_conf}}})
64-
_name, doc = temp_document(DOC)
65-
flake8_lint.pyls_lint(config, doc)
62+
workspace._config.update({'plugins': {'flake8': {'config': flake8_conf}}})
63+
_name, doc = temp_document(DOC, workspace)
64+
flake8_lint.pyls_lint(workspace, doc)
6665
call_args = popen_mock.call_args.args[0]
6766
assert 'flake8' in call_args
6867
assert '--config={}'.format(flake8_conf) in call_args
68+
69+
70+
def test_flake8_executable_param(workspace):
71+
with patch('pyls.plugins.flake8_lint.Popen') as popen_mock:
72+
mock_instance = popen_mock.return_value
73+
mock_instance.communicate.return_value = [bytes(), bytes()]
74+
75+
flake8_executable = '/tmp/flake8'
76+
workspace._config.update({'plugins': {'flake8': {'executable': flake8_executable}}})
77+
78+
_name, doc = temp_document(DOC, workspace)
79+
flake8_lint.pyls_lint(workspace, doc)
80+
81+
call_args = popen_mock.call_args.args[0]
82+
assert flake8_executable in call_args

0 commit comments

Comments
 (0)