Skip to content

Commit dc0f678

Browse files
Add support for flake8 per-file-ignores
1 parent a91a257 commit dc0f678

5 files changed

Lines changed: 97 additions & 2 deletions

File tree

pyls/config/flake8_conf.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
('ignore', 'plugins.flake8.ignore', list),
2727
('max-line-length', 'plugins.flake8.maxLineLength', int),
2828
('select', 'plugins.flake8.select', list),
29+
('per-file-ignores', 'plugins.flake8.perFileIgnores', list),
2930
]
3031

3132

pyls/config/source.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,10 @@ def _get_opt(config, key, option, opt_type):
6767

6868

6969
def _parse_list_opt(string):
70-
return [s.strip() for s in string.split(",") if s.strip()]
70+
if string.startswith("\n"):
71+
return [s.strip().rstrip(",") for s in string.split("\n") if s.strip()]
72+
else:
73+
return [s.strip() for s in string.split(",") if s.strip()]
7174

7275

7376
def _set_opt(config_dict, path, value):

pyls/plugins/flake8_lint.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@
66
from subprocess import Popen, PIPE
77
from pyls import hookimpl, lsp
88

9+
try:
10+
11+
from pathlib import PurePath
12+
except ImportError:
13+
from pathlib2 import PurePath
14+
15+
916
log = logging.getLogger(__name__)
1017
FIX_IGNORES_RE = re.compile(r'([^a-zA-Z0-9_,]*;.*(\W+||$))')
1118

@@ -22,12 +29,21 @@ def pyls_lint(workspace, document):
2229
settings = config.plugin_settings('flake8', document_path=document.path)
2330
log.debug("Got flake8 settings: %s", settings)
2431

32+
ignores = settings.get("ignore", [])
33+
per_file_ignores = settings.get("perFileIgnores")
34+
35+
if per_file_ignores:
36+
for path in per_file_ignores:
37+
file_pat, errors = path.split(":")
38+
if PurePath(document.path).match(file_pat):
39+
ignores.extend(errors.split(","))
40+
2541
opts = {
2642
'config': settings.get('config'),
2743
'exclude': settings.get('exclude'),
2844
'filename': settings.get('filename'),
2945
'hang-closing': settings.get('hangClosing'),
30-
'ignore': settings.get('ignore'),
46+
'ignore': ignores or None,
3147
'max-line-length': settings.get('maxLineLength'),
3248
'select': settings.get('select'),
3349
}

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
install_requires = [
1010
'configparser; python_version<"3.0"',
1111
'future>=0.14.0; python_version<"3"',
12+
'pathlib2>=2.3.5; python_version<"3"',
1213
'backports.functools_lru_cache; python_version<"3.2"',
1314
'jedi>=0.17.2,<0.18.0',
1415
'python-jsonrpc-server>=0.4.0',

test/plugins/test_flake8_lint.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,77 @@ def test_flake8_executable_param(workspace):
8484

8585
call_args = popen_mock.call_args.args[0]
8686
assert flake8_executable in call_args
87+
88+
89+
def get_flake8_cfg_settings(workspace, config_str):
90+
"""Write a ``setup.cfg``, load it in the workspace, and return the flake8 settings.
91+
92+
This function creates a ``setup.cfg``; you'll have to delete it yourself.
93+
"""
94+
95+
with open(os.path.join(workspace.root_path, "setup.cfg"), "w+") as f:
96+
f.write(config_str)
97+
98+
workspace.update_config({"pyls": {"configurationSources": ["flake8"]}})
99+
100+
return workspace._config.plugin_settings("flake8")
101+
102+
103+
def test_flake8_multiline(workspace):
104+
config_str = r"""[flake8]
105+
exclude =
106+
blah/,
107+
file_2.py
108+
"""
109+
110+
doc_str = "print('hi')\nimport os\n"
111+
112+
doc_uri = uris.from_fs_path(os.path.join(workspace.root_path, "blah/__init__.py"))
113+
workspace.put_document(doc_uri, doc_str)
114+
115+
flake8_settings = get_flake8_cfg_settings(workspace, config_str)
116+
117+
assert "exclude" in flake8_settings
118+
assert len(flake8_settings["exclude"]) == 2
119+
120+
with patch('pyls.plugins.flake8_lint.Popen') as popen_mock:
121+
mock_instance = popen_mock.return_value
122+
mock_instance.communicate.return_value = [bytes(), bytes()]
123+
124+
doc = workspace.get_document(doc_uri)
125+
flake8_lint.pyls_lint(workspace, doc)
126+
127+
call_args = popen_mock.call_args.args[0]
128+
assert call_args == ["flake8", "-", "--exclude=blah/,file_2.py"]
129+
130+
os.unlink(os.path.join(workspace.root_path, "setup.cfg"))
131+
132+
133+
def test_flake8_per_file_ignores(workspace):
134+
config_str = r"""[flake8]
135+
ignores = F403
136+
per-file-ignores =
137+
**/__init__.py:F401,E402
138+
test_something.py:E402,
139+
exclude =
140+
file_1.py
141+
file_2.py
142+
"""
143+
144+
doc_str = "print('hi')\nimport os\n"
145+
146+
doc_uri = uris.from_fs_path(os.path.join(workspace.root_path, "blah/__init__.py"))
147+
workspace.put_document(doc_uri, doc_str)
148+
149+
flake8_settings = get_flake8_cfg_settings(workspace, config_str)
150+
151+
assert "perFileIgnores" in flake8_settings
152+
assert len(flake8_settings["perFileIgnores"]) == 2
153+
assert "exclude" in flake8_settings
154+
assert len(flake8_settings["exclude"]) == 2
155+
156+
doc = workspace.get_document(doc_uri)
157+
res = flake8_lint.pyls_lint(workspace, doc)
158+
assert len(res) == 0
159+
160+
os.unlink(os.path.join(workspace.root_path, "setup.cfg"))

0 commit comments

Comments
 (0)