Skip to content

Fix B020 false positive for attribute iterables#562

Open
gaoflow wants to merge 1 commit into
PyCQA:mainfrom
gaoflow:fix-521-b020-attribute-access
Open

Fix B020 false positive for attribute iterables#562
gaoflow wants to merge 1 commit into
PyCQA:mainfrom
gaoflow:fix-521-b020-attribute-access

Conversation

@gaoflow

@gaoflow gaoflow commented Jun 25, 2026

Copy link
Copy Markdown

Fixes #521.

Summary

  • stop B020 from treating the base name of a plain attribute iterable like smoother.smoothers as the iterable being reassigned
  • keep method-call iterable cases such as values.items() covered
  • add a regression case for attribute access on the loop target name

Tests

  • uv run --python 3.13 --with '.[dev]' pytest tests/test_bugbear.py -k B020 -q
  • uv run --python 3.13 --with '.[dev]' pytest tests/test_bugbear.py -q
  • uv run --python 3.13 --with flake8 --with attrs flake8 bugbear.py tests/test_bugbear.py
  • uv run --python 3.13 --with mypy --with types-flake8 --with attrs --with flake8 mypy bugbear.py
  • git diff --check

@cooperlees cooperlees left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I'm not sure we want to fix this, open to other perspectives tho ... and I'll go with majority ...

Comment thread tests/eval_files/b020.py
Comment on lines +44 to +45
for smoother in smoother.smoothers:
print(smoother)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
for smoother in smoother.smoothers:
print(smoother)
for smoother_loop in smoother.smoothers:
print(smoother_loop)
smoother = smother_loop

I argue not doing this is a good practice even tho it's technically not overwriting what your iterating ...

I am a fan of being explicit even at the cost of more assignments etc.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes a B020 false positive where the loop target name appears as the base of an attribute-access iterable (e.g., for smoother in smoother.smoothers:), while preserving detection for method-call iterables (e.g., values.items()), and adds a regression test to cover the reported case from #521.

Changes:

  • Update B020 iterable name collection to ignore plain attribute access while still traversing method-call bases.
  • Add an eval-file regression case ensuring for smoother in smoother.smoothers: does not trigger B020.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
bugbear.py Adjusts B020NameFinder traversal to skip ast.Attribute nodes and special-case method calls so existing B020 coverage (like values.items()) remains.
tests/eval_files/b020.py Adds a regression example for attribute access on the loop target name that should not emit B020.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread bugbear.py
@@ -2214,6 +2214,18 @@ def visit(self, node) -> None:
class B020NameFinder(NameFinder):
"""Ignore names defined within the local scope of a comprehension."""
@gaoflow

gaoflow commented Jun 26, 2026

Copy link
Copy Markdown
Author

Thanks for looking. My reasoning for treating this as a false positive is that B020 is most useful when the loop target overwrites the iterable object itself, e.g. the warning protects for value in values: and receiver-style calls like for key in values.keys().

For plain attribute access, for smoother in smoother.smoothers: reads the iterable before the loop target is rebound, and the rebound name does not change the object that supplied .smoothers. That makes it closer to a normal attribute traversal than to the self-iteration bug B020 is trying to catch.

The patch keeps the existing method-call behavior (values.items(), etc.) because those still indicate iterating over the same named object. But I understand if the project prefers the more conservative warning despite the false positive.

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.

B020 false positives with iterable attribute acess

3 participants