Skip to content

B018: don't flag map() and friends the module binds to something else - #609

Open
LuisFigueroaG wants to merge 1 commit into
PyCQA:mainfrom
LuisFigueroaG:fix/b018-shadowed-builtins
Open

LuisFigueroaG wants to merge 1 commit into
PyCQA:mainfrom
LuisFigueroaG:fix/b018-shadowed-builtins

Conversation

@LuisFigueroaG

Copy link
Copy Markdown
Contributor

B018 reports a bare map(), filter(), reversed(), zip() or enumerate() 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:

# statsmodels/tsa/statespace/tests/test_kalman.py
def test_copied_filter(self):
    _, filter = self.init_filter()
    filter()  # B018, but this runs the Kalman filter

The same goes for a module with its own def map(func, items) or from mylib import map.

B031 and B911 already have this check for groupby() and batched() (#608). This makes it take the module the name should come from, and B018 uses it with builtins. Still reported:

  • names the module never binds, which is the usual case.
  • from builtins import map and from 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 on main (the alias case passes there and guards the regression). tox py310–py315, mypy and pep8_naming pass, and so does pre-commit.

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.

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.

🟡 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(), and enumerate() 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

Comment thread bugbear.py
and node.module == source
):
from_itertools = True
from_source = True
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.

2 participants