From 2d3466eccf66a2049d95542224d5985d79bcd1ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Riegel?= <96702577+LoicRiegel@users.noreply.github.com> Date: Mon, 8 Dec 2025 20:00:43 +0100 Subject: [PATCH] [`flake8-bugbear`] Accept immutable slice default arguments (`B008`) (#21823) Closes issue #21565 ## Summary As pointed out in the issue, slices are currently flagged by B008 but this behavior is incorrect because slices are immutable. ## Test Plan Added a test case in the "B006_B008.py" fixture. Sorry for the diff in the snapshots, the only thing that changes in those flies is the line numbers, though. You can also test this manually with this file: ```py # test_slice.py def c(d=slice(0, 3)): ... ``` ```sh > target/debug/ruff check tmp/test_slice.py --no-cache --select B008 All checks passed! ``` --- .../test/fixtures/flake8_bugbear/B006_B008.py | 3 + ...ke8_bugbear__tests__B006_B006_B008.py.snap | 258 +++++++++--------- ...ke8_bugbear__tests__B008_B006_B008.py.snap | 36 +-- ...ar__tests__preview__B006_B006_B008.py.snap | 258 +++++++++--------- crates/ruff_python_stdlib/src/typing.rs | 10 +- 5 files changed, 288 insertions(+), 277 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 77ab80b7ee..8e55d5b340 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 @@ -199,6 +199,9 @@ def bytes_okay(value=bytes(1)): def int_okay(value=int("12")): pass +# Allow immutable slice() +def slice_okay(value=slice(1,2)): + pass # Allow immutable complex() value def complex_okay(value=complex(1,2)): 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 e3f42e2da7..f4113617b5 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 @@ -236,227 +236,227 @@ help: Replace with `None`; initialize within function note: This is an unsafe fix and may change runtime behavior B006 [*] Do not use mutable data structures for argument defaults - --> B006_B008.py:239:20 + --> B006_B008.py:242:20 | -237 | # B006 and B008 -238 | # We should handle arbitrary nesting of these B008. -239 | def nested_combo(a=[float(3), dt.datetime.now()]): +240 | # B006 and B008 +241 | # We should handle arbitrary nesting of these B008. +242 | def nested_combo(a=[float(3), dt.datetime.now()]): | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -240 | pass +243 | pass | help: Replace with `None`; initialize within function -236 | -237 | # B006 and B008 -238 | # We should handle arbitrary nesting of these B008. +239 | +240 | # B006 and B008 +241 | # We should handle arbitrary nesting of these B008. - def nested_combo(a=[float(3), dt.datetime.now()]): -239 + def nested_combo(a=None): -240 | pass -241 | -242 | +242 + def nested_combo(a=None): +243 | pass +244 | +245 | note: This is an unsafe fix and may change runtime behavior B006 [*] Do not use mutable data structures for argument defaults - --> B006_B008.py:276:27 + --> B006_B008.py:279:27 | -275 | def mutable_annotations( -276 | a: list[int] | None = [], +278 | def mutable_annotations( +279 | a: list[int] | None = [], | ^^ -277 | b: Optional[Dict[int, int]] = {}, -278 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), +280 | b: Optional[Dict[int, int]] = {}, +281 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), | help: Replace with `None`; initialize within function -273 | -274 | -275 | def mutable_annotations( +276 | +277 | +278 | def mutable_annotations( - a: list[int] | None = [], -276 + a: list[int] | None = None, -277 | b: Optional[Dict[int, int]] = {}, -278 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), -279 | d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), +279 + a: list[int] | None = None, +280 | b: Optional[Dict[int, int]] = {}, +281 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), +282 | d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), note: This is an unsafe fix and may change runtime behavior B006 [*] Do not use mutable data structures for argument defaults - --> B006_B008.py:277:35 + --> B006_B008.py:280:35 | -275 | def mutable_annotations( -276 | a: list[int] | None = [], -277 | b: Optional[Dict[int, int]] = {}, +278 | def mutable_annotations( +279 | a: list[int] | None = [], +280 | b: Optional[Dict[int, int]] = {}, | ^^ -278 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), -279 | d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), +281 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), +282 | d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), | help: Replace with `None`; initialize within function -274 | -275 | def mutable_annotations( -276 | a: list[int] | None = [], +277 | +278 | def mutable_annotations( +279 | a: list[int] | None = [], - b: Optional[Dict[int, int]] = {}, -277 + b: Optional[Dict[int, int]] = None, -278 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), -279 | d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), -280 | ): +280 + b: Optional[Dict[int, int]] = None, +281 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), +282 | d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), +283 | ): note: This is an unsafe fix and may change runtime behavior B006 [*] Do not use mutable data structures for argument defaults - --> B006_B008.py:278:62 + --> B006_B008.py:281:62 | -276 | a: list[int] | None = [], -277 | b: Optional[Dict[int, int]] = {}, -278 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), +279 | a: list[int] | None = [], +280 | b: Optional[Dict[int, int]] = {}, +281 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), | ^^^^^ -279 | d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), -280 | ): +282 | d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), +283 | ): | help: Replace with `None`; initialize within function -275 | def mutable_annotations( -276 | a: list[int] | None = [], -277 | b: Optional[Dict[int, int]] = {}, +278 | def mutable_annotations( +279 | a: list[int] | None = [], +280 | b: Optional[Dict[int, int]] = {}, - c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), -278 + c: Annotated[Union[Set[str], abc.Sized], "annotation"] = None, -279 | d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), -280 | ): -281 | pass +281 + c: Annotated[Union[Set[str], abc.Sized], "annotation"] = None, +282 | d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), +283 | ): +284 | pass note: This is an unsafe fix and may change runtime behavior B006 [*] Do not use mutable data structures for argument defaults - --> B006_B008.py:279:80 + --> B006_B008.py:282:80 | -277 | b: Optional[Dict[int, int]] = {}, -278 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), -279 | d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), +280 | b: Optional[Dict[int, int]] = {}, +281 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), +282 | d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), | ^^^^^ -280 | ): -281 | pass +283 | ): +284 | pass | help: Replace with `None`; initialize within function -276 | a: list[int] | None = [], -277 | b: Optional[Dict[int, int]] = {}, -278 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), +279 | a: list[int] | None = [], +280 | b: Optional[Dict[int, int]] = {}, +281 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), - d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), -279 + d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = None, -280 | ): -281 | pass -282 | +282 + d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = None, +283 | ): +284 | pass +285 | note: This is an unsafe fix and may change runtime behavior B006 [*] Do not use mutable data structures for argument defaults - --> B006_B008.py:284:52 + --> B006_B008.py:287:52 | -284 | def single_line_func_wrong(value: dict[str, str] = {}): +287 | def single_line_func_wrong(value: dict[str, str] = {}): | ^^ -285 | """Docstring""" +288 | """Docstring""" | help: Replace with `None`; initialize within function -281 | pass -282 | -283 | - - def single_line_func_wrong(value: dict[str, str] = {}): -284 + def single_line_func_wrong(value: dict[str, str] = None): -285 | """Docstring""" +284 | pass +285 | 286 | -287 | + - def single_line_func_wrong(value: dict[str, str] = {}): +287 + def single_line_func_wrong(value: dict[str, str] = None): +288 | """Docstring""" +289 | +290 | note: This is an unsafe fix and may change runtime behavior B006 [*] Do not use mutable data structures for argument defaults - --> B006_B008.py:288:52 + --> B006_B008.py:291:52 | -288 | def single_line_func_wrong(value: dict[str, str] = {}): +291 | def single_line_func_wrong(value: dict[str, str] = {}): | ^^ -289 | """Docstring""" -290 | ... +292 | """Docstring""" +293 | ... | help: Replace with `None`; initialize within function -285 | """Docstring""" -286 | -287 | +288 | """Docstring""" +289 | +290 | - def single_line_func_wrong(value: dict[str, str] = {}): -288 + def single_line_func_wrong(value: dict[str, str] = None): -289 | """Docstring""" -290 | ... -291 | +291 + def single_line_func_wrong(value: dict[str, str] = None): +292 | """Docstring""" +293 | ... +294 | note: This is an unsafe fix and may change runtime behavior B006 [*] Do not use mutable data structures for argument defaults - --> B006_B008.py:293:52 + --> B006_B008.py:296:52 | -293 | def single_line_func_wrong(value: dict[str, str] = {}): +296 | def single_line_func_wrong(value: dict[str, str] = {}): | ^^ -294 | """Docstring"""; ... +297 | """Docstring"""; ... | help: Replace with `None`; initialize within function -290 | ... -291 | -292 | - - def single_line_func_wrong(value: dict[str, str] = {}): -293 + def single_line_func_wrong(value: dict[str, str] = None): -294 | """Docstring"""; ... +293 | ... +294 | 295 | -296 | + - def single_line_func_wrong(value: dict[str, str] = {}): +296 + def single_line_func_wrong(value: dict[str, str] = None): +297 | """Docstring"""; ... +298 | +299 | note: This is an unsafe fix and may change runtime behavior B006 [*] Do not use mutable data structures for argument defaults - --> B006_B008.py:297:52 + --> B006_B008.py:300:52 | -297 | def single_line_func_wrong(value: dict[str, str] = {}): +300 | def single_line_func_wrong(value: dict[str, str] = {}): | ^^ -298 | """Docstring"""; \ -299 | ... +301 | """Docstring"""; \ +302 | ... | help: Replace with `None`; initialize within function -294 | """Docstring"""; ... -295 | -296 | +297 | """Docstring"""; ... +298 | +299 | - def single_line_func_wrong(value: dict[str, str] = {}): -297 + def single_line_func_wrong(value: dict[str, str] = None): -298 | """Docstring"""; \ -299 | ... -300 | +300 + def single_line_func_wrong(value: dict[str, str] = None): +301 | """Docstring"""; \ +302 | ... +303 | note: This is an unsafe fix and may change runtime behavior B006 [*] Do not use mutable data structures for argument defaults - --> B006_B008.py:302:52 + --> B006_B008.py:305:52 | -302 | def single_line_func_wrong(value: dict[str, str] = { +305 | def single_line_func_wrong(value: dict[str, str] = { | ____________________________________________________^ -303 | | # This is a comment -304 | | }): +306 | | # This is a comment +307 | | }): | |_^ -305 | """Docstring""" +308 | """Docstring""" | help: Replace with `None`; initialize within function -299 | ... -300 | -301 | +302 | ... +303 | +304 | - def single_line_func_wrong(value: dict[str, str] = { - # This is a comment - }): -302 + def single_line_func_wrong(value: dict[str, str] = None): -303 | """Docstring""" -304 | -305 | +305 + def single_line_func_wrong(value: dict[str, str] = None): +306 | """Docstring""" +307 | +308 | note: This is an unsafe fix and may change runtime behavior B006 Do not use mutable data structures for argument defaults - --> B006_B008.py:308:52 + --> B006_B008.py:311:52 | -308 | def single_line_func_wrong(value: dict[str, str] = {}) \ +311 | def single_line_func_wrong(value: dict[str, str] = {}) \ | ^^ -309 | : \ -310 | """Docstring""" +312 | : \ +313 | """Docstring""" | help: Replace with `None`; initialize within function B006 [*] Do not use mutable data structures for argument defaults - --> B006_B008.py:313:52 + --> B006_B008.py:316:52 | -313 | def single_line_func_wrong(value: dict[str, str] = {}): +316 | def single_line_func_wrong(value: dict[str, str] = {}): | ^^ -314 | """Docstring without newline""" +317 | """Docstring without newline""" | help: Replace with `None`; initialize within function -310 | """Docstring""" -311 | -312 | +313 | """Docstring""" +314 | +315 | - def single_line_func_wrong(value: dict[str, str] = {}): -313 + def single_line_func_wrong(value: dict[str, str] = None): -314 | """Docstring without newline""" +316 + def single_line_func_wrong(value: dict[str, str] = None): +317 | """Docstring without newline""" note: This is an unsafe fix and may change runtime behavior 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 49da306103..edaaadb944 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 @@ -53,39 +53,39 @@ B008 Do not perform function call in argument defaults; instead, perform the cal | B008 Do not perform function call `dt.datetime.now` in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable - --> B006_B008.py:239:31 + --> B006_B008.py:242:31 | -237 | # B006 and B008 -238 | # We should handle arbitrary nesting of these B008. -239 | def nested_combo(a=[float(3), dt.datetime.now()]): +240 | # B006 and B008 +241 | # We should handle arbitrary nesting of these B008. +242 | def nested_combo(a=[float(3), dt.datetime.now()]): | ^^^^^^^^^^^^^^^^^ -240 | pass +243 | pass | B008 Do not perform function call `map` in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable - --> B006_B008.py:245:22 + --> B006_B008.py:248:22 | -243 | # Don't flag nested B006 since we can't guarantee that -244 | # it isn't made mutable by the outer operation. -245 | def no_nested_b006(a=map(lambda s: s.upper(), ["a", "b", "c"])): +246 | # Don't flag nested B006 since we can't guarantee that +247 | # it isn't made mutable by the outer operation. +248 | def no_nested_b006(a=map(lambda s: s.upper(), ["a", "b", "c"])): | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -246 | pass +249 | pass | B008 Do not perform function call `random.randint` in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable - --> B006_B008.py:250:19 + --> B006_B008.py:253:19 | -249 | # B008-ception. -250 | def nested_b008(a=random.randint(0, dt.datetime.now().year)): +252 | # B008-ception. +253 | def nested_b008(a=random.randint(0, dt.datetime.now().year)): | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -251 | pass +254 | pass | B008 Do not perform function call `dt.datetime.now` in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable - --> B006_B008.py:250:37 + --> B006_B008.py:253:37 | -249 | # B008-ception. -250 | def nested_b008(a=random.randint(0, dt.datetime.now().year)): +252 | # B008-ception. +253 | def nested_b008(a=random.randint(0, dt.datetime.now().year)): | ^^^^^^^^^^^^^^^^^ -251 | pass +254 | pass | 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 e3f42e2da7..f4113617b5 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 @@ -236,227 +236,227 @@ help: Replace with `None`; initialize within function note: This is an unsafe fix and may change runtime behavior B006 [*] Do not use mutable data structures for argument defaults - --> B006_B008.py:239:20 + --> B006_B008.py:242:20 | -237 | # B006 and B008 -238 | # We should handle arbitrary nesting of these B008. -239 | def nested_combo(a=[float(3), dt.datetime.now()]): +240 | # B006 and B008 +241 | # We should handle arbitrary nesting of these B008. +242 | def nested_combo(a=[float(3), dt.datetime.now()]): | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -240 | pass +243 | pass | help: Replace with `None`; initialize within function -236 | -237 | # B006 and B008 -238 | # We should handle arbitrary nesting of these B008. +239 | +240 | # B006 and B008 +241 | # We should handle arbitrary nesting of these B008. - def nested_combo(a=[float(3), dt.datetime.now()]): -239 + def nested_combo(a=None): -240 | pass -241 | -242 | +242 + def nested_combo(a=None): +243 | pass +244 | +245 | note: This is an unsafe fix and may change runtime behavior B006 [*] Do not use mutable data structures for argument defaults - --> B006_B008.py:276:27 + --> B006_B008.py:279:27 | -275 | def mutable_annotations( -276 | a: list[int] | None = [], +278 | def mutable_annotations( +279 | a: list[int] | None = [], | ^^ -277 | b: Optional[Dict[int, int]] = {}, -278 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), +280 | b: Optional[Dict[int, int]] = {}, +281 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), | help: Replace with `None`; initialize within function -273 | -274 | -275 | def mutable_annotations( +276 | +277 | +278 | def mutable_annotations( - a: list[int] | None = [], -276 + a: list[int] | None = None, -277 | b: Optional[Dict[int, int]] = {}, -278 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), -279 | d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), +279 + a: list[int] | None = None, +280 | b: Optional[Dict[int, int]] = {}, +281 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), +282 | d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), note: This is an unsafe fix and may change runtime behavior B006 [*] Do not use mutable data structures for argument defaults - --> B006_B008.py:277:35 + --> B006_B008.py:280:35 | -275 | def mutable_annotations( -276 | a: list[int] | None = [], -277 | b: Optional[Dict[int, int]] = {}, +278 | def mutable_annotations( +279 | a: list[int] | None = [], +280 | b: Optional[Dict[int, int]] = {}, | ^^ -278 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), -279 | d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), +281 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), +282 | d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), | help: Replace with `None`; initialize within function -274 | -275 | def mutable_annotations( -276 | a: list[int] | None = [], +277 | +278 | def mutable_annotations( +279 | a: list[int] | None = [], - b: Optional[Dict[int, int]] = {}, -277 + b: Optional[Dict[int, int]] = None, -278 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), -279 | d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), -280 | ): +280 + b: Optional[Dict[int, int]] = None, +281 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), +282 | d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), +283 | ): note: This is an unsafe fix and may change runtime behavior B006 [*] Do not use mutable data structures for argument defaults - --> B006_B008.py:278:62 + --> B006_B008.py:281:62 | -276 | a: list[int] | None = [], -277 | b: Optional[Dict[int, int]] = {}, -278 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), +279 | a: list[int] | None = [], +280 | b: Optional[Dict[int, int]] = {}, +281 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), | ^^^^^ -279 | d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), -280 | ): +282 | d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), +283 | ): | help: Replace with `None`; initialize within function -275 | def mutable_annotations( -276 | a: list[int] | None = [], -277 | b: Optional[Dict[int, int]] = {}, +278 | def mutable_annotations( +279 | a: list[int] | None = [], +280 | b: Optional[Dict[int, int]] = {}, - c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), -278 + c: Annotated[Union[Set[str], abc.Sized], "annotation"] = None, -279 | d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), -280 | ): -281 | pass +281 + c: Annotated[Union[Set[str], abc.Sized], "annotation"] = None, +282 | d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), +283 | ): +284 | pass note: This is an unsafe fix and may change runtime behavior B006 [*] Do not use mutable data structures for argument defaults - --> B006_B008.py:279:80 + --> B006_B008.py:282:80 | -277 | b: Optional[Dict[int, int]] = {}, -278 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), -279 | d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), +280 | b: Optional[Dict[int, int]] = {}, +281 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), +282 | d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), | ^^^^^ -280 | ): -281 | pass +283 | ): +284 | pass | help: Replace with `None`; initialize within function -276 | a: list[int] | None = [], -277 | b: Optional[Dict[int, int]] = {}, -278 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), +279 | a: list[int] | None = [], +280 | b: Optional[Dict[int, int]] = {}, +281 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), - d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = set(), -279 + d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = None, -280 | ): -281 | pass -282 | +282 + d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = None, +283 | ): +284 | pass +285 | note: This is an unsafe fix and may change runtime behavior B006 [*] Do not use mutable data structures for argument defaults - --> B006_B008.py:284:52 + --> B006_B008.py:287:52 | -284 | def single_line_func_wrong(value: dict[str, str] = {}): +287 | def single_line_func_wrong(value: dict[str, str] = {}): | ^^ -285 | """Docstring""" +288 | """Docstring""" | help: Replace with `None`; initialize within function -281 | pass -282 | -283 | - - def single_line_func_wrong(value: dict[str, str] = {}): -284 + def single_line_func_wrong(value: dict[str, str] = None): -285 | """Docstring""" +284 | pass +285 | 286 | -287 | + - def single_line_func_wrong(value: dict[str, str] = {}): +287 + def single_line_func_wrong(value: dict[str, str] = None): +288 | """Docstring""" +289 | +290 | note: This is an unsafe fix and may change runtime behavior B006 [*] Do not use mutable data structures for argument defaults - --> B006_B008.py:288:52 + --> B006_B008.py:291:52 | -288 | def single_line_func_wrong(value: dict[str, str] = {}): +291 | def single_line_func_wrong(value: dict[str, str] = {}): | ^^ -289 | """Docstring""" -290 | ... +292 | """Docstring""" +293 | ... | help: Replace with `None`; initialize within function -285 | """Docstring""" -286 | -287 | +288 | """Docstring""" +289 | +290 | - def single_line_func_wrong(value: dict[str, str] = {}): -288 + def single_line_func_wrong(value: dict[str, str] = None): -289 | """Docstring""" -290 | ... -291 | +291 + def single_line_func_wrong(value: dict[str, str] = None): +292 | """Docstring""" +293 | ... +294 | note: This is an unsafe fix and may change runtime behavior B006 [*] Do not use mutable data structures for argument defaults - --> B006_B008.py:293:52 + --> B006_B008.py:296:52 | -293 | def single_line_func_wrong(value: dict[str, str] = {}): +296 | def single_line_func_wrong(value: dict[str, str] = {}): | ^^ -294 | """Docstring"""; ... +297 | """Docstring"""; ... | help: Replace with `None`; initialize within function -290 | ... -291 | -292 | - - def single_line_func_wrong(value: dict[str, str] = {}): -293 + def single_line_func_wrong(value: dict[str, str] = None): -294 | """Docstring"""; ... +293 | ... +294 | 295 | -296 | + - def single_line_func_wrong(value: dict[str, str] = {}): +296 + def single_line_func_wrong(value: dict[str, str] = None): +297 | """Docstring"""; ... +298 | +299 | note: This is an unsafe fix and may change runtime behavior B006 [*] Do not use mutable data structures for argument defaults - --> B006_B008.py:297:52 + --> B006_B008.py:300:52 | -297 | def single_line_func_wrong(value: dict[str, str] = {}): +300 | def single_line_func_wrong(value: dict[str, str] = {}): | ^^ -298 | """Docstring"""; \ -299 | ... +301 | """Docstring"""; \ +302 | ... | help: Replace with `None`; initialize within function -294 | """Docstring"""; ... -295 | -296 | +297 | """Docstring"""; ... +298 | +299 | - def single_line_func_wrong(value: dict[str, str] = {}): -297 + def single_line_func_wrong(value: dict[str, str] = None): -298 | """Docstring"""; \ -299 | ... -300 | +300 + def single_line_func_wrong(value: dict[str, str] = None): +301 | """Docstring"""; \ +302 | ... +303 | note: This is an unsafe fix and may change runtime behavior B006 [*] Do not use mutable data structures for argument defaults - --> B006_B008.py:302:52 + --> B006_B008.py:305:52 | -302 | def single_line_func_wrong(value: dict[str, str] = { +305 | def single_line_func_wrong(value: dict[str, str] = { | ____________________________________________________^ -303 | | # This is a comment -304 | | }): +306 | | # This is a comment +307 | | }): | |_^ -305 | """Docstring""" +308 | """Docstring""" | help: Replace with `None`; initialize within function -299 | ... -300 | -301 | +302 | ... +303 | +304 | - def single_line_func_wrong(value: dict[str, str] = { - # This is a comment - }): -302 + def single_line_func_wrong(value: dict[str, str] = None): -303 | """Docstring""" -304 | -305 | +305 + def single_line_func_wrong(value: dict[str, str] = None): +306 | """Docstring""" +307 | +308 | note: This is an unsafe fix and may change runtime behavior B006 Do not use mutable data structures for argument defaults - --> B006_B008.py:308:52 + --> B006_B008.py:311:52 | -308 | def single_line_func_wrong(value: dict[str, str] = {}) \ +311 | def single_line_func_wrong(value: dict[str, str] = {}) \ | ^^ -309 | : \ -310 | """Docstring""" +312 | : \ +313 | """Docstring""" | help: Replace with `None`; initialize within function B006 [*] Do not use mutable data structures for argument defaults - --> B006_B008.py:313:52 + --> B006_B008.py:316:52 | -313 | def single_line_func_wrong(value: dict[str, str] = {}): +316 | def single_line_func_wrong(value: dict[str, str] = {}): | ^^ -314 | """Docstring without newline""" +317 | """Docstring without newline""" | help: Replace with `None`; initialize within function -310 | """Docstring""" -311 | -312 | +313 | """Docstring""" +314 | +315 | - def single_line_func_wrong(value: dict[str, str] = {}): -313 + def single_line_func_wrong(value: dict[str, str] = None): -314 | """Docstring without newline""" +316 + def single_line_func_wrong(value: dict[str, str] = None): +317 | """Docstring without newline""" note: This is an unsafe fix and may change runtime behavior diff --git a/crates/ruff_python_stdlib/src/typing.rs b/crates/ruff_python_stdlib/src/typing.rs index 63d7ccf32e..7f4abd367c 100644 --- a/crates/ruff_python_stdlib/src/typing.rs +++ b/crates/ruff_python_stdlib/src/typing.rs @@ -326,7 +326,15 @@ pub fn is_immutable_return_type(qualified_name: &[&str]) -> bool { | ["re", "compile"] | [ "", - "bool" | "bytes" | "complex" | "float" | "frozenset" | "int" | "str" | "tuple" + "bool" + | "bytes" + | "complex" + | "float" + | "frozenset" + | "int" + | "str" + | "tuple" + | "slice" ] ) }