-
-
Notifications
You must be signed in to change notification settings - Fork 278
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
Prefer last same-named function in a class rather than first in igetattr()
#1173
Prefer last same-named function in a class rather than first in igetattr()
#1173
Conversation
tests/unittest_inference.py
Outdated
assert len(inferred) == 2 | ||
assert isinstance(inferred[0], nodes.Const) | ||
assert isinstance(inferred[1], Generator) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm wondering if
class A:
def foo(self): ...
def foo(self):
yield
should be inferred as Const
and Generator
as Python will always use the last definition. Wouldn't it be better to only infer it as Generator
?
--
Some test cases to be aware of
if some_test:
def func():
return 42
else:
def func():
return bool
# should still return two results for `func()`
Functools.singledispatch should still work:
https://docs.python.org/3/library/functools.html#functools.singledispatch
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't it be better to only infer it as
Generator
?
My thinking leans the same way as it's the more "useful" definition.
Python will always use the last definition
Pretty much, but I wonder what to do about monkeypatching, or this (contrived) example:
class A:
def foo(self):
return 'first'
bar = foo(object())
def foo(self):
return 'second'
A().foo() # 'second'
A().bar # 'first'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just tested your example: This will already be inferred incorrectly. A().foo() ->'first'
. Possibly another bug?
As for the issue at hand. Would it work to filter previous definitions only if no other attributes are in between?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The case with two foo
function one redefined are a little contrived and probably not seen a lot in real "sane" code. The @overload
use case though seems interesting to test. Do you think this is really equivalent ?
Ref pylint-dev#1015. When there are multiple statements defining some attribute ClassDef.igetattr filters out later definitions if they are not in the same scope as the first (to support cases like "self.a = 1; self.a = 2" or "self.items = []; self.items += 1"). However, it checks the scope of the first attribute against the *parent scope* of the later attributes. For mundane statements this makes no difference, but for scope-introducing statements such as FunctionDef these are not the same.
9640bf2
to
4113a8f
Compare
We're closing tons of duplicates for this in pylint. I think special-casing functions (sans properties) is good enough. |
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #1173 +/- ##
=======================================
Coverage 92.75% 92.75%
=======================================
Files 94 94
Lines 11080 11084 +4
=======================================
+ Hits 10277 10281 +4
Misses 803 803
Flags with carried forward coverage won't be shown. Click here to find out more.
|
igetattr()
igetattr()
igetattr()
Steps
Description
Ref #1015. When there are multiple statements defining some attribute
ClassDef.igetattr
filters out later definitions if they are not in thesame scope as the first (to support cases like "self.a = 1; self.a = 2"
or "self.items = []; self.items += 1"). However, it checks the scope of
the first attribute against the parent scope of the later attributes.
For mundane statements this makes no difference, but for
scope-introducing statements such as
FunctionDef
these are not the same.Type of Changes
Related Issue
Closes #1015