Repository navigation
B911: don't flag a bare batched() the module binds to something else - #608
Merged
Merged
Conversation
A bare batched() call was always treated as itertools.batched, so a module with its own `def batched(iterable, n)` (a common backport for Pythons before 3.12) or one imported from another library got B911 for a function that has no strict parameter. B911 now reuses the check B031 already does for groupby(): the bare name counts as itertools.batched only when the module imports it from itertools or doesn't bind it at all. A try/except fallback that imports it from itertools is still reported, and itertools.batched(...) calls are always checked.
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
The guard incorrectly suppresses B911 diagnostics for assignment-based itertools.batched aliases, including try/except fallbacks, requiring a fix and regression coverage that preserves B031 behavior.
1 open issue
What changed in this PR
This PR reduces B911 false positives for custom batched() implementations by reusing B031’s module-level binding check.
Changes:
- Generalizes the itertools name resolver and its cache for use by B031 and B911.
- Adds regression cases for local definitions, third-party imports, and import fallbacks.
- Documents the B911 behavior change in the unreleased changelog.
| File | Description |
|---|---|
tests/eval_files/b911_shadowed.py |
Covers a locally defined batched and a qualified itertools call. |
tests/eval_files/b911_shadowed_import.py |
Covers a third-party batched import. |
tests/eval_files/b911_shadowed_fallback.py |
Keeps B911 reporting for an itertools import with a backport fallback. |
README.rst |
Adds the B911 changelog entry. |
bugbear.py |
Shares itertools binding resolution between B031 and B911. |
Review effort: Balanced
| ( | ||
| isinstance(node.func, ast.Name) | ||
| and node.func.id == "batched" | ||
| and self._bare_name_is_itertools("batched") |
Contributor
Author
There was a problem hiding this comment.
Good catch, fixed: batched = itertools.batched (also inside a try/except fallback) now counts as itertools again, with new eval files for both. B031 gets the same through the shared helper, so groupby = itertools.groupby is now covered too.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

B911 treats every bare
batched()call asitertools.batched. Projects that still support Python < 3.12 often ship their own backport, which has nostrictparameter, and they get B911 on every call:B031 already handles the same thing for
groupby()(#356): a baregroupbyonly counts as itertools when the module imports it from itertools or doesn't bind the name at all. This turns that helper into one that takes the name, and B911 now uses it forbatched. It also recognisesbatched = itertools.batchedassignments (including insidetry/except), which B031 gets forgroupbyas well. Some things are still reported:itertools.batched(...)calls.from itertools import batchedandfrom itertools import *.try: from itertools import batched / except ImportError: def batched(...)fallback, since on newer Pythons the name really is itertools.batched.batched = itertools.batched, also as atry/except AttributeErrorfallback.On about 48,000 files (site-packages from eight project virtualenvs, Ubuntu's Python 3.12 stdlib and the repos in my workspace), B911 reports drop from 30 to 4 and B031 stays at 14. Nothing new is reported. The 26 removed reports come from three sources, each installed in several venvs: fontTools (backport with no
strict), blosc2 (batchedimported from its ownproxy_sourcebackport) and the copy of more_itertools vendored in setuptools, which defines its ownbatchedwrapper.New cases are in
tests/eval_files/b911_shadowed*.pyandtests/eval_files/b031_shadowed_alias.py. Three of them fail onmain(the B911 alias cases pass there and guard the regression). tox py310–py315, mypy and pep8_naming pass, and so does pre-commit.