Skip to content

Fix unnecessary-direct-lambda-call when the lambda supplies a class-body scope - #11337

Open
chiruu12 wants to merge 2 commits into
pylint-dev:mainfrom
chiruu12:fix/9294-lambda-class-walrus
Open

Fix unnecessary-direct-lambda-call when the lambda supplies a class-body scope#11337
chiruu12 wants to merge 2 commits into
pylint-dev:mainfrom
chiruu12:fix/9294-lambda-class-walrus

Conversation

@chiruu12

Copy link
Copy Markdown

Type of Changes

Type
🐛 Bug fix

Description

Closes #9294.

unnecessary-direct-lambda-call fired on a directly called lambda whose body holds a comprehension
containing an assignment expression, inside a class body. Doing what the message says produces code
that does not compile:

class C:
    assert (lambda: all((x := object()) is x for _ in range(1)))()   # C3002
SyntaxError: assignment expression within a comprehension cannot be used in a class body

PEP 572 forbids that combination, and the lambda is what supplies the intervening function scope.

Scope of the restriction

Checked each form rather than assuming, since the guard should be no wider than the rule:

genexp / listcomp / setcomp / dictcomp with a walrus, in a class body   SyntaxError
walrus without a comprehension, in a class body                        compiles
comprehension without a walrus, in a class body                        compiles
any of the above inside a function or at module level                  compiles

So the new helper suppresses only when the call's frame is a ClassDef and the lambda body holds a
comprehension containing a NamedExpr.

One case is deliberately still reported:

class C:
    nested = (lambda: [(lambda: [(x := o) for o in range(1)])()])()

Inlining the outer lambda leaves the comprehension inside the inner one, which keeps a scope of its
own, so that compiles and both calls stay flagged. The helper checks that the comprehension's
nearest enclosing lambda or function is the called lambda itself, not something further in.

isinstance against concrete node types throughout, per AGENTS.md.

Tests

Appended to tests/functional/u/unnecessary/unnecessary_direct_lambda_call.py: the four suppressed
comprehension forms, plus four that must still report (bare walrus, plain comprehension, the nested
lambda above, and the same construct in a function rather than a class body). Expected output
regenerated with --update-functional-output.

The file fails on main and passes with the change.

Validation

pytest tests/test_functional.py -k test_functional     14 failed, 877 passed, 42 skipped
pylint pylint/checkers/lambda_expressions.py           10.00/10
pre-commit run --files <the four changed files>        all passed

The 14 failures are pre-existing. I ran the same selection on main with the change stashed and
diffed the failure lists: identical, same 14 names.

News fragment added at doc/whatsnew/fragments/9294.false_positive.

Copilot AI lite review requested due to automatic review settings August 24, 2026 11:08

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

DanielNoord
DanielNoord previously approved these changes Aug 26, 2026
@DanielNoord

Copy link
Copy Markdown
Collaborator

@chiruu12 Can you fix the spelling issues? Either by updating the dictionary we use or by changing the wording? :)

@codecov

codecov Bot commented Aug 26, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 96.43%. Comparing base (e8df942) to head (2a7a752).
⚠️ Report is 8 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main   #11337      +/-   ##
==========================================
+ Coverage   96.42%   96.43%   +0.01%     
==========================================
  Files         178      178              
  Lines       20112    20144      +32     
==========================================
+ Hits        19392    19425      +33     
+ Misses        720      719       -1     
Files with missing lines Coverage Δ
pylint/checkers/lambda_expressions.py 100.00% <100.00%> (ø)

... and 7 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions

This comment has been minimized.

@chiruu12

Copy link
Copy Markdown
Author

Done, reworded. Happy to add the word to custom_dict.txt instead if you would rather keep the term.

@DanielNoord

Copy link
Copy Markdown
Collaborator

@Pierre-Sassoulas I'll be away for a bit. Can you review this and merge it? Thanks in advance!

@Pierre-Sassoulas

Copy link
Copy Markdown
Member

Let's rebase on origin/main, the primer is a mess and brings a month of fixes :D

@github-actions

Copy link
Copy Markdown
Contributor

🤖 According to the primer, this change has no effect on the checked open source code. 🤖🎉

This comment was generated for commit 2a7a752

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

False positive unnecessary-direct-lambda-call / C3002 with assignment expression

4 participants