[flake8-bugbear] Add autofix for B006 (#6131)

## Summary

Reopening of https://github.com/astral-sh/ruff/pull/4880 

One open TODO as described in:
https://github.com/astral-sh/ruff/pull/4880#discussion_r1265110215

FYI @charliermarsh seeing as you commented you wanted to do final review
and merge. @konstin @dhruvmanila @MichaReiser as previous reviewers.

# Old Description
## Summary

Adds an autofix for B006 turning mutable argument defaults into None and
setting their original value back in the function body if still `None`
at runtime like so:
```python
def before(x=[]):
    pass
    
def after(x=None):
    if x is None:
        x = []
    pass
```

## Test Plan

Added an extra test case to existing fixture with more indentation.
Checked results for all old examples.

NOTE: Also adapted the jupyter notebook test as this checked for B006 as
well.

## Issue link

Closes: https://github.com/charliermarsh/ruff/issues/4693

---------

Co-authored-by: konstin <konstin@mailbox.org>
This commit is contained in:
qdegraaf 2023-08-10 13:06:40 +02:00 committed by GitHub
parent 4811af0f0b
commit 50dab9cea6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 461 additions and 132 deletions

View file

@ -68,6 +68,20 @@ def this_is_also_wrong(value={}):
...
class Foo:
@staticmethod
def this_is_also_wrong_and_more_indented(value={}):
pass
def multiline_arg_wrong(value={
}):
...
def single_line_func_wrong(value = {}): ...
def and_this(value=set()):
...

View file

@ -6,9 +6,6 @@ use crate::rules::{flake8_bugbear, flake8_pyi, ruff};
/// Run lint rules over a [`Parameters`] syntax node.
pub(crate) fn parameters(parameters: &Parameters, checker: &mut Checker) {
if checker.enabled(Rule::MutableArgumentDefault) {
flake8_bugbear::rules::mutable_argument_default(checker, parameters);
}
if checker.enabled(Rule::FunctionCallInDefaultArgument) {
flake8_bugbear::rules::function_call_in_argument_default(checker, parameters);
}

View file

@ -77,7 +77,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
parameters,
body,
type_params,
range: _,
range,
}) => {
if checker.enabled(Rule::DjangoNonLeadingReceiverDecorator) {
flake8_django::rules::non_leading_receiver_decorator(checker, decorator_list);
@ -204,6 +204,9 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
if checker.enabled(Rule::CachedInstanceMethod) {
flake8_bugbear::rules::cached_instance_method(checker, decorator_list);
}
if checker.enabled(Rule::MutableArgumentDefault) {
flake8_bugbear::rules::mutable_argument_default(checker, parameters, body, *range);
}
if checker.any_enabled(&[
Rule::UnnecessaryReturnNone,
Rule::ImplicitReturnValue,

View file

@ -1,10 +1,16 @@
use ruff_python_ast::{ParameterWithDefault, Parameters, Ranged};
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::docstrings::leading_space;
use ruff_python_ast::{ParameterWithDefault, Parameters, Ranged, Stmt};
use ruff_python_parser::lexer::lex_starts_at;
use ruff_python_parser::{Mode, Tok};
use ruff_python_semantic::analyze::typing::{is_immutable_annotation, is_mutable_expr};
use ruff_python_trivia::indentation_at_offset;
use ruff_source_file::Locator;
use ruff_text_size::TextRange;
use crate::checkers::ast::Checker;
use crate::registry::AsRule;
/// ## What it does
/// Checks for uses of mutable objects as function argument defaults.
@ -50,14 +56,26 @@ use crate::checkers::ast::Checker;
pub struct MutableArgumentDefault;
impl Violation for MutableArgumentDefault {
const AUTOFIX: AutofixKind = AutofixKind::Sometimes;
#[derive_message_formats]
fn message(&self) -> String {
format!("Do not use mutable data structures for argument defaults")
}
fn autofix_title(&self) -> Option<String> {
Some(format!(
"Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`"
))
}
}
/// B006
pub(crate) fn mutable_argument_default(checker: &mut Checker, parameters: &Parameters) {
pub(crate) fn mutable_argument_default(
checker: &mut Checker,
parameters: &Parameters,
body: &[Stmt],
func_range: TextRange,
) {
// Scan in reverse order to right-align zip().
for ParameterWithDefault {
parameter,
@ -79,9 +97,53 @@ pub(crate) fn mutable_argument_default(checker: &mut Checker, parameters: &Param
.as_ref()
.is_some_and(|expr| is_immutable_annotation(expr, checker.semantic()))
{
checker
.diagnostics
.push(Diagnostic::new(MutableArgumentDefault, default.range()));
let mut diagnostic = Diagnostic::new(MutableArgumentDefault, default.range());
// If the function body is on the same line as the function def, do not fix
if checker.patch(diagnostic.kind.rule())
&& !is_single_line(checker.locator(), func_range, body)
{
// Set the default arg value to None
let arg_edit = Edit::range_replacement("None".to_string(), default.range());
// Add conditional check to set the default arg to its original value if still None
let mut check_lines = String::new();
let indentation =
indentation_at_offset(body[0].start(), checker.locator()).unwrap_or_default();
let indentation = leading_space(indentation);
// body[0].start() starts at correct indentation so we do need to add indentation
// before pushing the if statement
check_lines.push_str(format!("if {} is None:\n", parameter.name.as_str()).as_str());
check_lines.push_str(indentation);
check_lines.push_str(checker.stylist().indentation());
check_lines.push_str(
format!(
"{} = {}",
parameter.name.as_str(),
checker.generator().expr(default),
)
.as_str(),
);
check_lines.push_str(&checker.stylist().line_ending());
check_lines.push_str(indentation);
let check_edit = Edit::insertion(check_lines, body[0].start());
diagnostic.set_fix(Fix::manual_edits(arg_edit, [check_edit]));
}
checker.diagnostics.push(diagnostic);
}
}
}
fn is_single_line(locator: &Locator, func_range: TextRange, body: &[Stmt]) -> bool {
let arg_string = locator.slice(func_range);
for (tok, range) in lex_starts_at(arg_string, Mode::Module, func_range.start()).flatten() {
match tok {
Tok::Colon => {
return !locator.contains_line_break(TextRange::new(range.end(), body[0].start()));
}
_ => continue,
}
}
false
}

View file

@ -1,123 +1,376 @@
---
source: crates/ruff/src/rules/flake8_bugbear/mod.rs
---
B006_B008.py:63:25: B006 Do not use mutable data structures for argument defaults
B006_B008.py:63:25: B006 [*] Do not use mutable data structures for argument defaults
|
63 | def this_is_wrong(value=[1, 2, 3]):
| ^^^^^^^^^ B006
64 | ...
|
= help: Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
B006_B008.py:67:30: B006 Do not use mutable data structures for argument defaults
Possible fix
60 60 | # Flag mutable literals/comprehensions
61 61 |
62 62 |
63 |-def this_is_wrong(value=[1, 2, 3]):
63 |+def this_is_wrong(value=None):
64 |+ if value is None:
65 |+ value = [1, 2, 3]
64 66 | ...
65 67 |
66 68 |
B006_B008.py:67:30: B006 [*] Do not use mutable data structures for argument defaults
|
67 | def this_is_also_wrong(value={}):
| ^^ B006
68 | ...
|
= help: Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
B006_B008.py:71:20: B006 Do not use mutable data structures for argument defaults
|
71 | def and_this(value=set()):
| ^^^^^ B006
72 | ...
|
Possible fix
64 64 | ...
65 65 |
66 66 |
67 |-def this_is_also_wrong(value={}):
67 |+def this_is_also_wrong(value=None):
68 |+ if value is None:
69 |+ value = {}
68 70 | ...
69 71 |
70 72 |
B006_B008.py:75:20: B006 Do not use mutable data structures for argument defaults
B006_B008.py:73:52: B006 [*] Do not use mutable data structures for argument defaults
|
75 | def this_too(value=collections.OrderedDict()):
| ^^^^^^^^^^^^^^^^^^^^^^^^^ B006
76 | ...
71 | class Foo:
72 | @staticmethod
73 | def this_is_also_wrong_and_more_indented(value={}):
| ^^ B006
74 | pass
|
= help: Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
B006_B008.py:79:32: B006 Do not use mutable data structures for argument defaults
Possible fix
70 70 |
71 71 | class Foo:
72 72 | @staticmethod
73 |- def this_is_also_wrong_and_more_indented(value={}):
73 |+ def this_is_also_wrong_and_more_indented(value=None):
74 |+ if value is None:
75 |+ value = {}
74 76 | pass
75 77 |
76 78 |
B006_B008.py:77:31: B006 [*] Do not use mutable data structures for argument defaults
|
77 | def multiline_arg_wrong(value={
| _______________________________^
78 | |
79 | | }):
| |_^ B006
80 | ...
|
= help: Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
Possible fix
74 74 | pass
75 75 |
76 76 |
77 |-def multiline_arg_wrong(value={
78 |-
79 |-}):
77 |+def multiline_arg_wrong(value=None):
78 |+ if value is None:
79 |+ value = {}
80 80 | ...
81 81 |
82 82 | def single_line_func_wrong(value = {}): ...
B006_B008.py:82:36: B006 Do not use mutable data structures for argument defaults
|
79 | async def async_this_too(value=collections.defaultdict()):
| ^^^^^^^^^^^^^^^^^^^^^^^^^ B006
80 | ...
81 |
82 | def single_line_func_wrong(value = {}): ...
| ^^ B006
|
= help: Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
B006_B008.py:83:26: B006 Do not use mutable data structures for argument defaults
B006_B008.py:85:20: B006 [*] Do not use mutable data structures for argument defaults
|
83 | def dont_forget_me(value=collections.deque()):
85 | def and_this(value=set()):
| ^^^^^ B006
86 | ...
|
= help: Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
Possible fix
82 82 | def single_line_func_wrong(value = {}): ...
83 83 |
84 84 |
85 |-def and_this(value=set()):
85 |+def and_this(value=None):
86 |+ if value is None:
87 |+ value = set()
86 88 | ...
87 89 |
88 90 |
B006_B008.py:89:20: B006 [*] Do not use mutable data structures for argument defaults
|
89 | def this_too(value=collections.OrderedDict()):
| ^^^^^^^^^^^^^^^^^^^^^^^^^ B006
90 | ...
|
= help: Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
Possible fix
86 86 | ...
87 87 |
88 88 |
89 |-def this_too(value=collections.OrderedDict()):
89 |+def this_too(value=None):
90 |+ if value is None:
91 |+ value = collections.OrderedDict()
90 92 | ...
91 93 |
92 94 |
B006_B008.py:93:32: B006 [*] Do not use mutable data structures for argument defaults
|
93 | async def async_this_too(value=collections.defaultdict()):
| ^^^^^^^^^^^^^^^^^^^^^^^^^ B006
94 | ...
|
= help: Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
Possible fix
90 90 | ...
91 91 |
92 92 |
93 |-async def async_this_too(value=collections.defaultdict()):
93 |+async def async_this_too(value=None):
94 |+ if value is None:
95 |+ value = collections.defaultdict()
94 96 | ...
95 97 |
96 98 |
B006_B008.py:97:26: B006 [*] Do not use mutable data structures for argument defaults
|
97 | def dont_forget_me(value=collections.deque()):
| ^^^^^^^^^^^^^^^^^^^ B006
84 | ...
98 | ...
|
= help: Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
B006_B008.py:88:46: B006 Do not use mutable data structures for argument defaults
|
87 | # N.B. we're also flagging the function call in the comprehension
88 | def list_comprehension_also_not_okay(default=[i**2 for i in range(3)]):
| ^^^^^^^^^^^^^^^^^^^^^^^^ B006
89 | pass
|
Possible fix
94 94 | ...
95 95 |
96 96 |
97 |-def dont_forget_me(value=collections.deque()):
97 |+def dont_forget_me(value=None):
98 |+ if value is None:
99 |+ value = collections.deque()
98 100 | ...
99 101 |
100 102 |
B006_B008.py:92:46: B006 Do not use mutable data structures for argument defaults
|
92 | def dict_comprehension_also_not_okay(default={i: i**2 for i in range(3)}):
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ B006
93 | pass
|
B006_B008.py:96:45: B006 Do not use mutable data structures for argument defaults
|
96 | def set_comprehension_also_not_okay(default={i**2 for i in range(3)}):
| ^^^^^^^^^^^^^^^^^^^^^^^^ B006
97 | pass
|
B006_B008.py:100:33: B006 Do not use mutable data structures for argument defaults
B006_B008.py:102:46: B006 [*] Do not use mutable data structures for argument defaults
|
100 | def kwonlyargs_mutable(*, value=[]):
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)]):
| ^^^^^^^^^^^^^^^^^^^^^^^^ B006
103 | pass
|
= help: Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
Possible fix
99 99 |
100 100 |
101 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)]):
102 |+def list_comprehension_also_not_okay(default=None):
103 |+ if default is None:
104 |+ default = [i ** 2 for i in range(3)]
103 105 | pass
104 106 |
105 107 |
B006_B008.py:106:46: B006 [*] Do not use mutable data structures for argument defaults
|
106 | def dict_comprehension_also_not_okay(default={i: i**2 for i in range(3)}):
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ B006
107 | pass
|
= help: Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
Possible fix
103 103 | pass
104 104 |
105 105 |
106 |-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 |+ if default is None:
108 |+ default = {i: i ** 2 for i in range(3)}
107 109 | pass
108 110 |
109 111 |
B006_B008.py:110:45: B006 [*] Do not use mutable data structures for argument defaults
|
110 | def set_comprehension_also_not_okay(default={i**2 for i in range(3)}):
| ^^^^^^^^^^^^^^^^^^^^^^^^ B006
111 | pass
|
= help: Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
Possible fix
107 107 | pass
108 108 |
109 109 |
110 |-def set_comprehension_also_not_okay(default={i**2 for i in range(3)}):
110 |+def set_comprehension_also_not_okay(default=None):
111 |+ if default is None:
112 |+ default = {i ** 2 for i in range(3)}
111 113 | pass
112 114 |
113 115 |
B006_B008.py:114:33: B006 [*] Do not use mutable data structures for argument defaults
|
114 | def kwonlyargs_mutable(*, value=[]):
| ^^ B006
101 | ...
115 | ...
|
= help: Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
B006_B008.py:221:20: B006 Do not use mutable data structures for argument defaults
Possible fix
111 111 | pass
112 112 |
113 113 |
114 |-def kwonlyargs_mutable(*, value=[]):
114 |+def kwonlyargs_mutable(*, value=None):
115 |+ if value is None:
116 |+ value = []
115 117 | ...
116 118 |
117 119 |
B006_B008.py:235:20: B006 [*] Do not use mutable data structures for argument defaults
|
219 | # B006 and B008
220 | # We should handle arbitrary nesting of these B008.
221 | def nested_combo(a=[float(3), dt.datetime.now()]):
233 | # B006 and B008
234 | # We should handle arbitrary nesting of these B008.
235 | def nested_combo(a=[float(3), dt.datetime.now()]):
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ B006
222 | pass
236 | pass
|
= help: Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
B006_B008.py:258:27: B006 Do not use mutable data structures for argument defaults
Possible fix
232 232 |
233 233 | # B006 and B008
234 234 | # We should handle arbitrary nesting of these B008.
235 |-def nested_combo(a=[float(3), dt.datetime.now()]):
235 |+def nested_combo(a=None):
236 |+ if a is None:
237 |+ a = [float(3), dt.datetime.now()]
236 238 | pass
237 239 |
238 240 |
B006_B008.py:272:27: B006 [*] Do not use mutable data structures for argument defaults
|
257 | def mutable_annotations(
258 | a: list[int] | None = [],
271 | def mutable_annotations(
272 | a: list[int] | None = [],
| ^^ B006
259 | b: Optional[Dict[int, int]] = {},
260 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(),
273 | b: Optional[Dict[int, int]] = {},
274 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(),
|
= help: Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
B006_B008.py:259:35: B006 Do not use mutable data structures for argument defaults
Possible fix
269 269 |
270 270 |
271 271 | def mutable_annotations(
272 |- a: list[int] | None = [],
272 |+ a: list[int] | None = None,
273 273 | b: Optional[Dict[int, int]] = {},
274 274 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(),
275 275 | d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = set(),
276 276 | ):
277 |+ if a is None:
278 |+ a = []
277 279 | pass
B006_B008.py:273:35: B006 [*] Do not use mutable data structures for argument defaults
|
257 | def mutable_annotations(
258 | a: list[int] | None = [],
259 | b: Optional[Dict[int, int]] = {},
271 | def mutable_annotations(
272 | a: list[int] | None = [],
273 | b: Optional[Dict[int, int]] = {},
| ^^ B006
260 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(),
261 | d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = set(),
274 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(),
275 | d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = set(),
|
= help: Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
B006_B008.py:260:62: B006 Do not use mutable data structures for argument defaults
Possible fix
270 270 |
271 271 | def mutable_annotations(
272 272 | a: list[int] | None = [],
273 |- b: Optional[Dict[int, int]] = {},
273 |+ b: Optional[Dict[int, int]] = None,
274 274 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(),
275 275 | d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = set(),
276 276 | ):
277 |+ if b is None:
278 |+ b = {}
277 279 | pass
B006_B008.py:274:62: B006 [*] Do not use mutable data structures for argument defaults
|
258 | a: list[int] | None = [],
259 | b: Optional[Dict[int, int]] = {},
260 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(),
272 | a: list[int] | None = [],
273 | b: Optional[Dict[int, int]] = {},
274 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(),
| ^^^^^ B006
261 | d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = set(),
262 | ):
275 | d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = set(),
276 | ):
|
= help: Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
B006_B008.py:261:80: B006 Do not use mutable data structures for argument defaults
Possible fix
271 271 | def mutable_annotations(
272 272 | a: list[int] | None = [],
273 273 | b: Optional[Dict[int, int]] = {},
274 |- c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(),
274 |+ c: Annotated[Union[Set[str], abc.Sized], "annotation"] = None,
275 275 | d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = set(),
276 276 | ):
277 |+ if c is None:
278 |+ c = set()
277 279 | pass
B006_B008.py:275:80: B006 [*] Do not use mutable data structures for argument defaults
|
259 | b: Optional[Dict[int, int]] = {},
260 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(),
261 | d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = set(),
273 | b: Optional[Dict[int, int]] = {},
274 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(),
275 | d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = set(),
| ^^^^^ B006
262 | ):
263 | pass
276 | ):
277 | pass
|
= help: Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
Possible fix
272 272 | a: list[int] | None = [],
273 273 | b: Optional[Dict[int, int]] = {},
274 274 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(),
275 |- d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = set(),
275 |+ d: typing_extensions.Annotated[Union[Set[str], abc.Sized], "annotation"] = None,
276 276 | ):
277 |+ if d is None:
278 |+ d = set()
277 279 | pass

View file

@ -1,83 +1,83 @@
---
source: crates/ruff/src/rules/flake8_bugbear/mod.rs
---
B006_B008.py:88:61: B008 Do not perform function call `range` in argument defaults
|
87 | # N.B. we're also flagging the function call in the comprehension
88 | def list_comprehension_also_not_okay(default=[i**2 for i in range(3)]):
| ^^^^^^^^ B008
89 | pass
|
B006_B008.py:92:64: B008 Do not perform function call `range` in argument defaults
|
92 | def dict_comprehension_also_not_okay(default={i: i**2 for i in range(3)}):
| ^^^^^^^^ B008
93 | pass
|
B006_B008.py:96:60: B008 Do not perform function call `range` in argument defaults
|
96 | def set_comprehension_also_not_okay(default={i**2 for i in range(3)}):
| ^^^^^^^^ B008
97 | pass
|
B006_B008.py:112:39: B008 Do not perform function call `time.time` in argument defaults
B006_B008.py:102:61: B008 Do not perform function call `range` in argument defaults
|
110 | # B008
111 | # Flag function calls as default args (including if they are part of a sub-expression)
112 | def in_fact_all_calls_are_wrong(value=time.time()):
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)]):
| ^^^^^^^^ B008
103 | pass
|
B006_B008.py:106:64: B008 Do not perform function call `range` in argument defaults
|
106 | def dict_comprehension_also_not_okay(default={i: i**2 for i in range(3)}):
| ^^^^^^^^ B008
107 | pass
|
B006_B008.py:110:60: B008 Do not perform function call `range` in argument defaults
|
110 | def set_comprehension_also_not_okay(default={i**2 for i in range(3)}):
| ^^^^^^^^ B008
111 | pass
|
B006_B008.py:126:39: B008 Do not perform function call `time.time` in argument defaults
|
124 | # B008
125 | # Flag function calls as default args (including if they are part of a sub-expression)
126 | def in_fact_all_calls_are_wrong(value=time.time()):
| ^^^^^^^^^^^ B008
113 | ...
127 | ...
|
B006_B008.py:116:12: B008 Do not perform function call `dt.datetime.now` in argument defaults
B006_B008.py:130:12: B008 Do not perform function call `dt.datetime.now` in argument defaults
|
116 | def f(when=dt.datetime.now() + dt.timedelta(days=7)):
130 | def f(when=dt.datetime.now() + dt.timedelta(days=7)):
| ^^^^^^^^^^^^^^^^^ B008
117 | pass
131 | pass
|
B006_B008.py:120:30: B008 Do not perform function call in argument defaults
B006_B008.py:134:30: B008 Do not perform function call in argument defaults
|
120 | def can_even_catch_lambdas(a=(lambda x: x)()):
134 | def can_even_catch_lambdas(a=(lambda x: x)()):
| ^^^^^^^^^^^^^^^ B008
121 | ...
135 | ...
|
B006_B008.py:221:31: B008 Do not perform function call `dt.datetime.now` in argument defaults
B006_B008.py:235:31: B008 Do not perform function call `dt.datetime.now` in argument defaults
|
219 | # B006 and B008
220 | # We should handle arbitrary nesting of these B008.
221 | def nested_combo(a=[float(3), dt.datetime.now()]):
233 | # B006 and B008
234 | # We should handle arbitrary nesting of these B008.
235 | def nested_combo(a=[float(3), dt.datetime.now()]):
| ^^^^^^^^^^^^^^^^^ B008
222 | pass
236 | pass
|
B006_B008.py:227:22: B008 Do not perform function call `map` in argument defaults
B006_B008.py:241:22: B008 Do not perform function call `map` in argument defaults
|
225 | # Don't flag nested B006 since we can't guarantee that
226 | # it isn't made mutable by the outer operation.
227 | def no_nested_b006(a=map(lambda s: s.upper(), ["a", "b", "c"])):
239 | # Don't flag nested B006 since we can't guarantee that
240 | # it isn't made mutable by the outer operation.
241 | def no_nested_b006(a=map(lambda s: s.upper(), ["a", "b", "c"])):
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ B008
228 | pass
242 | pass
|
B006_B008.py:232:19: B008 Do not perform function call `random.randint` in argument defaults
B006_B008.py:246:19: B008 Do not perform function call `random.randint` in argument defaults
|
231 | # B008-ception.
232 | def nested_b008(a=random.randint(0, dt.datetime.now().year)):
245 | # B008-ception.
246 | def nested_b008(a=random.randint(0, dt.datetime.now().year)):
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ B008
233 | pass
247 | pass
|
B006_B008.py:232:37: B008 Do not perform function call `dt.datetime.now` in argument defaults
B006_B008.py:246:37: B008 Do not perform function call `dt.datetime.now` in argument defaults
|
231 | # B008-ception.
232 | def nested_b008(a=random.randint(0, dt.datetime.now().year)):
245 | # B008-ception.
246 | def nested_b008(a=random.randint(0, dt.datetime.now().year)):
| ^^^^^^^^^^^^^^^^^ B008
233 | pass
247 | pass
|