python-lsp/python-lsp-ruff

`per-file-ignores` doesn't seem to be working

jacobmischka opened this issue ยท 18 comments

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 ignored 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!

Er, just kidding, the former example is invalid toml, so python-lsp-ruff was just not working at all apparently.

This also doesn't work:

[tool.ruff]
ignore = [
	"E501", # line length violations
	"E722", # bare except
]
per-file-ignores = { "__init__.py" = ["E402", "F401", "F403"] }

So it seems like per-file-ignores is not working for me in python-lsp-ruff at all.

Hmm, I can't confirm with your MWE. python-lsp-ruff does however not parse the contents of the pyproject file, instead it will just try to find one in the directory or any of the parent directories up to the workspace root and let ruff handle it if one is present. Can you run pylsp with log level DEBUG and parse the output to a file? E.g. by calling pylsp -vvv --log-file /tmp/pylsp.log
Interesting would be to see if python-lsp-ruff finds the pyproject.toml, so look for "Found pyproject file: ..."

Also is ruff in your PATH variable or is it installed in a virtual environment somewhere?

Interesting would be to see if python-lsp-ruff finds the pyproject.toml, so look for "Found pyproject file: ..."

It does find it, because it logged an error when my config was invalid toml in my first comment:

[ERROR][2022-12-15 11:08:30] .../vim/lsp/rpc.lua:733	"rpc"	"pylsp"	"stderr"	"2022-12-15 11:08:30,262 CST - ERROR - pylsp_ruff.ruff_lint - Error running ruff: error Failed to parse `/home/mischka/projects/interval2/sdk-py/pyproject.toml`: expected a table key, found a newline at line 44 column 21\n\n"

How do I run pylsp via the command line like you mentioned but attach it to neovim (or tell it to send me diagnostics some other way)? Or is there a way to pass those flags to my python-lsp-server config? I didn't see it in its docs.

Sorry, I figured it out. Here are what I think the relevant lines, but I can provide more if requested:

2022-12-20 14:20:41,569 CST - DEBUG - pylsp_ruff.ruff_lint - Got ruff settings: {'lineLength': None, 'exclude': None, 'config': None, 'select': None, 'enabled': True, 'executable': 'ruff', 'perFileIgnores': None, 'ignore': None}
2022-12-20 14:20:41,569 CST - DEBUG - pylsp_ruff.ruff_lint - Found pyproject file: /home/mischka/projects/interval2/sdk-py/pyproject.toml, skipping pylsp config.
2022-12-20 14:20:41,569 CST - DEBUG - pylsp_ruff.ruff_lint - Calling ruff with args: ['--quiet', '--format=json', '--no-fix', '--', '-'] on '/home/mischka/projects/interval2/sdk-py/src/interval_sdk/__init__.py'
2022-12-20 14:20:41,571 CST - DEBUG - pylsp.config.config -   finish pylsp_lint --> [[{'source': 'ruff', 'code': 'F403', 'range': {'start': {'line': 0, 'character': 0}, 'end': {'line': 0, 'character': 19}}, 'message': '`from .main import *` used; unable to detect undefined names', 'severity': 1}, {'source': 'ruff', 'code': 'F401', 'range': {'start': {'line': 1, 'character': 24}, 'end': {'line': 1, 'character': 26}}, 'message': '`classes.io.IO` imported but unused', 'severity': 1, 'tags': [1]}, {'source': 'ruff', 'code': 'F401', 'range': {'start': {'line': 2, 'character': 30}, 'end': {'line': 2, 'character': 37}}, 'message': '`classes.io_error.IOError` imported but unused', 'severity': 1, 'tags': [1]}]] [hook]

2022-12-20 14:20:41,571 CST - DEBUG - pylsp_jsonrpc.endpoint - Sending notification: textDocument/publishDiagnostics {'uri': 'file:///home/mischka/projects/interval2/sdk-py/src/interval_sdk/__init__.py', 'diagnostics': [{'source': 'ruff', 'code': 'F403', 'range': {'start': {'line': 0, 'character': 0}, 'end': {'line': 0, 'character': 19}}, 'message': '`from .main import *` used; unable to detect undefined names', 'severity': 1}, {'source': 'ruff', 'code': 'F401', 'range': {'start': {'line': 1, 'character': 24}, 'end': {'line': 1, 'character': 26}}, 'message': '`classes.io.IO` imported but unused', 'severity': 1, 'tags': [1]}, {'source': 'ruff', 'code': 'F401', 'range': {'start': {'line': 2, 'character': 30}, 'end': {'line': 2, 'character': 37}}, 'message': '`classes.io_error.IOError` imported but unused', 'severity': 1, 'tags': [1]}]}
(END)

I have ruff (and python-lsp-ruff) installed directly in my path ("globally" via the arch linux community ruff package and python-lsp-ruff's AUR package).

The debug messages look alright to me, but the above doesn't:

Error running ruff: error Failed to parse /home/mischka/projects/interval2/sdk-py/pyproject.toml: expected a table key, found a newline at line 44 column 21\n\n"

This error comes from ruff and not from pylsp/python-lsp-ruff, to me it seems like ruff has trouble reading the pyproject file. Can you paste the contents of your pyproject file? Are you using the latest version of ruff (0.0.189 in the arch repos)?

Right, that was just from that one time above where I already realized the config was invalid (see the first message in this thread). I've since fixed it (see the second message) and that error hasn't come up since (please note the date in that invalid toml error message).

Anyway, here's the entire thing:

[tool.poetry]
name = "..."
version = ".."
description = "..."
authors = ["..."]

[tool.poe.tasks]
demo = { script = 'demos:main' }
test = "pytest"
check = "pyright"
lint = "pylint src/"
ruff = "ruff src/"
format = "black src/"

[tool.poetry.dependencies]
(snip)

[tool.poetry.group.dev.dependencies]
(snip)

[tool.poetry.group.test.dependencies]
(snip)

[tool.pyright]
exclude = [
	"**/node_modules",
	"**/__pycache__",
]

[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"]

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

I think the issue here is that we need to pass the filename via --stdin-filename (unless I'm misreading the code); as-is, Ruff doesn't know that the path being linted ends in __init__.py.

Nice, I didn't know about that option, thanks for the input @charliermarsh!

@charliermarsh I have a working patch, but I am struggling with the unit tests as ruff doesn't seem to respect the pyproject in the temp path. Running ruff with --verbose shows that it still uses the current project root (and path) even if you parse something via stdin and give --stdin-filename. To fix the unit tests I will create local fixtures instead of temp files, but I was wondering if that was intended @charliermarsh?

@charliermarsh What do you think about ignoring the current CWD if the file is parsed via stdin and a stdin-filename is given and to look at the given path there instead?

@jhossbach - I think that fixed recently (astral-sh/ruff#1281), are you on 0.0.187 or newer?

That was it. This package is evolving so fast that it's hard to keep track to all the changes. Awesome work @charliermarsh!

Will update with the next version of ruff.

Tests aren't passing for me when trying to install the update:

    
        doc = workspace.get_document(doc_uri)
        diags = ruff_lint.pylsp_lint(workspace, doc)
>       assert diags == []
E       AssertionError: assert [{'code': 'E4...ity': 1, ...}] == []
E         Left contains 2 more items, first extra item: {'code': 'E402', 'message': 'Module level import not at top of file', 'range': {'end': {'character': 9, 'line': 2}, 'start': {'character': 0, 'line': 2}}, 'severity': 2, ...}
E         Use -v to get more diff

tests/test_ruff_lint.py:189: AssertionError

I am on ruff 0.0.191, I just updated it.

Oh, never mind, I see the dependencies now require 0.0.192 or higher. Thanks!

Arch package for ruff was updated since my last comment, I can confirm it's fixed now. Thanks again!