-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
pylint is confusing ExitStack() and AsyncExitStack() when both are used #7464
pylint is confusing ExitStack() and AsyncExitStack() when both are used #7464
Comments
Thank you for opening the issue. It look like it could be somewhat related to #4053 |
I don't see the relation: here, the modules are fully different (path and content). |
The problem is around pop_all() method. In contextlib.py, both ExitStack and AsyncExitStack are inheriting their pop_all() method from _BaseExitStack whose implementation looks like:
It seems pylint is inferring the type of pop_all() return type once and then re-using the same type again whatever the derived class is. |
Thank you for investigating, this root cause look like something that could fix a bunch of other bugs too. |
You are welcome, I'm glad to give back a bit to pylint. I've pushed my investigation further and was finally able to reproduce the problem out of contextlib usage. Consider the following two files, pylint finds 3 no-member issues in them:
other.py
unexpected_no_member_findings.py
|
Do you want to go further and try to fix this ? I can help you. I would start by adding a functional test with the content of your example in https://github.com/PyCQA/pylint/tree/main/tests/functional/n, then launch the test with |
I'd like to ! Thanks for your support offer, I'll start as you recommended. |
I would start looking into the import astroid
result1, result2 = astroid.extract_node("""
class Base:
def return_type(self):
return type(self)()
class A(other.Base):
def method(self):
return self.return_type()
class B(other.Base):
def method(self):
return self.return_type()
A().method() #@
B().method() #@
"""
) I would probably start looking here. Both of these currently return |
I was not able to investigate much yet but at least, I created the functional test demonstrating the observed issue: ce2a9f9 My next step is to look at astroid internals. |
It's possible to add the functional test with the problem and add a comment like "# TODO false negative / false positive see link to issue 1234" as creating the test is at least half the work 😄 |
Thanks for the hint, I amended the commit to insert such a TODO comment: 811d2c1 |
@DanielNoord It seems the type() support is not that minimal: in your code snipped, Uninferable is returned because there is an other.Base vs Base typo. After fixing it, .A instances are inferred. The bug seems located in inference_tip.py cache. If we disable it in _inference_tip_cached() implementation, the false negatives are fixed and the types are correctly inferred for all provided code samples. The cache key (func + node) seems incomplete. |
Do we need that inference_tip.py cache at all? I see the InferenceContext class in context.py has its own cache which seem more context aware. What kind of benchmark should I run to evaluate inference_tip.py cache usefulness? |
Hm, that is a good question. We should probably move that discussion to the |
Discussion moved to pylint-dev/astroid#1828. |
Bug description
pylint is confusing ExitStack() and AsyncExitStack() when analyzing two different modules using each.
Consider as a minimized example, the following two modules.
sync.py
async.py
Configuration
No response
Command used
Pylint output
Expected behavior
Pylint version
OS / Environment
Windows (reproduced also on Ubuntu 20.04 LTS).
Additional dependencies
No response
The text was updated successfully, but these errors were encountered: