Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[flake8-bugbear] add autofix for B006 mutable_argument_default #4880

Closed
wants to merge 14 commits into from
Closed

[flake8-bugbear] add autofix for B006 mutable_argument_default #4880

wants to merge 14 commits into from

Conversation

qdegraaf
Copy link
Contributor

@qdegraaf qdegraaf commented Jun 5, 2023

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:

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: #4693

@github-actions
Copy link
Contributor

github-actions bot commented Jun 5, 2023

PR Check Results

Ecosystem

ℹ️ ecosystem check detected changes. (+45, -45, 0 error(s))

airflow (+11, -11)

- airflow/models/dag.py:2125:30: B006 Do not use mutable data structures for argument defaults
+ airflow/models/dag.py:2125:30: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
- airflow/providers/amazon/aws/hooks/emr.py:259:78: B006 Do not use mutable data structures for argument defaults
+ airflow/providers/amazon/aws/hooks/emr.py:259:78: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
- airflow/providers/amazon/aws/operators/lambda_function.py:76:24: B006 Do not use mutable data structures for argument defaults
+ airflow/providers/amazon/aws/operators/lambda_function.py:76:24: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
- airflow/providers/amazon/aws/sensors/lambda_function.py:59:31: B006 Do not use mutable data structures for argument defaults
+ airflow/providers/amazon/aws/sensors/lambda_function.py:59:31: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
- airflow/providers/amazon/aws/transfers/azure_blob_to_s3.py:93:33: B006 Do not use mutable data structures for argument defaults
+ airflow/providers/amazon/aws/transfers/azure_blob_to_s3.py:93:33: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
- airflow/providers/amazon/aws/transfers/azure_blob_to_s3.py:94:31: B006 Do not use mutable data structures for argument defaults
+ airflow/providers/amazon/aws/transfers/azure_blob_to_s3.py:94:31: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
- airflow/providers/amazon/aws/transfers/redshift_to_s3.py:106:42: B006 Do not use mutable data structures for argument defaults
+ airflow/providers/amazon/aws/transfers/redshift_to_s3.py:106:42: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
- airflow/providers/amazon/aws/transfers/s3_to_redshift.py:99:42: B006 Do not use mutable data structures for argument defaults
+ airflow/providers/amazon/aws/transfers/s3_to_redshift.py:99:42: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
- airflow/utils/event_scheduler.py:32:16: B006 Do not use mutable data structures for argument defaults
+ airflow/utils/event_scheduler.py:32:16: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
- tests/api_connexion/endpoints/test_mapped_task_instance_endpoint.py:93:74: B006 Do not use mutable data structures for argument defaults
+ tests/api_connexion/endpoints/test_mapped_task_instance_endpoint.py:93:74: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
- tests/conftest.py:719:25: B006 Do not use mutable data structures for argument defaults
+ tests/conftest.py:719:25: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`

bokeh (+34, -34)

- examples/interaction/js_callbacks/js_on_event.py:15:53: B006 Do not use mutable data structures for argument defaults
+ examples/interaction/js_callbacks/js_on_event.py:15:53: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
- examples/server/app/events_app.py:16:35: B006 Do not use mutable data structures for argument defaults
+ examples/server/app/events_app.py:16:35: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
- examples/server/app/events_app.py:38:28: B006 Do not use mutable data structures for argument defaults
+ examples/server/app/events_app.py:38:28: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
- src/bokeh/application/handlers/code.py:82:78: B006 Do not use mutable data structures for argument defaults
+ src/bokeh/application/handlers/code.py:82:78: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
- src/bokeh/application/handlers/directory.py:110:65: B006 Do not use mutable data structures for argument defaults
+ src/bokeh/application/handlers/directory.py:110:65: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
- src/bokeh/application/handlers/notebook.py:66:65: B006 Do not use mutable data structures for argument defaults
+ src/bokeh/application/handlers/notebook.py:66:65: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
- src/bokeh/application/handlers/script.py:80:65: B006 Do not use mutable data structures for argument defaults
+ src/bokeh/application/handlers/script.py:80:65: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
- src/bokeh/application/handlers/server_lifecycle.py:55:65: B006 Do not use mutable data structures for argument defaults
+ src/bokeh/application/handlers/server_lifecycle.py:55:65: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
- src/bokeh/application/handlers/server_request_handler.py:57:65: B006 Do not use mutable data structures for argument defaults
+ src/bokeh/application/handlers/server_request_handler.py:57:65: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
- src/bokeh/core/json_encoder.py:178:51: B006 Do not use mutable data structures for argument defaults
+ src/bokeh/core/json_encoder.py:178:51: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
- src/bokeh/core/property/container.py:123:82: B006 Do not use mutable data structures for argument defaults
+ src/bokeh/core/property/container.py:123:82: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
- src/bokeh/core/property/container.py:150:82: B006 Do not use mutable data structures for argument defaults
+ src/bokeh/core/property/container.py:150:82: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
- src/bokeh/core/property/container.py:189:32: B006 Do not use mutable data structures for argument defaults
+ src/bokeh/core/property/container.py:189:32: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
- src/bokeh/core/property/container.py:297:32: B006 Do not use mutable data structures for argument defaults
+ src/bokeh/core/property/container.py:297:32: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
- src/bokeh/core/property/container.py:310:66: B006 Do not use mutable data structures for argument defaults
+ src/bokeh/core/property/container.py:310:66: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
- src/bokeh/core/property/visual.py:133:32: B006 Do not use mutable data structures for argument defaults
+ src/bokeh/core/property/visual.py:133:32: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
- src/bokeh/core/property/visual.py:92:32: B006 Do not use mutable data structures for argument defaults
+ src/bokeh/core/property/visual.py:92:32: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
- src/bokeh/core/property/wrappers.py:404:37: B006 Do not use mutable data structures for argument defaults
+ src/bokeh/core/property/wrappers.py:404:37: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
- src/bokeh/core/serialization.py:217:52: B006 Do not use mutable data structures for argument defaults
+ src/bokeh/core/serialization.py:217:52: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
- src/bokeh/embed/bundle.py:108:46: B006 Do not use mutable data structures for argument defaults
+ src/bokeh/embed/bundle.py:108:46: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
- src/bokeh/embed/bundle.py:108:70: B006 Do not use mutable data structures for argument defaults
+ src/bokeh/embed/bundle.py:108:70: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
- src/bokeh/embed/bundle.py:109:36: B006 Do not use mutable data structures for argument defaults
+ src/bokeh/embed/bundle.py:109:36: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
- src/bokeh/embed/bundle.py:109:61: B006 Do not use mutable data structures for argument defaults
+ src/bokeh/embed/bundle.py:109:61: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
- src/bokeh/embed/bundle.py:109:82: B006 Do not use mutable data structures for argument defaults
+ src/bokeh/embed/bundle.py:109:82: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
- src/bokeh/embed/elements.py:84:46: B006 Do not use mutable data structures for argument defaults
+ src/bokeh/embed/elements.py:84:46: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
- src/bokeh/embed/server.py:130:114: B006 Do not use mutable data structures for argument defaults
+ src/bokeh/embed/server.py:130:114: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
- src/bokeh/embed/standalone.py:299:52: B006 Do not use mutable data structures for argument defaults
+ src/bokeh/embed/standalone.py:299:52: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
- src/bokeh/layouts.py:317:26: B006 Do not use mutable data structures for argument defaults
+ src/bokeh/layouts.py:317:26: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
- src/bokeh/plotting/_renderer.py:144:56: B006 Do not use mutable data structures for argument defaults
+ src/bokeh/plotting/_renderer.py:144:56: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
- src/bokeh/plotting/_renderer.py:144:78: B006 Do not use mutable data structures for argument defaults
+ src/bokeh/plotting/_renderer.py:144:78: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
- tests/support/util/examples.py:77:90: B006 Do not use mutable data structures for argument defaults
+ tests/support/util/examples.py:77:90: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
- tests/unit/bokeh/models/_util_models.py:87:127: B006 Do not use mutable data structures for argument defaults
+ tests/unit/bokeh/models/_util_models.py:87:127: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
- tests/unit/bokeh/server/_util_server.py:66:35: B006 Do not use mutable data structures for argument defaults
+ tests/unit/bokeh/server/_util_server.py:66:35: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`
- tests/unit/bokeh/test_events.py:43:35: B006 Do not use mutable data structures for argument defaults
+ tests/unit/bokeh/test_events.py:43:35: B006 [*] Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`

Rules changed: 1
Rule Changes Additions Removals
B006 90 45 45

Benchmark

Linux

group                                      main                                   pr
-----                                      ----                                   --
formatter/large/dataset.py                 1.02      9.6±0.05ms     4.2 MB/sec    1.00      9.4±0.03ms     4.3 MB/sec
formatter/numpy/ctypeslib.py               1.01   1884.1±3.67µs     8.8 MB/sec    1.00   1868.9±3.87µs     8.9 MB/sec
formatter/numpy/globals.py                 1.00    210.4±0.28µs    14.0 MB/sec    1.00    210.2±1.44µs    14.0 MB/sec
formatter/pydantic/types.py                1.02      4.1±0.01ms     6.2 MB/sec    1.00      4.0±0.01ms     6.3 MB/sec
linter/all-rules/large/dataset.py          1.01     13.5±0.12ms     3.0 MB/sec    1.00     13.4±0.10ms     3.0 MB/sec
linter/all-rules/numpy/ctypeslib.py        1.01      3.4±0.02ms     4.9 MB/sec    1.00      3.4±0.01ms     5.0 MB/sec
linter/all-rules/numpy/globals.py          1.01    440.7±0.92µs     6.7 MB/sec    1.00    434.5±0.64µs     6.8 MB/sec
linter/all-rules/pydantic/types.py         1.00      6.0±0.06ms     4.2 MB/sec    1.00      6.0±0.05ms     4.2 MB/sec
linter/default-rules/large/dataset.py      1.00      6.5±0.02ms     6.2 MB/sec    1.00      6.5±0.02ms     6.2 MB/sec
linter/default-rules/numpy/ctypeslib.py    1.00   1401.5±5.19µs    11.9 MB/sec    1.00   1401.8±3.80µs    11.9 MB/sec
linter/default-rules/numpy/globals.py      1.02    155.3±0.30µs    19.0 MB/sec    1.00    152.8±2.58µs    19.3 MB/sec
linter/default-rules/pydantic/types.py     1.00      2.9±0.01ms     8.6 MB/sec    1.00      2.9±0.01ms     8.7 MB/sec

Windows

group                                      main                                   pr
-----                                      ----                                   --
formatter/large/dataset.py                 1.00     14.6±0.61ms     2.8 MB/sec    1.02     14.9±0.89ms     2.7 MB/sec
formatter/numpy/ctypeslib.py               1.00      2.8±0.15ms     5.9 MB/sec    1.05      3.0±0.18ms     5.6 MB/sec
formatter/numpy/globals.py                 1.00   321.5±25.30µs     9.2 MB/sec    1.03   331.4±31.54µs     8.9 MB/sec
formatter/pydantic/types.py                1.01      6.3±0.31ms     4.1 MB/sec    1.00      6.2±0.29ms     4.1 MB/sec
linter/all-rules/large/dataset.py          1.00     20.6±0.66ms  2024.3 KB/sec    1.08     22.2±0.84ms  1874.8 KB/sec
linter/all-rules/numpy/ctypeslib.py        1.00      5.6±0.21ms     3.0 MB/sec    1.00      5.6±0.28ms     3.0 MB/sec
linter/all-rules/numpy/globals.py          1.02   654.2±39.69µs     4.5 MB/sec    1.00   642.2±31.85µs     4.6 MB/sec
linter/all-rules/pydantic/types.py         1.01      9.6±0.55ms     2.7 MB/sec    1.00      9.5±0.50ms     2.7 MB/sec
linter/default-rules/large/dataset.py      1.01     10.9±1.04ms     3.7 MB/sec    1.00     10.9±0.48ms     3.7 MB/sec
linter/default-rules/numpy/ctypeslib.py    1.02      2.3±0.10ms     7.4 MB/sec    1.00      2.2±0.17ms     7.5 MB/sec
linter/default-rules/numpy/globals.py      1.09   292.7±24.20µs    10.1 MB/sec    1.00   267.4±18.36µs    11.0 MB/sec
linter/default-rules/pydantic/types.py     1.06      5.0±0.30ms     5.1 MB/sec    1.00      4.8±0.18ms     5.4 MB/sec

@qdegraaf qdegraaf changed the title [flake8-bugbear] add autofix for B006 mutable_argument_default [flake8-bugbear] add autofix for B006 mutable_argument_default Jun 22, 2023
@charliermarsh charliermarsh self-requested a review June 26, 2023 17:43
Copy link
Member

@konstin konstin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is really useful fix to have given how popular the problem is

@staticmethod
def this_is_also_wrong_and_more_indented(value={}):
pass

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

another test case i'd like to see is a multi-line default value

Copy link
Member

@charliermarsh charliermarsh Jul 7, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also need to handle same-line functions (we should just avoid trying to fix these):

def f(value = {}): ...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll add both and have already set fix to manual. Can also change to not suggest at all for same-line funcs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So multiline arg seems to do fine, but same-line func creates defunct Python. It's best to not fix these indeed. Is there a quick way to check if a function is one line, or its body is on the same line as its def?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

locator.contains_line_break between the colon (:) and the first body statement should work

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a check for single-line func and changed from AlwaysAutoFixableViolation to Violation and sometimes fixable (also already changed the fixes to manual as per request in another comment so unsure what type of Violation the rule should now be to be fair, as so far it appears to be the only rule using manual_edit(s))

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm my heuristic is not covering all cases in the end.

checker
                    .locator
                    .contains_line_break(TextRange::new(arguments.range().end(), body[0].start()))

Allows weird things like

def single_line_func_wrong(value = {}

                           )\
    : ...

To slip through. Is there a way to efficiently locate the range value of the :? I have found the lexer::lex but that would require getting a string representation of the function def. Is that the way to go, or is there a better way to locate single characters in parts of a StmtFunctionDef? Maybe a find_x_in_range like util or something along those lines?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using the lexer when creating a diagnostic can be useful, but it is preferred not to when possible. But I don't see how you can get away with not using the lexer here (we wrote a more lightweight lexer in the formatter, because getting to tokens is such a common task, maybe it's time to make it available to ruff too). You can get the string representation of the function def by using locator.slice(def.range()). You can then start lexing after the last argument, find the colon. Then use locator.contains_line_break(TextRange::new(colon.end(), first_statement.start()

Which raises an interesting question. Is this valid? Is this a suite or a single statement body

def single_line_func_wrong(value = {}):\
	...

Unrelated: @konstin a use case where StmtSuite would be handy... It would tell us right away whether it is a single statement or a suite.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the hyperclear instructions and context. I'll see if I can spot and autofix the

def single_line_func_wrong(value = {}):\
    ...

scenario without too much hassle and, if so, include it and only leave out the

def single_line_func_wrong(value = {}): ...

scenario.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I've managed to exclude def single_line_func_wrong(value = {}): ... based on your instructions. The other scenario you raise is tricky though. The lexer does not do anything with the \ and it counts as a line break for contains_line_break() so current implementation still tries to make:

def single_line_func_wrong(value = None):\
    if value is None:
        value = {}

of it, which is broken. Is there a way to discern \ line breaks from other line breaks? Or do we want to go a different route here?

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]));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Manual edits won't be applied when running --fix in the future and are intended to be used for fixes that are known to contain syntax errors. Do you expect the fixes to contain syntax errors? If not, consider using suggested instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently only syntax errors I am aware of that can occur is in the case of weirdly formatted single line funcs. See also: #4880 (comment) if that can be fixed it can go to suggested AFAIAC.

@dhruvmanila
Copy link
Member

dhruvmanila commented Jul 15, 2023

Sorry I didn't realize that merging #5776 would create merge conflicts here.

Edit: I've resolved the conflicts :)

Comment on lines -55 to +69
format!("Do not use mutable data structures for argument defaults")
format!("Replace mutable data structure with `None` in argument default and replace it with data structure inside the function if still `None`")
}
fn autofix_title(&self) -> Option<String> {
Some(format!(
"Do not use mutable data structures for argument defaults"
))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be reversed as in the new message (the one with "Replace...") would be the autofix title?

Copy link
Contributor Author

@qdegraaf qdegraaf Jul 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that was the case until: #4880 (comment) but that was more of a length argument. Agree that the phrasing now is potentially confusing. Can find a way to get the best of both worlds.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting! I think editors would be using the violation message to display instead of the autofix title and I believe that's the top level key in the diagnostic data sent by the LSP server as well. \cc @MichaReiser

@charliermarsh
Copy link
Member

(This PR is on me to do final review + merge.)

@qdegraaf qdegraaf closed this by deleting the head repository Jul 27, 2023
konstin added a commit that referenced this pull request Aug 10, 2023
## Summary

Reopening of #4880 

One open TODO as described in:
#4880 (comment)

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: #4693

---------

Co-authored-by: konstin <[email protected]>
durumu pushed a commit to durumu/ruff that referenced this pull request Aug 12, 2023
## Summary

Reopening of astral-sh#4880 

One open TODO as described in:
astral-sh#4880 (comment)

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: astral-sh#4693

---------

Co-authored-by: konstin <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Autofix B006 (mutable-argument-default)
5 participants