From 1e398202b9a63fcd91808a3205d3422b79435fa0 Mon Sep 17 00:00:00 2001 From: Yining Date: Thu, 22 Dec 2022 11:53:01 +1100 Subject: fix: ruff not registered as fixer (#4393) this commit fixes the issue reported at: https://github.com/dense-analysis/ale/issues/4301#issuecomment-1359289391 it also had some code refactored and tests added for ruff as fixer (missed in PR #4347). --- autoload/ale/fix/registry.vim | 5 ++ autoload/ale/fixers/ruff.vim | 67 ++++++++++++---- test/fixers/test_ruff_fixer_callback.vader | 122 +++++++++++++++++++++++++++++ 3 files changed, 178 insertions(+), 16 deletions(-) create mode 100644 test/fixers/test_ruff_fixer_callback.vader diff --git a/autoload/ale/fix/registry.vim b/autoload/ale/fix/registry.vim index b8d493f9..28e33926 100644 --- a/autoload/ale/fix/registry.vim +++ b/autoload/ale/fix/registry.vim @@ -580,6 +580,11 @@ let s:default_registry = { \ 'function': 'ale#fixers#raco_fmt#Fix', \ 'suggested_filetypes': ['racket'], \ 'description': 'Fix Racket files with raco fmt.', +\ }, +\ 'ruff': { +\ 'function': 'ale#fixers#ruff#Fix', +\ 'suggested_filetypes': ['python'], +\ 'description': 'Fix python files with ruff.', \ } \} diff --git a/autoload/ale/fixers/ruff.vim b/autoload/ale/fixers/ruff.vim index 92f9b75b..56bcf3df 100644 --- a/autoload/ale/fixers/ruff.vim +++ b/autoload/ale/fixers/ruff.vim @@ -1,6 +1,13 @@ " Author: Yining " Description: ruff as ALE fixer for python files +call ale#Set('python_ruff_executable', 'ruff') +call ale#Set('python_ruff_options', '') +call ale#Set('python_ruff_use_global', get(g:, 'ale_use_global_executables', 0)) +call ale#Set('python_ruff_change_directory', 1) +call ale#Set('python_ruff_auto_pipenv', 0) +call ale#Set('python_ruff_auto_poetry', 0) + function! ale#fixers#ruff#GetCwd(buffer) abort if ale#Var(a:buffer, 'python_ruff_change_directory') " Run from project root if found, else from buffer dir. @@ -9,7 +16,7 @@ function! ale#fixers#ruff#GetCwd(buffer) abort return !empty(l:project_root) ? l:project_root : '%s:h' endif - return '' + return '%s:h' endfunction function! ale#fixers#ruff#GetExecutable(buffer) abort @@ -26,29 +33,57 @@ function! ale#fixers#ruff#GetExecutable(buffer) abort return ale#python#FindExecutable(a:buffer, 'python_ruff', ['ruff']) endfunction -function! ale#fixers#ruff#GetCommand(buffer, version) abort - let l:executable = ale_linters#python#ruff#GetExecutable(a:buffer) +function! ale#fixers#ruff#GetCommand(buffer) abort + let l:executable = ale#fixers#ruff#GetExecutable(a:buffer) let l:exec_args = l:executable =~? 'pipenv\|poetry$' \ ? ' run ruff' \ : '' - " NOTE: ruff version `0.0.72` implement `--fix` with stdin return ale#Escape(l:executable) . l:exec_args - \ . ale#Pad(ale#Var(a:buffer, 'python_ruff_options')) - \ . ' --fix' - \ . (ale#semver#GTE(a:version, [0, 0, 72]) ? ' -' : ' %s') endfunction -function! ale#fixers#ruff#Fix(buffer) abort - let l:fix_cmd = {buffer -> ale#semver#RunWithVersionCheck( - \ buffer, - \ ale#fixers#ruff#GetExecutable(buffer), - \ '%e --version', - \ function('ale#fixers#ruff#GetCommand'), - \ )}(a:buffer) +function! ale#fixers#ruff#FixForVersion(buffer, version) abort + let l:executable = ale#fixers#ruff#GetExecutable(a:buffer) + let l:cmd = [ale#Escape(l:executable)] + + if l:executable =~? 'pipenv\|poetry$' + call extend(l:cmd, ['run', 'ruff']) + endif + + let l:options = ale#Var(a:buffer, 'python_ruff_options') + + if !empty(l:options) + call add(l:cmd, l:options) + endif + + " when --stdin-filename present, ruff will use it for proj root resolution + " https://github.com/charliermarsh/ruff/pull/1281 + let l:fname = expand('#' . a:buffer . '...') + call add(l:cmd, '--stdin-filename '.ale#Escape(ale#path#Simplify(l:fname))) + + call add(l:cmd, '--fix') + + " NOTE: ruff version `0.0.72` implements `--fix` with stdin + if ale#semver#GTE(a:version, [0, 0, 72]) + call add(l:cmd, '-') + else + call add(l:cmd, '%s') + endif return { - \ 'cwd': ale#fixers#ruff#GetCwd(a:buffer), - \ 'command': l:fix_cmd, + \ 'cwd': ale#fixers#ruff#GetCwd(a:buffer), + \ 'command': join(l:cmd, ' '), \} endfunction + +function! ale#fixers#ruff#Fix(buffer) abort + let l:executable = ale#fixers#ruff#GetExecutable(a:buffer) + let l:command = ale#fixers#ruff#GetCommand(a:buffer) . ale#Pad('--version') + + return ale#semver#RunWithVersionCheck( + \ a:buffer, + \ l:executable, + \ l:command, + \ function('ale#fixers#ruff#FixForVersion'), + \) +endfunction diff --git a/test/fixers/test_ruff_fixer_callback.vader b/test/fixers/test_ruff_fixer_callback.vader new file mode 100644 index 00000000..68c7a942 --- /dev/null +++ b/test/fixers/test_ruff_fixer_callback.vader @@ -0,0 +1,122 @@ +Before: + call ale#assert#SetUpFixerTest('python', 'ruff') + + let b:bin_dir = has('win32') ? 'Scripts' : 'bin' + +After: + call ale#assert#TearDownFixerTest() + + unlet! g:dir + unlet! b:bin_dir + +Execute(The ruff callback should return the correct default values): + let file_path = g:dir . '/../test-files/python/with_virtualenv/subdir/foo/bar.py' + + silent execute 'file ' . fnameescape(file_path) + + let fname = ale#Escape(ale#path#Simplify(file_path)) + + " --fix does not support stdin until 0.0.72 + GivenCommandOutput ['ruff 0.0.72'] + AssertFixer + \ { + \ 'cwd': ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/subdir'), + \ 'command': ale#Escape(ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/ruff')) . ' --stdin-filename ' . fname . ' --fix -', + \ } + +Execute(The ruff callback should not use stdin for older versions (< 0.0.72)): + let file_path = g:dir . '/../test-files/python/with_virtualenv/subdir/foo/bar.py' + + silent execute 'file ' . fnameescape(file_path) + + let fname = ale#Escape(ale#path#Simplify(file_path)) + + " --fix does not support stdin until 0.0.72 + GivenCommandOutput ['ruff 0.0.71'] + AssertFixer + \ { + \ 'cwd': ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/subdir'), + \ 'command': ale#Escape(ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/ruff')) . ' --stdin-filename ' . fname . ' --fix %s', + \ } + +Execute(The ruff callback should not change directory if the option is set to 0): + let g:ale_python_ruff_change_directory = 0 + + let file_path = g:dir . '/../test-files/python/with_virtualenv/subdir/foo/bar.py' + + silent execute 'file ' . fnameescape(file_path) + + let fname = ale#Escape(ale#path#Simplify(file_path)) + + " --fix does not support stdin until 0.0.72 + GivenCommandOutput ['ruff 0.0.72'] + AssertFixer + \ { + \ 'cwd': '%s:h', + \ 'command': ale#Escape(ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/ruff')) . ' --stdin-filename ' . fname . ' --fix -', + \ } + +Execute(The ruff callback should respect custom options): + let g:ale_python_ruff_options = '--ignore F401 -q' + + let file_path = g:dir . '/../test-files/python/with_virtualenv/subdir/foo/bar.py' + + silent execute 'file ' . fnameescape(file_path) + + let fname = ale#Escape(ale#path#Simplify(file_path)) + + GivenCommandOutput ['ruff 0.0.72'] + AssertFixer + \ { + \ 'cwd': ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/subdir'), + \ 'command': ale#Escape(ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/ruff')) + \ . ' --ignore F401 -q --stdin-filename '. fname . ' --fix -', + \ } + +Execute(Pipenv is detected when python_ruff_auto_pipenv is set): + let g:ale_python_ruff_auto_pipenv = 1 + let g:ale_python_ruff_change_directory = 0 + + let file_path = '../test-files/python/pipenv/whatever.py' + + call ale#test#SetFilename(file_path) + + let fname = ale#Escape(ale#path#Simplify(g:dir . '/'. file_path)) + + GivenCommandOutput ['ruff 0.0.72'] + AssertFixer + \ { + \ 'cwd': '%s:h', + \ 'command': ale#Escape('pipenv') . ' run ruff --stdin-filename ' . fname . ' --fix -' + \ } + +Execute(Poetry is detected when python_ruff_auto_poetry is set): + let g:ale_python_ruff_auto_poetry = 1 + let g:ale_python_ruff_change_directory = 0 + + call ale#test#SetFilename('../test-files/python/poetry/whatever.py') + + let fname = ale#Escape(ale#path#Simplify(g:dir .'/../test-files/python/poetry/whatever.py')) + + GivenCommandOutput ['ruff 0.0.72'] + AssertFixer + \ { + \ 'cwd': '%s:h', + \ 'command': ale#Escape('poetry') . ' run ruff --stdin-filename ' . fname . ' --fix -' + \ } + +Execute(Poetry is detected when python_ruff_auto_poetry is set, and cwd respects change_directory option): + let g:ale_python_ruff_auto_poetry = 1 + let g:ale_python_ruff_change_directory = 1 + + call ale#test#SetFilename('../test-files/python/poetry/whatever.py') + + let fname = ale#Escape(ale#path#Simplify(g:dir .'/../test-files/python/poetry/whatever.py')) + + GivenCommandOutput ['ruff 0.0.72'] + AssertFixer + \ { + \ 'cwd': ale#path#Simplify(g:dir . '/../test-files/python/poetry'), + \ 'command': ale#Escape('poetry') . ' run ruff --stdin-filename ' . fname . ' --fix -' + \ } + -- cgit v1.2.3