Repository navigation
B018: don't flag map() and friends the module binds to something else - #609
Open
LuisFigueroaG wants to merge 1 commit into
Open
LuisFigueroaG wants to merge 1 commit into
LuisFigueroaG wants to merge 1 commit into
Conversation
B018 reported every bare map(), filter(), reversed(), zip() and enumerate() statement as a lazy builtin, even when the module defines its own `def map()`, imports one from another library or assigns the name to some other callable. Those calls can do real work. The check B031 and B911 use to tell whether a bare groupby()/batched() is the itertools one now takes the module to compare against, and B018 uses it with builtins. `from builtins import map`, `map = builtins.map` and names the module never binds are still reported.
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
An active moderate issue remains because later module-level definitions or assignments do not override the earlier import, causing B018 to misidentify shadowed names as lazy builtins.
1 open issue
What changed in this PR
This pull request updates B018 to report bare lazy-iterator calls only when they resolve to Python builtins, avoiding false positives for module-defined or imported alternatives. It also generalizes module-binding resolution used by B031 and B911.
Changes:
- Generalizes module binding detection for arbitrary source modules and aliases.
- Applies builtin resolution to B018’s
map(),filter(),reversed(),zip(), andenumerate()checks. - Adds shadowing and alias regression fixtures.
- Documents the unreleased behavior change in
README.rst.
| File | Summary |
|---|---|
tests/eval_files/b018_shadowed.py |
Tests module-defined lazy-function names and builtin fallback behavior. |
tests/eval_files/b018_shadowed_import.py |
Tests builtin and third-party imports under lazy-builtin names. |
tests/eval_files/b018_shadowed_alias.py |
Tests assignments from builtins.map. |
README.rst |
Documents the unreleased B018 shadowing behavior. |
bugbear.py |
Generalizes name-resolution helpers and applies builtin resolution to B018, B031, and B911. A moderate issue remains because later definitions or assignments do not override earlier imports in source-order resolution. |
This pull request requires changes.
Review effort: Lite
| and node.module == source | ||
| ): | ||
| from_itertools = True | ||
| from_source = True |
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.

B018 reports a bare
map(),filter(),reversed(),zip()orenumerate()statement as a lazy builtin (#605), but it doesn't check that the name is the builtin. When the module binds it to something else, the call can do real work. From statsmodels' tests:The same goes for a module with its own
def map(func, items)orfrom mylib import map.B031 and B911 already have this check for
groupby()andbatched()(#608). This makes it take the module the name should come from, and B018 uses it withbuiltins. Still reported:from builtins import mapandfrom builtins import *.map = builtins.map.On about 51,000 files (site-packages from ten project virtualenvs, Ubuntu's Python 3.12 stdlib and the repos in my workspace), B018 reports go from 2887 to 2886. Nothing new is reported. The removed one is the statsmodels case above. The other 16 lazy-builtin reports stay, such as
map(np.random.shuffle, d1)in numpy's tests, which never shuffles anything.New cases are in
tests/eval_files/b018_shadowed*.py. Two of them fail onmain(the alias case passes there and guards the regression). tox py310–py315, mypy and pep8_naming pass, and so does pre-commit.