mirror of
https://github.com/astral-sh/ruff.git
synced 2025-11-13 17:26:53 +00:00
[flake8-bugbear] Include certain guaranteed-mutable expressions: tuples, generators, and assignment expressions (B006) (#20024)
Some checks are pending
CI / cargo build (msrv) (push) Blocked by required conditions
CI / cargo fuzz build (push) Blocked by required conditions
CI / python package (push) Waiting to run
CI / Determine changes (push) Waiting to run
CI / cargo fmt (push) Waiting to run
CI / cargo clippy (push) Blocked by required conditions
CI / cargo test (linux) (push) Blocked by required conditions
CI / cargo test (linux, release) (push) Blocked by required conditions
CI / cargo test (windows) (push) Blocked by required conditions
CI / cargo test (wasm) (push) Blocked by required conditions
CI / cargo build (release) (push) Waiting to run
CI / fuzz parser (push) Blocked by required conditions
CI / test scripts (push) Blocked by required conditions
CI / ecosystem (push) Blocked by required conditions
CI / Fuzz for new ty panics (push) Blocked by required conditions
CI / cargo shear (push) Blocked by required conditions
CI / pre-commit (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / formatter instabilities and black similarity (push) Blocked by required conditions
CI / test ruff-lsp (push) Blocked by required conditions
CI / check playground (push) Blocked by required conditions
CI / benchmarks instrumented (ruff) (push) Blocked by required conditions
CI / benchmarks instrumented (ty) (push) Blocked by required conditions
CI / benchmarks-walltime (push) Blocked by required conditions
[ty Playground] Release / publish (push) Waiting to run
Some checks are pending
CI / cargo build (msrv) (push) Blocked by required conditions
CI / cargo fuzz build (push) Blocked by required conditions
CI / python package (push) Waiting to run
CI / Determine changes (push) Waiting to run
CI / cargo fmt (push) Waiting to run
CI / cargo clippy (push) Blocked by required conditions
CI / cargo test (linux) (push) Blocked by required conditions
CI / cargo test (linux, release) (push) Blocked by required conditions
CI / cargo test (windows) (push) Blocked by required conditions
CI / cargo test (wasm) (push) Blocked by required conditions
CI / cargo build (release) (push) Waiting to run
CI / fuzz parser (push) Blocked by required conditions
CI / test scripts (push) Blocked by required conditions
CI / ecosystem (push) Blocked by required conditions
CI / Fuzz for new ty panics (push) Blocked by required conditions
CI / cargo shear (push) Blocked by required conditions
CI / pre-commit (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / formatter instabilities and black similarity (push) Blocked by required conditions
CI / test ruff-lsp (push) Blocked by required conditions
CI / check playground (push) Blocked by required conditions
CI / benchmarks instrumented (ruff) (push) Blocked by required conditions
CI / benchmarks instrumented (ty) (push) Blocked by required conditions
CI / benchmarks-walltime (push) Blocked by required conditions
[ty Playground] Release / publish (push) Waiting to run
## Summary Resolves #20004 The implementation now supports guaranteed-mutable expressions in the following cases: - Tuple literals with mutable elements (supporting deep nesting) - Generator expressions - Named expressions (walrus operator) containing mutable components Preserves original formatting for assignment value: ```python # Test case def f5(x=([1, ])): print(x) ``` ```python # Fix before def f5(x=(None)): if x is None: x = [1] print(x) ``` ```python # Fix after def f5(x=None): if x is None: x = ([1, ]) print(x) ``` The expansion of detected expressions and the new fixes gated behind previews. ## Test Plan - Added B006_9.py with a bunch of test cases - Generated snapshots --------- Co-authored-by: Igor Drokin <drokinii1017@gmail.com> Co-authored-by: dylwil3 <dylwil3@gmail.com>
This commit is contained in:
parent
805d179dc0
commit
673167a565
16 changed files with 1249 additions and 32 deletions
26
crates/ruff_linter/resources/test/fixtures/flake8_bugbear/B006_9.py
vendored
Normal file
26
crates/ruff_linter/resources/test/fixtures/flake8_bugbear/B006_9.py
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
def f1(x=([],)):
|
||||||
|
print(x)
|
||||||
|
|
||||||
|
|
||||||
|
def f2(x=(x for x in "x")):
|
||||||
|
print(x)
|
||||||
|
|
||||||
|
|
||||||
|
def f3(x=((x for x in "x"),)):
|
||||||
|
print(x)
|
||||||
|
|
||||||
|
|
||||||
|
def f4(x=(z := [1, ])):
|
||||||
|
print(x)
|
||||||
|
|
||||||
|
|
||||||
|
def f5(x=([1, ])):
|
||||||
|
print(x)
|
||||||
|
|
||||||
|
|
||||||
|
def w1(x=(1,)):
|
||||||
|
print(x)
|
||||||
|
|
||||||
|
|
||||||
|
def w2(x=(z := 3)):
|
||||||
|
print(x)
|
||||||
|
|
@ -245,3 +245,17 @@ pub(crate) const fn is_a003_class_scope_shadowing_expansion_enabled(
|
||||||
pub(crate) const fn is_refined_submodule_import_match_enabled(settings: &LinterSettings) -> bool {
|
pub(crate) const fn is_refined_submodule_import_match_enabled(settings: &LinterSettings) -> bool {
|
||||||
settings.preview.is_enabled()
|
settings.preview.is_enabled()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// github.com/astral-sh/ruff/issues/20004
|
||||||
|
pub(crate) const fn is_b006_check_guaranteed_mutable_expr_enabled(
|
||||||
|
settings: &LinterSettings,
|
||||||
|
) -> bool {
|
||||||
|
settings.preview.is_enabled()
|
||||||
|
}
|
||||||
|
|
||||||
|
// github.com/astral-sh/ruff/issues/20004
|
||||||
|
pub(crate) const fn is_b006_unsafe_fix_preserve_assignment_expr_enabled(
|
||||||
|
settings: &LinterSettings,
|
||||||
|
) -> bool {
|
||||||
|
settings.preview.is_enabled()
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@ mod tests {
|
||||||
#[test_case(Rule::MutableArgumentDefault, Path::new("B006_6.py"))]
|
#[test_case(Rule::MutableArgumentDefault, Path::new("B006_6.py"))]
|
||||||
#[test_case(Rule::MutableArgumentDefault, Path::new("B006_7.py"))]
|
#[test_case(Rule::MutableArgumentDefault, Path::new("B006_7.py"))]
|
||||||
#[test_case(Rule::MutableArgumentDefault, Path::new("B006_8.py"))]
|
#[test_case(Rule::MutableArgumentDefault, Path::new("B006_8.py"))]
|
||||||
|
#[test_case(Rule::MutableArgumentDefault, Path::new("B006_9.py"))]
|
||||||
#[test_case(Rule::MutableArgumentDefault, Path::new("B006_B008.py"))]
|
#[test_case(Rule::MutableArgumentDefault, Path::new("B006_B008.py"))]
|
||||||
#[test_case(Rule::MutableArgumentDefault, Path::new("B006_1.pyi"))]
|
#[test_case(Rule::MutableArgumentDefault, Path::new("B006_1.pyi"))]
|
||||||
#[test_case(Rule::NoExplicitStacklevel, Path::new("B028.py"))]
|
#[test_case(Rule::NoExplicitStacklevel, Path::new("B028.py"))]
|
||||||
|
|
@ -83,6 +84,17 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test_case(Rule::MapWithoutExplicitStrict, Path::new("B912.py"))]
|
#[test_case(Rule::MapWithoutExplicitStrict, Path::new("B912.py"))]
|
||||||
|
#[test_case(Rule::MutableArgumentDefault, Path::new("B006_1.py"))]
|
||||||
|
#[test_case(Rule::MutableArgumentDefault, Path::new("B006_2.py"))]
|
||||||
|
#[test_case(Rule::MutableArgumentDefault, Path::new("B006_3.py"))]
|
||||||
|
#[test_case(Rule::MutableArgumentDefault, Path::new("B006_4.py"))]
|
||||||
|
#[test_case(Rule::MutableArgumentDefault, Path::new("B006_5.py"))]
|
||||||
|
#[test_case(Rule::MutableArgumentDefault, Path::new("B006_6.py"))]
|
||||||
|
#[test_case(Rule::MutableArgumentDefault, Path::new("B006_7.py"))]
|
||||||
|
#[test_case(Rule::MutableArgumentDefault, Path::new("B006_8.py"))]
|
||||||
|
#[test_case(Rule::MutableArgumentDefault, Path::new("B006_9.py"))]
|
||||||
|
#[test_case(Rule::MutableArgumentDefault, Path::new("B006_B008.py"))]
|
||||||
|
#[test_case(Rule::MutableArgumentDefault, Path::new("B006_1.pyi"))]
|
||||||
fn preview_rules(rule_code: Rule, path: &Path) -> Result<()> {
|
fn preview_rules(rule_code: Rule, path: &Path) -> Result<()> {
|
||||||
let snapshot = format!(
|
let snapshot = format!(
|
||||||
"preview__{}_{}",
|
"preview__{}_{}",
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,8 @@ use std::fmt::Write;
|
||||||
use ruff_macros::{ViolationMetadata, derive_message_formats};
|
use ruff_macros::{ViolationMetadata, derive_message_formats};
|
||||||
use ruff_python_ast::helpers::is_docstring_stmt;
|
use ruff_python_ast::helpers::is_docstring_stmt;
|
||||||
use ruff_python_ast::name::QualifiedName;
|
use ruff_python_ast::name::QualifiedName;
|
||||||
use ruff_python_ast::{self as ast, Expr, Parameter};
|
use ruff_python_ast::parenthesize::parenthesized_range;
|
||||||
use ruff_python_codegen::{Generator, Stylist};
|
use ruff_python_ast::{self as ast, Expr, ParameterWithDefault};
|
||||||
use ruff_python_index::Indexer;
|
|
||||||
use ruff_python_semantic::SemanticModel;
|
use ruff_python_semantic::SemanticModel;
|
||||||
use ruff_python_semantic::analyze::function_type::is_stub;
|
use ruff_python_semantic::analyze::function_type::is_stub;
|
||||||
use ruff_python_semantic::analyze::typing::{is_immutable_annotation, is_mutable_expr};
|
use ruff_python_semantic::analyze::typing::{is_immutable_annotation, is_mutable_expr};
|
||||||
|
|
@ -13,8 +12,11 @@ use ruff_python_trivia::{indentation_at_offset, textwrap};
|
||||||
use ruff_source_file::LineRanges;
|
use ruff_source_file::LineRanges;
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::Locator;
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
|
use crate::preview::{
|
||||||
|
is_b006_check_guaranteed_mutable_expr_enabled,
|
||||||
|
is_b006_unsafe_fix_preserve_assignment_expr_enabled,
|
||||||
|
};
|
||||||
use crate::{Edit, Fix, FixAvailability, Violation};
|
use crate::{Edit, Fix, FixAvailability, Violation};
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
|
|
@ -111,8 +113,12 @@ pub(crate) fn mutable_argument_default(checker: &Checker, function_def: &ast::St
|
||||||
.iter()
|
.iter()
|
||||||
.map(|target| QualifiedName::from_dotted_name(target))
|
.map(|target| QualifiedName::from_dotted_name(target))
|
||||||
.collect();
|
.collect();
|
||||||
|
let is_mut_expr = if is_b006_check_guaranteed_mutable_expr_enabled(checker.settings()) {
|
||||||
if is_mutable_expr(default, checker.semantic())
|
is_guaranteed_mutable_expr(default, checker.semantic())
|
||||||
|
} else {
|
||||||
|
is_mutable_expr(default, checker.semantic())
|
||||||
|
};
|
||||||
|
if is_mut_expr
|
||||||
&& !parameter.annotation().is_some_and(|expr| {
|
&& !parameter.annotation().is_some_and(|expr| {
|
||||||
is_immutable_annotation(expr, checker.semantic(), extend_immutable_calls.as_slice())
|
is_immutable_annotation(expr, checker.semantic(), extend_immutable_calls.as_slice())
|
||||||
})
|
})
|
||||||
|
|
@ -120,35 +126,37 @@ pub(crate) fn mutable_argument_default(checker: &Checker, function_def: &ast::St
|
||||||
let mut diagnostic = checker.report_diagnostic(MutableArgumentDefault, default.range());
|
let mut diagnostic = checker.report_diagnostic(MutableArgumentDefault, default.range());
|
||||||
|
|
||||||
// If the function body is on the same line as the function def, do not fix
|
// If the function body is on the same line as the function def, do not fix
|
||||||
if let Some(fix) = move_initialization(
|
if let Some(fix) = move_initialization(function_def, parameter, default, checker) {
|
||||||
function_def,
|
|
||||||
¶meter.parameter,
|
|
||||||
default,
|
|
||||||
checker.semantic(),
|
|
||||||
checker.locator(),
|
|
||||||
checker.stylist(),
|
|
||||||
checker.indexer(),
|
|
||||||
checker.generator(),
|
|
||||||
) {
|
|
||||||
diagnostic.set_fix(fix);
|
diagnostic.set_fix(fix);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if the expression is guaranteed to create a mutable object.
|
||||||
|
fn is_guaranteed_mutable_expr(expr: &Expr, semantic: &SemanticModel) -> bool {
|
||||||
|
match expr {
|
||||||
|
Expr::Generator(_) => true,
|
||||||
|
Expr::Tuple(ast::ExprTuple { elts, .. }) => {
|
||||||
|
elts.iter().any(|e| is_guaranteed_mutable_expr(e, semantic))
|
||||||
|
}
|
||||||
|
Expr::Named(ast::ExprNamed { value, .. }) => is_guaranteed_mutable_expr(value, semantic),
|
||||||
|
_ => is_mutable_expr(expr, semantic),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Generate a [`Fix`] to move a mutable argument default initialization
|
/// Generate a [`Fix`] to move a mutable argument default initialization
|
||||||
/// into the function body.
|
/// into the function body.
|
||||||
#[expect(clippy::too_many_arguments)]
|
|
||||||
fn move_initialization(
|
fn move_initialization(
|
||||||
function_def: &ast::StmtFunctionDef,
|
function_def: &ast::StmtFunctionDef,
|
||||||
parameter: &Parameter,
|
parameter: &ParameterWithDefault,
|
||||||
default: &Expr,
|
default: &Expr,
|
||||||
semantic: &SemanticModel,
|
checker: &Checker,
|
||||||
locator: &Locator,
|
|
||||||
stylist: &Stylist,
|
|
||||||
indexer: &Indexer,
|
|
||||||
generator: Generator,
|
|
||||||
) -> Option<Fix> {
|
) -> Option<Fix> {
|
||||||
|
let indexer = checker.indexer();
|
||||||
|
let locator = checker.locator();
|
||||||
|
let stylist = checker.stylist();
|
||||||
|
|
||||||
let mut body = function_def.body.iter().peekable();
|
let mut body = function_def.body.iter().peekable();
|
||||||
|
|
||||||
// Avoid attempting to fix single-line functions.
|
// Avoid attempting to fix single-line functions.
|
||||||
|
|
@ -157,25 +165,58 @@ fn move_initialization(
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let range = match parenthesized_range(
|
||||||
|
default.into(),
|
||||||
|
parameter.into(),
|
||||||
|
checker.comment_ranges(),
|
||||||
|
checker.source(),
|
||||||
|
) {
|
||||||
|
Some(range) => range,
|
||||||
|
None => default.range(),
|
||||||
|
};
|
||||||
// Set the default argument value to `None`.
|
// Set the default argument value to `None`.
|
||||||
let default_edit = Edit::range_replacement("None".to_string(), default.range());
|
let default_edit = Edit::range_replacement("None".to_string(), range);
|
||||||
|
|
||||||
// If the function is a stub, this is the only necessary edit.
|
// If the function is a stub, this is the only necessary edit.
|
||||||
if is_stub(function_def, semantic) {
|
if is_stub(function_def, checker.semantic()) {
|
||||||
return Some(Fix::unsafe_edit(default_edit));
|
return Some(Fix::unsafe_edit(default_edit));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add an `if`, to set the argument to its original value if still `None`.
|
// Add an `if`, to set the argument to its original value if still `None`.
|
||||||
let mut content = String::new();
|
let mut content = String::new();
|
||||||
let _ = write!(&mut content, "if {} is None:", parameter.name());
|
let _ = write!(&mut content, "if {} is None:", parameter.parameter.name());
|
||||||
content.push_str(stylist.line_ending().as_str());
|
content.push_str(stylist.line_ending().as_str());
|
||||||
content.push_str(stylist.indentation());
|
content.push_str(stylist.indentation());
|
||||||
|
if is_b006_unsafe_fix_preserve_assignment_expr_enabled(checker.settings()) {
|
||||||
|
let annotation = if let Some(ann) = parameter.annotation() {
|
||||||
|
format!(": {}", locator.slice(ann))
|
||||||
|
} else {
|
||||||
|
String::new()
|
||||||
|
};
|
||||||
|
let _ = write!(
|
||||||
|
&mut content,
|
||||||
|
"{}{} = {}",
|
||||||
|
parameter.parameter.name(),
|
||||||
|
annotation,
|
||||||
|
locator.slice(
|
||||||
|
parenthesized_range(
|
||||||
|
default.into(),
|
||||||
|
parameter.into(),
|
||||||
|
checker.comment_ranges(),
|
||||||
|
checker.source()
|
||||||
|
)
|
||||||
|
.unwrap_or(default.range())
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
let _ = write!(
|
let _ = write!(
|
||||||
&mut content,
|
&mut content,
|
||||||
"{} = {}",
|
"{} = {}",
|
||||||
parameter.name(),
|
parameter.name(),
|
||||||
generator.expr(default)
|
checker.generator().expr(default)
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
content.push_str(stylist.line_ending().as_str());
|
content.push_str(stylist.line_ending().as_str());
|
||||||
|
|
||||||
// Determine the indentation depth of the function body.
|
// Determine the indentation depth of the function body.
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/flake8_bugbear/mod.rs
|
||||||
|
---
|
||||||
|
B006 [*] Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_9.py:17:11
|
||||||
|
|
|
||||||
|
17 | def f5(x=([1, ])):
|
||||||
|
| ^^^^^
|
||||||
|
18 | print(x)
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
14 | print(x)
|
||||||
|
15 |
|
||||||
|
16 |
|
||||||
|
- def f5(x=([1, ])):
|
||||||
|
17 + def f5(x=None):
|
||||||
|
18 + if x is None:
|
||||||
|
19 + x = [1]
|
||||||
|
20 | print(x)
|
||||||
|
21 |
|
||||||
|
22 |
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/flake8_bugbear/mod.rs
|
||||||
|
---
|
||||||
|
B006 [*] Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_1.py:3:22
|
||||||
|
|
|
||||||
|
1 | # Docstring followed by a newline
|
||||||
|
2 |
|
||||||
|
3 | def foobar(foor, bar={}):
|
||||||
|
| ^^
|
||||||
|
4 | """
|
||||||
|
5 | """
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
1 | # Docstring followed by a newline
|
||||||
|
2 |
|
||||||
|
- def foobar(foor, bar={}):
|
||||||
|
3 + def foobar(foor, bar=None):
|
||||||
|
4 | """
|
||||||
|
5 | """
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/flake8_bugbear/mod.rs
|
||||||
|
---
|
||||||
|
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/flake8_bugbear/mod.rs
|
||||||
|
---
|
||||||
|
B006 [*] Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_2.py:4:22
|
||||||
|
|
|
||||||
|
2 | # Regression test for https://github.com/astral-sh/ruff/issues/7155
|
||||||
|
3 |
|
||||||
|
4 | def foobar(foor, bar={}):
|
||||||
|
| ^^
|
||||||
|
5 | """
|
||||||
|
6 | """
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
1 | # Docstring followed by whitespace with no newline
|
||||||
|
2 | # Regression test for https://github.com/astral-sh/ruff/issues/7155
|
||||||
|
3 |
|
||||||
|
- def foobar(foor, bar={}):
|
||||||
|
4 + def foobar(foor, bar=None):
|
||||||
|
5 | """
|
||||||
|
6 | """
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/flake8_bugbear/mod.rs
|
||||||
|
---
|
||||||
|
B006 [*] Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_3.py:4:22
|
||||||
|
|
|
||||||
|
4 | def foobar(foor, bar={}):
|
||||||
|
| ^^
|
||||||
|
5 | """
|
||||||
|
6 | """
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
1 | # Docstring with no newline
|
||||||
|
2 |
|
||||||
|
3 |
|
||||||
|
- def foobar(foor, bar={}):
|
||||||
|
4 + def foobar(foor, bar=None):
|
||||||
|
5 | """
|
||||||
|
6 | """
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/flake8_bugbear/mod.rs
|
||||||
|
---
|
||||||
|
B006 [*] Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_4.py:7:26
|
||||||
|
|
|
||||||
|
6 | class FormFeedIndent:
|
||||||
|
7 | def __init__(self, a=[]):
|
||||||
|
| ^^
|
||||||
|
8 | print(a)
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
4 |
|
||||||
|
5 |
|
||||||
|
6 | class FormFeedIndent:
|
||||||
|
- def __init__(self, a=[]):
|
||||||
|
7 + def __init__(self, a=None):
|
||||||
|
8 + if a is None:
|
||||||
|
9 + a = []
|
||||||
|
10 | print(a)
|
||||||
|
11 |
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
@ -0,0 +1,314 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/flake8_bugbear/mod.rs
|
||||||
|
---
|
||||||
|
B006 [*] Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_5.py:5:49
|
||||||
|
|
|
||||||
|
5 | def import_module_wrong(value: dict[str, str] = {}):
|
||||||
|
| ^^
|
||||||
|
6 | import os
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
2 | # https://github.com/astral-sh/ruff/issues/7616
|
||||||
|
3 |
|
||||||
|
4 |
|
||||||
|
- def import_module_wrong(value: dict[str, str] = {}):
|
||||||
|
5 + def import_module_wrong(value: dict[str, str] = None):
|
||||||
|
6 | import os
|
||||||
|
7 + if value is None:
|
||||||
|
8 + value: dict[str, str] = {}
|
||||||
|
9 |
|
||||||
|
10 |
|
||||||
|
11 | def import_module_with_values_wrong(value: dict[str, str] = {}):
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
||||||
|
B006 [*] Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_5.py:9:61
|
||||||
|
|
|
||||||
|
9 | def import_module_with_values_wrong(value: dict[str, str] = {}):
|
||||||
|
| ^^
|
||||||
|
10 | import os
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
6 | import os
|
||||||
|
7 |
|
||||||
|
8 |
|
||||||
|
- def import_module_with_values_wrong(value: dict[str, str] = {}):
|
||||||
|
9 + def import_module_with_values_wrong(value: dict[str, str] = None):
|
||||||
|
10 | import os
|
||||||
|
11 |
|
||||||
|
12 + if value is None:
|
||||||
|
13 + value: dict[str, str] = {}
|
||||||
|
14 | return 2
|
||||||
|
15 |
|
||||||
|
16 |
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
||||||
|
B006 [*] Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_5.py:15:50
|
||||||
|
|
|
||||||
|
15 | def import_modules_wrong(value: dict[str, str] = {}):
|
||||||
|
| ^^
|
||||||
|
16 | import os
|
||||||
|
17 | import sys
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
12 | return 2
|
||||||
|
13 |
|
||||||
|
14 |
|
||||||
|
- def import_modules_wrong(value: dict[str, str] = {}):
|
||||||
|
15 + def import_modules_wrong(value: dict[str, str] = None):
|
||||||
|
16 | import os
|
||||||
|
17 | import sys
|
||||||
|
18 | import itertools
|
||||||
|
19 + if value is None:
|
||||||
|
20 + value: dict[str, str] = {}
|
||||||
|
21 |
|
||||||
|
22 |
|
||||||
|
23 | def from_import_module_wrong(value: dict[str, str] = {}):
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
||||||
|
B006 [*] Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_5.py:21:54
|
||||||
|
|
|
||||||
|
21 | def from_import_module_wrong(value: dict[str, str] = {}):
|
||||||
|
| ^^
|
||||||
|
22 | from os import path
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
18 | import itertools
|
||||||
|
19 |
|
||||||
|
20 |
|
||||||
|
- def from_import_module_wrong(value: dict[str, str] = {}):
|
||||||
|
21 + def from_import_module_wrong(value: dict[str, str] = None):
|
||||||
|
22 | from os import path
|
||||||
|
23 + if value is None:
|
||||||
|
24 + value: dict[str, str] = {}
|
||||||
|
25 |
|
||||||
|
26 |
|
||||||
|
27 | def from_imports_module_wrong(value: dict[str, str] = {}):
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
||||||
|
B006 [*] Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_5.py:25:55
|
||||||
|
|
|
||||||
|
25 | def from_imports_module_wrong(value: dict[str, str] = {}):
|
||||||
|
| ^^
|
||||||
|
26 | from os import path
|
||||||
|
27 | from sys import version_info
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
22 | from os import path
|
||||||
|
23 |
|
||||||
|
24 |
|
||||||
|
- def from_imports_module_wrong(value: dict[str, str] = {}):
|
||||||
|
25 + def from_imports_module_wrong(value: dict[str, str] = None):
|
||||||
|
26 | from os import path
|
||||||
|
27 | from sys import version_info
|
||||||
|
28 + if value is None:
|
||||||
|
29 + value: dict[str, str] = {}
|
||||||
|
30 |
|
||||||
|
31 |
|
||||||
|
32 | def import_and_from_imports_module_wrong(value: dict[str, str] = {}):
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
||||||
|
B006 [*] Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_5.py:30:66
|
||||||
|
|
|
||||||
|
30 | def import_and_from_imports_module_wrong(value: dict[str, str] = {}):
|
||||||
|
| ^^
|
||||||
|
31 | import os
|
||||||
|
32 | from sys import version_info
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
27 | from sys import version_info
|
||||||
|
28 |
|
||||||
|
29 |
|
||||||
|
- def import_and_from_imports_module_wrong(value: dict[str, str] = {}):
|
||||||
|
30 + def import_and_from_imports_module_wrong(value: dict[str, str] = None):
|
||||||
|
31 | import os
|
||||||
|
32 | from sys import version_info
|
||||||
|
33 + if value is None:
|
||||||
|
34 + value: dict[str, str] = {}
|
||||||
|
35 |
|
||||||
|
36 |
|
||||||
|
37 | def import_docstring_module_wrong(value: dict[str, str] = {}):
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
||||||
|
B006 [*] Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_5.py:35:59
|
||||||
|
|
|
||||||
|
35 | def import_docstring_module_wrong(value: dict[str, str] = {}):
|
||||||
|
| ^^
|
||||||
|
36 | """Docstring"""
|
||||||
|
37 | import os
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
32 | from sys import version_info
|
||||||
|
33 |
|
||||||
|
34 |
|
||||||
|
- def import_docstring_module_wrong(value: dict[str, str] = {}):
|
||||||
|
35 + def import_docstring_module_wrong(value: dict[str, str] = None):
|
||||||
|
36 | """Docstring"""
|
||||||
|
37 | import os
|
||||||
|
38 + if value is None:
|
||||||
|
39 + value: dict[str, str] = {}
|
||||||
|
40 |
|
||||||
|
41 |
|
||||||
|
42 | def import_module_wrong(value: dict[str, str] = {}):
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
||||||
|
B006 [*] Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_5.py:40:49
|
||||||
|
|
|
||||||
|
40 | def import_module_wrong(value: dict[str, str] = {}):
|
||||||
|
| ^^
|
||||||
|
41 | """Docstring"""
|
||||||
|
42 | import os; import sys
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
37 | import os
|
||||||
|
38 |
|
||||||
|
39 |
|
||||||
|
- def import_module_wrong(value: dict[str, str] = {}):
|
||||||
|
40 + def import_module_wrong(value: dict[str, str] = None):
|
||||||
|
41 | """Docstring"""
|
||||||
|
42 | import os; import sys
|
||||||
|
43 + if value is None:
|
||||||
|
44 + value: dict[str, str] = {}
|
||||||
|
45 |
|
||||||
|
46 |
|
||||||
|
47 | def import_module_wrong(value: dict[str, str] = {}):
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
||||||
|
B006 [*] Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_5.py:45:49
|
||||||
|
|
|
||||||
|
45 | def import_module_wrong(value: dict[str, str] = {}):
|
||||||
|
| ^^
|
||||||
|
46 | """Docstring"""
|
||||||
|
47 | import os; import sys; x = 1
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
42 | import os; import sys
|
||||||
|
43 |
|
||||||
|
44 |
|
||||||
|
- def import_module_wrong(value: dict[str, str] = {}):
|
||||||
|
45 + def import_module_wrong(value: dict[str, str] = None):
|
||||||
|
46 | """Docstring"""
|
||||||
|
47 + if value is None:
|
||||||
|
48 + value: dict[str, str] = {}
|
||||||
|
49 | import os; import sys; x = 1
|
||||||
|
50 |
|
||||||
|
51 |
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
||||||
|
B006 [*] Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_5.py:50:49
|
||||||
|
|
|
||||||
|
50 | def import_module_wrong(value: dict[str, str] = {}):
|
||||||
|
| ^^
|
||||||
|
51 | """Docstring"""
|
||||||
|
52 | import os; import sys
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
47 | import os; import sys; x = 1
|
||||||
|
48 |
|
||||||
|
49 |
|
||||||
|
- def import_module_wrong(value: dict[str, str] = {}):
|
||||||
|
50 + def import_module_wrong(value: dict[str, str] = None):
|
||||||
|
51 | """Docstring"""
|
||||||
|
52 | import os; import sys
|
||||||
|
53 + if value is None:
|
||||||
|
54 + value: dict[str, str] = {}
|
||||||
|
55 |
|
||||||
|
56 |
|
||||||
|
57 | def import_module_wrong(value: dict[str, str] = {}):
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
||||||
|
B006 [*] Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_5.py:55:49
|
||||||
|
|
|
||||||
|
55 | def import_module_wrong(value: dict[str, str] = {}):
|
||||||
|
| ^^
|
||||||
|
56 | import os; import sys
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
52 | import os; import sys
|
||||||
|
53 |
|
||||||
|
54 |
|
||||||
|
- def import_module_wrong(value: dict[str, str] = {}):
|
||||||
|
55 + def import_module_wrong(value: dict[str, str] = None):
|
||||||
|
56 | import os; import sys
|
||||||
|
57 + if value is None:
|
||||||
|
58 + value: dict[str, str] = {}
|
||||||
|
59 |
|
||||||
|
60 |
|
||||||
|
61 | def import_module_wrong(value: dict[str, str] = {}):
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
||||||
|
B006 [*] Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_5.py:59:49
|
||||||
|
|
|
||||||
|
59 | def import_module_wrong(value: dict[str, str] = {}):
|
||||||
|
| ^^
|
||||||
|
60 | import os; import sys; x = 1
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
56 | import os; import sys
|
||||||
|
57 |
|
||||||
|
58 |
|
||||||
|
- 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: dict[str, str] = {}
|
||||||
|
62 | import os; import sys; x = 1
|
||||||
|
63 |
|
||||||
|
64 |
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
||||||
|
B006 [*] Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_5.py:63:49
|
||||||
|
|
|
||||||
|
63 | def import_module_wrong(value: dict[str, str] = {}):
|
||||||
|
| ^^
|
||||||
|
64 | import os; import sys
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
60 | import os; import sys; x = 1
|
||||||
|
61 |
|
||||||
|
62 |
|
||||||
|
- def import_module_wrong(value: dict[str, str] = {}):
|
||||||
|
63 + def import_module_wrong(value: dict[str, str] = None):
|
||||||
|
64 | import os; import sys
|
||||||
|
65 + if value is None:
|
||||||
|
66 + value: dict[str, str] = {}
|
||||||
|
67 |
|
||||||
|
68 |
|
||||||
|
69 | def import_module_wrong(value: dict[str, str] = {}): import os
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
||||||
|
B006 Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_5.py:67:49
|
||||||
|
|
|
||||||
|
67 | def import_module_wrong(value: dict[str, str] = {}): import os
|
||||||
|
| ^^
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
|
||||||
|
B006 Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_5.py:70:49
|
||||||
|
|
|
||||||
|
70 | def import_module_wrong(value: dict[str, str] = {}): import os; import sys
|
||||||
|
| ^^
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
|
||||||
|
B006 Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_5.py:73:49
|
||||||
|
|
|
||||||
|
73 | def import_module_wrong(value: dict[str, str] = {}): \
|
||||||
|
| ^^
|
||||||
|
74 | import os
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/flake8_bugbear/mod.rs
|
||||||
|
---
|
||||||
|
B006 [*] Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_6.py:4:22
|
||||||
|
|
|
||||||
|
2 | # Same as B006_2.py, but import instead of docstring
|
||||||
|
3 |
|
||||||
|
4 | def foobar(foor, bar={}):
|
||||||
|
| ^^
|
||||||
|
5 | import os
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
1 | # Import followed by whitespace with no newline
|
||||||
|
2 | # Same as B006_2.py, but import instead of docstring
|
||||||
|
3 |
|
||||||
|
- def foobar(foor, bar={}):
|
||||||
|
- import os
|
||||||
|
4 + def foobar(foor, bar=None):
|
||||||
|
5 + import os
|
||||||
|
6 + if bar is None:
|
||||||
|
7 + bar = {}
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/flake8_bugbear/mod.rs
|
||||||
|
---
|
||||||
|
B006 [*] Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_7.py:4:22
|
||||||
|
|
|
||||||
|
2 | # Same as B006_3.py, but import instead of docstring
|
||||||
|
3 |
|
||||||
|
4 | def foobar(foor, bar={}):
|
||||||
|
| ^^
|
||||||
|
5 | import os
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
1 | # Import with no newline
|
||||||
|
2 | # Same as B006_3.py, but import instead of docstring
|
||||||
|
3 |
|
||||||
|
- def foobar(foor, bar={}):
|
||||||
|
- import os
|
||||||
|
4 + def foobar(foor, bar=None):
|
||||||
|
5 + import os
|
||||||
|
6 + if bar is None:
|
||||||
|
7 + bar = {}
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
@ -0,0 +1,92 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/flake8_bugbear/mod.rs
|
||||||
|
---
|
||||||
|
B006 [*] Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_8.py:1:19
|
||||||
|
|
|
||||||
|
1 | def foo(a: list = []):
|
||||||
|
| ^^
|
||||||
|
2 | raise NotImplementedError("")
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
- def foo(a: list = []):
|
||||||
|
1 + def foo(a: list = None):
|
||||||
|
2 | raise NotImplementedError("")
|
||||||
|
3 |
|
||||||
|
4 |
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
||||||
|
B006 [*] Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_8.py:5:19
|
||||||
|
|
|
||||||
|
5 | def bar(a: dict = {}):
|
||||||
|
| ^^
|
||||||
|
6 | """ This one also has a docstring"""
|
||||||
|
7 | raise NotImplementedError("and has some text in here")
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
2 | raise NotImplementedError("")
|
||||||
|
3 |
|
||||||
|
4 |
|
||||||
|
- def bar(a: dict = {}):
|
||||||
|
5 + def bar(a: dict = None):
|
||||||
|
6 | """ This one also has a docstring"""
|
||||||
|
7 | raise NotImplementedError("and has some text in here")
|
||||||
|
8 |
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
||||||
|
B006 [*] Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_8.py:10:19
|
||||||
|
|
|
||||||
|
10 | def baz(a: list = []):
|
||||||
|
| ^^
|
||||||
|
11 | """This one raises a different exception"""
|
||||||
|
12 | raise IndexError()
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
7 | raise NotImplementedError("and has some text in here")
|
||||||
|
8 |
|
||||||
|
9 |
|
||||||
|
- def baz(a: list = []):
|
||||||
|
10 + def baz(a: list = None):
|
||||||
|
11 | """This one raises a different exception"""
|
||||||
|
12 + if a is None:
|
||||||
|
13 + a: list = []
|
||||||
|
14 | raise IndexError()
|
||||||
|
15 |
|
||||||
|
16 |
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
||||||
|
B006 [*] Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_8.py:15:19
|
||||||
|
|
|
||||||
|
15 | def qux(a: list = []):
|
||||||
|
| ^^
|
||||||
|
16 | raise NotImplementedError
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
12 | raise IndexError()
|
||||||
|
13 |
|
||||||
|
14 |
|
||||||
|
- def qux(a: list = []):
|
||||||
|
15 + def qux(a: list = None):
|
||||||
|
16 | raise NotImplementedError
|
||||||
|
17 |
|
||||||
|
18 |
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
||||||
|
B006 [*] Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_8.py:19:20
|
||||||
|
|
|
||||||
|
19 | def quux(a: list = []):
|
||||||
|
| ^^
|
||||||
|
20 | raise NotImplemented
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
16 | raise NotImplementedError
|
||||||
|
17 |
|
||||||
|
18 |
|
||||||
|
- def quux(a: list = []):
|
||||||
|
19 + def quux(a: list = None):
|
||||||
|
20 | raise NotImplemented
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
@ -0,0 +1,99 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/flake8_bugbear/mod.rs
|
||||||
|
---
|
||||||
|
B006 [*] Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_9.py:1:10
|
||||||
|
|
|
||||||
|
1 | def f1(x=([],)):
|
||||||
|
| ^^^^^
|
||||||
|
2 | print(x)
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
- def f1(x=([],)):
|
||||||
|
1 + def f1(x=None):
|
||||||
|
2 + if x is None:
|
||||||
|
3 + x = ([],)
|
||||||
|
4 | print(x)
|
||||||
|
5 |
|
||||||
|
6 |
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
||||||
|
B006 [*] Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_9.py:5:10
|
||||||
|
|
|
||||||
|
5 | def f2(x=(x for x in "x")):
|
||||||
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
6 | print(x)
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
2 | print(x)
|
||||||
|
3 |
|
||||||
|
4 |
|
||||||
|
- def f2(x=(x for x in "x")):
|
||||||
|
5 + def f2(x=None):
|
||||||
|
6 + if x is None:
|
||||||
|
7 + x = (x for x in "x")
|
||||||
|
8 | print(x)
|
||||||
|
9 |
|
||||||
|
10 |
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
||||||
|
B006 [*] Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_9.py:9:10
|
||||||
|
|
|
||||||
|
9 | def f3(x=((x for x in "x"),)):
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
10 | print(x)
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
6 | print(x)
|
||||||
|
7 |
|
||||||
|
8 |
|
||||||
|
- def f3(x=((x for x in "x"),)):
|
||||||
|
9 + def f3(x=None):
|
||||||
|
10 + if x is None:
|
||||||
|
11 + x = ((x for x in "x"),)
|
||||||
|
12 | print(x)
|
||||||
|
13 |
|
||||||
|
14 |
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
||||||
|
B006 [*] Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_9.py:13:11
|
||||||
|
|
|
||||||
|
13 | def f4(x=(z := [1, ])):
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
14 | print(x)
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
10 | print(x)
|
||||||
|
11 |
|
||||||
|
12 |
|
||||||
|
- def f4(x=(z := [1, ])):
|
||||||
|
13 + def f4(x=None):
|
||||||
|
14 + if x is None:
|
||||||
|
15 + x = (z := [1, ])
|
||||||
|
16 | print(x)
|
||||||
|
17 |
|
||||||
|
18 |
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
||||||
|
B006 [*] Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_9.py:17:11
|
||||||
|
|
|
||||||
|
17 | def f5(x=([1, ])):
|
||||||
|
| ^^^^^
|
||||||
|
18 | print(x)
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
14 | print(x)
|
||||||
|
15 |
|
||||||
|
16 |
|
||||||
|
- def f5(x=([1, ])):
|
||||||
|
17 + def f5(x=None):
|
||||||
|
18 + if x is None:
|
||||||
|
19 + x = ([1, ])
|
||||||
|
20 | print(x)
|
||||||
|
21 |
|
||||||
|
22 |
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
@ -0,0 +1,462 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/flake8_bugbear/mod.rs
|
||||||
|
---
|
||||||
|
B006 [*] Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_B008.py:63:25
|
||||||
|
|
|
||||||
|
63 | def this_is_wrong(value=[1, 2, 3]):
|
||||||
|
| ^^^^^^^^^
|
||||||
|
64 | ...
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
60 | # Flag mutable literals/comprehensions
|
||||||
|
61 |
|
||||||
|
62 |
|
||||||
|
- def this_is_wrong(value=[1, 2, 3]):
|
||||||
|
63 + def this_is_wrong(value=None):
|
||||||
|
64 | ...
|
||||||
|
65 |
|
||||||
|
66 |
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
||||||
|
B006 [*] Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_B008.py:67:30
|
||||||
|
|
|
||||||
|
67 | def this_is_also_wrong(value={}):
|
||||||
|
| ^^
|
||||||
|
68 | ...
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
64 | ...
|
||||||
|
65 |
|
||||||
|
66 |
|
||||||
|
- def this_is_also_wrong(value={}):
|
||||||
|
67 + def this_is_also_wrong(value=None):
|
||||||
|
68 | ...
|
||||||
|
69 |
|
||||||
|
70 |
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
||||||
|
B006 [*] Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_B008.py:73:52
|
||||||
|
|
|
||||||
|
71 | class Foo:
|
||||||
|
72 | @staticmethod
|
||||||
|
73 | def this_is_also_wrong_and_more_indented(value={}):
|
||||||
|
| ^^
|
||||||
|
74 | pass
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
70 |
|
||||||
|
71 | class Foo:
|
||||||
|
72 | @staticmethod
|
||||||
|
- def this_is_also_wrong_and_more_indented(value={}):
|
||||||
|
73 + def this_is_also_wrong_and_more_indented(value=None):
|
||||||
|
74 | pass
|
||||||
|
75 |
|
||||||
|
76 |
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
||||||
|
B006 [*] Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_B008.py:77:31
|
||||||
|
|
|
||||||
|
77 | def multiline_arg_wrong(value={
|
||||||
|
| _______________________________^
|
||||||
|
78 | |
|
||||||
|
79 | | }):
|
||||||
|
| |_^
|
||||||
|
80 | ...
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
74 | pass
|
||||||
|
75 |
|
||||||
|
76 |
|
||||||
|
- def multiline_arg_wrong(value={
|
||||||
|
-
|
||||||
|
- }):
|
||||||
|
77 + def multiline_arg_wrong(value=None):
|
||||||
|
78 | ...
|
||||||
|
79 |
|
||||||
|
80 | def single_line_func_wrong(value = {}): ...
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
||||||
|
B006 Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_B008.py:82:36
|
||||||
|
|
|
||||||
|
80 | ...
|
||||||
|
81 |
|
||||||
|
82 | def single_line_func_wrong(value = {}): ...
|
||||||
|
| ^^
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
|
||||||
|
B006 [*] Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_B008.py:85:20
|
||||||
|
|
|
||||||
|
85 | def and_this(value=set()):
|
||||||
|
| ^^^^^
|
||||||
|
86 | ...
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
82 | def single_line_func_wrong(value = {}): ...
|
||||||
|
83 |
|
||||||
|
84 |
|
||||||
|
- def and_this(value=set()):
|
||||||
|
85 + def and_this(value=None):
|
||||||
|
86 | ...
|
||||||
|
87 |
|
||||||
|
88 |
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
||||||
|
B006 [*] Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_B008.py:89:20
|
||||||
|
|
|
||||||
|
89 | def this_too(value=collections.OrderedDict()):
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
90 | ...
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
86 | ...
|
||||||
|
87 |
|
||||||
|
88 |
|
||||||
|
- def this_too(value=collections.OrderedDict()):
|
||||||
|
89 + def this_too(value=None):
|
||||||
|
90 | ...
|
||||||
|
91 |
|
||||||
|
92 |
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
||||||
|
B006 [*] Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_B008.py:93:32
|
||||||
|
|
|
||||||
|
93 | async def async_this_too(value=collections.defaultdict()):
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
94 | ...
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
90 | ...
|
||||||
|
91 |
|
||||||
|
92 |
|
||||||
|
- async def async_this_too(value=collections.defaultdict()):
|
||||||
|
93 + async def async_this_too(value=None):
|
||||||
|
94 | ...
|
||||||
|
95 |
|
||||||
|
96 |
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
||||||
|
B006 [*] Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_B008.py:97:26
|
||||||
|
|
|
||||||
|
97 | def dont_forget_me(value=collections.deque()):
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
98 | ...
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
94 | ...
|
||||||
|
95 |
|
||||||
|
96 |
|
||||||
|
- def dont_forget_me(value=collections.deque()):
|
||||||
|
97 + def dont_forget_me(value=None):
|
||||||
|
98 | ...
|
||||||
|
99 |
|
||||||
|
100 |
|
||||||
|
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
|
||||||
|
102 | def list_comprehension_also_not_okay(default=[i**2 for i in range(3)]):
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
103 | pass
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
99 |
|
||||||
|
100 |
|
||||||
|
101 | # N.B. we're also flagging the function call in the comprehension
|
||||||
|
- 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
|
||||||
|
104 |
|
||||||
|
105 |
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
||||||
|
B006 [*] Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_B008.py:106:46
|
||||||
|
|
|
||||||
|
106 | def dict_comprehension_also_not_okay(default={i: i**2 for i in range(3)}):
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
107 | pass
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
103 | pass
|
||||||
|
104 |
|
||||||
|
105 |
|
||||||
|
- def dict_comprehension_also_not_okay(default={i: i**2 for i in range(3)}):
|
||||||
|
106 + def dict_comprehension_also_not_okay(default=None):
|
||||||
|
107 | pass
|
||||||
|
108 |
|
||||||
|
109 |
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
||||||
|
B006 [*] Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_B008.py:110:45
|
||||||
|
|
|
||||||
|
110 | def set_comprehension_also_not_okay(default={i**2 for i in range(3)}):
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
111 | pass
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
107 | pass
|
||||||
|
108 |
|
||||||
|
109 |
|
||||||
|
- def set_comprehension_also_not_okay(default={i**2 for i in range(3)}):
|
||||||
|
110 + def set_comprehension_also_not_okay(default=None):
|
||||||
|
111 | pass
|
||||||
|
112 |
|
||||||
|
113 |
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
||||||
|
B006 [*] Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_B008.py:114:33
|
||||||
|
|
|
||||||
|
114 | def kwonlyargs_mutable(*, value=[]):
|
||||||
|
| ^^
|
||||||
|
115 | ...
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
111 | pass
|
||||||
|
112 |
|
||||||
|
113 |
|
||||||
|
- def kwonlyargs_mutable(*, value=[]):
|
||||||
|
114 + def kwonlyargs_mutable(*, value=None):
|
||||||
|
115 | ...
|
||||||
|
116 |
|
||||||
|
117 |
|
||||||
|
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
|
||||||
|
|
|
||||||
|
237 | # B006 and B008
|
||||||
|
238 | # We should handle arbitrary nesting of these B008.
|
||||||
|
239 | def nested_combo(a=[float(3), dt.datetime.now()]):
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
240 | pass
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
236 |
|
||||||
|
237 | # B006 and B008
|
||||||
|
238 | # 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 |
|
||||||
|
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
|
||||||
|
|
|
||||||
|
275 | def mutable_annotations(
|
||||||
|
276 | a: list[int] | None = [],
|
||||||
|
| ^^
|
||||||
|
277 | b: Optional[Dict[int, int]] = {},
|
||||||
|
278 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(),
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
273 |
|
||||||
|
274 |
|
||||||
|
275 | 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(),
|
||||||
|
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
|
||||||
|
|
|
||||||
|
275 | def mutable_annotations(
|
||||||
|
276 | a: list[int] | 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(),
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
274 |
|
||||||
|
275 | def mutable_annotations(
|
||||||
|
276 | 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 | ):
|
||||||
|
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
|
||||||
|
|
|
||||||
|
276 | a: list[int] | 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(),
|
||||||
|
280 | ):
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
275 | def mutable_annotations(
|
||||||
|
276 | a: list[int] | None = [],
|
||||||
|
277 | 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
|
||||||
|
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
|
||||||
|
|
|
||||||
|
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 | ):
|
||||||
|
281 | 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(),
|
||||||
|
- 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 |
|
||||||
|
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
|
||||||
|
|
|
||||||
|
284 | def single_line_func_wrong(value: dict[str, str] = {}):
|
||||||
|
| ^^
|
||||||
|
285 | """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"""
|
||||||
|
286 |
|
||||||
|
287 |
|
||||||
|
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
|
||||||
|
|
|
||||||
|
288 | def single_line_func_wrong(value: dict[str, str] = {}):
|
||||||
|
| ^^
|
||||||
|
289 | """Docstring"""
|
||||||
|
290 | ...
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
285 | """Docstring"""
|
||||||
|
286 |
|
||||||
|
287 |
|
||||||
|
- def single_line_func_wrong(value: dict[str, str] = {}):
|
||||||
|
288 + def single_line_func_wrong(value: dict[str, str] = None):
|
||||||
|
289 | """Docstring"""
|
||||||
|
290 | ...
|
||||||
|
291 |
|
||||||
|
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
|
||||||
|
|
|
||||||
|
293 | def single_line_func_wrong(value: dict[str, str] = {}):
|
||||||
|
| ^^
|
||||||
|
294 | """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"""; ...
|
||||||
|
295 |
|
||||||
|
296 |
|
||||||
|
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
|
||||||
|
|
|
||||||
|
297 | def single_line_func_wrong(value: dict[str, str] = {}):
|
||||||
|
| ^^
|
||||||
|
298 | """Docstring"""; \
|
||||||
|
299 | ...
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
294 | """Docstring"""; ...
|
||||||
|
295 |
|
||||||
|
296 |
|
||||||
|
- def single_line_func_wrong(value: dict[str, str] = {}):
|
||||||
|
297 + def single_line_func_wrong(value: dict[str, str] = None):
|
||||||
|
298 | """Docstring"""; \
|
||||||
|
299 | ...
|
||||||
|
300 |
|
||||||
|
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
|
||||||
|
|
|
||||||
|
302 | def single_line_func_wrong(value: dict[str, str] = {
|
||||||
|
| ____________________________________________________^
|
||||||
|
303 | | # This is a comment
|
||||||
|
304 | | }):
|
||||||
|
| |_^
|
||||||
|
305 | """Docstring"""
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
299 | ...
|
||||||
|
300 |
|
||||||
|
301 |
|
||||||
|
- 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 |
|
||||||
|
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
|
||||||
|
|
|
||||||
|
308 | def single_line_func_wrong(value: dict[str, str] = {}) \
|
||||||
|
| ^^
|
||||||
|
309 | : \
|
||||||
|
310 | """Docstring"""
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
|
||||||
|
B006 [*] Do not use mutable data structures for argument defaults
|
||||||
|
--> B006_B008.py:313:52
|
||||||
|
|
|
||||||
|
313 | def single_line_func_wrong(value: dict[str, str] = {}):
|
||||||
|
| ^^
|
||||||
|
314 | """Docstring without newline"""
|
||||||
|
|
|
||||||
|
help: Replace with `None`; initialize within function
|
||||||
|
310 | """Docstring"""
|
||||||
|
311 |
|
||||||
|
312 |
|
||||||
|
- def single_line_func_wrong(value: dict[str, str] = {}):
|
||||||
|
313 + def single_line_func_wrong(value: dict[str, str] = None):
|
||||||
|
314 | """Docstring without newline"""
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
Loading…
Add table
Add a link
Reference in a new issue