python-lsp / python-lsp-ruff Goto Github PK
View Code? Open in Web Editor NEWLinter plugin for pylsp based on ruff.
License: MIT License
Linter plugin for pylsp based on ruff.
License: MIT License
I am using the Helix editor with pylsp as the language server and python-lsp-ruff as plugin for ruff. Most diagnostics appear inline in the editor as expected except E501 which is related to line legth. Running ruff directly on the violating file shows the error in the terminal.
ruff test.py
test.py:3:89: E501 Line too long (100 > 88 characters)
The log from pylsp is here:
2023-02-24 12:50:41,955 IST - DEBUG - pylsp.config.config - pylsp_lint [hook]
config: <pylsp.config.config.Config object at 0x104791f50>
workspace: <pylsp.workspace.Workspace object at 0x104830ad0>
document: file:///Users/rkshthrmsh/ws/sandbox/test.py
is_saved: True
2023-02-24 12:50:41,956 IST - DEBUG - pylsp.config.config - Got user config from PyCodeStyleConfig: {}
2023-02-24 12:50:41,957 IST - DEBUG - pylsp.config.config - Got project config from PyCodeStyleConfig: {}
2023-02-24 12:50:41,957 IST - DEBUG - pylsp.config.config - With configuration: {'plugins': {'pyflakes': {'enabled': False}, 'pydocstyle': {'enabled': False}, 'rope_rename': {'enabled': False}, 'ruff': {'exclude': None, 'ignore': None, 'select': ['D'], 'lineLength': None, 'perFileIgnores': None, 'executable': 'ruff', 'config': None, 'enabled': True}, 'autopep8': {'enabled': False}, 'flake8': {'enabled': False}, 'preload': {'modules': ['OpenGL', 'PIL', 'array', 'audioop', 'binascii', 'cPickle', 'cStringIO', 'cmath', 'collections', 'datetime', 'errno', 'exceptions', 'gc', 'imageop', 'imp', 'itertools', 'marshal', 'math', 'matplotlib', 'mmap', 'mpmath', 'msvcrt', 'networkx', 'nose', 'nt', 'numpy', 'operator', 'os', 'os.path', 'pandas', 'parser', 'rgbimg', 'scipy', 'signal', 'skimage', 'sklearn', 'statsmodels', 'strop', 'sympy', 'sys', 'thread', 'time', 'wx', 'xxsubtype', 'zipimport', 'zlib']}, 'rope_autoimport': {'enabled': False, 'memory': False}, 'jedi_completion': {'fuzzy': True, 'include_class_objects': True, 'include_function_objects': True}, 'rope_completion': {'enabled': False, 'eager': False}, 'pycodestyle': {'enabled': False}, 'yapf': {'enabled': True}, 'pylint': {'enabled': False, 'args': [], 'executable': None}, 'mccabe': {'enabled': False}}, 'rope': {'extensionModules': ['OpenGL', 'PIL', 'array', 'audioop', 'binascii', 'cPickle', 'cStringIO', 'cmath', 'collections', 'datetime', 'errno', 'exceptions', 'gc', 'imageop', 'imp', 'itertools', 'marshal', 'math', 'matplotlib', 'mmap', 'mpmath', 'msvcrt', 'networkx', 'nose', 'nt', 'numpy', 'operator', 'os', 'os.path', 'pandas', 'parser', 'rgbimg', 'scipy', 'signal', 'skimage', 'sklearn', 'statsmodels', 'strop', 'sympy', 'sys', 'thread', 'time', 'wx', 'xxsubtype', 'zipimport', 'zlib']}}
2023-02-24 12:50:41,958 IST - DEBUG - pylsp_ruff.ruff_lint - Got ruff settings: {'exclude': None, 'ignore': None, 'select': ['D'], 'lineLength': None, 'perFileIgnores': None, 'line_length': 100, 'executable': 'ruff', 'config': None, 'enabled': True}
2023-02-24 12:50:41,958 IST - DEBUG - pylsp_ruff.ruff_lint - Calling ruff with args: ['--quiet', '--format=json', '--no-fix', '--force-exclude', '--stdin-filename', '/Users/rkshthrmsh/ws/sandbox/test.py', '--select=D', '--', '-'] on '/Users/rkshthrmsh/ws/sandbox/test.py'
2023-02-24 12:50:41,971 IST - DEBUG - pylsp.config.config - finish pylsp_lint --> [[]] [hook]
2023-02-24 12:50:41,972 IST - DEBUG - pylsp_jsonrpc.endpoint - Sending notification: textDocument/publishDiagnostics {'uri': 'file:///Users/rkshthrmsh/ws/sandbox/test.py', 'diagnostics': []}
2023-02-24 12:50:43,477 IST - DEBUG - pylsp_jsonrpc.endpoint - Handling notification from client {'jsonrpc': '2.0', 'method': 'textDocument/didSave', 'params': {'text': '"""Implement CCSDS 123.0-B-2 Compression.\n\nCCSDS 123.0-B-2 specifies a standard for Low-Complexity Lossless and Near-Lossless Multispectral and\nHyper\n"""\n', 'textDocument': {'uri': 'file:///Users/rkshthrmsh/ws/sandbox/test.py'}}}
2023-02-24 12:50:43,480 IST - DEBUG - pylsp.config.config - pylsp_document_did_save [hook]
config: <pylsp.config.config.Config object at 0x104791f50>
workspace: <pylsp.workspace.Workspace object at 0x104830ad0>
document: file:///Users/rkshthrmsh/ws/sandbox/test.py
2023-02-24 12:50:43,480 IST - DEBUG - pylsp.config.config - finish pylsp_document_did_save --> [] [hook]
2023-02-24 12:50:43,480 IST - DEBUG - pylsp_jsonrpc.endpoint - Handling request from client {'jsonrpc': '2.0', 'method': 'shutdown', 'params': None, 'id': 1}
2023-02-24 12:50:43,480 IST - DEBUG - pylsp_jsonrpc.endpoint - Got result from synchronous request handler: None
2023-02-24 12:50:43,481 IST - DEBUG - pylsp_jsonrpc.endpoint - Handling notification from client {'jsonrpc': '2.0', 'method': 'exit', 'params': None}
Continuation from the conversation in #22
Actions intended for publishing for
For PyPi there is a Github Action that we can use. For that I would like to change the ownership of the Pypi package to the python lsp project. Then we can store the credentials for the pylsp Pypi account in Github to be used as action. Can we do this @ccordoba12?
NVIM v0.9.1
pylsp: 1.7.3
ruff: 0.0.267
Linting a file where I know there are issues does not work.
I've got the following traceback in the log:
2023-05-16 11:18:42,852 CEST - INFO - pylsp.config.config - Updated settings to {'plugins': {'mccabe': {'enabled': False}, 'ruff': {'extendSelect': ['I'], 'enabled': True}}, 'configurationSources': ['flake8']}
2023-05-16 11:18:42,853 CEST - INFO - pylsp.config.config - Disabled plugins: [<module 'pyls_isort.plugin' from '/home/nicoe/.local/share/nvim/mason/packages/python-lsp-server/venv/lib/python3.11/site-packages/pyls_isort/plugin.py'>, <module 'pylsp.plugins.flake8_lint' from '/home/nicoe/.local/share/nvim/mason/packages/python-lsp-server/venv/lib/python3.11/site-packages/pylsp/plugins/flake8_lint.py'>, <module 'pylsp.plugins.mccabe_lint' from '/home/nicoe/.local/share/nvim/mason/packages/python-lsp-server/venv/lib/python3.11/site-packages/pylsp/plugins/mccabe_lint.py'>, <module 'pylsp.plugins.pycodestyle_lint' from '/home/nicoe/.local/share/nvim/mason/packages/python-lsp-server/venv/lib/python3.11/site-packages/pylsp/plugins/pycodestyle_lint.py'>, <module 'pylsp.plugins.pydocstyle_lint' from '/home/nicoe/.local/share/nvim/mason/packages/python-lsp-server/venv/lib/python3.11/site-packages/pylsp/plugins/pydocstyle_lint.py'>, <module 'pylsp.plugins.pyflakes_lint' from '/home/nicoe/.local/share/nvim/mason/packages/python-lsp-server/venv/lib/python3.11/site-packages/pylsp/plugins/pyflakes_lint.py'>, <module 'pylsp.plugins.pylint_lint' from '/home/nicoe/.local/share/nvim/mason/packages/python-lsp-server/venv/lib/python3.11/site-packages/pylsp/plugins/pylint_lint.py'>, <module 'pylsp.plugins.rope_autoimport' from '/home/nicoe/.local/share/nvim/mason/packages/python-lsp-server/venv/lib/python3.11/site-packages/pylsp/plugins/rope_autoimport.py'>, <module 'pylsp.plugins.rope_completion' from '/home/nicoe/.local/share/nvim/mason/packages/python-lsp-server/venv/lib/python3.11/site-packages/pylsp/plugins/rope_completion.py'>, <module 'pylsp.plugins.rope_rename' from '/home/nicoe/.local/share/nvim/mason/packages/python-lsp-server/venv/lib/python3.11/site-packages/pylsp/plugins/rope_rename.py'>]
2023-05-16 11:18:43,386 CEST - WARNING - pylsp.config.config - Failed to load hook pylsp_lint: While structuring typing.List[pylsp_ruff.ruff.Check] (1 sub-exception)
+ Exception Group Traceback (most recent call last):
| File "/home/nicoe/.local/share/nvim/mason/packages/python-lsp-server/venv/lib/python3.11/site-packages/pylsp/config/config.py", line 33, in _hookexec
| return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| File "/home/nicoe/.local/share/nvim/mason/packages/python-lsp-server/venv/lib/python3.11/site-packages/pluggy/_manager.py", line 327, in traced_hookexec
| return outcome.get_result()
| ^^^^^^^^^^^^^^^^^^^^
| File "/home/nicoe/.local/share/nvim/mason/packages/python-lsp-server/venv/lib/python3.11/site-packages/pluggy/_result.py", line 60, in get_result
| raise ex[1].with_traceback(ex[2])
| File "/home/nicoe/.local/share/nvim/mason/packages/python-lsp-server/venv/lib/python3.11/site-packages/pluggy/_result.py", line 33, in from_call
| result = func()
| ^^^^^^
| File "/home/nicoe/.local/share/nvim/mason/packages/python-lsp-server/venv/lib/python3.11/site-packages/pluggy/_manager.py", line 324, in <lambda>
| lambda: oldcall(hook_name, hook_impls, kwargs, firstresult)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| File "/home/nicoe/.local/share/nvim/mason/packages/python-lsp-server/venv/lib/python3.11/site-packages/pluggy/_callers.py", line 60, in _multicall
| return outcome.get_result()
| ^^^^^^^^^^^^^^^^^^^^
| File "/home/nicoe/.local/share/nvim/mason/packages/python-lsp-server/venv/lib/python3.11/site-packages/pluggy/_result.py", line 60, in get_result
| raise ex[1].with_traceback(ex[2])
| File "/home/nicoe/.local/share/nvim/mason/packages/python-lsp-server/venv/lib/python3.11/site-packages/pluggy/_callers.py", line 39, in _multicall
| res = hook_impl.function(*args)
| ^^^^^^^^^^^^^^^^^^^^^^^^^
| File "/home/nicoe/.local/share/nvim/mason/packages/python-lsp-server/venv/lib/python3.11/site-packages/pylsp_ruff/plugin.py", line 125, in pylsp_lint
| checks = run_ruff_check(workspace, document)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| File "/home/nicoe/.local/share/nvim/mason/packages/python-lsp-server/venv/lib/python3.11/site-packages/pylsp_ruff/plugin.py", line 354, in run_ruff_check
| return converter.structure(result, List[RuffCheck])
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| File "/home/nicoe/.local/share/nvim/mason/packages/python-lsp-server/venv/lib/python3.11/site-packages/cattrs/converters.py", line 309, in structure
| return self._structure_func.dispatch(cl)(obj, cl)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| File "/home/nicoe/.local/share/nvim/mason/packages/python-lsp-server/venv/lib/python3.11/site-packages/cattrs/converters.py", line 510, in _structure_list
| raise IterableValidationError(
| cattrs.errors.IterableValidationError: While structuring typing.List[pylsp_ruff.ruff.Check] (1 sub-exception)
+-+---------------- 1 ----------------
| Exception Group Traceback (most recent call last):
| File "/home/nicoe/.local/share/nvim/mason/packages/python-lsp-server/venv/lib/python3.11/site-packages/cattrs/converters.py", line 502, in _structure_list
| res.append(handler(e, elem_type))
| ^^^^^^^^^^^^^^^^^^^^^
| File "<cattrs generated structure pylsp_ruff.ruff.Check>", line 35, in structure_Check
| if errors: raise __c_cve('While structuring ' + 'Check', errors, __cl)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| cattrs.errors.ClassValidationError: While structuring Check (1 sub-exception)
| Structuring typing.List[pylsp_ruff.ruff.Check] @ index 0
+-+---------------- 1 ----------------
| Exception Group Traceback (most recent call last):
| File "<cattrs generated structure pylsp_ruff.ruff.Check>", line 31, in structure_Check
| res['fix'] = __c_structure_fix(o['fix'], __c_type_fix)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| File "/home/nicoe/.local/share/nvim/mason/packages/python-lsp-server/venv/lib/python3.11/site-packages/cattrs/converters.py", line 574, in _structure_optional
| return self._structure_func.dispatch(other)(obj, other)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| File "<cattrs generated structure pylsp_ruff.ruff.Fix>", line 14, in structure_Fix
| if errors: raise __c_cve('While structuring ' + 'Fix', errors, __cl)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| cattrs.errors.ClassValidationError: While structuring Fix (1 sub-exception)
| Structuring class Check @ attribute fix
+-+---------------- 1 ----------------
| Traceback (most recent call last):
| File "<cattrs generated structure pylsp_ruff.ruff.Fix>", line 5, in structure_Fix
| res['edits'] = __c_structure_edits(o['edits'], __c_type_edits)
| ~^^^^^^^^^
| KeyError: 'edits'
| Structuring class Fix @ attribute edits
+------------------------------------
I tried using an older version of ruff but it didn't work (I haven't tested with older version of pylsp because uninstalling python-lsp-ruff did bring the linting back).
'fix all' of code action should consider the range,
the statement in def pylsp_code_actions(
:
range : Dict
Range argument given by pylsp. Not used here.
should be not true, this range i guess should be used later in checks_with_fixes
to filter fixes only in this range.
otherwise 'fix all' probably in the action list all the time, but that actually maybe would get action nothing from it.
This package currently supports ruff 0.1.*
but not 0.2.0
. Reading through the release blog post it looks like there are no changes that will cause problems, so it should be safe to relax the dependency to "ruff>=0.1.5, <0.3.0"
python-lsp-ruff/pyproject.toml
Lines 36 to 38 in f5bcc65
Hi, as far as I can see, the new ruff formatter comparable to black is not yet supported by this plugin. If I understand it correctly, the term "format" in the code of this repo relates to fixing errors. Would it be possible to add formatting (in the sense of black) as a new code action?
With #25 being merged soon, the question remains whether formatting should be enabled by default and error codes should be given to be auto-fixed when running formatting.
I don't really mind on or the other, so I'm open to suggestions.
If e.g. isort-codes should be used for formatting per default, we should also disable pylsp-isort
.
Hello, giving this a go, and i am running into this strange situation where Syntax errors stop being shown if the pyproject.toml
file contains a select =
line.
without:
E class CustomFilter(PythonFilter):))) โ โ SyntaxError: Unexpected token ')'
ignore_dirs = ["__pycache__"]
with:
class CustomFilter(PythonFilter):)))
ignore_dirs = ["__pycache__"]
command line version works with the config file, so it's not a typo issue.
configuration is recommended lspconfig and
local lspconfig = require('lspconfig')
lspconfig.pylsp.setup {
plugins = {
ruff = {
enabled = true,
},
}
}
extendSelect
also doesn't seem to work.
Currently the CodeAction "Disable for this line" is only present if the error is flagged as autofix-able, but I'd like to have it for non-autofixable errors too.
It's a very minor convenience boost :-)
Thanks for a great plugin!
Magnus
Hi,
Is config option for this project also applies for ruff.toml or only for pyproject.toml? If not, is it possible to have possibility to pass ruff.toml instead of pyproject.toml?
Currently, when custom config is set during setup, project-local configuration files are ignored. I wonder whether this behavior is the result of an explicit design decision, or if it is open for discussion and subject to change. I imagined the setting to be a default config, used not to set the same settings across all projects, but to separate the configuration of LSP and Ruff and overridden by local settings.
For example, how to set "E501"(Line too long) become a Hint level diagnostics?
I've been using python-lsp-server 1.7.x
and python-lsp-ruff 1.2.0
with Emacs 29 and eglot
since January or thereabouts, and it's been a great experience. I recently tried upgrading to newer versions of python-lsp-ruff
, but with all newer versions (1.3.0, 1.4.0, and 1.5.0) I no longer receive any diagnostics. For example, I've tested the following:
def hello():
print('Hello')
print('World')
for which I get a SyntaxError (E999) diagnostic on line 3 with python-lsp-ruff 1.2.0
, but no diagnostics for newer versions. I've been trying to find out the underlying cause but simply can't figure it out. I experience the same behaviour whether I use older or newer versions of ruff
, and older or newer versions of eglot
. As far as I can tell, this appears to be due a change in python-lsp-ruff >= 1.3.0
, rather than in python-lsp-server
, ruff
, or eglot
.
Do you have any idea what might be causing this, or what information I can provide to help figure this out?
Hi, I'm fairly unfamiliar with ruff and formatting in general, and so I'm trying to understand how to control its behaviour.
I have this configuration:
"pylsp.plugins.ruff.enabled": true,
"pylsp.plugins.ruff.extendSelect": ["E", "D", "C90", "I"],
"pylsp.plugins.ruff.ignore": ["E265"],
"pylsp.plugins.ruff.format": ["D"],
"pylsp.plugins.ruff.preview": true,
"pylsp.plugins.ruff.lineLength": 79,
Then, I introduce this typo: a = 1
. This gets correctly signaled by ruff with E221 (this code requires preview
). However, when I run the command :call CocAction('format')
this error gets fixed. This is not what I expect, the error should not be fixed because this family of errors is not explicitly indicated in the ruff.format
option. This does seem to work for I
errors, though.
Am I doing anything wrong or is this the expected behaviour? To be honest, I'm not even sure if :call CocAction('format')
is the correct way to invoke ruff format
.
Thanks for the the help and more generally for this great plugin!
This is an example - this sort of problem doesn't happen every time, not even most of the time, but it does happen enough to shake my confidence in the errors I'm getting:
โ return (
๏ โ โ LockingPassthrough(NewProduct, lock) โ Undefined name `Status`
โ โ .filter(NewProduct.deleted_on.is_(None))
โ โ .join(subquery, Pipeline.product_id == NewProduct.id)
โ )
As you can see, there's nothing about "Status" on that line. It's been like this for about 10 or 20 minutes. I had Status in there, but I corrected the problem; sadly, the red error never went away.
My question is twofold:
Thanks!
I'm trying to setup python-lsp-ruff
, but for some reason ruff format
doesn't seem to be running.
Here is my config
Running ruff format --diff src
:
Is there a way to debug these sort of issues?
โฏ pip install python-lsp-ruff
Collecting python-lsp-ruff
Downloading python_lsp_ruff-1.4.0-py3-none-any.whl (9.2 kB)
Collecting ruff>=0.0.260 (from python-lsp-ruff)
Using cached ruff-0.0.267.tar.gz (1.1 MB)
Installing build dependencies ... done
Getting requirements to build wheel ... done
Preparing metadata (pyproject.toml) ... error
error: subprocess-exited-with-error
ร Preparing metadata (pyproject.toml) did not run successfully.
โ exit code: 1
โฐโ> [22 lines of output]
error: failed to get ruff
as a dependency of package ruff_cli v0.0.267 (/data/data/com.termux/files/usr/tmp/pip-install-4ta5rki6/ruff_55c9c69c060f4940954cdd8d1f2a0b40/crates/ruff_cli)
Caused by:
failed to load source for dependency `ruff`
Caused by:
Unable to update /data/data/com.termux/files/usr/tmp/pip-install-4ta5rki6/ruff_55c9c69c060f4940954cdd8d1f2a0b40/local_dependencies/ruff
Caused by:
failed to parse manifest at `/data/data/com.termux/files/usr/tmp/pip-install-4ta5rki6/ruff_55c9c69c060f4940954cdd8d1f2a0b40/local_dependencies/ruff/Cargo.toml`
Caused by:
error inheriting `colored` from workspace root manifest's `workspace.dependencies.colored`
Caused by:
failed to find a workspace root
๐ฅ maturin failed
Caused by: Cargo metadata failed. Does your crate compile with `cargo build`?
Caused by: `cargo metadata` exited with an error:
Error running maturin: Command '['maturin', 'pep517', 'write-dist-info', '--metadata-directory', '/data/data/com.termux/files/usr/tmp/pip-modern-metadata-osjlu_8g', '--interpreter', '/data/data/com.termux/files/usr/bin/python3']' returned non-zero exit status 1.
Checking for Rust toolchain....
Running `maturin pep517 write-dist-info --metadata-directory /data/data/com.termux/files/usr/tmp/pip-modern-metadata-osjlu_8g --interpreter /data/data/com.termux/files/usr/bin/python3`
[end of output]
note: This error originates from a subprocess, and is likely not a problem with pip.
error: metadata-generation-failed
ร Encountered error while generating package metadata.
โฐโ> See above for output.
note: This is an issue with the package mentioned above, not pip.
hint: See above for details.
As someone only needing the linting part of ruff, I'd like to be able to disable the formatter, which conflicts with the formatter I do use.
I spent the better part of the day trying to figure out why black always broke the formatting when running inside of my editor but not when running from our pre-commit hook or manually in the terminal... Now I finally figured out that it was actually this plugin having formatting enabled by default.
Ruff formatting is not 100% compatible with black, which basically stops me from using this plugin entirely in my workflow. Which sucks because I do actually want the linting part of ruff.
Otherwise I guess I'll need to setup another language server for which I can then entirely disable document formatting
Thank you all for this package. I find it very useful for linting code in jupyter notebooks via jupyterlab-lsp
.
As a conda user, I would find it useful if the package was available to install with conda, not just pip.
Thanks again!
I'm sending the following configuration to pylsp via the didChangeConfiguration notification but I don't get the desired effect of disabling error code D101:
{
"pylsp": {
"plugins": {
"pycodestyle": {
"enabled": false
},
"pyflakes": {
"enabled": false
},
"ruff": {
"enabled": true,
"ignore": [
"D101"
]
}
}
}
}
However, if I switch pylsp.ruff.enabled
to false
, the plugin is disabled, so the editor part of my setup must be working.
I use python-lsp-server in Neovim and also have python-lsp-ruff installed. I wonder, how I receive updates of Ruff because it used as a plugin and Mason doesn't know explicitly about python-lsp-ruff.
The plugin does not seem to be working with the Helix Editor. Here is my languages.toml
file. I have tried to explicitly disable the other linters. Is there anything missing here?
[[language]]
name = "python"
# Disable flake8 (disabled by default), pycodestyle,
# pydocstyle, pyflakes, and mccabe for ruff
[language.config.pylsp.plugins.pycodestyle]
enabled = false
[language.config.pylsp.plugins.pydocstyle]
enabled = false
convention = 'pep257'
[language.config.pylsp.plugins.pyflakes]
enabled = false
[language.config.pylsp.plugins.mccabe]
enabled = false
[language.config.pylsp.plugins.ruff]
enabled = true
This works in both ruff
via CLI and with python-lsp-ruff
; none of the listed errors are visible in __init__.py
files:
Edit: No it doesn't, please see comment below.
[tool.ruff]
ignore = [
"E501", # line length violations
"E722", # bare except
]
per-file-ignores = {
# Ignore import violations in all `__init__.py` files
"__init__.py" = ["E402", "F401", "F403"]
}
This works when invoking ruff
via CLI, but not in python-lsp-ruff
; the per-file-ignores are visible in the editor but not in the command line (the global ignore
d errors are still invisible in both):
[tool.ruff]
ignore = [
"E501", # line length violations
"E722", # bare except
]
# Ignore import violations in all `__init__.py` files
[tool.ruff.per-file-ignores]
"__init__.py" = ["E402", "F401", "F403"]
It seems like python-lsp-ruff
doesn't parse sub-tables specified via headers somehow?
Thank you for this project!
I get the following in test_ruff_code_actions
:
workspace = <pylsp.workspace.Workspace object at 0x7f0938b57130>
def test_ruff_code_actions(workspace):
_, doc = temp_document(codeaction_str, workspace)
diags = ruff_lint.pylsp_lint(workspace, doc)
range_ = cattrs.unstructure(
Range(start=Position(line=0, character=0), end=Position(line=0, character=0))
)
actions = ruff_lint.pylsp_code_actions(
workspace._config, workspace, doc, range=range_, context={"diagnostics": diags}
)
actions = converter.structure(actions, List[CodeAction])
for action in actions:
> assert action.title in codeactions
E AssertionError: assert 'Ruff: Organize imports' in ['Ruff (F401): Remove unused import: `os`', 'Ruff (F401): Disable for this line', 'Ruff (F841): Remove assignment to unused variable `a`', 'Ruff (F841): Disable for this line', 'Ruff: Fix All']
E + where 'Ruff: Organize imports' = CodeAction(title='Ruff: Organize imports', kind=<CodeActionKind.SourceOrganizeImports: 'source.organizeImports'>, diag...range=1:0-2:0, new_text='import os\n\n\n')]}, document_changes=None, change_annotations=None), command=None, data=None).title
tests/test_code_actions.py:76: AssertionError
If the executable is specified in the LSP config, the command line to run ruff is constructed and executed in
python-lsp-ruff/pylsp_ruff/plugin.py
Lines 517 to 519 in c018265
This call is missing the subcommand to actually execute with ruff. Compare to the call constructed for the fallback usage of the Python module in
python-lsp-ruff/pylsp_ruff/plugin.py
Lines 527 to 529 in c018265
which includes str(subcommand)
.
Without the subcommand ruff seems to fallback to linting and does nothing to the buffer when trying to format through the LSP. Just adding str(subcommand)
to the executable command fixes this for me.
Hi there. I am wondering what I am doing wrong here. I have several rules I like to change for nearly all my projects, like line-length, single vs double quotes, etc. I have made a .ruff.toml
in my dotfiles folder and in my CocConfig I added "pylsp.plugins.ruff.config": "~/dotfiles/ruff.toml"
to link to it for use.
I can see linting errors when I remove the line, and when I add it they go away. Am I doing this wrong?
If it matters I'm using VIm, not NeoVim. I also have the following pylsp settings:
{
"pylsp.enable": true,
"pylsp.builtin.enableInstallPythonLspRuff": true,
"pylsp.plugins.pycodestyle.enabled": false,
"pylsp.plugins.pyflakes.enabled": false,
"pylsp.plugins.mccabe.enabled": false,
"pylsp.plugins.ruff.format": [
"I"
],
"pylsp.plugins.ruff.config": "~/dotfiles/ruff.toml"
}
Setting enabled key here does not affect anything.
However, setting ignore key causes ruff to ignore the specified key.
pylsp settings
local lspconfig = require("lspconfig")
lspconfig["pylsp"].setup({
settings = {
pylsp = {
plugins = {
ruff = {
enabled = false,
ignore = {
"E741",
},
},
},
},
},
I'm not sure how reproducible this will be on other environments (although it might not be too hard to replicate with a Dockerfile, especially if there's a pipx
- ready image), but currently I'm running into this (on MacOS, fwiw), after
pipx install --force "ruff>=0.1"
And it goes away after
pipx install --force "ruff<0.1"
Some info about versions:
$ pipx list | rg 'ruff|lsp'
package python-lsp-server 1.8.2, installed using Python 3.11.6
- pylsp
package ruff 0.0.292, installed using Python 3.11.6
- ruff
$ pipx runpip python-lsp-server freeze | rg ruff
python-lsp-ruff==1.5.2
ruff==0.1.0
Based on the above, even though I've got the incompatible ruff
version in my python-lsp-server
environment, I can avoid this issue if ruff --version
is compatible. Conversely (?), if I had a good version range in the python-lsp-server
venv, it wouldn't matter if my globally-installed ruff
had breaking changes.
Limited testing with my pipx environments:
at 10:12:30 ๐ โฏ ~/.local/pipx/venvs/python-lsp-server/bin/python -c 'import sys; import os; os.system(sys.executable + " -m ruff --version")'
ruff 0.1.0
at 10:12:54 ๐ โฏ ~/.local/pipx/venvs/ruff/bin/python -c 'import sys; import os; os.system(sys.executable + " -m ruff --version")'
ruff 0.0.292
I'd hope that testing in a CPython python -m venv
environment would be sufficient, but it's possible that different python distributions (e.g. circuitpython) or project tools (pdm, poetry, etc.) might behave differently.
Based on personal anecdotal evidence, I haven't run into issues with using sys.executable
like this in the past, but there are a lot of environments I haven't worked in yet (embedded, WASM, etc.)
Originally posted by @znd4 in #49 (comment)
I want to use python-lsp-server
and python-lsp-ruff
with neovim
, but I get the following error.
Other plugins such as python-lsp-black
work.
LspLog
[ERROR][2023-11-19 23:17:03] .../vim/lsp/rpc.lua:734 "rpc" "/home/Ttayu/.local/share/nvim/mason/bin/pylsp" "stderr" "2023-11-19 23:17:03,317 JST - ERROR - pylsp_jsonrpc.streams - Failed to write message to output file {'jsonrpc': '2.0', 'method': 'textDocument/publishDiagnostics', 'params': {'uri': 'file:///home/Ttayu/sample.py', 'diagnostics': [{'range': {'start': {'line': 1, 'character': 7}, 'end': {'line': 1, 'character': 13}}, 'message': 'shutil
imported but unused', 'severity': 1, 'code': 'F401', 'source': 'ruff', 'tags': [1], 'data': Fix(edits=[Edit(content='', location=Location(row=2, column=1), end_location=Location(row=3, column=1))], message='Remove unused import: shutil
', applicability='safe')}, {'range': {'start': {'line': 15, 'character': 0}, 'end': {'line': 15, 'character': 14}}, 'message': 'Module level import not at top of file', 'severity': 2, 'code': 'E402', 'source': 'ruff', 'tags': []}, {'range': {'start': {'line': 15, 'character': 7}, 'end': {'line': 15, 'character': 14}}, 'message': 'pathlib
imported but unused', 'severity': 1, 'code': 'F401', 'source': 'ruff', 'tags': [1], 'data': Fix(edits=[Edit(content='', location=Location(row=16, column=1), end_location=Location(row=17, column=1))], message='Remove unused import: pathlib
', applicability='safe')}, {'source': 'mypy', 'range': {'start': {'line': 9, 'character': 15}, 'end': {'line': 9, 'character': 38}}, 'message': '"filter[Any]" has no attribute "exists"', 'severity': 1, 'code': 'attr-defined'}]}}\nTraceback (most recent call last):\n File "/home/Ttayu/.local/share/nvim/mason/packages/python-lsp-server/venv/lib/python3.10/site-packages/pylsp_jsonrpc/streams.py", line 97, in write\n body = json.dumps(message, **self._json_dumps_args)\nTypeError: Fix(edits=[Edit(content='', location=Location(row=2, column=1), end_location=Location(row=3, column=1))], message='Remove unused import: shutil
', applicability='safe') is not JSON serializable\n"
import shutil
from pathlib import Path
import Path
python-lsp-ruff: 1.6.0
ruff: 0.1.6
OS:
Linux 5.15.133.1-microsoft-standard-WSL2
5.15.0-88-generic
NeoVim: NVIM v0.9.4, v0.10.0-dev-09a17f9
Build type: Release
LuaJIT 2.1.1692716794
/home/Ttayu/.local/share/nvim/mason/packages/python-lsp-server/venv/bin/pip list
Package Version
--------------------- --------
astroid 3.0.1
attrs 23.1.0
autopep8 2.0.4
cattrs 23.2.1
dill 0.3.7
docstring-to-markdown 0.13
flake8 6.1.0
importlib-metadata 6.8.0
isort 5.12.0
jedi 0.19.1
lsprotocol 2023.0.0
mccabe 0.7.0
packaging 23.2
parso 0.8.3
pip 23.2.1
platformdirs 4.0.0
pluggy 1.3.0
pycodestyle 2.11.1
pydocstyle 6.3.0
pyflakes 3.1.0
pylint 3.0.2
python-lsp-jsonrpc 1.1.2
python-lsp-ruff 1.6.0
python-lsp-server 1.9.0
pytoolconfig 1.2.6
rope 1.11.0
ruff 0.1.6
setuptools 65.5.0
snowballstemmer 2.2.0
tomli 2.0.1
tomlkit 0.12.3
ujson 5.8.0
whatthepatch 1.0.5
yapf 0.40.2
zipp 3.17.0
When hitting ctrl+s to save a file, the LSP action to format a file is invoked. I found the ruff plugin to be the cause, here's the log file from python-lsp-server:
2023-10-18 08:41:40,113 CEST - ERROR - pylsp_ruff.plugin - Error running ruff: error: unexpected argument '--format' found
tip: to pass '--format' as a value, use '-- --format'
Usage: ruff check <--verbose|--quiet|--silent> [FILES]...
For more information, try '--help'.
Seems like this option is deprecated in 0.1.0: astral-sh/ruff#7984
I currently use ruff-lsp inside of neovim and I decided to install python-lsp-server
in addition to get all the nice lsp stuff like 'go to definition' and such. I tried using python-lsp-ruff
instead of ruff-lsp
because I thought it made more sense to have everything in one language server, but I was sad to find it does not act the same as ruff-lsp
. Is that normal?
The main pain points for me are:
ruff-lsp
are displayed as errors by python-lsp-ruff
, e.g. unused imports
or Redefinition of unused...
ruff-lsp
I have things like organize imports
I am not entirely sure if that's a neovim thing or if that's a python-lsp-ruff
thing, but I thought I would post it here first, feel free to redirect me if this is out of your hands ๐
BTW, I tried two different methods to install python-lsp-ruff
, both yielded the same outcome. The first one was a direct pip install
, the second one was through Mason using the :PylspInstall
command I discovered in this issue.
If the client configuration contains pylsp.plugins.flake8.enabled = true
(which is necessary for flake8 to enable in pylsp), then this seems to always override the documented python-lsp-ruff behaviour of auto-disabling flake8.
I think this applies for all the linters that are auto-disabled by python-lsp-ruff, although in the other cases they are enabled by default so leaving enabled = true
out of the client config will solve the problem.
What I observe with my LSP client (eglot) is the following sequence of events:
initialize
python-lsp-ruff
and flake8_lint
.pylsp_settings
hook. It will merge 'flake8': {'enabled': False}
into the plugins settings (along with the same for other other auto-disabled plugins.)pylsp_settings
hook, which also sets 'flake8': {'enabled': False}
(not sure if these happen in a guaranteed order, but the outcome is the same - flake8 is definitely disabled!)pylsp -v
will log a Disabled plugins:
line that includes pylsp.plugins.flake8_lint
.'workspace/didChangeConfiguration'
with 'params': {'settings': {'pylsp': {'plugins': [...] 'flake8': {'enabled': True} [...]
pylsp -v
will log a Disabled plugins:
line that no longer includes pylsp.plugins.flake8_lint
.This may be an eglot bug(?) but from what I've seen it seems likely most clients will send these events in this sequence.
flake8
binary on the PATH of the venv works, as then the plugin enables but never produces any results.didChangeConfiguration
. However this seems counter to the overall architecture of LSP, where the language-specific implementation is delegated to the server.The best idea I've come up with for a fix would actually be a python-lsp feature, not a python-lsp-ruff change. Although hopefully there's a simpler way to solve this in python-lsp-ruff, I'm pretty unfamiliar with LSP.
The idea is, pylsp could support a setting like pylsp.plugins.NAME.enabled = 'project'
setting that will call a hook in the plugin that checks for the configuration files or keys used by that plugin's linter in the project, and only enables the plugin if some configuration is found. Most of this logic already exists in the plugins.
If this does seem like a good feature then I'm happy to raise it on the main pylsp repo, and potentially raise some PRs.
With the introduction of the unsafe
auto-fixes in ruff, I feel having a single toggle in pylsp for enabling/disabling them are quite too inefficient or "too safe", as either make all unsafe fixes disappear, or making the Fix all
-code action quite unsafe in nature
My idea is instead, if you leave pylsp.plugins.ruff.unsafeFixes
as False
then the Fix all
-code-action should fix all safe
rules, but still make the individual unsafe
rules available and actionable on the respective diagnostic/location
This strikes the balance of being safe with the Fix all
-code-action, and still being able to discover and make a choice on the unsafe
fix
(If you instead set pylsp.plugins.ruff.unsafeFixes
to True
, then the plugin should work exactly as now (because then you signed up for the "unsafety-ness"))
With that being said, the unsafe
-code actions should probably indicate they are unsafe somehow
If this isn't too crazy of an idea, I'd happily try to implement it :-)
See the discussion in #22.
When I try to "Organize imports" via code actions, I observe the following unexpected behaviour:
After organizing import with python-lsp-ruff:
Expected behaviour (below screenshot is obtained by using code actions with ruff-lsp
):
As you can see, a random i
is inserted at the beginning, and the c
from the class
statement disappeared.
Performing the code action with ruff-lsp
and running ruff --fix file.py --extendSelect "I"
on the command line provide the expected result.
For reference, I am on WSL Ubuntu using Emacs (29) with eglot
.
Not sure if this an issue something with Emacs/eglot or my setup, but as I don't have the issue with ruff-lsp
I thought it might be worth checking here if anyone else has the same issue?
I posted here, but just want to crosspost in case you are able to answer it better python-lsp/python-lsp-server#553
I'm running emacs with lsp-mode, and have pylsp set up with this plugin
I'm having an issue setting specific ignore rules. for example:
(lsp-register-custom-settings '(
("pylsp.plugins.ruff.enabled" t)
("pylsp.plugins.ruff.lineLength" 88)
("pylsp.plugins.ruff.ignore" "D215")
))
I get this error:
ERROR - pylsp_ruff.plugin - Error running ruff: error: invalid value '2' for '--ignore <RULE_CODE>'
But if I change my config to use the more general D category ("pylsp.plugins.ruff.ignore" "D")
instead of a specific rule then everything works fine
See discussion in #1.
FAILED tests/test_code_actions.py::test_ruff_code_actions - ValueError: Position.character should be in range [0:2147483647], but was -1.
FAILED tests/test_code_actions.py::test_import_action - ValueError: Position.character should be in range [0:2147483647], but was -1.
tests/test_code_actions.py:78:
tests/test_code_actions.py:103:
flake8, mccabe, and pycodestyle are currently disabled by this plugin. Should pyflakes also be disabled? It's enabled by default by python-lsp-server.
If the executable
configuration param is specified but points to an executable that does not exist then run_ruff()
throws an exception and prevents other python-lsp-server
linters from running. With a valid executable specified multiple lint errors are flagged from multiple linters (including ruff). With an invalid executable specified no lint errors are flagged (not even from other linters).
For example:
2023-12-22 13:21:14,431 GMT - DEBUG - pylsp_ruff.plugin - Calling ruff with args: ['--quiet', '--exit-zero', '--output-format=json', '--extension=ipynb:python', '--no-fix', '--force-exclude', '--stdin-filename=<redacted>', '--preview', '--extend-select=E,W,F', '--', '-'] on '<redacted>''
2023-12-22 13:21:14,439 GMT - ERROR - pylsp_ruff.plugin - Can't execute ruff with given executable 'ruff'.
2023-12-22 13:21:14,440 GMT - WARNING - pylsp.config.config - Failed to load hook pylsp_lint: cannot access local variable 'p' where it is not associated with a value
Traceback (most recent call last):
File "/<redacted>/.config/coc/extensions/@yaegassy/coc-pylsp-data/pylsp/venv/lib/python3.11/site-packages/pylsp/config/config.py", line 40, in _hookexec
return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/<redacted>/.config/coc/extensions/@yaegassy/coc-pylsp-data/pylsp/venv/lib/python3.11/site-packages/pluggy/_manager.py", line 457, in traced_hookexec
return outcome.get_result()
^^^^^^^^^^^^^^^^^^^^
File "/<redacted>/.config/coc/extensions/@yaegassy/coc-pylsp-data/pylsp/venv/lib/python3.11/site-packages/pluggy/_result.py", line 114, in get_result
raise exc.with_traceback(exc.__traceback__)
File "/<redacted>/.config/coc/extensions/@yaegassy/coc-pylsp-data/pylsp/venv/lib/python3.11/site-packages/pluggy/_result.py", line 76, in from_call
result = func()
^^^^^^
File "/<redacted>/.config/coc/extensions/@yaegassy/coc-pylsp-data/pylsp/venv/lib/python3.11/site-packages/pluggy/_manager.py", line 454, in <lambda>
lambda: oldcall(hook_name, hook_impls, caller_kwargs, firstresult)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/<redacted>/.config/coc/extensions/@yaegassy/coc-pylsp-data/pylsp/venv/lib/python3.11/site-packages/pluggy/_callers.py", line 113, in _multicall
raise exception.with_traceback(exception.__traceback__)
File "/<redacted>/.config/coc/extensions/@yaegassy/coc-pylsp-data/pylsp/venv/lib/python3.11/site-packages/pluggy/_callers.py", line 77, in _multicall
res = hook_impl.function(*args)
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/<redacted>/.config/coc/extensions/@yaegassy/coc-pylsp-data/pylsp/venv/lib/python3.11/site-packages/pylsp_ruff/plugin.py", line 172, in pylsp_lint
checks = run_ruff_check(document=document, settings=settings)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/<redacted>/.config/coc/extensions/@yaegassy/coc-pylsp-data/pylsp/venv/lib/python3.11/site-packages/pylsp_ruff/plugin.py", line 442, in run_ruff_check
result = run_ruff(
^^^^^^^^^
File "/<redacted>/.config/coc/extensions/@yaegassy/coc-pylsp-data/pylsp/venv/lib/python3.11/site-packages/pylsp_ruff/plugin.py", line 525, in run_ruff
(stdout, stderr) = p.communicate(document_source.encode())
^
UnboundLocalError: cannot access local variable 'p' where it is not associated with a value
Versions:
Prior to commit ea5f874a
, python-lsp-ruff
would silently (apart from a debug message) fall back to running ruff
via the python module if the specified executable was not found. Now an error message is logged following the Popen()
failure, but the code still attempts to use the pipe (which is not defined following the exception). That throws an exception which is not caught and as a result any subsequent linters aren't run (so not only do we not se
I see two options for resolving this (other than making sure the executable
config param is set correctly :-p):
ruff
via the python module (similar to previous behaviour, but with the option to not even attempt to run the executable if it's not specified).I'd suggest the second option as that will provide a better user experience. That assumes commit ea5f874a
was simply intended to shortcut the attempt to call the executable if it was not set, rather than intended to remove the fallback behaviour.
This issue was discovered while investigating yaegassy/coc-pylsp#24.
class PluginSettings
doesn't seem to support quote-style ? Seems inefficient to add ruff.toml just for that config
Do you think its okay to add that option as well ? or maybe some dynamic options handler ?
python-lsp-ruff
gives the following error if ruff
is not in the environment. This error appears to cause all lint processes served by pylsp
to stop.
2023-01-06 19:02:47,691 JST - WARNING - pylsp.config.config - Failed to load hook pylsp_lint: [Errno 2] No such file or directory: 'ruff'
Traceback (most recent call last):
// ...snip
FileNotFoundError: [Errno 2] No such file or directory: 'ruff'
I think it might be necessary to make some adjustments, such as checked the exists of a ruff command.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.