ruff icon indicating copy to clipboard operation
ruff copied to clipboard

Per file selection

Open henryiii opened this issue 2 years ago • 9 comments

I'd like a way to activate a rule for a subset of files; basically the inverse of per-file-ignores. In my case, I'd like to activate pydocstyle on the main module, but not tests, examples, docs, benchmarks, support files, setup.py, etc.

Current and possible options:

  • Use a second ruff.toml/pyproject.toml inside the package. This is not ideal, as I don't want to add extra files (especially pyproject.toml's, as those should only be at the root of packages). This is the only one in the list that would work today (that I know of). .ruff.toml (#2988) would help a little, but still not my preferred solution for this case - I'd like all configuration in a single file.
  • Add tool.ruff.per-file-extend-select (technically, per-file-ignores is also extend, so maybe for symmetry it could be tool.ruff.per-file-extend-select). This would then be "src/**.py" = ["D"].
  • Support negation in tool.ruff.per-file-ignores like a gitignore. So "!src/**.py" = ["D"] would ignore D on anything except src/**.py files.

Thoughts?

Here's what I would have to put without this:

[tool.ruff.per-file-ignores]
"doc/**.py" = ["D"]
"tests/**.py" = ["D"]
"bench/**.py" = ["D"]
".ci/**.py" = ["D"]
"cmake_ext.py" = ["D"]
"version.py" = ["D"]
"setup.py" = ["D"]

henryiii avatar Feb 23 '23 15:02 henryiii

I suspect that the last option would be much easier to support than per-file-extend-select. I'm open to it!

charliermarsh avatar Feb 23 '23 18:02 charliermarsh

(The way per-file-ignores work right now is that we still run the ignored rules over those files, we just suppress the violations. We couldn't use the same strategy for per-file-extend-select -- we'd have to enable curating a rule set for every file, which would be a more significant refactor.)

charliermarsh avatar Feb 23 '23 18:02 charliermarsh

This feature will be useful for big repositories (eg. PyTorch) to incrementally adopt stricter rules in different components.

Potentially run checks on all rules from the per-file-select as well for everyone, then suppress for files not in this group?

justinchuby avatar Apr 25 '23 14:04 justinchuby

It's useful for small repositories as well. 👀

Kludex avatar Apr 25 '23 14:04 Kludex

If someone wants to work on this, I'd be happy to review a proposal. I expect there to be some prototype / design work.

zanieb avatar Nov 12 '23 02:11 zanieb

Leaving my notes here in case another contributor wants to pick this up.

The glob mechanism in Ruff is based on globset, and it looks like the options supported there are supported in Ruff.

The only negation option that's supported is single character negation (e.g., [!abc] being the inverse of [abc]). I thought I could be clever and abuse this, but it doesn't seem very reliable. (It also looks awful.)

Extended globbing has negation, which could work, but extended globs are not likely to be supported by globset: https://github.com/BurntSushi/ripgrep/issues/2608

globset is part of the ripgrep project. Ripgrep allows negation by using a ! prefix. Putting a ! in front of your glob will match everything except for the glob. (Link to ripgrep's globbing docs')

The ! prefix approach seems reasonable and easy to explain/document. "!foo/*" would match everything except for "foo/*". Only a ! prefix would be treated specially. Any other !s would be treated as part of the glob.

(And yes, I do realize that this was a lot of work to reach exactly what @henryiii suggested in his third bullet point :joy: Hopefully this helps other curious folks save themselves some time/effort.)

@zanieb Does the ! prefix approach seem reasonable to you?

ryangalamb avatar Mar 13 '24 17:03 ryangalamb

I'm supportive of adding negations via !.

charliermarsh avatar Apr 05 '24 17:04 charliermarsh

I'm supportive as well. Is someone interested in putting up a prototype?

zanieb avatar Apr 05 '24 17:04 zanieb

I think @carljm may be interested.

charliermarsh avatar Apr 05 '24 17:04 charliermarsh

See some discussion at https://github.com/astral-sh/ruff/pull/10863#discussion_r1559906597 on how negative patterns should behave when the pattern does match the file (i.e. the negative pattern doesn't hit). Should this "un-ignore" the listed patterns, or do nothing (patterns are always only additive to what's ignored)?

carljm avatar Apr 10 '24 19:04 carljm