From 154d1c10adfaf139eb83e7cd44814c531d8286f2 Mon Sep 17 00:00:00 2001 From: Brent Westbrook <36778786+ntBre@users.noreply.github.com> Date: Tue, 28 Jul 2026 12:15:12 -0400 Subject: [PATCH] [`flake8-bugbear`] Mark `range` as immutable (`B008`) (#27247) Summary -- Fixes #27245. Test Plan -- Updated existing snapshots. These were previously emitting both B006 on the outer comprehensions and B008 on the inner `range` call, but now the inner diagnostic is omitted because `range` is immutable. --- .../test/fixtures/flake8_bugbear/B006_B008.py | 2 +- ...ke8_bugbear__tests__B006_B006_B008.py.snap | 4 +-- ...ke8_bugbear__tests__B008_B006_B008.py.snap | 25 ------------------- ...ar__tests__preview__B006_B006_B008.py.snap | 4 +-- crates/ruff_python_stdlib/src/typing.rs | 1 + 5 files changed, 6 insertions(+), 30 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_bugbear/B006_B008.py b/crates/ruff_linter/resources/test/fixtures/flake8_bugbear/B006_B008.py index 8e55d5b340..8f461b4dbb 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_bugbear/B006_B008.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_bugbear/B006_B008.py @@ -98,7 +98,7 @@ def dont_forget_me(value=collections.deque()): ... -# N.B. we're also flagging the function call in the comprehension +# B006 still flags mutable comprehension defaults. def list_comprehension_also_not_okay(default=[i**2 for i in range(3)]): pass diff --git a/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B006_B006_B008.py.snap b/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B006_B006_B008.py.snap index 9ee2465a7f..7bdf721a3f 100644 --- a/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B006_B006_B008.py.snap +++ b/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B006_B006_B008.py.snap @@ -149,14 +149,14 @@ note: This is an unsafe fix and may change runtime behavior B006 [*] Do not use mutable data structures for argument defaults --> B006_B008.py:102:46 | -101 | # N.B. we're also flagging the function call in the comprehension +101 | # B006 still flags mutable comprehension defaults. 102 | def list_comprehension_also_not_okay(default=[i**2 for i in range(3)]): | ^^^^^^^^^^^^^^^^^^^^^^^^ 103 | pass | help: Replace with `None`; initialize within function | -101 | # N.B. we're also flagging the function call in the comprehension +101 | # B006 still flags mutable comprehension defaults. - def list_comprehension_also_not_okay(default=[i**2 for i in range(3)]): 102 + def list_comprehension_also_not_okay(default=None): 103 | pass diff --git a/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B008_B006_B008.py.snap b/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B008_B006_B008.py.snap index edaaadb944..3fbd47e194 100644 --- a/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B008_B006_B008.py.snap +++ b/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B008_B006_B008.py.snap @@ -1,31 +1,6 @@ --- source: crates/ruff_linter/src/rules/flake8_bugbear/mod.rs --- -B008 Do not perform function call `range` in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable - --> B006_B008.py:102:61 - | -101 | # N.B. we're also flagging the function call in the comprehension -102 | def list_comprehension_also_not_okay(default=[i**2 for i in range(3)]): - | ^^^^^^^^ -103 | pass - | - -B008 Do not perform function call `range` in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable - --> B006_B008.py:106:64 - | -106 | def dict_comprehension_also_not_okay(default={i: i**2 for i in range(3)}): - | ^^^^^^^^ -107 | pass - | - -B008 Do not perform function call `range` in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable - --> B006_B008.py:110:60 - | -110 | def set_comprehension_also_not_okay(default={i**2 for i in range(3)}): - | ^^^^^^^^ -111 | pass - | - B008 Do not perform function call `time.time` in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable --> B006_B008.py:126:39 | diff --git a/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__preview__B006_B006_B008.py.snap b/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__preview__B006_B006_B008.py.snap index 9ee2465a7f..7bdf721a3f 100644 --- a/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__preview__B006_B006_B008.py.snap +++ b/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__preview__B006_B006_B008.py.snap @@ -149,14 +149,14 @@ note: This is an unsafe fix and may change runtime behavior B006 [*] Do not use mutable data structures for argument defaults --> B006_B008.py:102:46 | -101 | # N.B. we're also flagging the function call in the comprehension +101 | # B006 still flags mutable comprehension defaults. 102 | def list_comprehension_also_not_okay(default=[i**2 for i in range(3)]): | ^^^^^^^^^^^^^^^^^^^^^^^^ 103 | pass | help: Replace with `None`; initialize within function | -101 | # N.B. we're also flagging the function call in the comprehension +101 | # B006 still flags mutable comprehension defaults. - def list_comprehension_also_not_okay(default=[i**2 for i in range(3)]): 102 + def list_comprehension_also_not_okay(default=None): 103 | pass diff --git a/crates/ruff_python_stdlib/src/typing.rs b/crates/ruff_python_stdlib/src/typing.rs index d3c97889fe..7e80065446 100644 --- a/crates/ruff_python_stdlib/src/typing.rs +++ b/crates/ruff_python_stdlib/src/typing.rs @@ -324,6 +324,7 @@ pub fn is_immutable_return_type(qualified_name: &[&str]) -> bool { | "float" | "frozenset" | "int" + | "range" | "str" | "tuple" | "slice"