From f96dfc179f333c853349443cedb888188ebffd3b Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Mon, 2 Dec 2024 14:28:27 +0100 Subject: [PATCH] Revert: [pyflakes] Avoid false positives in `@no_type_check` contexts (F821, F722) (#14615) (#14726) --- .../fixtures/pyflakes/{F722_0.py => F722.py} | 0 .../test/fixtures/pyflakes/F722_1.py | 21 -------------- .../test/fixtures/pyflakes/F821_30.py | 21 -------------- crates/ruff_linter/src/checkers/ast/mod.rs | 9 ------ crates/ruff_linter/src/rules/pyflakes/mod.rs | 4 +-- ...rules__pyflakes__tests__F722_F722.py.snap} | 4 +-- ...ules__pyflakes__tests__F722_F722_1.py.snap | 29 ------------------- ...les__pyflakes__tests__F821_F821_30.py.snap | 29 ------------------- crates/ruff_python_semantic/src/model.rs | 21 -------------- 9 files changed, 3 insertions(+), 135 deletions(-) rename crates/ruff_linter/resources/test/fixtures/pyflakes/{F722_0.py => F722.py} (100%) delete mode 100644 crates/ruff_linter/resources/test/fixtures/pyflakes/F722_1.py delete mode 100644 crates/ruff_linter/resources/test/fixtures/pyflakes/F821_30.py rename crates/ruff_linter/src/rules/pyflakes/snapshots/{ruff_linter__rules__pyflakes__tests__F722_F722_0.py.snap => ruff_linter__rules__pyflakes__tests__F722_F722.py.snap} (63%) delete mode 100644 crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F722_F722_1.py.snap delete mode 100644 crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F821_F821_30.py.snap diff --git a/crates/ruff_linter/resources/test/fixtures/pyflakes/F722_0.py b/crates/ruff_linter/resources/test/fixtures/pyflakes/F722.py similarity index 100% rename from crates/ruff_linter/resources/test/fixtures/pyflakes/F722_0.py rename to crates/ruff_linter/resources/test/fixtures/pyflakes/F722.py diff --git a/crates/ruff_linter/resources/test/fixtures/pyflakes/F722_1.py b/crates/ruff_linter/resources/test/fixtures/pyflakes/F722_1.py deleted file mode 100644 index 203aa2b3ef269..0000000000000 --- a/crates/ruff_linter/resources/test/fixtures/pyflakes/F722_1.py +++ /dev/null @@ -1,21 +0,0 @@ -"""Regression test for #13824. - -Don't report an error when the function being annotated has the -`@no_type_check` decorator. - -However, we still want to ignore this annotation on classes. See -https://github.com/python/typing/pull/1615/files and the discussion on #14615. -""" - -from typing import no_type_check - - -@no_type_check -def f(arg: "this isn't python") -> "this isn't python either": - x: "this also isn't python" = 0 - - -@no_type_check -class C: - def f(arg: "this isn't python") -> "this isn't python either": - x: "this also isn't python" = 1 diff --git a/crates/ruff_linter/resources/test/fixtures/pyflakes/F821_30.py b/crates/ruff_linter/resources/test/fixtures/pyflakes/F821_30.py deleted file mode 100644 index d0c1b812b460e..0000000000000 --- a/crates/ruff_linter/resources/test/fixtures/pyflakes/F821_30.py +++ /dev/null @@ -1,21 +0,0 @@ -"""Regression test for #13824. - -Don't report an error when the function being annotated has the -`@no_type_check` decorator. - -However, we still want to ignore this annotation on classes. See -https://github.com/python/typing/pull/1615/files and the discussion on #14615. -""" - -import typing - - -@typing.no_type_check -def f(arg: "A") -> "R": - x: "A" = 1 - - -@typing.no_type_check -class C: - def f(self, arg: "B") -> "S": - x: "B" = 1 diff --git a/crates/ruff_linter/src/checkers/ast/mod.rs b/crates/ruff_linter/src/checkers/ast/mod.rs index 1c2d077dd207b..5fcf91b8e5bb0 100644 --- a/crates/ruff_linter/src/checkers/ast/mod.rs +++ b/crates/ruff_linter/src/checkers/ast/mod.rs @@ -723,12 +723,6 @@ impl<'a> Visitor<'a> for Checker<'a> { // Visit the decorators and arguments, but avoid the body, which will be // deferred. for decorator in decorator_list { - if self - .semantic - .match_typing_expr(&decorator.expression, "no_type_check") - { - self.semantic.flags |= SemanticModelFlags::NO_TYPE_CHECK; - } self.visit_decorator(decorator); } @@ -1897,9 +1891,6 @@ impl<'a> Checker<'a> { /// Visit an [`Expr`], and treat it as a type definition. fn visit_type_definition(&mut self, expr: &'a Expr) { - if self.semantic.in_no_type_check() { - return; - } let snapshot = self.semantic.flags; self.semantic.flags |= SemanticModelFlags::TYPE_DEFINITION; self.visit_expr(expr); diff --git a/crates/ruff_linter/src/rules/pyflakes/mod.rs b/crates/ruff_linter/src/rules/pyflakes/mod.rs index 7fb0f32673a8d..c01397206f2be 100644 --- a/crates/ruff_linter/src/rules/pyflakes/mod.rs +++ b/crates/ruff_linter/src/rules/pyflakes/mod.rs @@ -94,8 +94,7 @@ mod tests { #[test_case(Rule::YieldOutsideFunction, Path::new("F704.py"))] #[test_case(Rule::ReturnOutsideFunction, Path::new("F706.py"))] #[test_case(Rule::DefaultExceptNotLast, Path::new("F707.py"))] - #[test_case(Rule::ForwardAnnotationSyntaxError, Path::new("F722_0.py"))] - #[test_case(Rule::ForwardAnnotationSyntaxError, Path::new("F722_1.py"))] + #[test_case(Rule::ForwardAnnotationSyntaxError, Path::new("F722.py"))] #[test_case(Rule::RedefinedWhileUnused, Path::new("F811_0.py"))] #[test_case(Rule::RedefinedWhileUnused, Path::new("F811_1.py"))] #[test_case(Rule::RedefinedWhileUnused, Path::new("F811_2.py"))] @@ -160,7 +159,6 @@ mod tests { #[test_case(Rule::UndefinedName, Path::new("F821_26.pyi"))] #[test_case(Rule::UndefinedName, Path::new("F821_27.py"))] #[test_case(Rule::UndefinedName, Path::new("F821_28.py"))] - #[test_case(Rule::UndefinedName, Path::new("F821_30.py"))] #[test_case(Rule::UndefinedExport, Path::new("F822_0.py"))] #[test_case(Rule::UndefinedExport, Path::new("F822_0.pyi"))] #[test_case(Rule::UndefinedExport, Path::new("F822_1.py"))] diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F722_F722_0.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F722_F722.py.snap similarity index 63% rename from crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F722_F722_0.py.snap rename to crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F722_F722.py.snap index 0e45ac706c607..3a41c4a06203c 100644 --- a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F722_F722_0.py.snap +++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F722_F722.py.snap @@ -2,14 +2,14 @@ source: crates/ruff_linter/src/rules/pyflakes/mod.rs snapshot_kind: text --- -F722_0.py:9:12: F722 Syntax error in forward annotation: `///` +F722.py:9:12: F722 Syntax error in forward annotation: `///` | 9 | def g() -> "///": | ^^^^^ F722 10 | pass | -F722_0.py:13:4: F722 Syntax error in forward annotation: `List[int]☃` +F722.py:13:4: F722 Syntax error in forward annotation: `List[int]☃` | 13 | X: """List[int]"""'☃' = [] | ^^^^^^^^^^^^^^^^^^ F722 diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F722_F722_1.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F722_F722_1.py.snap deleted file mode 100644 index f79147a188710..0000000000000 --- a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F722_F722_1.py.snap +++ /dev/null @@ -1,29 +0,0 @@ ---- -source: crates/ruff_linter/src/rules/pyflakes/mod.rs -snapshot_kind: text ---- -F722_1.py:20:16: F722 Syntax error in forward annotation: `this isn't python` - | -18 | @no_type_check -19 | class C: -20 | def f(arg: "this isn't python") -> "this isn't python either": - | ^^^^^^^^^^^^^^^^^^^ F722 -21 | x: "this also isn't python" = 1 - | - -F722_1.py:20:40: F722 Syntax error in forward annotation: `this isn't python either` - | -18 | @no_type_check -19 | class C: -20 | def f(arg: "this isn't python") -> "this isn't python either": - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ F722 -21 | x: "this also isn't python" = 1 - | - -F722_1.py:21:12: F722 Syntax error in forward annotation: `this also isn't python` - | -19 | class C: -20 | def f(arg: "this isn't python") -> "this isn't python either": -21 | x: "this also isn't python" = 1 - | ^^^^^^^^^^^^^^^^^^^^^^^^ F722 - | diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F821_F821_30.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F821_F821_30.py.snap deleted file mode 100644 index 65b4a6cb293c7..0000000000000 --- a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F821_F821_30.py.snap +++ /dev/null @@ -1,29 +0,0 @@ ---- -source: crates/ruff_linter/src/rules/pyflakes/mod.rs -snapshot_kind: text ---- -F821_30.py:20:23: F821 Undefined name `B` - | -18 | @typing.no_type_check -19 | class C: -20 | def f(self, arg: "B") -> "S": - | ^ F821 -21 | x: "B" = 1 - | - -F821_30.py:20:31: F821 Undefined name `S` - | -18 | @typing.no_type_check -19 | class C: -20 | def f(self, arg: "B") -> "S": - | ^ F821 -21 | x: "B" = 1 - | - -F821_30.py:21:13: F821 Undefined name `B` - | -19 | class C: -20 | def f(self, arg: "B") -> "S": -21 | x: "B" = 1 - | ^ F821 - | diff --git a/crates/ruff_python_semantic/src/model.rs b/crates/ruff_python_semantic/src/model.rs index 579c7e290afe7..b5d7e993ec201 100644 --- a/crates/ruff_python_semantic/src/model.rs +++ b/crates/ruff_python_semantic/src/model.rs @@ -1717,11 +1717,6 @@ impl<'a> SemanticModel<'a> { self.flags.intersects(SemanticModelFlags::ANNOTATION) } - /// Return `true` if the model is in a `@no_type_check` context. - pub const fn in_no_type_check(&self) -> bool { - self.flags.intersects(SemanticModelFlags::NO_TYPE_CHECK) - } - /// Return `true` if the model is in a typing-only type annotation. pub const fn in_typing_only_annotation(&self) -> bool { self.flags @@ -2403,22 +2398,6 @@ bitflags! { /// [PEP 257]: https://peps.python.org/pep-0257/#what-is-a-docstring const ATTRIBUTE_DOCSTRING = 1 << 25; - /// The model is in a [no_type_check] context. - /// - /// This is used to skip type checking when the `@no_type_check` decorator is found. - /// - /// For example (adapted from [#13824]): - /// ```python - /// from typing import no_type_check - /// - /// @no_type_check - /// def fn(arg: "A") -> "R": - /// pass - /// ``` - /// - /// [no_type_check]: https://docs.python.org/3/library/typing.html#typing.no_type_check - /// [#13824]: https://github.com/astral-sh/ruff/issues/13824 - const NO_TYPE_CHECK = 1 << 26; /// The model is in the value expression of a [PEP 613] explicit type alias. /// /// For example: