From 563daa8a86e5fe38dcdcfba5cc7a93a84bc2d550 Mon Sep 17 00:00:00 2001 From: Carl Meyer Date: Thu, 11 Apr 2024 19:30:28 -0600 Subject: [PATCH] Fix docs and add overlap test for negated per-file-ignores (#10863) Refs #3172 ## Summary Fix a typo in the docs example, and add a test for the case where a negative pattern and a positive pattern overlap. The behavior here is simple: patterns (positive or negative) are always additive if they hit (i.e. match for a positive pattern, don't match for a negated pattern). We never "un-ignore" previously-ignored rules based on a pattern (positive or negative) failing to hit. It's simple enough that I don't really see other cases we need to add tests for (the tests we have cover all branches in the ignores_from_path function that implements the core logic), but open to reviewer feedback. I also didn't end up changing the docs to explain this more, because I think they are accurate as written and don't wrongly imply any more complex behavior. Open to reviewer feedback on this as well! After some discussion, I think allowing negative patterns to un-ignore rules is too confusing and easy to get wrong; if we need that, we should add `per-file-selects` instead. ## Test Plan Test/docs only change; tests pass, docs render and look right. --------- Co-authored-by: Alex Waygood --- crates/ruff/tests/lint.rs | 36 ++++++++++++++++++++++++++++ crates/ruff_workspace/src/options.rs | 2 +- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/crates/ruff/tests/lint.rs b/crates/ruff/tests/lint.rs index d02b112f934dc..47767a6a4d700 100644 --- a/crates/ruff/tests/lint.rs +++ b/crates/ruff/tests/lint.rs @@ -1248,3 +1248,39 @@ fn negated_per_file_ignores_absolute() -> Result<()> { }); Ok(()) } + +/// patterns are additive, can't use negative patterns to "un-ignore" +#[test] +fn negated_per_file_ignores_overlap() -> Result<()> { + let tempdir = TempDir::new()?; + let ruff_toml = tempdir.path().join("ruff.toml"); + fs::write( + &ruff_toml, + r#" +[lint.per-file-ignores] +"*.py" = ["RUF"] +"!foo.py" = ["RUF"] +"#, + )?; + let foo_file = tempdir.path().join("foo.py"); + fs::write(foo_file, "")?; + let bar_file = tempdir.path().join("bar.py"); + fs::write(bar_file, "")?; + + assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) + .args(STDIN_BASE_OPTIONS) + .arg("--config") + .arg(&ruff_toml) + .arg("--select") + .arg("RUF901") + .current_dir(&tempdir) + , @r###" + success: true + exit_code: 0 + ----- stdout ----- + All checks passed! + + ----- stderr ----- + "###); + Ok(()) +} diff --git a/crates/ruff_workspace/src/options.rs b/crates/ruff_workspace/src/options.rs index 2553290464f3e..555af0b0a7324 100644 --- a/crates/ruff_workspace/src/options.rs +++ b/crates/ruff_workspace/src/options.rs @@ -916,7 +916,7 @@ pub struct LintCommonOptions { "__init__.py" = ["E402"] "path/to/file.py" = ["E402"] # Ignore `D` rules everywhere except for the `src/` directory. - "!src/**.py" = ["F401"] + "!src/**.py" = ["D"] "# )] pub per_file_ignores: Option>>,