diff --git a/crates/ruff/resources/test/fixtures/flake8_pyi/PYI015.py b/crates/ruff/resources/test/fixtures/flake8_pyi/PYI015.py index 37a4f4d867..16ca34e318 100644 --- a/crates/ruff/resources/test/fixtures/flake8_pyi/PYI015.py +++ b/crates/ruff/resources/test/fixtures/flake8_pyi/PYI015.py @@ -91,3 +91,4 @@ field27 = list[str] field28 = builtins.str field29 = str field30 = str | bytes | None +field31: typing.Final = field30 diff --git a/crates/ruff/resources/test/fixtures/flake8_pyi/PYI015.pyi b/crates/ruff/resources/test/fixtures/flake8_pyi/PYI015.pyi index 860ee255fb..10f7a70770 100644 --- a/crates/ruff/resources/test/fixtures/flake8_pyi/PYI015.pyi +++ b/crates/ruff/resources/test/fixtures/flake8_pyi/PYI015.pyi @@ -98,3 +98,4 @@ field27 = list[str] field28 = builtins.str field29 = str field30 = str | bytes | None +field31: typing.Final = field30 diff --git a/crates/ruff/src/rules/flake8_pyi/rules/simple_defaults.rs b/crates/ruff/src/rules/flake8_pyi/rules/simple_defaults.rs index ec891299d9..b1ed3595b0 100644 --- a/crates/ruff/src/rules/flake8_pyi/rules/simple_defaults.rs +++ b/crates/ruff/src/rules/flake8_pyi/rules/simple_defaults.rs @@ -298,6 +298,16 @@ fn is_special_assignment(target: &Expr, semantic: &SemanticModel) -> bool { } } +/// Returns `true` if this is an assignment to a simple `Final`-annotated variable. +fn is_final_assignment(annotation: &Expr, value: &Expr, semantic: &SemanticModel) -> bool { + if matches!(value, Expr::Name(_) | Expr::Attribute(_)) { + if semantic.match_typing_expr(annotation, "Final") { + return true; + } + } + false +} + /// Returns `true` if the a class is an enum, based on its base classes. fn is_enum(bases: &[Expr], semantic: &SemanticModel) -> bool { return bases.iter().any(|expr| { @@ -438,6 +448,9 @@ pub(crate) fn annotated_assignment_default_in_stub( if is_type_var_like_call(value, checker.semantic()) { return; } + if is_final_assignment(annotation, value, checker.semantic()) { + return; + } if is_valid_default_value_with_annotation(value, true, checker.locator, checker.semantic()) { return; }