Skip to content

Commit 6dd41c1

Browse files
committed
Merge remote-tracking branch 'upstream/develop' into develop
2 parents 60b5005 + 78dee3d commit 6dd41c1

27 files changed

+595
-181
lines changed

.circleci/config.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414

1515
python3-test:
1616
docker:
17-
- image: "python:3.5-stretch"
17+
- image: "python:3.6-stretch"
1818
steps:
1919
- checkout
2020
# To test Jedi environments
@@ -35,7 +35,7 @@ jobs:
3535

3636
publish:
3737
docker:
38-
- image: "python:3.5-stretch"
38+
- image: "python:3.6-stretch"
3939
steps:
4040
- checkout
4141
- run: ./scripts/circle/pypi.sh

appveyor.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ environment:
66
PYTHON_VERSION: "2.7.15"
77
PYTHON_ARCH: "64"
88

9-
- PYTHON: "C:\\Python35"
10-
PYTHON_VERSION: "3.5.7"
9+
- PYTHON: "C:\\Python36"
10+
PYTHON_VERSION: "3.6.8"
1111
PYTHON_ARCH: "64"
1212

1313
matrix:

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

pyls/config/pycodestyle_conf.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
('ignore', 'plugins.pycodestyle.ignore', list),
1616
('max-line-length', 'plugins.pycodestyle.maxLineLength', int),
1717
('select', 'plugins.pycodestyle.select', list),
18+
('aggressive', 'plugins.pycodestyle.aggressive', int),
1819
]
1920

2021

pyls/lsp.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@ class CompletionItemKind(object):
2424
Color = 16
2525
File = 17
2626
Reference = 18
27+
Folder = 19
28+
EnumMember = 20
29+
Constant = 21
30+
Struct = 22
31+
Event = 23
32+
Operator = 24
33+
TypeParameter = 25
2734

2835

2936
class DocumentHighlightKind(object):

pyls/plugins/autopep8_format.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Copyright 2018 Palantir Technologies, Inc.
22
import logging
3-
from autopep8 import fix_code
3+
import pycodestyle
4+
from autopep8 import fix_code, continued_indentation as autopep8_c_i
45
from pyls import hookimpl
56

67
log = logging.getLogger(__name__)
@@ -31,8 +32,16 @@ def _format(config, document, line_range=None):
3132
if line_range:
3233
options['line_range'] = list(line_range)
3334

35+
# Temporarily re-monkey-patch the continued_indentation checker - #771
36+
del pycodestyle._checks['logical_line'][pycodestyle.continued_indentation]
37+
pycodestyle.register_check(autopep8_c_i)
38+
3439
new_source = fix_code(document.source, options=options)
3540

41+
# Switch it back
42+
del pycodestyle._checks['logical_line'][autopep8_c_i]
43+
pycodestyle.register_check(pycodestyle.continued_indentation)
44+
3645
if new_source == document.source:
3746
return []
3847

@@ -57,6 +66,7 @@ def _autopep8_config(config):
5766
'ignore': settings.get('ignore'),
5867
'max_line_length': settings.get('maxLineLength'),
5968
'select': settings.get('select'),
69+
'aggressive': settings.get('aggressive'),
6070
}
6171

6272
# Filter out null options

pyls/plugins/flake8_lint.py

Lines changed: 28 additions & 15 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,39 +41,44 @@ 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
42-
args = build_args(opts, document.path)
43-
output = run_flake8(args)
44+
flake8_executable = settings.get('executable', 'flake8')
45+
46+
args = build_args(opts)
47+
output = run_flake8(flake8_executable, args, document)
4448
return parse_stdout(document, output)
4549

4650

47-
def run_flake8(args):
51+
def run_flake8(flake8_executable, args, document):
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)
55-
p = Popen(cmd, stdout=PIPE, stderr=PIPE)
63+
p = Popen(cmd, stdin=PIPE, 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)
60-
p = Popen(cmd, stdout=PIPE, stderr=PIPE)
61-
(stdout, stderr) = p.communicate()
68+
p = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE)
69+
(stdout, stderr) = p.communicate(document.source.encode())
6270
if stderr:
6371
log.error("Error while running flake8 '%s'", stderr.decode())
6472
return stdout.decode()
6573

6674

67-
def build_args(options, doc_path):
75+
def build_args(options):
6876
"""Build arguments for calling flake8.
6977
7078
Args:
7179
options: dictionary of argument names and their values.
72-
doc_path: path of the document to lint.
7380
"""
74-
args = [doc_path]
81+
args = ['-'] # use stdin
7582
for arg_name, arg_val in options.items():
7683
if arg_val is None:
7784
continue
@@ -118,10 +125,16 @@ def parse_stdout(document, stdout):
118125
diagnostics = []
119126
lines = stdout.splitlines()
120127
for raw_line in lines:
121-
parsed_line = re.match(r'(.*):(\d*):(\d*): (\w*) (.*)', raw_line).groups()
122-
if not parsed_line or len(parsed_line) != 5:
128+
parsed_line = re.match(r'(.*):(\d*):(\d*): (\w*) (.*)', raw_line)
129+
if not parsed_line:
130+
log.debug("Flake8 output parser can't parse line '%s'", raw_line)
131+
continue
132+
133+
parsed_line = parsed_line.groups()
134+
if len(parsed_line) != 5:
123135
log.debug("Flake8 output parser can't parse line '%s'", raw_line)
124136
continue
137+
125138
_, line, character, code, msg = parsed_line
126139
line = int(line) - 1
127140
character = int(character) - 1

pyls/plugins/jedi_completion.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,25 @@ def pyls_completions(config, document, position):
6767
snippet_support = completion_capabilities.get('completionItem', {}).get('snippetSupport')
6868

6969
should_include_params = settings.get('include_params')
70+
should_include_class_objects = settings.get('include_class_objects', True)
71+
7072
include_params = snippet_support and should_include_params and use_snippets(document, position)
71-
return [_format_completion(c, include_params) for c in completions] or None
73+
include_class_objects = snippet_support and should_include_class_objects and use_snippets(document, position)
74+
75+
ready_completions = [
76+
_format_completion(c, include_params)
77+
for c in completions
78+
]
79+
80+
if include_class_objects:
81+
for c in completions:
82+
if c.type == 'class':
83+
completion_dict = _format_completion(c, False)
84+
completion_dict['kind'] = lsp.CompletionItemKind.TypeParameter
85+
completion_dict['label'] += ' object'
86+
ready_completions.append(completion_dict)
87+
88+
return ready_completions or None
7289

7390
def is_exception_class(name):
7491
"""
@@ -170,6 +187,7 @@ def _format_completion(d, include_params=True):
170187
snippet += ')$0'
171188
completion['insertText'] = snippet
172189
elif len(positional_args) == 1:
190+
completion['insertTextFormat'] = lsp.InsertTextFormat.Snippet
173191
completion['insertText'] = d.name + '($0)'
174192
else:
175193
completion['insertText'] = d.name + '()'
@@ -180,7 +198,7 @@ def _format_completion(d, include_params=True):
180198
def _label(definition):
181199
sig = definition.get_signatures()
182200
if definition.type in ('function', 'method') and sig:
183-
params = ', '.join([param.name for param in sig[0].params])
201+
params = ', '.join(param.name for param in sig[0].params)
184202
return '{}({})'.format(definition.name, params)
185203

186204
return definition.name

pyls/plugins/jedi_rename.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Copyright 2020 Palantir Technologies, Inc.
2+
import logging
3+
4+
from pyls import hookimpl, uris, _utils
5+
6+
log = logging.getLogger(__name__)
7+
8+
9+
@hookimpl
10+
def pyls_rename(config, workspace, document, position, new_name): # pylint: disable=unused-argument
11+
log.debug('Executing rename of %s to %s', document.word_at_position(position), new_name)
12+
kwargs = _utils.position_to_jedi_linecolumn(document, position)
13+
kwargs['new_name'] = new_name
14+
try:
15+
refactoring = document.jedi_script().rename(**kwargs)
16+
except NotImplementedError:
17+
raise Exception('No support for renaming in Python 2/3.5 with Jedi. '
18+
'Consider using the rope_rename plugin instead')
19+
log.debug('Finished rename: %s', refactoring.get_diff())
20+
changes = []
21+
for file_path, changed_file in refactoring.get_changed_files().items():
22+
uri = uris.from_fs_path(file_path)
23+
doc = workspace.get_maybe_document(uri)
24+
changes.append({
25+
'textDocument': {
26+
'uri': uri,
27+
'version': doc.version if doc else None
28+
},
29+
'edits': [
30+
{
31+
'range': {
32+
'start': {'line': 0, 'character': 0},
33+
'end': {
34+
'line': _num_lines(changed_file.get_new_code()),
35+
'character': 0,
36+
},
37+
},
38+
'newText': changed_file.get_new_code(),
39+
}
40+
],
41+
})
42+
return {'documentChanges': changes}
43+
44+
45+
def _num_lines(file_contents):
46+
'Count the number of lines in the given string.'
47+
return len(file_contents.splitlines())

pyls/plugins/pycodestyle_lint.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,26 @@
11
# Copyright 2017 Palantir Technologies, Inc.
22
import logging
33
import pycodestyle
4-
from autopep8 import continued_indentation as autopep8_c_i
54
from pyls import hookimpl, lsp
65

7-
# Check if autopep8's continued_indentation implementation
8-
# is overriding pycodestyle's and if so, re-register
9-
# the check using pycodestyle's implementation as expected
10-
if autopep8_c_i in pycodestyle._checks['logical_line']:
11-
del pycodestyle._checks['logical_line'][autopep8_c_i]
12-
pycodestyle.register_check(pycodestyle.continued_indentation)
6+
try:
7+
from autopep8 import continued_indentation as autopep8_c_i
8+
except ImportError:
9+
pass
10+
else:
11+
# Check if autopep8's continued_indentation implementation
12+
# is overriding pycodestyle's and if so, re-register
13+
# the check using pycodestyle's implementation as expected
14+
if autopep8_c_i in pycodestyle._checks['logical_line']:
15+
del pycodestyle._checks['logical_line'][autopep8_c_i]
16+
pycodestyle.register_check(pycodestyle.continued_indentation)
1317

1418
log = logging.getLogger(__name__)
1519

1620

1721
@hookimpl
18-
def pyls_lint(config, document):
22+
def pyls_lint(workspace, document):
23+
config = workspace._config
1924
settings = config.plugin_settings('pycodestyle')
2025
log.debug("Got pycodestyle settings: %s", settings)
2126

0 commit comments

Comments
 (0)