Skip to content

Commit 36bc725

Browse files
[flake8-bugbear] Avoid adding default initializers to stubs (B006) (#10152)
## Summary Adapts the fix for rule B006 to no longer modify the body of function stubs, while retaining the change in method signature. ## Test Plan The existing tests for B006 were adapted to reflect this change in behavior. ## Relevant issue #10083
1 parent 8f92da8 commit 36bc725

6 files changed

+87
-146
lines changed

crates/ruff_linter/src/rules/flake8_bugbear/rules/mutable_argument_default.rs

+23-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use ast::call_path::{from_qualified_name, CallPath};
22
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
33
use ruff_macros::{derive_message_formats, violation};
44
use ruff_python_ast::helpers::is_docstring_stmt;
5-
use ruff_python_ast::{self as ast, Expr, Parameter, ParameterWithDefault};
5+
use ruff_python_ast::{self as ast, Expr, Parameter, ParameterWithDefault, Stmt};
66
use ruff_python_codegen::{Generator, Stylist};
77
use ruff_python_index::Indexer;
88
use ruff_python_semantic::analyze::typing::{is_immutable_annotation, is_mutable_expr};
@@ -152,6 +152,11 @@ fn move_initialization(
152152
// Set the default argument value to `None`.
153153
let default_edit = Edit::range_replacement("None".to_string(), default.range());
154154

155+
// If the function is a stub, this is the only necessary edit.
156+
if is_stub(function_def) {
157+
return Some(Fix::unsafe_edit(default_edit));
158+
}
159+
155160
// Add an `if`, to set the argument to its original value if still `None`.
156161
let mut content = String::new();
157162
content.push_str(&format!("if {} is None:", parameter.name.as_str()));
@@ -204,3 +209,20 @@ fn move_initialization(
204209
let initialization_edit = Edit::insertion(content, pos);
205210
Some(Fix::unsafe_edits(default_edit, [initialization_edit]))
206211
}
212+
213+
/// Returns `true` if a function has an empty body, and is therefore a stub.
214+
///
215+
/// A function body is considered to be empty if it contains only `pass` statements, `...` literals,
216+
/// and docstrings.
217+
fn is_stub(function_def: &ast::StmtFunctionDef) -> bool {
218+
function_def.body.iter().all(|stmt| match stmt {
219+
Stmt::Pass(_) => true,
220+
Stmt::Expr(ast::StmtExpr { value, range: _ }) => {
221+
matches!(
222+
value.as_ref(),
223+
Expr::StringLiteral(_) | Expr::EllipsisLiteral(_)
224+
)
225+
}
226+
_ => false,
227+
})
228+
}

crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B006_B006_1.py.snap

-5
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,3 @@ B006_1.py:3:22: B006 [*] Do not use mutable data structures for argument default
1919
3 |+def foobar(foor, bar=None):
2020
4 4 | """
2121
5 5 | """
22-
6 |+
23-
7 |+ if bar is None:
24-
8 |+ bar = {}
25-
26-

crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B006_B006_2.py.snap

+1-6
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,4 @@ B006_2.py:4:22: B006 [*] Do not use mutable data structures for argument default
1919
4 |-def foobar(foor, bar={}):
2020
4 |+def foobar(foor, bar=None):
2121
5 5 | """
22-
6 |- """
23-
6 |+ """
24-
7 |+ if bar is None:
25-
8 |+ bar = {}
26-
27-
22+
6 6 | """

crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B006_B006_3.py.snap

+2-7
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,5 @@ B006_3.py:4:22: B006 [*] Do not use mutable data structures for argument default
1616
3 3 |
1717
4 |-def foobar(foor, bar={}):
1818
4 |+def foobar(foor, bar=None):
19-
5 |+ """
20-
5 6 | """
21-
6 |- """
22-
7 |+ if bar is None:
23-
8 |+ bar = {}
24-
25-
19+
5 5 | """
20+
6 6 | """

0 commit comments

Comments
 (0)