From 1db7d9e75959ebefc0b3d06fa7b134cd910b8961 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Tue, 20 Jun 2023 21:29:12 -0400 Subject: [PATCH] Avoid erroneous RUF013 violations for quoted annotations (#5234) ## Summary Temporary fix for #5231: if we can't flag and fix these properly, just disabling them for now. \cc @dhruvmanila ## Test Plan `cargo test` --- .../resources/test/fixtures/ruff/RUF013_0.py | 15 +++++++++++++ .../src/rules/ruff/rules/implicit_optional.rs | 21 ++++++++++++------- ..._ruff__tests__PY39_RUF013_RUF013_0.py.snap | 2 ++ ...ules__ruff__tests__RUF013_RUF013_0.py.snap | 2 ++ 4 files changed, 33 insertions(+), 7 deletions(-) diff --git a/crates/ruff/resources/test/fixtures/ruff/RUF013_0.py b/crates/ruff/resources/test/fixtures/ruff/RUF013_0.py index 90252f46a1..527fe792ee 100644 --- a/crates/ruff/resources/test/fixtures/ruff/RUF013_0.py +++ b/crates/ruff/resources/test/fixtures/ruff/RUF013_0.py @@ -185,3 +185,18 @@ def f(arg: Union[Annotated[int, ...], Annotated[Optional[float], ...]] = None): def f(arg: Union[Annotated[int, ...], Union[str, bytes]] = None): # RUF011 pass + + +# Quoted + + +def f(arg: "int" = None): + pass + + +def f(arg: "str" = None): + pass + + +def f(arg: "Optional[int]" = None): + pass diff --git a/crates/ruff/src/rules/ruff/rules/implicit_optional.rs b/crates/ruff/src/rules/ruff/rules/implicit_optional.rs index 2cc6f1dbc0..dd0d5a7721 100644 --- a/crates/ruff/src/rules/ruff/rules/implicit_optional.rs +++ b/crates/ruff/src/rules/ruff/rules/implicit_optional.rs @@ -142,6 +142,7 @@ enum TypingTarget<'a> { None, Any, Object, + ForwardReference, Optional, Union(Vec<&'a Expr>), Literal(Vec<&'a Expr>), @@ -175,6 +176,10 @@ impl<'a> TypingTarget<'a> { value: Constant::None, .. }) => Some(TypingTarget::None), + Expr::Constant(ast::ExprConstant { + value: Constant::Str(_), + .. + }) => Some(TypingTarget::ForwardReference), _ => semantic.resolve_call_path(expr).and_then(|call_path| { if semantic.match_typing_call_path(&call_path, "Any") { Some(TypingTarget::Any) @@ -196,8 +201,8 @@ impl<'a> TypingTarget<'a> { | TypingTarget::Object => true, TypingTarget::Literal(elements) => elements.iter().any(|element| { let Some(new_target) = TypingTarget::try_from_expr(element, semantic) else { - return false; - }; + return false; + }; // Literal can only contain `None`, a literal value, other `Literal` // or an enum value. match new_target { @@ -208,8 +213,8 @@ impl<'a> TypingTarget<'a> { }), TypingTarget::Union(elements) => elements.iter().any(|element| { let Some(new_target) = TypingTarget::try_from_expr(element, semantic) else { - return false; - }; + return false; + }; match new_target { TypingTarget::None => true, _ => new_target.contains_none(semantic), @@ -217,13 +222,15 @@ impl<'a> TypingTarget<'a> { }), TypingTarget::Annotated(element) => { let Some(new_target) = TypingTarget::try_from_expr(element, semantic) else { - return false; - }; + return false; + }; match new_target { TypingTarget::None => true, _ => new_target.contains_none(semantic), } } + // TODO(charlie): Add support for forward references (quoted annotations). + TypingTarget::ForwardReference => true, } } } @@ -305,7 +312,7 @@ fn generate_fix(checker: &Checker, conversion_type: ConversionType, expr: &Expr) } } -/// RUF011 +/// RUF013 pub(crate) fn implicit_optional(checker: &mut Checker, arguments: &Arguments) { for ArgWithDefault { def, diff --git a/crates/ruff/src/rules/ruff/snapshots/ruff__rules__ruff__tests__PY39_RUF013_RUF013_0.py.snap b/crates/ruff/src/rules/ruff/snapshots/ruff__rules__ruff__tests__PY39_RUF013_RUF013_0.py.snap index 956b055d44..72f5f885b6 100644 --- a/crates/ruff/src/rules/ruff/snapshots/ruff__rules__ruff__tests__PY39_RUF013_RUF013_0.py.snap +++ b/crates/ruff/src/rules/ruff/snapshots/ruff__rules__ruff__tests__PY39_RUF013_RUF013_0.py.snap @@ -312,5 +312,7 @@ RUF013_0.py:186:12: RUF013 [*] PEP 484 prohibits implicit `Optional` 186 |-def f(arg: Union[Annotated[int, ...], Union[str, bytes]] = None): # RUF011 186 |+def f(arg: Optional[Union[Annotated[int, ...], Union[str, bytes]]] = None): # RUF011 187 187 | pass +188 188 | +189 189 | diff --git a/crates/ruff/src/rules/ruff/snapshots/ruff__rules__ruff__tests__RUF013_RUF013_0.py.snap b/crates/ruff/src/rules/ruff/snapshots/ruff__rules__ruff__tests__RUF013_RUF013_0.py.snap index 23ff31a6b6..7ec7c527d2 100644 --- a/crates/ruff/src/rules/ruff/snapshots/ruff__rules__ruff__tests__RUF013_RUF013_0.py.snap +++ b/crates/ruff/src/rules/ruff/snapshots/ruff__rules__ruff__tests__RUF013_RUF013_0.py.snap @@ -312,5 +312,7 @@ RUF013_0.py:186:12: RUF013 [*] PEP 484 prohibits implicit `Optional` 186 |-def f(arg: Union[Annotated[int, ...], Union[str, bytes]] = None): # RUF011 186 |+def f(arg: Union[Annotated[int, ...], Union[str, bytes]] | None = None): # RUF011 187 187 | pass +188 188 | +189 189 |