diff --git a/crates/ruff_linter/resources/test/fixtures/ruff/RUF069.py b/crates/ruff_linter/resources/test/fixtures/ruff/RUF069.py index c7e0060c5e..b7f7dd6b0d 100644 --- a/crates/ruff_linter/resources/test/fixtures/ruff/RUF069.py +++ b/crates/ruff_linter/resources/test/fixtures/ruff/RUF069.py @@ -7,15 +7,24 @@ class A: ... class B: ... +# Good __all__ = "A" + "B" __all__: list[str] = ["A", "B"] -__all__: list[str] = ["A", "B", "A"] __all__: typing.Any = ("A", "B") -__all__: typing.Any = ("A", "B", "B") __all__ = ["A", "B"] +__all__ += ["A", "B"] +__all__.extend(["A", "B"]) + +# Bad +__all__: list[str] = ["A", "B", "A"] +__all__: typing.Any = ("A", "B", "B") __all__ = ["A", "A", "B"] __all__ = ["A", "B", "A"] __all__ = ["A", "A", "B", "B"] +__all__ += ["B", "B"] +__all__.extend(["B", "B"]) + +# Bad, unsafe __all__ = [ "A", "A", @@ -23,7 +32,3 @@ __all__ = [ # Comment "B", ] -__all__ += ["B", "B"] -__all__ += ["A", "B"] -__all__.extend(["B", "B"]) -__all__.extend(["A", "B"]) diff --git a/crates/ruff_linter/resources/test/fixtures/ruff/RUF069.pyi b/crates/ruff_linter/resources/test/fixtures/ruff/RUF069.pyi new file mode 100644 index 0000000000..b7f7dd6b0d --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/ruff/RUF069.pyi @@ -0,0 +1,34 @@ +import typing + + +class A: ... + + +class B: ... + + +# Good +__all__ = "A" + "B" +__all__: list[str] = ["A", "B"] +__all__: typing.Any = ("A", "B") +__all__ = ["A", "B"] +__all__ += ["A", "B"] +__all__.extend(["A", "B"]) + +# Bad +__all__: list[str] = ["A", "B", "A"] +__all__: typing.Any = ("A", "B", "B") +__all__ = ["A", "A", "B"] +__all__ = ["A", "B", "A"] +__all__ = ["A", "A", "B", "B"] +__all__ += ["B", "B"] +__all__.extend(["B", "B"]) + +# Bad, unsafe +__all__ = [ + "A", + "A", + "B", + # Comment + "B", +] diff --git a/crates/ruff_linter/src/rules/ruff/mod.rs b/crates/ruff_linter/src/rules/ruff/mod.rs index 77ea096f5c..3aeccc309a 100644 --- a/crates/ruff_linter/src/rules/ruff/mod.rs +++ b/crates/ruff_linter/src/rules/ruff/mod.rs @@ -117,6 +117,7 @@ mod tests { #[test_case(Rule::LoggingEagerConversion, Path::new("RUF065_1.py"))] #[test_case(Rule::PropertyWithoutReturn, Path::new("RUF066.py"))] #[test_case(Rule::DuplicateEntryInDunderAll, Path::new("RUF069.py"))] + #[test_case(Rule::DuplicateEntryInDunderAll, Path::new("RUF069.pyi"))] #[test_case(Rule::RedirectedNOQA, Path::new("RUF101_0.py"))] #[test_case(Rule::RedirectedNOQA, Path::new("RUF101_1.py"))] #[test_case(Rule::InvalidRuleCode, Path::new("RUF102.py"))] diff --git a/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF069_RUF069.py.snap b/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF069_RUF069.py.snap index 74d5680fca..5edd133abf 100644 --- a/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF069_RUF069.py.snap +++ b/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF069_RUF069.py.snap @@ -2,199 +2,197 @@ source: crates/ruff_linter/src/rules/ruff/mod.rs --- RUF069 [*] `__all__` contains duplicate entries - --> RUF069.py:12:33 + --> RUF069.py:19:33 | -10 | __all__ = "A" + "B" -11 | __all__: list[str] = ["A", "B"] -12 | __all__: list[str] = ["A", "B", "A"] +18 | # Bad +19 | __all__: list[str] = ["A", "B", "A"] | ^^^ -13 | __all__: typing.Any = ("A", "B") -14 | __all__: typing.Any = ("A", "B", "B") +20 | __all__: typing.Any = ("A", "B", "B") +21 | __all__ = ["A", "A", "B"] | help: Remove duplicate entries from `__all__` -9 | -10 | __all__ = "A" + "B" -11 | __all__: list[str] = ["A", "B"] +16 | __all__.extend(["A", "B"]) +17 | +18 | # Bad - __all__: list[str] = ["A", "B", "A"] -12 + __all__: list[str] = ["A", "B"] -13 | __all__: typing.Any = ("A", "B") -14 | __all__: typing.Any = ("A", "B", "B") -15 | __all__ = ["A", "B"] +19 + __all__: list[str] = ["A", "B"] +20 | __all__: typing.Any = ("A", "B", "B") +21 | __all__ = ["A", "A", "B"] +22 | __all__ = ["A", "B", "A"] RUF069 [*] `__all__` contains duplicate entries - --> RUF069.py:14:34 + --> RUF069.py:20:34 | -12 | __all__: list[str] = ["A", "B", "A"] -13 | __all__: typing.Any = ("A", "B") -14 | __all__: typing.Any = ("A", "B", "B") +18 | # Bad +19 | __all__: list[str] = ["A", "B", "A"] +20 | __all__: typing.Any = ("A", "B", "B") | ^^^ -15 | __all__ = ["A", "B"] -16 | __all__ = ["A", "A", "B"] +21 | __all__ = ["A", "A", "B"] +22 | __all__ = ["A", "B", "A"] | help: Remove duplicate entries from `__all__` -11 | __all__: list[str] = ["A", "B"] -12 | __all__: list[str] = ["A", "B", "A"] -13 | __all__: typing.Any = ("A", "B") +17 | +18 | # Bad +19 | __all__: list[str] = ["A", "B", "A"] - __all__: typing.Any = ("A", "B", "B") -14 + __all__: typing.Any = ("A", "B") -15 | __all__ = ["A", "B"] -16 | __all__ = ["A", "A", "B"] -17 | __all__ = ["A", "B", "A"] +20 + __all__: typing.Any = ("A", "B") +21 | __all__ = ["A", "A", "B"] +22 | __all__ = ["A", "B", "A"] +23 | __all__ = ["A", "A", "B", "B"] RUF069 [*] `__all__` contains duplicate entries - --> RUF069.py:16:17 + --> RUF069.py:21:17 | -14 | __all__: typing.Any = ("A", "B", "B") -15 | __all__ = ["A", "B"] -16 | __all__ = ["A", "A", "B"] +19 | __all__: list[str] = ["A", "B", "A"] +20 | __all__: typing.Any = ("A", "B", "B") +21 | __all__ = ["A", "A", "B"] | ^^^ -17 | __all__ = ["A", "B", "A"] -18 | __all__ = ["A", "A", "B", "B"] +22 | __all__ = ["A", "B", "A"] +23 | __all__ = ["A", "A", "B", "B"] | help: Remove duplicate entries from `__all__` -13 | __all__: typing.Any = ("A", "B") -14 | __all__: typing.Any = ("A", "B", "B") -15 | __all__ = ["A", "B"] +18 | # Bad +19 | __all__: list[str] = ["A", "B", "A"] +20 | __all__: typing.Any = ("A", "B", "B") - __all__ = ["A", "A", "B"] -16 + __all__ = ["A", "B"] -17 | __all__ = ["A", "B", "A"] -18 | __all__ = ["A", "A", "B", "B"] -19 | __all__ = [ +21 + __all__ = ["A", "B"] +22 | __all__ = ["A", "B", "A"] +23 | __all__ = ["A", "A", "B", "B"] +24 | __all__ += ["B", "B"] RUF069 [*] `__all__` contains duplicate entries - --> RUF069.py:17:22 + --> RUF069.py:22:22 | -15 | __all__ = ["A", "B"] -16 | __all__ = ["A", "A", "B"] -17 | __all__ = ["A", "B", "A"] +20 | __all__: typing.Any = ("A", "B", "B") +21 | __all__ = ["A", "A", "B"] +22 | __all__ = ["A", "B", "A"] | ^^^ -18 | __all__ = ["A", "A", "B", "B"] -19 | __all__ = [ +23 | __all__ = ["A", "A", "B", "B"] +24 | __all__ += ["B", "B"] | help: Remove duplicate entries from `__all__` -14 | __all__: typing.Any = ("A", "B", "B") -15 | __all__ = ["A", "B"] -16 | __all__ = ["A", "A", "B"] +19 | __all__: list[str] = ["A", "B", "A"] +20 | __all__: typing.Any = ("A", "B", "B") +21 | __all__ = ["A", "A", "B"] - __all__ = ["A", "B", "A"] -17 + __all__ = ["A", "B"] -18 | __all__ = ["A", "A", "B", "B"] -19 | __all__ = [ -20 | "A", +22 + __all__ = ["A", "B"] +23 | __all__ = ["A", "A", "B", "B"] +24 | __all__ += ["B", "B"] +25 | __all__.extend(["B", "B"]) RUF069 [*] `__all__` contains duplicate entries - --> RUF069.py:18:17 + --> RUF069.py:23:17 | -16 | __all__ = ["A", "A", "B"] -17 | __all__ = ["A", "B", "A"] -18 | __all__ = ["A", "A", "B", "B"] +21 | __all__ = ["A", "A", "B"] +22 | __all__ = ["A", "B", "A"] +23 | __all__ = ["A", "A", "B", "B"] | ^^^ -19 | __all__ = [ -20 | "A", +24 | __all__ += ["B", "B"] +25 | __all__.extend(["B", "B"]) | help: Remove duplicate entries from `__all__` -15 | __all__ = ["A", "B"] -16 | __all__ = ["A", "A", "B"] -17 | __all__ = ["A", "B", "A"] +20 | __all__: typing.Any = ("A", "B", "B") +21 | __all__ = ["A", "A", "B"] +22 | __all__ = ["A", "B", "A"] - __all__ = ["A", "A", "B", "B"] -18 + __all__ = ["A", "B", "B"] -19 | __all__ = [ -20 | "A", -21 | "A", +23 + __all__ = ["A", "B", "B"] +24 | __all__ += ["B", "B"] +25 | __all__.extend(["B", "B"]) +26 | RUF069 [*] `__all__` contains duplicate entries - --> RUF069.py:18:27 + --> RUF069.py:23:27 | -16 | __all__ = ["A", "A", "B"] -17 | __all__ = ["A", "B", "A"] -18 | __all__ = ["A", "A", "B", "B"] +21 | __all__ = ["A", "A", "B"] +22 | __all__ = ["A", "B", "A"] +23 | __all__ = ["A", "A", "B", "B"] | ^^^ -19 | __all__ = [ -20 | "A", +24 | __all__ += ["B", "B"] +25 | __all__.extend(["B", "B"]) | help: Remove duplicate entries from `__all__` -15 | __all__ = ["A", "B"] -16 | __all__ = ["A", "A", "B"] -17 | __all__ = ["A", "B", "A"] +20 | __all__: typing.Any = ("A", "B", "B") +21 | __all__ = ["A", "A", "B"] +22 | __all__ = ["A", "B", "A"] - __all__ = ["A", "A", "B", "B"] -18 + __all__ = ["A", "A", "B"] -19 | __all__ = [ -20 | "A", -21 | "A", +23 + __all__ = ["A", "A", "B"] +24 | __all__ += ["B", "B"] +25 | __all__.extend(["B", "B"]) +26 | RUF069 [*] `__all__` contains duplicate entries - --> RUF069.py:21:5 + --> RUF069.py:24:18 | -19 | __all__ = [ -20 | "A", -21 | "A", - | ^^^ -22 | "B", -23 | # Comment +22 | __all__ = ["A", "B", "A"] +23 | __all__ = ["A", "A", "B", "B"] +24 | __all__ += ["B", "B"] + | ^^^ +25 | __all__.extend(["B", "B"]) | help: Remove duplicate entries from `__all__` -18 | __all__ = ["A", "A", "B", "B"] -19 | __all__ = [ -20 | "A", +21 | __all__ = ["A", "A", "B"] +22 | __all__ = ["A", "B", "A"] +23 | __all__ = ["A", "A", "B", "B"] + - __all__ += ["B", "B"] +24 + __all__ += ["B"] +25 | __all__.extend(["B", "B"]) +26 | +27 | # Bad, unsafe + +RUF069 [*] `__all__` contains duplicate entries + --> RUF069.py:25:22 + | +23 | __all__ = ["A", "A", "B", "B"] +24 | __all__ += ["B", "B"] +25 | __all__.extend(["B", "B"]) + | ^^^ +26 | +27 | # Bad, unsafe + | +help: Remove duplicate entries from `__all__` +22 | __all__ = ["A", "B", "A"] +23 | __all__ = ["A", "A", "B", "B"] +24 | __all__ += ["B", "B"] + - __all__.extend(["B", "B"]) +25 + __all__.extend(["B"]) +26 | +27 | # Bad, unsafe +28 | __all__ = [ + +RUF069 [*] `__all__` contains duplicate entries + --> RUF069.py:30:5 + | +28 | __all__ = [ +29 | "A", +30 | "A", + | ^^^ +31 | "B", +32 | # Comment + | +help: Remove duplicate entries from `__all__` +27 | # Bad, unsafe +28 | __all__ = [ +29 | "A", - "A", -21 | "B", -22 | # Comment -23 | "B", +30 | "B", +31 | # Comment +32 | "B", RUF069 [*] `__all__` contains duplicate entries - --> RUF069.py:24:5 + --> RUF069.py:33:5 | -22 | "B", -23 | # Comment -24 | "B", +31 | "B", +32 | # Comment +33 | "B", | ^^^ -25 | ] -26 | __all__ += ["B", "B"] +34 | ] | help: Remove duplicate entries from `__all__` -20 | "A", -21 | "A", -22 | "B", +29 | "A", +30 | "A", +31 | "B", - # Comment - "B", -23 + # Comment, -24 | ] -25 | __all__ += ["B", "B"] -26 | __all__ += ["A", "B"] +32 + # Comment, +33 | ] note: This is an unsafe fix and may change runtime behavior - -RUF069 [*] `__all__` contains duplicate entries - --> RUF069.py:26:18 - | -24 | "B", -25 | ] -26 | __all__ += ["B", "B"] - | ^^^ -27 | __all__ += ["A", "B"] -28 | __all__.extend(["B", "B"]) - | -help: Remove duplicate entries from `__all__` -23 | # Comment -24 | "B", -25 | ] - - __all__ += ["B", "B"] -26 + __all__ += ["B"] -27 | __all__ += ["A", "B"] -28 | __all__.extend(["B", "B"]) -29 | __all__.extend(["A", "B"]) - -RUF069 [*] `__all__` contains duplicate entries - --> RUF069.py:28:22 - | -26 | __all__ += ["B", "B"] -27 | __all__ += ["A", "B"] -28 | __all__.extend(["B", "B"]) - | ^^^ -29 | __all__.extend(["A", "B"]) - | -help: Remove duplicate entries from `__all__` -25 | ] -26 | __all__ += ["B", "B"] -27 | __all__ += ["A", "B"] - - __all__.extend(["B", "B"]) -28 + __all__.extend(["B"]) -29 | __all__.extend(["A", "B"]) diff --git a/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF069_RUF069.pyi.snap b/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF069_RUF069.pyi.snap new file mode 100644 index 0000000000..88d5795f93 --- /dev/null +++ b/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF069_RUF069.pyi.snap @@ -0,0 +1,198 @@ +--- +source: crates/ruff_linter/src/rules/ruff/mod.rs +--- +RUF069 [*] `__all__` contains duplicate entries + --> RUF069.pyi:19:33 + | +18 | # Bad +19 | __all__: list[str] = ["A", "B", "A"] + | ^^^ +20 | __all__: typing.Any = ("A", "B", "B") +21 | __all__ = ["A", "A", "B"] + | +help: Remove duplicate entries from `__all__` +16 | __all__.extend(["A", "B"]) +17 | +18 | # Bad + - __all__: list[str] = ["A", "B", "A"] +19 + __all__: list[str] = ["A", "B"] +20 | __all__: typing.Any = ("A", "B", "B") +21 | __all__ = ["A", "A", "B"] +22 | __all__ = ["A", "B", "A"] + +RUF069 [*] `__all__` contains duplicate entries + --> RUF069.pyi:20:34 + | +18 | # Bad +19 | __all__: list[str] = ["A", "B", "A"] +20 | __all__: typing.Any = ("A", "B", "B") + | ^^^ +21 | __all__ = ["A", "A", "B"] +22 | __all__ = ["A", "B", "A"] + | +help: Remove duplicate entries from `__all__` +17 | +18 | # Bad +19 | __all__: list[str] = ["A", "B", "A"] + - __all__: typing.Any = ("A", "B", "B") +20 + __all__: typing.Any = ("A", "B") +21 | __all__ = ["A", "A", "B"] +22 | __all__ = ["A", "B", "A"] +23 | __all__ = ["A", "A", "B", "B"] + +RUF069 [*] `__all__` contains duplicate entries + --> RUF069.pyi:21:17 + | +19 | __all__: list[str] = ["A", "B", "A"] +20 | __all__: typing.Any = ("A", "B", "B") +21 | __all__ = ["A", "A", "B"] + | ^^^ +22 | __all__ = ["A", "B", "A"] +23 | __all__ = ["A", "A", "B", "B"] + | +help: Remove duplicate entries from `__all__` +18 | # Bad +19 | __all__: list[str] = ["A", "B", "A"] +20 | __all__: typing.Any = ("A", "B", "B") + - __all__ = ["A", "A", "B"] +21 + __all__ = ["A", "B"] +22 | __all__ = ["A", "B", "A"] +23 | __all__ = ["A", "A", "B", "B"] +24 | __all__ += ["B", "B"] + +RUF069 [*] `__all__` contains duplicate entries + --> RUF069.pyi:22:22 + | +20 | __all__: typing.Any = ("A", "B", "B") +21 | __all__ = ["A", "A", "B"] +22 | __all__ = ["A", "B", "A"] + | ^^^ +23 | __all__ = ["A", "A", "B", "B"] +24 | __all__ += ["B", "B"] + | +help: Remove duplicate entries from `__all__` +19 | __all__: list[str] = ["A", "B", "A"] +20 | __all__: typing.Any = ("A", "B", "B") +21 | __all__ = ["A", "A", "B"] + - __all__ = ["A", "B", "A"] +22 + __all__ = ["A", "B"] +23 | __all__ = ["A", "A", "B", "B"] +24 | __all__ += ["B", "B"] +25 | __all__.extend(["B", "B"]) + +RUF069 [*] `__all__` contains duplicate entries + --> RUF069.pyi:23:17 + | +21 | __all__ = ["A", "A", "B"] +22 | __all__ = ["A", "B", "A"] +23 | __all__ = ["A", "A", "B", "B"] + | ^^^ +24 | __all__ += ["B", "B"] +25 | __all__.extend(["B", "B"]) + | +help: Remove duplicate entries from `__all__` +20 | __all__: typing.Any = ("A", "B", "B") +21 | __all__ = ["A", "A", "B"] +22 | __all__ = ["A", "B", "A"] + - __all__ = ["A", "A", "B", "B"] +23 + __all__ = ["A", "B", "B"] +24 | __all__ += ["B", "B"] +25 | __all__.extend(["B", "B"]) +26 | + +RUF069 [*] `__all__` contains duplicate entries + --> RUF069.pyi:23:27 + | +21 | __all__ = ["A", "A", "B"] +22 | __all__ = ["A", "B", "A"] +23 | __all__ = ["A", "A", "B", "B"] + | ^^^ +24 | __all__ += ["B", "B"] +25 | __all__.extend(["B", "B"]) + | +help: Remove duplicate entries from `__all__` +20 | __all__: typing.Any = ("A", "B", "B") +21 | __all__ = ["A", "A", "B"] +22 | __all__ = ["A", "B", "A"] + - __all__ = ["A", "A", "B", "B"] +23 + __all__ = ["A", "A", "B"] +24 | __all__ += ["B", "B"] +25 | __all__.extend(["B", "B"]) +26 | + +RUF069 [*] `__all__` contains duplicate entries + --> RUF069.pyi:24:18 + | +22 | __all__ = ["A", "B", "A"] +23 | __all__ = ["A", "A", "B", "B"] +24 | __all__ += ["B", "B"] + | ^^^ +25 | __all__.extend(["B", "B"]) + | +help: Remove duplicate entries from `__all__` +21 | __all__ = ["A", "A", "B"] +22 | __all__ = ["A", "B", "A"] +23 | __all__ = ["A", "A", "B", "B"] + - __all__ += ["B", "B"] +24 + __all__ += ["B"] +25 | __all__.extend(["B", "B"]) +26 | +27 | # Bad, unsafe + +RUF069 [*] `__all__` contains duplicate entries + --> RUF069.pyi:25:22 + | +23 | __all__ = ["A", "A", "B", "B"] +24 | __all__ += ["B", "B"] +25 | __all__.extend(["B", "B"]) + | ^^^ +26 | +27 | # Bad, unsafe + | +help: Remove duplicate entries from `__all__` +22 | __all__ = ["A", "B", "A"] +23 | __all__ = ["A", "A", "B", "B"] +24 | __all__ += ["B", "B"] + - __all__.extend(["B", "B"]) +25 + __all__.extend(["B"]) +26 | +27 | # Bad, unsafe +28 | __all__ = [ + +RUF069 [*] `__all__` contains duplicate entries + --> RUF069.pyi:30:5 + | +28 | __all__ = [ +29 | "A", +30 | "A", + | ^^^ +31 | "B", +32 | # Comment + | +help: Remove duplicate entries from `__all__` +27 | # Bad, unsafe +28 | __all__ = [ +29 | "A", + - "A", +30 | "B", +31 | # Comment +32 | "B", + +RUF069 [*] `__all__` contains duplicate entries + --> RUF069.pyi:33:5 + | +31 | "B", +32 | # Comment +33 | "B", + | ^^^ +34 | ] + | +help: Remove duplicate entries from `__all__` +29 | "A", +30 | "A", +31 | "B", + - # Comment + - "B", +32 + # Comment, +33 | ] +note: This is an unsafe fix and may change runtime behavior