summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorw0rp <devw0rp@gmail.com>2023-02-08 09:11:31 +0000
committerw0rp <devw0rp@gmail.com>2023-02-08 09:11:31 +0000
commit4c162877e2943ac8f6b29bc79ccf313f8eb88ba6 (patch)
tree7f40105c0a914615ae3bd1bdfb607d1409222b9f
parent6ff1f0b200f9d280b44b9fa59fde232bdb9fe32f (diff)
downloadale-4c162877e2943ac8f6b29bc79ccf313f8eb88ba6.zip
#2172 Auto PATH with ale_python_auto_virtualenv
Automatically set `PATH` for some Python linters that seem to need it when g:ale_python_auto_virtualenv or b:ale_python_auto_virtualenv is `1`.
-rw-r--r--ale_linters/python/jedils.vim8
-rw-r--r--ale_linters/python/pylsp.vim8
-rw-r--r--ale_linters/python/pyright.vim8
-rw-r--r--autoload/ale/python.vim20
-rw-r--r--doc/ale-python.txt105
-rw-r--r--plugin/ale.vim4
-rw-r--r--test/linter/test_jedils.vader47
-rw-r--r--test/linter/test_pylsp.vader14
-rw-r--r--test/linter/test_pyright.vader14
-rwxr-xr-xtest/test-files/python/with_virtualenv/env/bin/jedi-language-server0
10 files changed, 174 insertions, 54 deletions
diff --git a/ale_linters/python/jedils.vim b/ale_linters/python/jedils.vim
index eae5fb07..d3e15bf2 100644
--- a/ale_linters/python/jedils.vim
+++ b/ale_linters/python/jedils.vim
@@ -16,12 +16,16 @@ endfunction
function! ale_linters#python#jedils#GetCommand(buffer) abort
let l:executable = ale_linters#python#jedils#GetExecutable(a:buffer)
-
let l:exec_args = l:executable =~? 'pipenv$'
\ ? ' run jedi-language-server'
\ : ''
+ let l:env_string = ''
+
+ if ale#Var(a:buffer, 'python_auto_virtualenv')
+ let l:env_string = ale#python#AutoVirtualenvEnvString(a:buffer)
+ endif
- return ale#Escape(l:executable) . l:exec_args
+ return l:env_string . ale#Escape(l:executable) . l:exec_args
endfunction
call ale#linter#Define('python', {
diff --git a/ale_linters/python/pylsp.vim b/ale_linters/python/pylsp.vim
index a699e4f6..a1c31018 100644
--- a/ale_linters/python/pylsp.vim
+++ b/ale_linters/python/pylsp.vim
@@ -37,12 +37,16 @@ endfunction
function! ale_linters#python#pylsp#GetCommand(buffer) abort
let l:executable = ale_linters#python#pylsp#GetExecutable(a:buffer)
-
let l:exec_args = l:executable =~? 'pipenv\|poetry$'
\ ? ' run pylsp'
\ : ''
+ let l:env_string = ''
+
+ if ale#Var(a:buffer, 'python_auto_virtualenv')
+ let l:env_string = ale#python#AutoVirtualenvEnvString(a:buffer)
+ endif
- return ale#Escape(l:executable) . l:exec_args . ale#Pad(ale#Var(a:buffer, 'python_pylsp_options'))
+ return l:env_string . ale#Escape(l:executable) . l:exec_args . ale#Pad(ale#Var(a:buffer, 'python_pylsp_options'))
endfunction
call ale#linter#Define('python', {
diff --git a/ale_linters/python/pyright.vim b/ale_linters/python/pyright.vim
index f16af84c..ccade0c9 100644
--- a/ale_linters/python/pyright.vim
+++ b/ale_linters/python/pyright.vim
@@ -64,12 +64,16 @@ endfunction
function! ale_linters#python#pyright#GetCommand(buffer) abort
let l:executable = ale_linters#python#pyright#GetExecutable(a:buffer)
-
let l:exec_args = l:executable =~? 'pipenv\|poetry$'
\ ? ' run pyright'
\ : ''
+ let l:env_string = ''
+
+ if ale#Var(a:buffer, 'python_auto_virtualenv')
+ let l:env_string = ale#python#AutoVirtualenvEnvString(a:buffer)
+ endif
- return ale#Escape(l:executable) . l:exec_args . ' --stdio'
+ return l:env_string . ale#Escape(l:executable) . l:exec_args . ' --stdio'
endfunction
call ale#linter#Define('python', {
diff --git a/autoload/ale/python.vim b/autoload/ale/python.vim
index 7a998414..92e48da8 100644
--- a/autoload/ale/python.vim
+++ b/autoload/ale/python.vim
@@ -1,4 +1,4 @@
-" Author: w0rp <devw0rp@gmail.com>
+" Author: w0rp <dev@w0rp.com>
" Description: Functions for integrating with Python linters.
call ale#Set('python_auto_pipenv', '0')
@@ -96,6 +96,24 @@ function! ale#python#FindVirtualenv(buffer) abort
return $VIRTUAL_ENV
endfunction
+" Automatically determine virtualenv environment variables and build
+" a string of them to prefix linter commands with.
+function! ale#python#AutoVirtualenvEnvString(buffer) abort
+ let l:venv_dir = ale#python#FindVirtualenv(a:buffer)
+ let l:sep = has('win32') ? ';' : ':'
+
+ if !empty(l:venv_dir)
+ let l:vars = [
+ \ ['PATH', ale#path#Simplify(l:venv_dir . '/bin') . l:sep . $PATH],
+ \]
+
+ " We don't need a space between var as ale#Env adds one.
+ return join(map(l:vars, 'ale#Env(v:val[0], v:val[1])'), '')
+ endif
+
+ return ''
+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
diff --git a/doc/ale-python.txt b/doc/ale-python.txt
index aad64b1d..d7c5cacc 100644
--- a/doc/ale-python.txt
+++ b/doc/ale-python.txt
@@ -20,6 +20,17 @@ g:ale_python_auto_poetry *g:ale_python_auto_poetry*
if true. This is overridden by a manually-set executable.
+g:ale_python_auto_virtualenv *g:ale_python_auto_virtualenv*
+ *b:ale_python_auto_virtualenv*
+ Type: |Number|
+ Default: `0`
+
+ If set to `1`, ALE will automatically set environment variables for commands
+ such as `PATH` to attempt to make the experience of running Python linters
+ via virtualenv easier, without the need for another plugin or some
+ specialised setup.
+
+
===============================================================================
ALE Python Project Root Behavior *ale-python-root*
@@ -88,24 +99,24 @@ g:ale_python_autoflake_use_global *g:ale_python_autoflake_use_global*
===============================================================================
autoimport *ale-python-autoimport*
-g:ale_python_autoimport_executable *g:ale_python_autoimport_executable*
- *b:ale_python_autoimport_executable*
+g:ale_python_autoimport_executable *g:ale_python_autoimport_executable*
+ *b:ale_python_autoimport_executable*
Type: |String|
Default: `'autoimport'`
See |ale-integrations-local-executables|
-g:ale_python_autoimport_options *g:ale_python_autoimport_options*
- *b:ale_python_autoimport_options*
+g:ale_python_autoimport_options *g:ale_python_autoimport_options*
+ *b:ale_python_autoimport_options*
Type: |String|
Default: `''`
This variable can be set to pass extra options to autoimport.
-g:ale_python_autoimport_use_global *g:ale_python_autoimport_use_global*
- *b:ale_python_autoimport_use_global*
+g:ale_python_autoimport_use_global *g:ale_python_autoimport_use_global*
+ *b:ale_python_autoimport_use_global*
Type: |Number|
Default: `get(g:, 'ale_use_global_executables', 0)`
@@ -338,7 +349,7 @@ g:ale_python_flake8_auto_poetry *g:ale_python_flake8_auto_poetry*
flakehell *ale-python-flakehell*
g:ale_python_flakehell_change_directory*g:ale_python_flakehell_change_directory*
- *b:ale_python_flakehell_change_directory*
+ *b:ale_python_flakehell_change_directory*
Type: |String|
Default: `project`
@@ -349,8 +360,8 @@ g:ale_python_flakehell_change_directory*g:ale_python_flakehell_change_directory*
Python is executed from yourself.
-g:ale_python_flakehell_executable *g:ale_python_flakehell_executable*
- *b:ale_python_flakehell_executable*
+g:ale_python_flakehell_executable *g:ale_python_flakehell_executable*
+ *b:ale_python_flakehell_executable*
Type: |String|
Default: `'flakehell'`
@@ -360,8 +371,8 @@ g:ale_python_flakehell_executable *g:ale_python_flakehell_executable*
invoke `'python` `-m` `flakehell'`.
-g:ale_python_flakehell_options *g:ale_python_flakehell_options*
- *b:ale_python_flakehell_options*
+g:ale_python_flakehell_options *g:ale_python_flakehell_options*
+ *b:ale_python_flakehell_options*
Type: |String|
Default: `''`
@@ -369,8 +380,8 @@ g:ale_python_flakehell_options *g:ale_python_flakehell_options*
lint invocation.
-g:ale_python_flakehell_use_global *g:ale_python_flakehell_use_global*
- *b:ale_python_flakehell_use_global*
+g:ale_python_flakehell_use_global *g:ale_python_flakehell_use_global*
+ *b:ale_python_flakehell_use_global*
Type: |Number|
Default: `get(g:, 'ale_use_global_executables', 0)`
@@ -381,8 +392,8 @@ g:ale_python_flakehell_use_global *g:ale_python_flakehell_use_global*
Both variables can be set with `b:` buffer variables instead.
-g:ale_python_flakehell_auto_pipenv *g:ale_python_flakehell_auto_pipenv*
- *b:ale_python_flakehell_auto_pipenv*
+g:ale_python_flakehell_auto_pipenv *g:ale_python_flakehell_auto_pipenv*
+ *b:ale_python_flakehell_auto_pipenv*
Type: |Number|
Default: `0`
@@ -975,13 +986,13 @@ g:ale_python_pylint_use_msg_id *g:ale_python_pylint_use_msg_id*
===============================================================================
-pylsp *ale-python-pylsp*
+pylsp *ale-python-pylsp*
`pylsp` will be run from a detected project root, per |ale-python-root|.
-g:ale_python_pylsp_executable *g:ale_python_pylsp_executable*
- *b:ale_python_pylsp_executable*
+g:ale_python_pylsp_executable *g:ale_python_pylsp_executable*
+ *b:ale_python_pylsp_executable*
Type: |String|
Default: `'pylsp'`
@@ -991,16 +1002,16 @@ g:ale_python_pylsp_executable *g:ale_python_pylsp_executable
Set this to `'poetry'` to invoke `'poetry` `run` `pyls'`.
-g:ale_python_pylsp_use_global *g:ale_python_pylsp_use_global*
- *b:ale_python_pylsp_use_global*
+g:ale_python_pylsp_use_global *g:ale_python_pylsp_use_global*
+ *b:ale_python_pylsp_use_global*
Type: |Number|
Default: `get(g:, 'ale_use_global_executables', 0)`
See |ale-integrations-local-executables|
-g:ale_python_pylsp_auto_pipenv *g:ale_python_pylsp_auto_pipenv*
- *b:ale_python_pylsp_auto_pipenv*
+g:ale_python_pylsp_auto_pipenv *g:ale_python_pylsp_auto_pipenv*
+ *b:ale_python_pylsp_auto_pipenv*
Type: |Number|
Default: `0`
@@ -1008,8 +1019,8 @@ g:ale_python_pylsp_auto_pipenv *g:ale_python_pylsp_auto_pipenv
if true. This is overridden by a manually-set executable.
-g:ale_python_pylsp_auto_poetry *g:ale_python_pylsp_auto_poetry*
- *b:ale_python_pylsp_auto_poetry*
+g:ale_python_pylsp_auto_poetry *g:ale_python_pylsp_auto_poetry*
+ *b:ale_python_pylsp_auto_poetry*
Type: |Number|
Default: `0`
@@ -1017,8 +1028,8 @@ g:ale_python_pylsp_auto_poetry *g:ale_python_pylsp_auto_poetry
if true. This is overridden by a manually-set executable.
-g:ale_python_pylsp_config *g:ale_python_pylsp_config*
- *b:ale_python_pylsp_config*
+g:ale_python_pylsp_config *g:ale_python_pylsp_config*
+ *b:ale_python_pylsp_config*
Type: |Dictionary|
Default: `{}`
@@ -1035,8 +1046,8 @@ g:ale_python_pylsp_config *g:ale_python_pylsp_config
\ }
<
-g:ale_python_pylsp_options *g:ale_python_pylsp_options*
- *b:ale_python_pylsp_options*
+g:ale_python_pylsp_options *g:ale_python_pylsp_options*
+ *b:ale_python_pylsp_options*
Type: |String|
Default: `''`
@@ -1158,10 +1169,10 @@ g:ale_python_pyright_config *g:ale_python_pyright_config*
<
===============================================================================
-refurb *ale-python-refurb*
+refurb *ale-python-refurb*
-g:ale_python_refurb_change_directory *g:ale_python_refurb_change_directory*
- *b:ale_python_refurb_change_directory*
+g:ale_python_refurb_change_directory *g:ale_python_refurb_change_directory*
+ *b:ale_python_refurb_change_directory*
Type: |Number|
Default: `1`
@@ -1170,8 +1181,8 @@ g:ale_python_refurb_change_directory *g:ale_python_refurb_change_directory
`refurb` will be run from the buffer's directory.
-g:ale_python_refurb_executable *g:ale_python_refurb_executable*
- *b:ale_python_refurb_executable*
+g:ale_python_refurb_executable *g:ale_python_refurb_executable*
+ *b:ale_python_refurb_executable*
Type: |String|
Default: `'refurb'`
@@ -1181,8 +1192,8 @@ g:ale_python_refurb_executable *g:ale_python_refurb_executable
Set this to `'poetry'` to invoke `'poetry` `run` `refurb'`.
-g:ale_python_refurb_options *g:ale_python_refurb_options*
- *b:ale_python_refurb_options*
+g:ale_python_refurb_options *g:ale_python_refurb_options*
+ *b:ale_python_refurb_options*
Type: |String|
Default: `''`
@@ -1192,16 +1203,16 @@ g:ale_python_refurb_options *g:ale_python_refurb_options
For example, to select/enable and/or disable some error codes,
you may want to set >
let g:ale_python_refurb_options = '--ignore 100'
-g:ale_python_refurb_use_global *g:ale_python_refurb_use_global*
- *b:ale_python_refurb_use_global*
+g:ale_python_refurb_use_global *g:ale_python_refurb_use_global*
+ *b:ale_python_refurb_use_global*
Type: |Number|
Default: `get(g:, 'ale_use_global_executables', 0)`
See |ale-integrations-local-executables|
-g:ale_python_refurb_auto_pipenv *g:ale_python_refurb_auto_pipenv*
- *b:ale_python_refurb_auto_pipenv*
+g:ale_python_refurb_auto_pipenv *g:ale_python_refurb_auto_pipenv*
+ *b:ale_python_refurb_auto_pipenv*
Type: |Number|
Default: `0`
@@ -1209,8 +1220,8 @@ g:ale_python_refurb_auto_pipenv *g:ale_python_refurb_auto_pipenv
if true. This is overridden by a manually-set executable.
-g:ale_python_refurb_auto_poetry *g:ale_python_refurb_auto_poetry*
- *b:ale_python_refurb_auto_poetry*
+g:ale_python_refurb_auto_poetry *g:ale_python_refurb_auto_poetry*
+ *b:ale_python_refurb_auto_poetry*
Type: |Number|
Default: `0`
@@ -1335,8 +1346,8 @@ g:ale_python_unimport_auto_poetry *g:ale_python_unimport_auto_poetry*
if true. This is overridden by a manually-set executable.
-g:ale_python_unimport_executable *g:ale_python_unimport_executable*
- *b:ale_python_unimport_executable*
+g:ale_python_unimport_executable *g:ale_python_unimport_executable*
+ *b:ale_python_unimport_executable*
Type: |String|
Default: `'unimport'`
@@ -1346,8 +1357,8 @@ g:ale_python_unimport_executable *g:ale_python_unimport_executable*
Set this to `'poetry'` to invoke `'poetry` `run` `unimport'`.
-g:ale_python_unimport_options *g:ale_python_unimport_options*
- *b:ale_python_unimport_options*
+g:ale_python_unimport_options *g:ale_python_unimport_options*
+ *b:ale_python_unimport_options*
Type: |String|
Default: `''`
@@ -1355,8 +1366,8 @@ g:ale_python_unimport_options *g:ale_python_unimport_options*
invocation.
-g:ale_python_unimport_use_global *g:ale_python_unimport_use_global*
- *b:ale_python_unimport_use_global*
+g:ale_python_unimport_use_global *g:ale_python_unimport_use_global*
+ *b:ale_python_unimport_use_global*
Type: |Number|
Default: `get(g:, 'ale_use_global_executables', 0)`
diff --git a/plugin/ale.vim b/plugin/ale.vim
index b9786bb0..f9b6cab8 100644
--- a/plugin/ale.vim
+++ b/plugin/ale.vim
@@ -178,6 +178,10 @@ let g:ale_python_auto_pipenv = get(g:, 'ale_python_auto_pipenv', 0)
" Enable automatic detection of poetry for Python linters.
let g:ale_python_auto_poetry = get(g:, 'ale_python_auto_poetry', 0)
+" Enable automatic adjustment of environment variables for Python linters.
+" The variables are set based on ALE's virtualenv detection.
+let g:ale_python_auto_virtualenv = get(g:, 'ale_python_auto_virtualenv', 0)
+
" This variable can be overridden to set the GO111MODULE environment variable.
let g:ale_go_go111module = get(g:, 'ale_go_go111module', '')
diff --git a/test/linter/test_jedils.vader b/test/linter/test_jedils.vader
new file mode 100644
index 00000000..0c2781bd
--- /dev/null
+++ b/test/linter/test_jedils.vader
@@ -0,0 +1,47 @@
+Before:
+ call ale#assert#SetUpLinterTest('python', 'jedils')
+ Save b:ale_python_auto_virtualenv
+
+ let b:bin_dir = has('win32') ? 'Scripts' : 'bin'
+
+After:
+ unlet! b:bin_dir
+ unlet! b:venv_bin
+ unlet! b:sep
+ unlet! b:executable
+
+ call ale#assert#TearDownLinterTest()
+
+Execute(The jedi-language-server command callback should return default string):
+ call ale#test#SetFilename('./foo.py')
+
+ AssertLinter 'jedi-language-server', ale#Escape('jedi-language-server')
+
+Execute(The jedi-language-server executable should be configurable):
+ let g:ale_python_jedils_executable = '~/.local/bin/jedi-language-server'
+
+ AssertLinter '~/.local/bin/jedi-language-server' , ale#Escape('~/.local/bin/jedi-language-server')
+
+Execute(virtualenv vars should be used when ale_python_auto_virtualenv = 1):
+ let b:ale_python_auto_virtualenv = 1
+ call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py')
+
+ let b:venv_bin = ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir)
+ let b:sep = has('win32') ? ';' : ':'
+ let b:executable = ale#path#Simplify(b:venv_bin . '/jedi-language-server')
+
+ AssertLinter b:executable, ale#Env('PATH', b:venv_bin . b:sep . $PATH)
+ \ . ale#Escape(b:executable)
+
+Execute(You should be able to override the jedi-language-server virtualenv lookup):
+ call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py')
+
+ let g:ale_python_jedils_use_global = 1
+
+ AssertLinter 'jedi-language-server', ale#Escape('jedi-language-server')
+
+Execute(Setting executable to 'pipenv' appends 'run jedi-language-server'):
+ let g:ale_python_jedils_executable = 'path/to/pipenv'
+ call ale#test#SetFilename('../test-files/dummy')
+
+ AssertLinter 'path/to/pipenv', ale#Escape('path/to/pipenv') . ' run jedi-language-server'
diff --git a/test/linter/test_pylsp.vader b/test/linter/test_pylsp.vader
index 34cc30c6..d1490978 100644
--- a/test/linter/test_pylsp.vader
+++ b/test/linter/test_pylsp.vader
@@ -1,10 +1,13 @@
Before:
call ale#assert#SetUpLinterTest('python', 'pylsp')
+ Save b:ale_python_auto_virtualenv
let b:bin_dir = has('win32') ? 'Scripts' : 'bin'
After:
unlet! b:bin_dir
+ unlet! b:venv_bin
+ unlet! b:sep
unlet! b:executable
call ale#assert#TearDownLinterTest()
@@ -40,6 +43,17 @@ Execute(The pylsp executable should be run from the virtualenv path):
AssertEqual ale#Escape(b:executable),
\ ale_linters#python#pylsp#GetCommand(bufnr(''))
+Execute(virtualenv vars should be used when ale_python_auto_virtualenv = 1):
+ let b:ale_python_auto_virtualenv = 1
+ call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py')
+
+ let b:venv_bin = ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir)
+ let b:sep = has('win32') ? ';' : ':'
+ let b:executable = ale#path#Simplify(b:venv_bin . '/pylsp')
+
+ AssertLinter b:executable, ale#Env('PATH', b:venv_bin . b:sep . $PATH)
+ \ . ale#Escape(b:executable)
+
Execute(You should be able to override the pylsp virtualenv lookup):
call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py')
diff --git a/test/linter/test_pyright.vader b/test/linter/test_pyright.vader
index 303efa24..c81ab4b4 100644
--- a/test/linter/test_pyright.vader
+++ b/test/linter/test_pyright.vader
@@ -1,10 +1,13 @@
Before:
call ale#assert#SetUpLinterTest('python', 'pyright')
+ Save b:ale_python_auto_virtualenv
let b:bin_dir = has('win32') ? 'Scripts' : 'bin'
After:
unlet! b:bin_dir
+ unlet! b:venv_bin
+ unlet! b:sep
unlet! b:executable
call ale#assert#TearDownLinterTest()
@@ -132,6 +135,17 @@ Execute(The pyright callbacks should detect virtualenv directories):
AssertLinter b:executable, ale#Escape(b:executable) . ' --stdio'
+Execute(virtualenv vars should be used when ale_python_auto_virtualenv = 1):
+ let b:ale_python_auto_virtualenv = 1
+ call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py')
+
+ let b:venv_bin = ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir)
+ let b:sep = has('win32') ? ';' : ':'
+ let b:executable = ale#path#Simplify(b:venv_bin . '/pyright-langserver')
+
+ AssertLinter b:executable, ale#Env('PATH', b:venv_bin . b:sep . $PATH)
+ \ . ale#Escape(b:executable) . ' --stdio'
+
Execute(Setting executable to 'pipenv' should append 'run pyright'):
call ale#test#SetFilename('../test-files')
diff --git a/test/test-files/python/with_virtualenv/env/bin/jedi-language-server b/test/test-files/python/with_virtualenv/env/bin/jedi-language-server
new file mode 100755
index 00000000..e69de29b
--- /dev/null
+++ b/test/test-files/python/with_virtualenv/env/bin/jedi-language-server