Skip to content

Commit

Permalink
[flake8-bugbear] Avoid adding default initializers to stubs (`B006…
Browse files Browse the repository at this point in the history
…`) (#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
  • Loading branch information
Philipp-Thiel authored Feb 28, 2024
1 parent 8f92da8 commit 36bc725
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 146 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use ast::call_path::{from_qualified_name, CallPath};
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::is_docstring_stmt;
use ruff_python_ast::{self as ast, Expr, Parameter, ParameterWithDefault};
use ruff_python_ast::{self as ast, Expr, Parameter, ParameterWithDefault, Stmt};
use ruff_python_codegen::{Generator, Stylist};
use ruff_python_index::Indexer;
use ruff_python_semantic::analyze::typing::{is_immutable_annotation, is_mutable_expr};
Expand Down Expand Up @@ -152,6 +152,11 @@ fn move_initialization(
// Set the default argument value to `None`.
let default_edit = Edit::range_replacement("None".to_string(), default.range());

// If the function is a stub, this is the only necessary edit.
if is_stub(function_def) {
return Some(Fix::unsafe_edit(default_edit));
}

// Add an `if`, to set the argument to its original value if still `None`.
let mut content = String::new();
content.push_str(&format!("if {} is None:", parameter.name.as_str()));
Expand Down Expand Up @@ -204,3 +209,20 @@ fn move_initialization(
let initialization_edit = Edit::insertion(content, pos);
Some(Fix::unsafe_edits(default_edit, [initialization_edit]))
}

/// Returns `true` if a function has an empty body, and is therefore a stub.
///
/// A function body is considered to be empty if it contains only `pass` statements, `...` literals,
/// and docstrings.
fn is_stub(function_def: &ast::StmtFunctionDef) -> bool {
function_def.body.iter().all(|stmt| match stmt {
Stmt::Pass(_) => true,
Stmt::Expr(ast::StmtExpr { value, range: _ }) => {
matches!(
value.as_ref(),
Expr::StringLiteral(_) | Expr::EllipsisLiteral(_)
)
}
_ => false,
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,3 @@ B006_1.py:3:22: B006 [*] Do not use mutable data structures for argument default
3 |+def foobar(foor, bar=None):
4 4 | """
5 5 | """
6 |+
7 |+ if bar is None:
8 |+ bar = {}


Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,4 @@ B006_2.py:4:22: B006 [*] Do not use mutable data structures for argument default
4 |-def foobar(foor, bar={}):
4 |+def foobar(foor, bar=None):
5 5 | """
6 |- """
6 |+ """
7 |+ if bar is None:
8 |+ bar = {}


6 6 | """
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,5 @@ B006_3.py:4:22: B006 [*] Do not use mutable data structures for argument default
3 3 |
4 |-def foobar(foor, bar={}):
4 |+def foobar(foor, bar=None):
5 |+ """
5 6 | """
6 |- """
7 |+ if bar is None:
8 |+ bar = {}


5 5 | """
6 6 | """
Loading

0 comments on commit 36bc725

Please sign in to comment.