diff --git a/crates/ruff/resources/test/fixtures/flake8_bugbear/B006_B008.py b/crates/ruff/resources/test/fixtures/flake8_bugbear/B006_B008.py index 475506225a876..e10418901595c 100644 --- a/crates/ruff/resources/test/fixtures/flake8_bugbear/B006_B008.py +++ b/crates/ruff/resources/test/fixtures/flake8_bugbear/B006_B008.py @@ -240,12 +240,16 @@ def foo(f=lambda x: print(x)): from collections import abc from typing import Annotated, Dict, Optional, Sequence, Union, Set +import typing_extensions def immutable_annotations( a: Sequence[int] | None = [], b: Optional[abc.Mapping[int, int]] = {}, c: Annotated[Union[abc.Set[str], abc.Sized], "annotation"] = set(), + d: typing_extensions.Annotated[ + Union[abc.Set[str], abc.Sized], "annotation" + ] = set(), ): pass @@ -254,5 +258,6 @@ def mutable_annotations( a: list[int] | None = [], b: Optional[Dict[int, int]] = {}, c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), + d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), ): pass diff --git a/crates/ruff/src/rules/flake8_bugbear/snapshots/ruff__rules__flake8_bugbear__tests__B006_B006_B008.py.snap b/crates/ruff/src/rules/flake8_bugbear/snapshots/ruff__rules__flake8_bugbear__tests__B006_B006_B008.py.snap index f1fc165498682..abac933f98a73 100644 --- a/crates/ruff/src/rules/flake8_bugbear/snapshots/ruff__rules__flake8_bugbear__tests__B006_B006_B008.py.snap +++ b/crates/ruff/src/rules/flake8_bugbear/snapshots/ruff__rules__flake8_bugbear__tests__B006_B006_B008.py.snap @@ -81,33 +81,43 @@ B006_B008.py:221:20: B006 Do not use mutable data structures for argument defaul 222 | pass | -B006_B008.py:254:27: B006 Do not use mutable data structures for argument defaults +B006_B008.py:258:27: B006 Do not use mutable data structures for argument defaults | -253 | def mutable_annotations( -254 | a: list[int] | None = [], +257 | def mutable_annotations( +258 | a: list[int] | None = [], | ^^ B006 -255 | b: Optional[Dict[int, int]] = {}, -256 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), +259 | b: Optional[Dict[int, int]] = {}, +260 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), | -B006_B008.py:255:35: B006 Do not use mutable data structures for argument defaults +B006_B008.py:259:35: B006 Do not use mutable data structures for argument defaults | -253 | def mutable_annotations( -254 | a: list[int] | None = [], -255 | b: Optional[Dict[int, int]] = {}, +257 | def mutable_annotations( +258 | a: list[int] | None = [], +259 | b: Optional[Dict[int, int]] = {}, | ^^ B006 -256 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), -257 | ): +260 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), +261 | d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), | -B006_B008.py:256:62: B006 Do not use mutable data structures for argument defaults +B006_B008.py:260:62: B006 Do not use mutable data structures for argument defaults | -254 | a: list[int] | None = [], -255 | b: Optional[Dict[int, int]] = {}, -256 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), +258 | a: list[int] | None = [], +259 | b: Optional[Dict[int, int]] = {}, +260 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), | ^^^^^ B006 -257 | ): -258 | pass +261 | d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), +262 | ): + | + +B006_B008.py:261:80: B006 Do not use mutable data structures for argument defaults + | +259 | b: Optional[Dict[int, int]] = {}, +260 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), +261 | d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), + | ^^^^^ B006 +262 | ): +263 | pass | diff --git a/crates/ruff_python_semantic/src/analyze/typing.rs b/crates/ruff_python_semantic/src/analyze/typing.rs index 05799e5dbaacb..fbc481b779632 100644 --- a/crates/ruff_python_semantic/src/analyze/typing.rs +++ b/crates/ruff_python_semantic/src/analyze/typing.rs @@ -207,7 +207,7 @@ pub fn is_immutable_annotation(expr: &Expr, semantic: &SemanticModel) -> bool { } } else if matches!(call_path.as_slice(), ["typing", "Optional"]) { is_immutable_annotation(slice, semantic) - } else if matches!(call_path.as_slice(), ["typing", "Annotated"]) { + } else if is_pep_593_generic_type(call_path.as_slice()) { if let Expr::Tuple(ast::ExprTuple { elts, .. }) = slice.as_ref() { elts.first() .is_some_and(|elt| is_immutable_annotation(elt, semantic))