Skip to content

Conversation

maxmynter
Copy link
Contributor

@maxmynter maxmynter commented Mar 30, 2025

Closes #17042

Summary

This PR fixes the issue outlined in #17042 where RUF100 (unused-noqa) fails to detect unused file-level noqa directives (# ruff: noqa or # ruff: noqa: {code}).

The issue stems from two underlying causes:

  1. For blanket file-level directives (# ruff: noqa), there's a circular dependency: the directive exempts all rules including RUF100 itself, which prevents checking for usage. This isn't changed by this PR. I would argue it is intendend behavior - a blanket # ruff: noqa directive should exempt all rules including RUF100 itself.

  2. For code-specific file-level directives (e.g. # ruff: noqa: F841), the handling was missing in the check_noqa function. This is added in this PR.

Notes

  • For file-level directives, the matches array is pre-populated with the specified codes during parsing, unlike line-level directives which only populate their matches array when actually suppressing diagnostics. This difference requires the somewhat clunky handling of both cases. I would appreciate guidance on a cleaner design :)

  • A more fundamental solution would be to change how file-level directives initialize the matches array in FileNoqaDirectives::extract(), but that requires more substantial changes as it breaks existing functionality. I suspect discussions in Make noqa parsing consistent and more robust #16483 are relevant for this.

Test Plan

  • Local verification
  • Added a test case and fixture

by implementing a check on them.
There is different handling necessary as the matches array
is prepopulated for file level directives.
Copy link
Contributor

github-actions bot commented Mar 30, 2025

ruff-ecosystem results

Linter (stable)

✅ ecosystem check detected no linter changes.

Linter (preview)

ℹ️ ecosystem check detected linter changes. (+17 -0 violations, +0 -0 fixes in 5 projects; 50 projects unchanged)

ibis-project/ibis (+1 -0 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --no-fix --output-format concise --preview

+ ibis/backends/tests/signature/typecheck.py:8:1: RUF100 Unused `noqa` directive (unused: `D205`, `D415`, `D400`)

python/typeshed (+2 -0 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --no-fix --output-format concise --preview --select E,F,FA,I,PYI,RUF,UP,W

+ stdlib/asyncio/__init__.pyi:1:1: RUF100 [*] Unused `noqa` directive (non-enabled: `PLR5501`)
+ stdlib/typing.pyi:2:1: RUF100 [*] Unused `noqa` directive (unused: `F811`)

scikit-build/scikit-build-core (+6 -0 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --no-fix --output-format concise --preview

+ tests/packages/importlib_editable/pkg/pmod_a.py:1:1: RUF100 [*] Unused `noqa` directive (unused: `I001`)
+ tests/packages/importlib_editable/pkg/sub_a/pmod_b.py:1:1: RUF100 [*] Unused `noqa` directive (unused: `I001`)
+ tests/packages/importlib_editable/pkg/sub_b/pmod_c.py:1:1: RUF100 [*] Unused `noqa` directive (unused: `I001`)
+ tests/packages/importlib_editable/pkg/sub_b/sub_c/pmod_d.py:1:1: RUF100 [*] Unused `noqa` directive (unused: `I001`)
+ tests/packages/importlib_editable/pkg/sub_b/sub_d/pmod_e.py:1:1: RUF100 [*] Unused `noqa` directive (unused: `I001`)
+ tests/packages/importlib_editable/pmod.py:1:1: RUF100 [*] Unused `noqa` directive (unused: `I001`)

indico/indico (+1 -0 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --no-fix --output-format concise --preview

+ indico/legacy/pdfinterface/conference.py:8:1: RUF100 [*] Unused `noqa` directive (unused: `PLR1702`)

astropy/astropy (+7 -0 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --no-fix --output-format concise --preview

+ astropy/cosmology/_src/core.py:2:1: RUF100 [*] Unused `noqa` directive (unused: `RUF009`)
+ astropy/cosmology/_src/flrw/base.py:2:1: RUF100 [*] Unused `noqa` directive (unused: `RUF009`)
+ astropy/cosmology/_src/flrw/w0cdm.py:2:1: RUF100 [*] Unused `noqa` directive (unused: `RUF009`)
+ astropy/cosmology/_src/flrw/w0wacdm.py:2:1: RUF100 [*] Unused `noqa` directive (unused: `RUF009`)
+ astropy/cosmology/_src/flrw/w0wzcdm.py:2:1: RUF100 [*] Unused `noqa` directive (unused: `RUF009`)
+ astropy/cosmology/_src/flrw/wpwazpcdm.py:2:1: RUF100 [*] Unused `noqa` directive (unused: `RUF009`)
+ astropy/units/tests/test_quantity_annotations.py:2:1: RUF100 [*] Unused `noqa` directive (unused: `FA100`, `FA102`)

Changes by rule (1 rules affected)

code total + violation - violation + fix - fix
RUF100 17 17 0 0 0

@MichaReiser
Copy link
Member

I'll leave this to @dylwil3 to review. What's important is that we gate these changes behind preview because it is a "significant" increase of a stable rule's scope.

@MichaReiser MichaReiser added the rule Implementing or modifying a lint rule label Mar 31, 2025
@ddeepwell
Copy link

I'm curious how this PR handles the case with # ruff: noqa: {code1}, {code2}, where code2 is a code for a used directive while code1 is for an unused directive which should be removed? This case isn't in the original issue (#17042), but it's basically the same concern, except that the valid code should remain after a fix.

@dylwil3
Copy link
Collaborator

dylwil3 commented Mar 31, 2025

@maxmynter could you add some test cases along the lines of what @ddeepwell mentioned? and also gate the change behind preview when you get a chance?

I'm gonna try to check out some of the ecosystem reports to see if we're getting any false positives before diving into the implementation

Thank you for your help with this!

@maxmynter
Copy link
Contributor Author

@dylwil3 is the implementation of the feature guard in ecbe562 sufficient?

I am a unsure since I haven't worked with feature guards -- let me know if something is missing.

@maxmynter
Copy link
Contributor Author

maxmynter commented Mar 31, 2025

Thanks for flagging @ddeepwell, the current implementation deletes the whole file level ruff: noqa: directive if one code is wrong.

Edit: This is not the case. I had misremembered rule F841 which does not apply at the file root; deletion in the example that prompted this comment was wanted.

The proposed changes handle (and test) the cases when one code is unused and the other one is used.

@maxmynter
Copy link
Contributor Author

@dylwil3 ping :)

No worries if you don't have the bandwidth at the moment; i just wanted to let you know that I'm unsure about the next steps here.

@dylwil3
Copy link
Collaborator

dylwil3 commented Apr 2, 2025

Thanks for the ping! Hoping to get to this tomorrow morning - sorry for the delay!

Copy link
Collaborator

@dylwil3 dylwil3 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good, thank you! The gating behind preview looks correct. I'm not sure why it's not reflected in the ecosystem check... I can't reproduce it locally. I'll try to investigate it.

In the meantime, I've just left one more issue to address about preserving the prefix used by the user for file-level directives.

@maxmynter maxmynter requested a review from dylwil3 April 4, 2025 04:25
Copy link
Collaborator

@dylwil3 dylwil3 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! One small change and then looks like there are some merge conflicts to resolve as well

@maxmynter maxmynter requested a review from dylwil3 April 4, 2025 21:53
@maxmynter
Copy link
Contributor Author

Merge conflicts were with test cases that i added in #17138. They're resolved now.

Copy link
Collaborator

@dylwil3 dylwil3 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wonderful, thank you!

@dylwil3 dylwil3 merged commit f1d4ba3 into astral-sh:main Apr 7, 2025
22 checks passed
dcreager added a commit that referenced this pull request Apr 7, 2025
* main: (42 commits)
  [playground] New default program (#17277)
  [red-knot] Add `--python-platform` CLI option (#17284)
  [red-knot] Allow ellipsis default params in stub functions (#17243)
  [red-knot] Fix stale syntax errors in playground (#17280)
  Update Rust crate clap to v4.5.35 (#17273)
  Fix RUF100 to detect unused file-level noqa directives with specific codes (#17042) (#17061)
  [ci] Fix pattern for code changes (#17275)
  [`airflow`] Update oudated `AIR301`, `AIR302` rules (#17123)
  [docs] fix formatting of "See Style Guide" link (#17272)
  [red-knot] Support stub packages (#17204)
  ruff_annotate_snippets: address unused code warnings
  [red-knot] Add a couple more tests for `*` imports (#17270)
  [red-knot] Add 'Format document' to playground (#17217)
  Update actions/setup-node action to v4.3.0 (#17259)
  Update actions/upload-artifact action to v4.6.2 (#17261)
  Update actions/download-artifact action to v4.2.1 (#17258)
  Update actions/setup-python action to v5.5.0 (#17260)
  Update actions/cache action to v4.2.3 (#17256)
  Update Swatinem/rust-cache action to v2.7.8 (#17255)
  Update actions/checkout action to v4.2.2 (#17257)
  ...
dcreager added a commit that referenced this pull request Apr 8, 2025
* main: (222 commits)
  [playground] New default program (#17277)
  [red-knot] Add `--python-platform` CLI option (#17284)
  [red-knot] Allow ellipsis default params in stub functions (#17243)
  [red-knot] Fix stale syntax errors in playground (#17280)
  Update Rust crate clap to v4.5.35 (#17273)
  Fix RUF100 to detect unused file-level noqa directives with specific codes (#17042) (#17061)
  [ci] Fix pattern for code changes (#17275)
  [`airflow`] Update oudated `AIR301`, `AIR302` rules (#17123)
  [docs] fix formatting of "See Style Guide" link (#17272)
  [red-knot] Support stub packages (#17204)
  ruff_annotate_snippets: address unused code warnings
  [red-knot] Add a couple more tests for `*` imports (#17270)
  [red-knot] Add 'Format document' to playground (#17217)
  Update actions/setup-node action to v4.3.0 (#17259)
  Update actions/upload-artifact action to v4.6.2 (#17261)
  Update actions/download-artifact action to v4.2.1 (#17258)
  Update actions/setup-python action to v5.5.0 (#17260)
  Update actions/cache action to v4.2.3 (#17256)
  Update Swatinem/rust-cache action to v2.7.8 (#17255)
  Update actions/checkout action to v4.2.2 (#17257)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
rule Implementing or modifying a lint rule
Projects
None yet
Development

Successfully merging this pull request may close these issues.

RUF100 fails to catch # ruff: noqa
4 participants