From f6b0a28cbacba36954cec02bffaee9f126610d69 Mon Sep 17 00:00:00 2001 From: w0rp Date: Wed, 14 Jun 2017 16:20:30 +0100 Subject: [PATCH] Split up the flake8 and ansible-lint handlers --- ale_linters/ansible/ansible-lint.vim | 9 -- ale_linters/ansible/ansible_lint.vim | 48 ++++++++++ ale_linters/python/flake8.vim | 61 ++++++++++++- autoload/ale/fixers/autopep8.vim | 2 +- autoload/ale/fixers/isort.vim | 2 +- autoload/ale/fixers/yapf.vim | 2 +- autoload/ale/handlers/python.vim | 87 ------------------- autoload/ale/python.vim | 20 +++++ .../test_python_fixer_command_callback.vader | 8 +- test/handler/test_ansible_lint_handler.vader | 33 +++++++ test/handler/test_common_handlers.vader | 72 --------------- test/handler/test_flake8_handler.vader | 74 +++++++++++++++- 12 files changed, 240 insertions(+), 178 deletions(-) delete mode 100644 ale_linters/ansible/ansible-lint.vim create mode 100644 ale_linters/ansible/ansible_lint.vim delete mode 100644 autoload/ale/handlers/python.vim create mode 100644 test/handler/test_ansible_lint_handler.vader diff --git a/ale_linters/ansible/ansible-lint.vim b/ale_linters/ansible/ansible-lint.vim deleted file mode 100644 index 7f641b6..0000000 --- a/ale_linters/ansible/ansible-lint.vim +++ /dev/null @@ -1,9 +0,0 @@ -" Author: Bjorn Neergaard -" Description: ansible-lint for ansible-yaml files - -call ale#linter#Define('ansible', { -\ 'name': 'ansible', -\ 'executable': 'ansible', -\ 'command': 'ansible-lint -p %t', -\ 'callback': 'ale#handlers#python#HandlePEP8Format', -\}) diff --git a/ale_linters/ansible/ansible_lint.vim b/ale_linters/ansible/ansible_lint.vim new file mode 100644 index 0000000..3efd95f --- /dev/null +++ b/ale_linters/ansible/ansible_lint.vim @@ -0,0 +1,48 @@ +" Author: Bjorn Neergaard +" Description: ansible-lint for ansible-yaml files + +function! ale_linters#ansible#ansible_lint#Handle(buffer, lines) abort + for l:line in a:lines[:10] + if match(l:line, '^Traceback') >= 0 + return [{ + \ 'lnum': 1, + \ 'text': 'An exception was thrown. See :ALEDetail', + \ 'detail': join(a:lines, "\n"), + \}] + endif + endfor + + " Matches patterns line the following: + " + " test.yml:35: [EANSIBLE0002] Trailing whitespace + let l:pattern = '\v^[a-zA-Z]?:?[^:]+:(\d+):?(\d+)?: \[?([[:alnum:]]+)\]? (.*)$' + let l:output = [] + + for l:match in ale#util#GetMatches(a:lines, l:pattern) + let l:code = l:match[3] + + if (l:code ==# 'EANSIBLE002') + \ && !ale#Var(a:buffer, 'warn_about_trailing_whitespace') + " Skip warnings for trailing whitespace if the option is off. + continue + endif + + let l:item = { + \ 'lnum': l:match[1] + 0, + \ 'col': l:match[2] + 0, + \ 'text': l:code . ': ' . l:match[4], + \ 'type': l:code[:0] ==# 'E' ? 'E' : 'W', + \} + + call add(l:output, l:item) + endfor + + return l:output +endfunction + +call ale#linter#Define('ansible', { +\ 'name': 'ansible', +\ 'executable': 'ansible', +\ 'command': 'ansible-lint -p %t', +\ 'callback': 'ale_linters#ansible#ansible_lint#Handle', +\}) diff --git a/ale_linters/python/flake8.vim b/ale_linters/python/flake8.vim index 253c710..7af02d4 100644 --- a/ale_linters/python/flake8.vim +++ b/ale_linters/python/flake8.vim @@ -94,6 +94,65 @@ function! ale_linters#python#flake8#GetCommand(buffer, version_output) abort \ . l:display_name_args . ' -' endfunction +let s:end_col_pattern_map = { +\ 'F405': '\(.\+\) may be undefined', +\ 'F821': 'undefined name ''\([^'']\+\)''', +\ 'F999': '^''\([^'']\+\)''', +\ 'F841': 'local variable ''\([^'']\+\)''', +\} + +function! ale_linters#python#flake8#Handle(buffer, lines) abort + for l:line in a:lines[:10] + if match(l:line, '^Traceback') >= 0 + return [{ + \ 'lnum': 1, + \ 'text': 'An exception was thrown. See :ALEDetail', + \ 'detail': join(a:lines, "\n"), + \}] + endif + endfor + + " Matches patterns line the following: + " + " Matches patterns line the following: + " + " stdin:6:6: E111 indentation is not a multiple of four + " test.yml:35: [EANSIBLE0002] Trailing whitespace + let l:pattern = '\v^[a-zA-Z]?:?[^:]+:(\d+):?(\d+)?: ([[:alnum:]]+) (.*)$' + let l:output = [] + + for l:match in ale#util#GetMatches(a:lines, l:pattern) + let l:code = l:match[3] + + if (l:code ==# 'W291' || l:code ==# 'W293') + \ && !ale#Var(a:buffer, 'warn_about_trailing_whitespace') + " Skip warnings for trailing whitespace if the option is off. + continue + endif + + let l:item = { + \ 'lnum': l:match[1] + 0, + \ 'col': l:match[2] + 0, + \ 'text': l:code . ': ' . l:match[4], + \ 'type': l:code[:0] ==# 'E' ? 'E' : 'W', + \} + + let l:end_col_pattern = get(s:end_col_pattern_map, l:code, '') + + if !empty(l:end_col_pattern) + let l:end_col_match = matchlist(l:match[4], l:end_col_pattern) + + if !empty(l:end_col_match) + let l:item.end_col = l:item.col + len(l:end_col_match[1]) - 1 + endif + endif + + call add(l:output, l:item) + endfor + + return l:output +endfunction + call ale#linter#Define('python', { \ 'name': 'flake8', \ 'executable_callback': 'ale_linters#python#flake8#GetExecutable', @@ -101,5 +160,5 @@ call ale#linter#Define('python', { \ {'callback': 'ale_linters#python#flake8#VersionCheck'}, \ {'callback': 'ale_linters#python#flake8#GetCommand', 'output_stream': 'both'}, \ ], -\ 'callback': 'ale#handlers#python#HandlePEP8Format', +\ 'callback': 'ale_linters#python#flake8#Handle', \}) diff --git a/autoload/ale/fixers/autopep8.vim b/autoload/ale/fixers/autopep8.vim index 9227133..32d2824 100644 --- a/autoload/ale/fixers/autopep8.vim +++ b/autoload/ale/fixers/autopep8.vim @@ -2,7 +2,7 @@ " Description: Fixing files with autopep8. function! ale#fixers#autopep8#Fix(buffer) abort - let l:executable = ale#handlers#python#GetExecutable(a:buffer, 'autopep8') + let l:executable = ale#python#GetExecutable(a:buffer, 'autopep8') if empty(l:executable) return 0 endif diff --git a/autoload/ale/fixers/isort.vim b/autoload/ale/fixers/isort.vim index 04830b2..c37f12f 100644 --- a/autoload/ale/fixers/isort.vim +++ b/autoload/ale/fixers/isort.vim @@ -2,7 +2,7 @@ " Description: Fixing Python imports with isort. function! ale#fixers#isort#Fix(buffer) abort - let l:executable = ale#handlers#python#GetExecutable(a:buffer, 'isort') + let l:executable = ale#python#GetExecutable(a:buffer, 'isort') if empty(l:executable) return 0 endif diff --git a/autoload/ale/fixers/yapf.vim b/autoload/ale/fixers/yapf.vim index 46da408..3eae09b 100644 --- a/autoload/ale/fixers/yapf.vim +++ b/autoload/ale/fixers/yapf.vim @@ -2,7 +2,7 @@ " Description: Fixing Python files with yapf. function! ale#fixers#yapf#Fix(buffer) abort - let l:executable = ale#handlers#python#GetExecutable(a:buffer, 'yapf') + let l:executable = ale#python#GetExecutable(a:buffer, 'yapf') if empty(l:executable) return 0 endif diff --git a/autoload/ale/handlers/python.vim b/autoload/ale/handlers/python.vim deleted file mode 100644 index ba1cc57..0000000 --- a/autoload/ale/handlers/python.vim +++ /dev/null @@ -1,87 +0,0 @@ -" Author: w0rp -" Description: Error handling for flake8, etc. - -let s:end_col_pattern_map = { -\ 'F405': '\(.\+\) may be undefined', -\ 'F821': 'undefined name ''\([^'']\+\)''', -\ 'F999': '^''\([^'']\+\)''', -\ 'F841': 'local variable ''\([^'']\+\)''', -\} - -function! ale#handlers#python#HandlePEP8Format(buffer, lines) abort - for l:line in a:lines[:10] - if match(l:line, '^Traceback') >= 0 - return [{ - \ 'lnum': 1, - \ 'text': 'An exception was thrown. See :ALEDetail', - \ 'detail': join(a:lines, "\n"), - \}] - endif - endfor - - " Matches patterns line the following: - " - " Matches patterns line the following: - " - " stdin:6:6: E111 indentation is not a multiple of four - " test.yml:35: [EANSIBLE0002] Trailing whitespace - let l:pattern = '\v^[a-zA-Z]?:?[^:]+:(\d+):?(\d+)?: \[?([[:alnum:]]+)\]? (.*)$' - let l:output = [] - - for l:match in ale#util#GetMatches(a:lines, l:pattern) - let l:code = l:match[3] - - if (l:code ==# 'W291' || l:code ==# 'W293' || l:code ==# 'EANSIBLE002') - \ && !ale#Var(a:buffer, 'warn_about_trailing_whitespace') - " Skip warnings for trailing whitespace if the option is off. - continue - endif - - if l:code ==# 'I0011' - " Skip 'Locally disabling' message - continue - endif - - let l:item = { - \ 'lnum': l:match[1] + 0, - \ 'col': l:match[2] + 0, - \ 'text': l:code . ': ' . l:match[4], - \ 'type': l:code[:0] ==# 'E' ? 'E' : 'W', - \} - - let l:end_col_pattern = get(s:end_col_pattern_map, l:code, '') - - if !empty(l:end_col_pattern) - let l:end_col_match = matchlist(l:match[4], l:end_col_pattern) - - if !empty(l:end_col_match) - let l:item.end_col = l:item.col + len(l:end_col_match[1]) - 1 - endif - endif - - call add(l:output, l:item) - endfor - - return l:output -endfunction - -" Given a buffer number and a command name, find the path to the executable. -" First search on a virtualenv for Python, if nothing is found, try the global -" command. Returns an empty string if cannot find the executable -function! ale#handlers#python#GetExecutable(buffer, cmd_name) abort - let l:virtualenv = ale#python#FindVirtualenv(a:buffer) - - if !empty(l:virtualenv) - let l:ve_executable = l:virtualenv . '/bin/' . a:cmd_name - - if executable(l:ve_executable) - return l:ve_executable - endif - endif - - if executable(a:cmd_name) - return a:cmd_name - endif - - return '' -endfunction diff --git a/autoload/ale/python.vim b/autoload/ale/python.vim index d901968..f835e94 100644 --- a/autoload/ale/python.vim +++ b/autoload/ale/python.vim @@ -9,6 +9,26 @@ let g:ale_virtualenv_dir_names = get(g:, 'ale_virtualenv_dir_names', [ \ 'virtualenv', \]) +" Given a buffer number and a command name, find the path to the executable. +" First search on a virtualenv for Python, if nothing is found, try the global +" command. Returns an empty string if cannot find the executable +function! ale#python#GetExecutable(buffer, cmd_name) abort + let l:virtualenv = ale#python#FindVirtualenv(a:buffer) + + if !empty(l:virtualenv) + let l:ve_executable = l:virtualenv . '/bin/' . a:cmd_name + + if executable(l:ve_executable) + return l:ve_executable + endif + endif + + if executable(a:cmd_name) + return a:cmd_name + endif + + return '' +endfunction " Given a buffer number, find the project root directory for Python. " The root directory is defined as the first directory found while searching diff --git a/test/fixers/test_python_fixer_command_callback.vader b/test/fixers/test_python_fixer_command_callback.vader index 59135d3..7ee0caf 100644 --- a/test/fixers/test_python_fixer_command_callback.vader +++ b/test/fixers/test_python_fixer_command_callback.vader @@ -11,18 +11,18 @@ After: Execute(The python GetExecutable callbacks should return the correct path): AssertEqual \ '', - \ ale#handlers#python#GetExecutable(bufnr(''), 'isort') + \ ale#python#GetExecutable(bufnr(''), 'isort') silent execute 'file ' . fnameescape(g:dir . '/python_paths/with_virtualenv/subdir/foo/bar.py') AssertEqual \ g:dir . '/python_paths/with_virtualenv/env/bin/isort', - \ ale#handlers#python#GetExecutable(bufnr(''), 'isort') + \ ale#python#GetExecutable(bufnr(''), 'isort') AssertEqual \ g:dir . '/python_paths/with_virtualenv/env/bin/autopep8', - \ ale#handlers#python#GetExecutable(bufnr(''), 'autopep8') + \ ale#python#GetExecutable(bufnr(''), 'autopep8') AssertEqual \ g:dir . '/python_paths/with_virtualenv/env/bin/yapf', - \ ale#handlers#python#GetExecutable(bufnr(''), 'yapf') + \ ale#python#GetExecutable(bufnr(''), 'yapf') Execute(The autopep8 callbacks should return the correct default values): diff --git a/test/handler/test_ansible_lint_handler.vader b/test/handler/test_ansible_lint_handler.vader new file mode 100644 index 0000000..6e0261d --- /dev/null +++ b/test/handler/test_ansible_lint_handler.vader @@ -0,0 +1,33 @@ +Before: + runtime ale_linters/ansible/ansible_lint.vim + +After: + call ale#linter#Reset() + +Execute(The ansible-lint handler should handle basic errors): + AssertEqual + \ [ + \ { + \ 'lnum': 35, + \ 'col': 0, + \ 'type': 'E', + \ 'text': "EANSIBLE0002: Trailing whitespace", + \ }, + \ ], + \ ale_linters#ansible#ansible_lint#Handle(42, [ + \ "test.yml:35: [EANSIBLE0002] Trailing whitespace", + \ ]) + +Execute (The ansible-lint handler should handle names with spaces): + AssertEqual + \ [ + \ { + \ 'lnum': 6, + \ 'col': 6, + \ 'type': 'E', + \ 'text': 'E111: indentation is not a multiple of four', + \ }, + \ ], + \ ale_linters#python#flake8#Handle(42, [ + \ 'C:\something\with spaces.yml:6:6: E111 indentation is not a multiple of four', + \ ]) diff --git a/test/handler/test_common_handlers.vader b/test/handler/test_common_handlers.vader index 0a83f94..9a27394 100644 --- a/test/handler/test_common_handlers.vader +++ b/test/handler/test_common_handlers.vader @@ -40,78 +40,6 @@ Execute(HandleCSSLintFormat should handle CSS errors without groups): \ 'something.css: line 8, col 3, Warning - Unknown property ''fill-opacity''.', \ ]) -Execute (HandlePEP8Format should handle the correct lines of output): - AssertEqual - \ [ - \ { - \ 'lnum': 6, - \ 'col': 6, - \ 'type': 'E', - \ 'text': 'E111: indentation is not a multiple of four', - \ }, - \ { - \ 'lnum': 35, - \ 'col': 0, - \ 'type': 'E', - \ 'text': "EANSIBLE0002: Trailing whitespace", - \ }, - \ ], - \ ale#handlers#python#HandlePEP8Format(42, [ - \ "stdin:6:6: E111 indentation is not a multiple of four", - \ "test.yml:35: [EANSIBLE0002] Trailing whitespace", - \ ]) - -Execute (HandlePEP8Format should handle names with spaces): - AssertEqual - \ [ - \ { - \ 'lnum': 6, - \ 'col': 6, - \ 'type': 'E', - \ 'text': 'E111: indentation is not a multiple of four', - \ }, - \ ], - \ ale#handlers#python#HandlePEP8Format(42, [ - \ 'C:\something\with spaces.py:6:6: E111 indentation is not a multiple of four', - \ ]) - -Execute (HandlePEP8Format should stack traces): - AssertEqual - \ [ - \ { - \ 'lnum': 1, - \ 'text': 'An exception was thrown. See :ALEDetail', - \ 'detail': join([ - \ 'Traceback (most recent call last):', - \ ' File "/usr/local/bin/flake8", line 7, in ', - \ ' from flake8.main.cli import main', - \ ' File "/usr/local/lib/python2.7/dist-packages/flake8/main/cli.py", line 2, in ', - \ ' from flake8.main import application', - \ ' File "/usr/local/lib/python2.7/dist-packages/flake8/main/application.py", line 17, in ', - \ ' from flake8.plugins import manager as plugin_manager', - \ ' File "/usr/local/lib/python2.7/dist-packages/flake8/plugins/manager.py", line 5, in ', - \ ' import pkg_resources', - \ ' File "/usr/lib/python2.7/dist-packages/pkg_resources/__init__.py", line 35, in ', - \ ' import email.parser', - \ 'ImportError: No module named parser', - \ ], "\n"), - \ }, - \ ], - \ ale#handlers#python#HandlePEP8Format(42, [ - \ 'Traceback (most recent call last):', - \ ' File "/usr/local/bin/flake8", line 7, in ', - \ ' from flake8.main.cli import main', - \ ' File "/usr/local/lib/python2.7/dist-packages/flake8/main/cli.py", line 2, in ', - \ ' from flake8.main import application', - \ ' File "/usr/local/lib/python2.7/dist-packages/flake8/main/application.py", line 17, in ', - \ ' from flake8.plugins import manager as plugin_manager', - \ ' File "/usr/local/lib/python2.7/dist-packages/flake8/plugins/manager.py", line 5, in ', - \ ' import pkg_resources', - \ ' File "/usr/lib/python2.7/dist-packages/pkg_resources/__init__.py", line 35, in ', - \ ' import email.parser', - \ 'ImportError: No module named parser', - \ ]) - Execute (HandleGCCFormat should handle the correct lines of output): AssertEqual \ [ diff --git a/test/handler/test_flake8_handler.vader b/test/handler/test_flake8_handler.vader index 15345d8..969d4ec 100644 --- a/test/handler/test_flake8_handler.vader +++ b/test/handler/test_flake8_handler.vader @@ -1,5 +1,24 @@ +Before: + runtime ale_linters/python/flake8.vim -Execute(End column indexes should be set for certain errors): +After: + call ale#linter#Reset() + +Execute(The flake8 handler should handle basic errors): + AssertEqual + \ [ + \ { + \ 'lnum': 6, + \ 'col': 6, + \ 'type': 'E', + \ 'text': 'E111: indentation is not a multiple of four', + \ }, + \ ], + \ ale_linters#python#flake8#Handle(1, [ + \ 'stdin:6:6: E111 indentation is not a multiple of four', + \ ]) + +Execute(The flake8 handler should set end column indexes should be set for certain errors): AssertEqual \ [ \ { @@ -38,10 +57,61 @@ Execute(End column indexes should be set for certain errors): \ 'text': 'F841: local variable ''test'' is assigned to but never used', \ }, \ ], - \ ale#handlers#python#HandlePEP8Format(1, [ + \ ale_linters#python#flake8#Handle(1, [ \ 'foo.py:25:1: F821 undefined name ''foo''', \ 'foo.py:28:5: F405 hello may be undefined, or defined from star imports: x', \ 'foo.py:104:5: F999 ''continue'' not properly in loop', \ 'foo.py:106:5: F999 ''break'' outside loop', \ 'foo.py:109:5: F841 local variable ''test'' is assigned to but never used', \ ]) + +Execute(The flake8 handler should handle stack traces): + AssertEqual + \ [ + \ { + \ 'lnum': 1, + \ 'text': 'An exception was thrown. See :ALEDetail', + \ 'detail': join([ + \ 'Traceback (most recent call last):', + \ ' File "/usr/local/bin/flake8", line 7, in ', + \ ' from flake8.main.cli import main', + \ ' File "/usr/local/lib/python2.7/dist-packages/flake8/main/cli.py", line 2, in ', + \ ' from flake8.main import application', + \ ' File "/usr/local/lib/python2.7/dist-packages/flake8/main/application.py", line 17, in ', + \ ' from flake8.plugins import manager as plugin_manager', + \ ' File "/usr/local/lib/python2.7/dist-packages/flake8/plugins/manager.py", line 5, in ', + \ ' import pkg_resources', + \ ' File "/usr/lib/python2.7/dist-packages/pkg_resources/__init__.py", line 35, in ', + \ ' import email.parser', + \ 'ImportError: No module named parser', + \ ], "\n"), + \ }, + \ ], + \ ale_linters#python#flake8#Handle(42, [ + \ 'Traceback (most recent call last):', + \ ' File "/usr/local/bin/flake8", line 7, in ', + \ ' from flake8.main.cli import main', + \ ' File "/usr/local/lib/python2.7/dist-packages/flake8/main/cli.py", line 2, in ', + \ ' from flake8.main import application', + \ ' File "/usr/local/lib/python2.7/dist-packages/flake8/main/application.py", line 17, in ', + \ ' from flake8.plugins import manager as plugin_manager', + \ ' File "/usr/local/lib/python2.7/dist-packages/flake8/plugins/manager.py", line 5, in ', + \ ' import pkg_resources', + \ ' File "/usr/lib/python2.7/dist-packages/pkg_resources/__init__.py", line 35, in ', + \ ' import email.parser', + \ 'ImportError: No module named parser', + \ ]) + +Execute (The flake8 handler should handle names with spaces): + AssertEqual + \ [ + \ { + \ 'lnum': 6, + \ 'col': 6, + \ 'type': 'E', + \ 'text': 'E111: indentation is not a multiple of four', + \ }, + \ ], + \ ale_linters#python#flake8#Handle(42, [ + \ 'C:\something\with spaces.py:6:6: E111 indentation is not a multiple of four', + \ ])