diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_bugbear/B006_5.py b/crates/ruff_linter/resources/test/fixtures/flake8_bugbear/B006_5.py index 998fe9479de11e..b2bde5afa118dc 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_bugbear/B006_5.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_bugbear/B006_5.py @@ -35,3 +35,40 @@ def import_and_from_imports_module_wrong(value: dict[str, str] = {}): def import_docstring_module_wrong(value: dict[str, str] = {}): """Docstring""" import os + + +def import_module_wrong(value: dict[str, str] = {}): + """Docstring""" + import os; import sys + + +def import_module_wrong(value: dict[str, str] = {}): + """Docstring""" + import os; import sys; x = 1 + + +def import_module_wrong(value: dict[str, str] = {}): + """Docstring""" + import os; import sys + + +def import_module_wrong(value: dict[str, str] = {}): + import os; import sys + + +def import_module_wrong(value: dict[str, str] = {}): + import os; import sys; x = 1 + + +def import_module_wrong(value: dict[str, str] = {}): + import os; import sys + + +def import_module_wrong(value: dict[str, str] = {}): import os + + +def import_module_wrong(value: dict[str, str] = {}): import os; import sys + + +def import_module_wrong(value: dict[str, str] = {}): \ + import os diff --git a/crates/ruff_linter/src/rules/flake8_bugbear/rules/mutable_argument_default.rs b/crates/ruff_linter/src/rules/flake8_bugbear/rules/mutable_argument_default.rs index 261a8f68b36e4a..3387090484eec1 100644 --- a/crates/ruff_linter/src/rules/flake8_bugbear/rules/mutable_argument_default.rs +++ b/crates/ruff_linter/src/rules/flake8_bugbear/rules/mutable_argument_default.rs @@ -141,8 +141,9 @@ fn move_initialization( ) -> Option { let mut body = function_def.body.iter().peekable(); + // Avoid attempting to fix single-line functions. let statement = body.peek()?; - if indexer.in_multi_statement_line(statement, locator) { + if indexer.preceded_by_multi_statement_line(statement, locator) { return None; } @@ -170,15 +171,18 @@ fn move_initialization( // Find the position to insert the initialization after docstring and imports let mut pos = locator.line_start(statement.start()); while let Some(statement) = body.next() { - if is_docstring_stmt(statement) { - // If the statement in the function is a docstring, insert _after_ it. - if let Some(statement) = body.peek() { + // If the statement is a docstring or an import, insert _after_ it. + if is_docstring_stmt(statement) + || statement.is_import_stmt() + || statement.is_import_from_stmt() + { + if let Some(next) = body.peek() { // If there's a second statement, insert _before_ it, but ensure this isn't a // multi-statement line. if indexer.in_multi_statement_line(statement, locator) { - return None; + continue; } - pos = locator.line_start(statement.start()); + pos = locator.line_start(next.start()); } else if locator.full_line_end(statement.end()) == locator.text_len() { // If the statement is at the end of the file, without a trailing newline, insert // _after_ it with an extra newline. @@ -186,16 +190,8 @@ fn move_initialization( pos = locator.full_line_end(statement.end()); break; } else { - // If the docstring is the only statement, insert _after_ it. + // If this is the only statement, insert _after_ it. pos = locator.full_line_end(statement.end()); - } - } else if statement.is_import_stmt() || statement.is_import_from_stmt() { - // If the statement in the function is an import, insert _after_ it. - pos = locator.full_line_end(statement.end()); - if pos == locator.text_len() { - // If the statement is at the end of the file, without a trailing newline, insert - // _after_ it with an extra newline. - content = format!("{}{}", stylist.line_ending().as_str(), content); break; } } else { diff --git a/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B006_B006_5.py.snap b/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B006_B006_5.py.snap index 1624f70c6648da..d741dc3258eba5 100644 --- a/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B006_B006_5.py.snap +++ b/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B006_B006_5.py.snap @@ -37,11 +37,12 @@ B006_5.py:9:61: B006 [*] Do not use mutable data structures for argument default 9 |-def import_module_with_values_wrong(value: dict[str, str] = {}): 9 |+def import_module_with_values_wrong(value: dict[str, str] = None): 10 10 | import os - 11 |+ if value is None: - 12 |+ value = {} -11 13 | +11 11 | + 12 |+ if value is None: + 13 |+ value = {} 12 14 | return 2 13 15 | +14 16 | B006_5.py:15:50: B006 [*] Do not use mutable data structures for argument defaults | @@ -151,8 +152,162 @@ B006_5.py:35:59: B006 [*] Do not use mutable data structures for argument defaul 35 |+def import_docstring_module_wrong(value: dict[str, str] = None): 36 36 | """Docstring""" 37 37 | import os - 38 |+ - 39 |+ if value is None: - 40 |+ value = {} + 38 |+ if value is None: + 39 |+ value = {} +38 40 | +39 41 | +40 42 | def import_module_wrong(value: dict[str, str] = {}): + +B006_5.py:40:49: B006 [*] Do not use mutable data structures for argument defaults + | +40 | def import_module_wrong(value: dict[str, str] = {}): + | ^^ B006 +41 | """Docstring""" +42 | import os; import sys + | + = help: Replace with `None`; initialize within function + +ℹ Possible fix +37 37 | import os +38 38 | +39 39 | +40 |-def import_module_wrong(value: dict[str, str] = {}): + 40 |+def import_module_wrong(value: dict[str, str] = None): +41 41 | """Docstring""" +42 42 | import os; import sys + 43 |+ if value is None: + 44 |+ value = {} +43 45 | +44 46 | +45 47 | def import_module_wrong(value: dict[str, str] = {}): + +B006_5.py:45:49: B006 [*] Do not use mutable data structures for argument defaults + | +45 | def import_module_wrong(value: dict[str, str] = {}): + | ^^ B006 +46 | """Docstring""" +47 | import os; import sys; x = 1 + | + = help: Replace with `None`; initialize within function + +ℹ Possible fix +42 42 | import os; import sys +43 43 | +44 44 | +45 |-def import_module_wrong(value: dict[str, str] = {}): + 45 |+def import_module_wrong(value: dict[str, str] = None): +46 46 | """Docstring""" + 47 |+ if value is None: + 48 |+ value = {} +47 49 | import os; import sys; x = 1 +48 50 | +49 51 | + +B006_5.py:50:49: B006 [*] Do not use mutable data structures for argument defaults + | +50 | def import_module_wrong(value: dict[str, str] = {}): + | ^^ B006 +51 | """Docstring""" +52 | import os; import sys + | + = help: Replace with `None`; initialize within function + +ℹ Possible fix +47 47 | import os; import sys; x = 1 +48 48 | +49 49 | +50 |-def import_module_wrong(value: dict[str, str] = {}): + 50 |+def import_module_wrong(value: dict[str, str] = None): +51 51 | """Docstring""" +52 52 | import os; import sys + 53 |+ if value is None: + 54 |+ value = {} +53 55 | +54 56 | +55 57 | def import_module_wrong(value: dict[str, str] = {}): + +B006_5.py:55:49: B006 [*] Do not use mutable data structures for argument defaults + | +55 | def import_module_wrong(value: dict[str, str] = {}): + | ^^ B006 +56 | import os; import sys + | + = help: Replace with `None`; initialize within function + +ℹ Possible fix +52 52 | import os; import sys +53 53 | +54 54 | +55 |-def import_module_wrong(value: dict[str, str] = {}): + 55 |+def import_module_wrong(value: dict[str, str] = None): +56 56 | import os; import sys + 57 |+ if value is None: + 58 |+ value = {} +57 59 | +58 60 | +59 61 | def import_module_wrong(value: dict[str, str] = {}): + +B006_5.py:59:49: B006 [*] Do not use mutable data structures for argument defaults + | +59 | def import_module_wrong(value: dict[str, str] = {}): + | ^^ B006 +60 | import os; import sys; x = 1 + | + = help: Replace with `None`; initialize within function + +ℹ Possible fix +56 56 | import os; import sys +57 57 | +58 58 | +59 |-def import_module_wrong(value: dict[str, str] = {}): + 59 |+def import_module_wrong(value: dict[str, str] = None): + 60 |+ if value is None: + 61 |+ value = {} +60 62 | import os; import sys; x = 1 +61 63 | +62 64 | + +B006_5.py:63:49: B006 [*] Do not use mutable data structures for argument defaults + | +63 | def import_module_wrong(value: dict[str, str] = {}): + | ^^ B006 +64 | import os; import sys + | + = help: Replace with `None`; initialize within function + +ℹ Possible fix +60 60 | import os; import sys; x = 1 +61 61 | +62 62 | +63 |-def import_module_wrong(value: dict[str, str] = {}): + 63 |+def import_module_wrong(value: dict[str, str] = None): +64 64 | import os; import sys + 65 |+ if value is None: + 66 |+ value = {} +65 67 | +66 68 | +67 69 | def import_module_wrong(value: dict[str, str] = {}): import os + +B006_5.py:67:49: B006 Do not use mutable data structures for argument defaults + | +67 | def import_module_wrong(value: dict[str, str] = {}): import os + | ^^ B006 + | + = help: Replace with `None`; initialize within function + +B006_5.py:70:49: B006 Do not use mutable data structures for argument defaults + | +70 | def import_module_wrong(value: dict[str, str] = {}): import os; import sys + | ^^ B006 + | + = help: Replace with `None`; initialize within function + +B006_5.py:73:49: B006 Do not use mutable data structures for argument defaults + | +73 | def import_module_wrong(value: dict[str, str] = {}): \ + | ^^ B006 +74 | import os + | + = help: Replace with `None`; initialize within function 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 8272eb6aa6a099..6f868ac491c64e 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 @@ -424,7 +424,7 @@ B006_B008.py:288:52: B006 [*] Do not use mutable data structures for argument de 291 293 | 292 294 | -B006_B008.py:293:52: B006 Do not use mutable data structures for argument defaults +B006_B008.py:293:52: B006 [*] Do not use mutable data structures for argument defaults | 293 | def single_line_func_wrong(value: dict[str, str] = {}): | ^^ B006 @@ -432,7 +432,19 @@ B006_B008.py:293:52: B006 Do not use mutable data structures for argument defaul | = help: Replace with `None`; initialize within function -B006_B008.py:297:52: B006 Do not use mutable data structures for argument defaults +ℹ Possible fix +290 290 | ... +291 291 | +292 292 | +293 |-def single_line_func_wrong(value: dict[str, str] = {}): + 293 |+def single_line_func_wrong(value: dict[str, str] = None): + 294 |+ if value is None: + 295 |+ value = {} +294 296 | """Docstring"""; ... +295 297 | +296 298 | + +B006_B008.py:297:52: B006 [*] Do not use mutable data structures for argument defaults | 297 | def single_line_func_wrong(value: dict[str, str] = {}): | ^^ B006 @@ -441,6 +453,18 @@ B006_B008.py:297:52: B006 Do not use mutable data structures for argument defaul | = help: Replace with `None`; initialize within function +ℹ Possible fix +294 294 | """Docstring"""; ... +295 295 | +296 296 | +297 |-def single_line_func_wrong(value: dict[str, str] = {}): + 297 |+def single_line_func_wrong(value: dict[str, str] = None): + 298 |+ if value is None: + 299 |+ value = {} +298 300 | """Docstring"""; \ +299 301 | ... +300 302 | + B006_B008.py:302:52: B006 [*] Do not use mutable data structures for argument defaults | 302 | def single_line_func_wrong(value: dict[str, str] = {