From 19229e8e276a6527c179ae2cb7e0420a1c62996f Mon Sep 17 00:00:00 2001 From: w0rp Date: Fri, 7 Aug 2020 12:16:13 +0100 Subject: [PATCH] Close #2472 - Add support for pyright --- ale_linters/python/pyright.vim | 43 +++++++ autoload/ale/linter.vim | 2 +- doc/ale-python.txt | 60 +++++++++ doc/ale-supported-languages-and-tools.txt | 1 + doc/ale.txt | 3 +- supported-tools.md | 1 + .../test_pyright_command_callback.vader | 116 ++++++++++++++++++ test/test_filetype_linter_defaults.vader | 2 +- 8 files changed, 225 insertions(+), 3 deletions(-) create mode 100644 ale_linters/python/pyright.vim create mode 100644 test/command_callback/test_pyright_command_callback.vader diff --git a/ale_linters/python/pyright.vim b/ale_linters/python/pyright.vim new file mode 100644 index 00000000..422ecd61 --- /dev/null +++ b/ale_linters/python/pyright.vim @@ -0,0 +1,43 @@ +call ale#Set('python_pyright_executable', 'pyright-langserver') +call ale#Set('python_pyright_config', {}) + +function! ale_linters#python#pyright#GetConfig(buffer) abort + let l:config = deepcopy(ale#Var(a:buffer, 'python_pyright_config')) + + if !has_key(l:config, 'python') + let l:config.python = {} + endif + + if type(l:config.python) is v:t_dict + " Automatically detect the virtualenv path and use it. + if !has_key(l:config.python, 'venvPath') + let l:venv = ale#python#FindVirtualenv(a:buffer) + + if !empty(l:venv) + let l:config.python.venvPath = l:venv + endif + endif + + " Automatically use the version of Python in virtualenv. + if type(get(l:config.python, 'venvPath')) is v:t_string + \&& !empty(l:config.python.venvPath) + \&& !has_key(l:config.python, 'pythonPath') + let l:config.python.pythonPath = ale#path#Simplify( + \ l:config.python.venvPath + \ . (has('win32') ? '/Scripts/python' : '/bin/python') + \) + endif + endif + + return l:config +endfunction + +call ale#linter#Define('python', { +\ 'name': 'pyright', +\ 'lsp': 'stdio', +\ 'executable': {b -> ale#Var(b, 'python_pyright_executable')}, +\ 'command': '%e --stdio', +\ 'project_root': function('ale#python#FindProjectRoot'), +\ 'completion_filter': 'ale#completion#python#CompletionItemFilter', +\ 'lsp_config': function('ale_linters#python#pyright#GetConfig'), +\}) diff --git a/autoload/ale/linter.vim b/autoload/ale/linter.vim index a85f06e2..f81b62be 100644 --- a/autoload/ale/linter.vim +++ b/autoload/ale/linter.vim @@ -44,7 +44,7 @@ let s:default_ale_linters = { \ 'help': [], \ 'perl': ['perlcritic'], \ 'perl6': [], -\ 'python': ['flake8', 'mypy', 'pylint'], +\ 'python': ['flake8', 'mypy', 'pylint', 'pyright'], \ 'rust': ['cargo'], \ 'spec': [], \ 'text': [], diff --git a/doc/ale-python.txt b/doc/ale-python.txt index 93f1d668..60b0771d 100644 --- a/doc/ale-python.txt +++ b/doc/ale-python.txt @@ -598,6 +598,7 @@ g:ale_python_pylint_use_msg_id *g:ale_python_pylint_use_msg_id* Use message for output (e.g. I0011) instead of symbolic name of the message (e.g. locally-disabled). + =============================================================================== pyls *ale-python-pyls* @@ -682,6 +683,65 @@ g:ale_python_pyre_auto_pipenv *g:ale_python_pyre_auto_pipenv* if true. This is overridden by a manually-set executable. +=============================================================================== +pyright *ale-python-pyright* + +The `pyrlight` linter requires a recent version of `pyright` which includes +the `pyright-langserver` executable. You can install `pyright` on your system +through `npm` with `sudo npm install -g pyright` or similar. + +Refer to their README for installation instructions: +https://github.com/Microsoft/pyright + +`pyright` needs to know the path to your Python executable and probably a +virtualenv to run. ALE will try to detect these automatically. +See |g:ale_python_pyright_config|. + + +g:ale_python_pyright_executable *g:ale_python_pyright_executable* + *b:ale_python_pyright_executable* + Type: |String| + Default: `'pyright-langserver'` + + The executable for running `pyright`, which is typically installed globally. + + +g:ale_python_pyright_config *g:ale_python_pyright_config* + *b:ale_python_pyright_config* + Type: |Dictionary| + Default: `{}` + + Settings for configuring the `pyright` language server. + + See pyright's documentation for a full list of options: + https://github.com/microsoft/pyright/blob/master/docs/settings.md + + ALE will automatically try to set defaults for `venvPath` and `pythonPath` + so your project can automatically be checked with the right libraries. + You can override these settings with whatever you want in your ftplugin + file like so: > + + let b:ale_python_pyright_config = { + \ 'python': { + \ 'pythonPath': '/bin/python', + \ 'venvPath': '/other/dir', + \ }, + \} +< + If `venvPath` is set, but `pythonPath` is not, + ALE will use `venvPath . '/bin/python'` or similar as `pythonPath`. + + A commonly used setting for `pyright` is disabling language services + apart from type checking and "hover" (|ale-hover|), you can set this + setting like so, or use whatever other settings you want: > + + let b:ale_python_pyright_config = { + \ 'pyright': { + \ 'disableLanguageServices': v:true, + \ }, + \} +< + =============================================================================== reorder-python-imports *ale-python-reorder_python_imports* diff --git a/doc/ale-supported-languages-and-tools.txt b/doc/ale-supported-languages-and-tools.txt index 8d142721..2dc05287 100644 --- a/doc/ale-supported-languages-and-tools.txt +++ b/doc/ale-supported-languages-and-tools.txt @@ -372,6 +372,7 @@ Notes: * `pylint`!! * `pyls` * `pyre` + * `pyright` * `reorder-python-imports` * `vulture`!! * `yapf` diff --git a/doc/ale.txt b/doc/ale.txt index e6b3e58d..e1b38292 100644 --- a/doc/ale.txt +++ b/doc/ale.txt @@ -1290,7 +1290,7 @@ g:ale_linters *g:ale_linters* \ 'help': [], \ 'perl': ['perlcritic'], \ 'perl6': [], - \ 'python': ['flake8', 'mypy', 'pylint'], + \ 'python': ['flake8', 'mypy', 'pylint', 'pyright'], \ 'rust': ['cargo'], \ 'spec': [], \ 'text': [], @@ -2578,6 +2578,7 @@ documented in additional help files. pylint................................|ale-python-pylint| pyls..................................|ale-python-pyls| pyre..................................|ale-python-pyre| + pyright...............................|ale-python-pyright| reorder-python-imports................|ale-python-reorder_python_imports| vulture...............................|ale-python-vulture| yapf..................................|ale-python-yapf| diff --git a/supported-tools.md b/supported-tools.md index dc90c2d7..03650db2 100644 --- a/supported-tools.md +++ b/supported-tools.md @@ -380,6 +380,7 @@ formatting. * [pylama](https://github.com/klen/pylama) :floppy_disk: * [pylint](https://www.pylint.org/) :floppy_disk: * [pyls](https://github.com/palantir/python-language-server) :warning: + * [pyright](https://github.com/microsoft/pyright) * [pyre](https://github.com/facebook/pyre-check) :warning: * [reorder-python-imports](https://github.com/asottile/reorder_python_imports) * [vulture](https://github.com/jendrikseipp/vulture) :warning: :floppy_disk: diff --git a/test/command_callback/test_pyright_command_callback.vader b/test/command_callback/test_pyright_command_callback.vader new file mode 100644 index 00000000..3e421bd9 --- /dev/null +++ b/test/command_callback/test_pyright_command_callback.vader @@ -0,0 +1,116 @@ +Before: + call ale#assert#SetUpLinterTest('python', 'pyright') + + let b:bin_dir = has('win32') ? 'Scripts' : 'bin' + +After: + unlet! b:bin_dir + unlet! b:executable + + call ale#assert#TearDownLinterTest() + +Execute(The command callback should return the correct default string): + AssertLinter + \ 'pyright-langserver', + \ ale#Escape('pyright-langserver') . ' --stdio' + +Execute(The executable should be configurable): + let g:ale_python_pyright_executable = '/bin/foo-bar' + + AssertLinter + \ '/bin/foo-bar', + \ ale#Escape('/bin/foo-bar') . ' --stdio' + +Execute(The default configuration should be mostly empty): + " The default configuration needs to have at least one key in it, + " or the server won't start up properly. + AssertLSPConfig {'python': {}} + + let b:ale_python_pyright_config = {} + + AssertLSPConfig {'python': {}} + +Execute(virtualenv paths should be set in configuration by default): + call ale#test#SetFilename('python_paths/with_virtualenv/subdir/foo/bar.py') + + AssertLSPConfig { + \ 'python': { + \ 'pythonPath': ale#path#Simplify(g:dir . '/python_paths/with_virtualenv/env/' . b:bin_dir . '/python'), + \ 'venvPath': ale#path#Simplify(g:dir . '/python_paths/with_virtualenv/env'), + \ }, + \} + +Execute(The pythonPath should be set based on whatever the ovveride for the venvPath is set to): + call ale#test#SetFilename('python_paths/with_virtualenv/subdir/foo/bar.py') + + " This overrides the default detection of the path. + let b:ale_python_pyright_config = { + \ 'python': { + \ 'venvPath': '/foo/bar', + \ }, + \} + + AssertLSPConfig { + \ 'python': { + \ 'pythonPath': ale#path#Simplify('/foo/bar/' . b:bin_dir . '/python'), + \ 'venvPath': '/foo/bar', + \ }, + \} + +Execute(You should be able to override pythonPath when venvPath is detected): + call ale#test#SetFilename('python_paths/with_virtualenv/subdir/foo/bar.py') + + " This overrides the default detection of the path. + let b:ale_python_pyright_config = { + \ 'python': { + \ 'pythonPath': '/bin/python', + \ }, + \} + + AssertLSPConfig { + \ 'python': { + \ 'pythonPath': '/bin/python', + \ 'venvPath': ale#path#Simplify(g:dir . '/python_paths/with_virtualenv/env'), + \ }, + \} + +Execute(You should be able to override both pythonPath and venvPath): + call ale#test#SetFilename('python_paths/with_virtualenv/subdir/foo/bar.py') + + " This overrides the default detection of the path. + let b:ale_python_pyright_config = { + \ 'python': { + \ 'pythonPath': '/bin/python', + \ 'venvPath': '/other/dir', + \ }, + \} + + AssertLSPConfig { + \ 'python': { + \ 'pythonPath': '/bin/python', + \ 'venvPath': '/other/dir', + \ }, + \} + +Execute(You should be able to define other settings): + call ale#test#SetFilename('python_paths/with_virtualenv/subdir/foo/bar.py') + + let b:ale_python_pyright_config = { + \ 'python': { + \ 'analysis': {'logLevel': 'warning'}, + \ }, + \ 'pyright': { + \ 'disableLanguageServices': v:true, + \ }, + \} + + AssertLSPConfig { + \ 'python': { + \ 'analysis': {'logLevel': 'warning'}, + \ 'pythonPath': ale#path#Simplify(g:dir . '/python_paths/with_virtualenv/env/' . b:bin_dir . '/python'), + \ 'venvPath': ale#path#Simplify(g:dir . '/python_paths/with_virtualenv/env'), + \ }, + \ 'pyright': { + \ 'disableLanguageServices': v:true, + \ }, + \} diff --git a/test/test_filetype_linter_defaults.vader b/test/test_filetype_linter_defaults.vader index 95ec3b9a..842cc394 100644 --- a/test/test_filetype_linter_defaults.vader +++ b/test/test_filetype_linter_defaults.vader @@ -32,7 +32,7 @@ Execute(The defaults for the help filetype should be correct): AssertEqual [], GetLinterNames('help') Execute(The defaults for the python filetype should be correct): - AssertEqual ['flake8', 'mypy', 'pylint'], GetLinterNames('python') + AssertEqual ['flake8', 'mypy', 'pylint', 'pyright'], GetLinterNames('python') let g:ale_linters_explicit = 1