Skip to content

B031: don't count mutually exclusive branch usages - #572

Open
Sonike wants to merge 2 commits into
PyCQA:mainfrom
Sonike:fix/b031-conditional-branches
Open

B031: don't count mutually exclusive branch usages#572
Sonike wants to merge 2 commits into
PyCQA:mainfrom
Sonike:fix/b031-conditional-branches

Conversation

@Sonike

@Sonike Sonike commented Aug 30, 2026

Copy link
Copy Markdown

Fixes #465.

Summary

  • track the maximum number of groupby generator uses along each mutually exclusive if/elif/else path instead of summing all branches
  • preserve B031 diagnostics for repeated uses on the same path, uses after a conditional, condition expressions that consume the generator, and nested loops
  • add focused eval fixtures for both the false-positive regression and the preserved warning cases
  • update the unreleased changelog entry

Validation

  • tox -e py313 — 80 passed, 1 skipped; 98% coverage
  • Python 3.14 full test run — 81 passed
  • pre-commit run --all-files — isort, Black, flake8, and rstcheck passed
  • git diff --check

Scope

This PR is limited to mutually exclusive conditional branches. The annotation-target case mentioned later in the issue was already fixed separately in #558.

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

Updates B031 to avoid false positives across mutually exclusive conditional branches.

Changes:

  • Adds branch-aware generator usage tracking.
  • Adds regression and preserved-warning fixtures.
  • Updates the unreleased changelog.

Reviewed changes

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

File Description
bugbear.py Implements branch-aware B031 analysis.
tests/eval_files/b031.py Adds conditional-branch fixtures.
README.rst Documents the B031 change.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread bugbear.py Outdated
Comment on lines +1407 to +1420
if isinstance(node, ast.For):
num_usages = self._check_b031_group_usage(
node.target, group_name, num_usages, repeated
)
num_usages = self._check_b031_group_usage(
node.iter, group_name, num_usages, repeated
)
# Any body reference may run once per nested loop iteration.
num_usages = self._check_b031_group_usages(
node.body, group_name, num_usages, True
)
return self._check_b031_group_usages(
node.orelse, group_name, num_usages, repeated
)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Good catch. I added failing fixtures for conditional branches inside both while and async for, then updated the traversal to treat those loop bodies as repeated. The full Python 3.13/3.14 test runs and all pre-commit checks pass in 98fec80.

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.

B031 does not take into account if-else statements

2 participants