Ruff use json-lines output format (#4656)

* Ruff use json-lines output format
* Fix Ruff: add -q to prevent non json output

Using the json-lines output format allows for setting of the end_line,
end_col and code field of the handle output.

Additionally, the first letter of the code is used to determine the type
field.

Co-authored-by: w0rp <w0rp@users.noreply.github.com>
This commit is contained in:
Finn Steffens 2023-12-10 12:45:01 +01:00 committed by GitHub
parent ecc796b3d7
commit 9a23ec1f60
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 29 additions and 25 deletions

View File

@ -47,22 +47,25 @@ function! ale_linters#python#ruff#GetCommand(buffer, version) abort
" NOTE: ruff version `0.0.69` supports liniting input from stdin " NOTE: ruff version `0.0.69` supports liniting input from stdin
" NOTE: ruff version `0.1.0` deprecates `--format text` " NOTE: ruff version `0.1.0` deprecates `--format text`
return ale#Escape(l:executable) . l:exec_args return ale#Escape(l:executable) . l:exec_args . ' -q'
\ . ale#Pad(ale#Var(a:buffer, 'python_ruff_options')) \ . ale#Pad(ale#Var(a:buffer, 'python_ruff_options'))
\ . (ale#semver#GTE(a:version, [0, 1, 0]) ? ' --output-format text' : ' --format text') \ . (ale#semver#GTE(a:version, [0, 1, 0]) ? ' --output-format json-lines' : ' --format json-lines')
\ . (ale#semver#GTE(a:version, [0, 0, 69]) ? ' --stdin-filename %s -' : ' %s') \ . (ale#semver#GTE(a:version, [0, 0, 69]) ? ' --stdin-filename %s -' : ' %s')
endfunction endfunction
function! ale_linters#python#ruff#Handle(buffer, lines) abort function! ale_linters#python#ruff#Handle(buffer, lines) abort
"Example: path/to/file.py:10:5: E999 SyntaxError: unexpected indent
let l:pattern = '\v^[a-zA-Z]?:?[^:]+:(\d+):(\d+)?:? (.+)$'
let l:output = [] let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:pattern) for l:line in a:lines
let l:item = json_decode(l:line)
call add(l:output, { call add(l:output, {
\ 'lnum': l:match[1] + 0, \ 'lnum': l:item.location.row,
\ 'col': l:match[2] + 0, \ 'col': l:item.location.column,
\ 'text': l:match[3], \ 'end_lnum': l:item.end_location.row,
\ 'end_col': l:item.end_location.column - 1,
\ 'code': l:item.code,
\ 'text': l:item.message,
\ 'type': l:item.code =~? '\vE\d+' ? 'E' : 'W',
\}) \})
endfor endfor

View File

@ -6,7 +6,8 @@ Before:
call ale#assert#SetUpLinterTest('python', 'ruff') call ale#assert#SetUpLinterTest('python', 'ruff')
let b:bin_dir = has('win32') ? 'Scripts' : 'bin' let b:bin_dir = has('win32') ? 'Scripts' : 'bin'
let b:command_tail = ' --format text --stdin-filename %s -' let b:command_head = ale#Escape('ruff') . ' -q'
let b:command_tail = ' --format json-lines --stdin-filename %s -'
GivenCommandOutput ['ruff 0.0.83'] GivenCommandOutput ['ruff 0.0.83']
@ -19,51 +20,51 @@ After:
Execute(The ruff callbacks should return the correct default values): Execute(The ruff callbacks should return the correct default values):
AssertLinterCwd expand('%:p:h') AssertLinterCwd expand('%:p:h')
AssertLinter 'ruff', ale#Escape('ruff') . b:command_tail AssertLinter 'ruff', b:command_head . b:command_tail
Execute(ruff should run with the file path of buffer in old versions): Execute(ruff should run with the file path of buffer in old versions):
" version `0.0.69` supports liniting input from stdin " version `0.0.69` supports liniting input from stdin
GivenCommandOutput ['ruff 0.0.68'] GivenCommandOutput ['ruff 0.0.68']
AssertLinterCwd expand('%:p:h') AssertLinterCwd expand('%:p:h')
AssertLinter 'ruff', ale#Escape('ruff') . b:command_tail[:-23] . ' %s' AssertLinter 'ruff', b:command_head . b:command_tail[:-23] . ' %s'
Execute(ruff should run with the --output-format flag in new versions): Execute(ruff should run with the --output-format flag in new versions):
GivenCommandOutput ['ruff 0.1.0'] GivenCommandOutput ['ruff 0.1.0']
AssertLinterCwd expand('%:p:h') AssertLinterCwd expand('%:p:h')
AssertLinter 'ruff', ale#Escape('ruff') . ' --output-format text --stdin-filename %s -' AssertLinter 'ruff', b:command_head . ' --output-format json-lines --stdin-filename %s -'
Execute(ruff should run with the stdin in new enough versions): Execute(ruff should run with the stdin in new enough versions):
GivenCommandOutput ['ruff 0.0.83'] GivenCommandOutput ['ruff 0.0.83']
AssertLinterCwd expand('%:p:h') AssertLinterCwd expand('%:p:h')
AssertLinter 'ruff', ale#Escape('ruff') . b:command_tail[:-3] . ' -' AssertLinter 'ruff', b:command_head . b:command_tail[:-3] . ' -'
" AssertLinter 'ruff', ale#Escape('ruff') . b:command_tail[:-3] . '--format text -' " AssertLinter 'ruff', b:command_head . b:command_tail[:-3] . '--format json-lines -'
Execute(The option for disabling changing directories should work): Execute(The option for disabling changing directories should work):
let g:ale_python_ruff_change_directory = 0 let g:ale_python_ruff_change_directory = 0
AssertLinterCwd '' AssertLinterCwd ''
AssertLinter 'ruff', ale#Escape('ruff') . b:command_tail AssertLinter 'ruff', b:command_head . b:command_tail
Execute(The ruff executable should be configurable, and escaped properly): Execute(The ruff executable should be configurable, and escaped properly):
let g:ale_python_ruff_executable = 'executable with spaces' let g:ale_python_ruff_executable = 'executable with spaces'
AssertLinter 'executable with spaces', ale#Escape('executable with spaces') . b:command_tail AssertLinter 'executable with spaces', ale#Escape('executable with spaces') . ' -q' . b:command_tail
Execute(The ruff command callback should let you set options): Execute(The ruff command callback should let you set options):
let g:ale_python_ruff_options = '--some-flag' let g:ale_python_ruff_options = '--some-flag'
AssertLinter 'ruff', ale#Escape('ruff') . ' --some-flag' . b:command_tail AssertLinter 'ruff', b:command_head . ' --some-flag' . b:command_tail
let g:ale_python_ruff_options = '--some-option value' let g:ale_python_ruff_options = '--some-option value'
AssertLinter 'ruff', ale#Escape('ruff') . ' --some-option value' . b:command_tail AssertLinter 'ruff', b:command_head . ' --some-option value' . b:command_tail
Execute(The ruff callbacks shouldn't detect virtualenv directories where they don't exist): Execute(The ruff callbacks shouldn't detect virtualenv directories where they don't exist):
call ale#test#SetFilename('../test-files/python/no_virtualenv/subdir/foo/bar.py') call ale#test#SetFilename('../test-files/python/no_virtualenv/subdir/foo/bar.py')
AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/python/no_virtualenv/subdir') AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/python/no_virtualenv/subdir')
AssertLinter 'ruff', ale#Escape('ruff') . b:command_tail AssertLinter 'ruff', b:command_head . b:command_tail
Execute(The ruff callbacks should detect virtualenv directories): Execute(The ruff callbacks should detect virtualenv directories):
call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py') call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py')
@ -71,20 +72,20 @@ Execute(The ruff callbacks should detect virtualenv directories):
\ g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/ruff' \ g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/ruff'
\) \)
AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/subdir') AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/subdir')
AssertLinter b:executable, ale#Escape(b:executable) . b:command_tail AssertLinter b:executable, ale#Escape(b:executable) . ' -q' . b:command_tail
Execute(You should able able to use the global ruff instead): Execute(You should able able to use the global ruff instead):
call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py') call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py')
let g:ale_python_ruff_use_global = 1 let g:ale_python_ruff_use_global = 1
AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/subdir') AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/subdir')
AssertLinter 'ruff', ale#Escape('ruff') . b:command_tail AssertLinter 'ruff', b:command_head . b:command_tail
Execute(Setting executable to 'pipenv' appends 'run ruff'): Execute(Setting executable to 'pipenv' appends 'run ruff'):
let g:ale_python_ruff_executable = 'path/to/pipenv' let g:ale_python_ruff_executable = 'path/to/pipenv'
let g:ale_python_ruff_use_global = 1 let g:ale_python_ruff_use_global = 1
AssertLinter 'path/to/pipenv', ale#Escape('path/to/pipenv') . ' run ruff' AssertLinter 'path/to/pipenv', ale#Escape('path/to/pipenv') . ' run ruff -q'
\ . b:command_tail \ . b:command_tail
Execute(Pipenv is detected when python_ruff_auto_pipenv is set): Execute(Pipenv is detected when python_ruff_auto_pipenv is set):
@ -92,14 +93,14 @@ Execute(Pipenv is detected when python_ruff_auto_pipenv is set):
call ale#test#SetFilename('../test-files/python/pipenv/whatever.py') call ale#test#SetFilename('../test-files/python/pipenv/whatever.py')
AssertLinterCwd expand('%:p:h') AssertLinterCwd expand('%:p:h')
AssertLinter 'pipenv', ale#Escape('pipenv') . ' run ruff' AssertLinter 'pipenv', ale#Escape('pipenv') . ' run ruff -q'
\ . b:command_tail \ . b:command_tail
Execute(Setting executable to 'poetry' appends 'run ruff'): Execute(Setting executable to 'poetry' appends 'run ruff'):
let g:ale_python_ruff_executable = 'path/to/poetry' let g:ale_python_ruff_executable = 'path/to/poetry'
let g:ale_python_ruff_use_global = 1 let g:ale_python_ruff_use_global = 1
AssertLinter 'path/to/poetry', ale#Escape('path/to/poetry') . ' run ruff' AssertLinter 'path/to/poetry', ale#Escape('path/to/poetry') . ' run ruff -q'
\ . b:command_tail \ . b:command_tail
Execute(poetry is detected when python_ruff_auto_poetry is set): Execute(poetry is detected when python_ruff_auto_poetry is set):
@ -107,5 +108,5 @@ Execute(poetry is detected when python_ruff_auto_poetry is set):
call ale#test#SetFilename('../test-files/python/poetry/whatever.py') call ale#test#SetFilename('../test-files/python/poetry/whatever.py')
AssertLinterCwd expand('%:p:h') AssertLinterCwd expand('%:p:h')
AssertLinter 'poetry', ale#Escape('poetry') . ' run ruff' AssertLinter 'poetry', ale#Escape('poetry') . ' run ruff -q'
\ . b:command_tail \ . b:command_tail