Skip to content

Fix a crash in not-async-context-manager when the manager has no name - #11103

Merged
Pierre-Sassoulas merged 5 commits into
pylint-dev:mainfrom
binggao1230:fix-11102-async-slice-name
Jun 14, 2026
Merged

Fix a crash in not-async-context-manager when the manager has no name#11103
Pierre-Sassoulas merged 5 commits into
pylint-dev:mainfrom
binggao1230:fix-11102-async-slice-name

Conversation

@binggao1230

Copy link
Copy Markdown
Contributor

Type of Changes

Type
🐛 Bug fix

Description

async with slice(None): crashed pylint:

File "pylint/checkers/async_checker.py", line 92, in visit_asyncwith
    "not-async-context-manager", node=node, args=(inferred.name,)
AttributeError: 'Slice' object has no attribute 'name'

visit_asyncwith builds the not-async-context-manager message argument from inferred.name, but the inferred context manager isn't guaranteed to have a name. slice(None) infers to a Slice node, which has no name, so emitting the (otherwise correct) warning raised AttributeError and aborted the run.

It now falls back to the inferred type name when there is no name, so slice(None) reports Async context manager 'slice' doesn't implement __aenter__ and __aexit__. — consistent with how the other value managers are already reported (e.g. async with 42'int'). Among the value nodes that can appear here only Slice lacks a name (Const/List/Tuple/Dict all expose their type name), so this covers the reported case.

Added the slice(None) case to the existing not_async_context_manager functional test (crashes on main, passes here).

Closes #11102

visit_asyncwith built the message argument from inferred.name, but an
inferred context manager need not have a name -- e.g. async with slice(None)
infers to a Slice node -- so pylint crashed with AttributeError instead of
emitting not-async-context-manager. Fall back to the inferred type name
(slice), matching how other value managers are already reported (int, ...).

Closes pylint-dev#11102
@codecov

codecov Bot commented Jun 13, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 96.29%. Comparing base (2f47d86) to head (2027451).

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##             main   #11103   +/-   ##
=======================================
  Coverage   96.29%   96.29%           
=======================================
  Files         178      178           
  Lines       19737    19743    +6     
=======================================
+ Hits        19006    19012    +6     
  Misses        731      731           
Files with missing lines Coverage Δ
pylint/checkers/async_checker.py 100.00% <100.00%> (ø)
pylint/checkers/typecheck.py 96.58% <100.00%> (+0.01%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@Pierre-Sassoulas Pierre-Sassoulas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thank you for contributing to pylint ! Let's anticipate other similar issue and use domain knowledge to make the guard better.

Comment on lines +61 to +62
async with slice(None): # [not-async-context-manager]
pass

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Let's also add a with slice(None):. And move it to the functional test of the checker or checkers that are going to crash when we do :)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good call. The synchronous with slice(None): crashes not-context-manager in the same way (astroid raises AttributeInferenceError on the missing .name), so I added a functional case for it in tests/functional/n/not_context_manager.py and fixed that checker too (verified red before the fix, green after).

Comment thread pylint/checkers/async_checker.py Outdated
# inferred from ``slice(...)``); fall back to its inferred type name.
inferred_name = (
getattr(inferred, "name", None) or inferred.pytype().rsplit(".", 1)[-1]
)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We can often narrow down the type of the inferred node using the visitor pattern filtering and domain knowledge about python syntax in order to use isinstance check instead of getattr

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done. I checked what actually reaches this point: every other inferred result is name-bearing (a class/function, or an instance such as the int that astroid models as a named Const for 42); a Slice from slice(...) is the only nameless case. So the guard is now an explicit isinstance(inferred, nodes.Slice) that falls back to the builtin type name, instead of getattr(..., "name", None). Same guard applied to the sync not-context-manager site.

@Pierre-Sassoulas Pierre-Sassoulas added this to the 4.0.7 milestone Jun 14, 2026
Replace the getattr-based name fallback with an explicit isinstance check on
nodes.Slice (the one inferred result reaching these checks without a name;
everything else, including the int from a Const, is name-bearing).

Apply the same guard to typecheck's not-context-manager check, which crashed
identically on 'with slice(None):', and add a functional test case there.
Comment thread pylint/checkers/async_checker.py Outdated
# ``int`` from ``42``, which astroid models as a named ``Const``).
inferred_name = (
inferred.pytype().rsplit(".", 1)[-1]
if isinstance(inferred, nodes.Slice)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm not certain we can be sure that Slice is the only node without a name attribute here, I'd rather have an allow list of node known to work (baseinstance/classdef/functiondef/module etc.)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good point, switched to that approach in c0a184e. Both sites now read .name only from an allow list of node types that define it (ClassDef, FunctionDef, Module, bases.BaseInstance) and fall back to the inferred type name otherwise, so any unforeseen nameless node degrades gracefully instead of crashing. The existing functional cases (instances, generators, int, etc.) are all BaseInstance/ClassDef so their messages are unchanged, and slice(...) takes the fallback and still reports slice.

@Pierre-Sassoulas Pierre-Sassoulas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thank you for checking, let's just invert the logic from disallow list to allow list to avoid future crash if the list is not perfect and let's merge.

Read .name only from ClassDef/FunctionDef/Module/BaseInstance (the nodes
known to define it) and fall back to the inferred type name for anything
else, instead of special-casing Slice. This avoids relying on Slice being
the only nameless inferred node.
Comment thread pylint/checkers/async_checker.py
Pierre-Sassoulas and others added 2 commits June 14, 2026 17:03
Co-authored-by: Pierre Sassoulas <pierre.sassoulas@gmail.com>
Keeps the typecheck.py allow list identical to the async_checker.py one
after the review suggestion added nodes.Lambda there.
@binggao1230

binggao1230 commented Jun 14, 2026

Copy link
Copy Markdown
Contributor Author

Mirrored your nodes.Lambda suggestion to the identical allow list in typecheck.py (the sync not-context-manager site) so the two stay in lockstep — the suggestion UI could only touch the async_checker.py hunk. Functional tests for both still pass. Ready to merge from my side.

@Pierre-Sassoulas Pierre-Sassoulas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Great, thank you !

@Pierre-Sassoulas
Pierre-Sassoulas merged commit c4f8d9b into pylint-dev:main Jun 14, 2026
44 checks passed
Pierre-Sassoulas added a commit that referenced this pull request Jun 14, 2026
… when the manager has no name (#11107)

Fix a crash in not--context-manager when the manager has no name (#11103)

visit_asyncwith / visit_with built the message argument from inferred.name, but an
inferred context manager need not have a name -- e.g. async with slice(None)
infers to a Slice node, so pylint crashed with AttributeError instead of
emitting not-async-context-manager. Fall back to the inferred type name
(slice), matching how other value managers are already reported (int, ...).

Closes #11102


(cherry picked from commit c4f8d9b)

Co-authored-by: Vincent Gao <gaobing1230@gmail.com>
Co-authored-by: Pierre Sassoulas <pierre.sassoulas@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport maintenance/4.0.x Crash 💥 A bug that makes pylint crash

2 participants