-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Fix/attrs init overload #19104
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
base: master
Are you sure you want to change the base?
Fix/attrs init overload #19104
Conversation
This comment has been minimized.
This comment has been minimized.
I'm afraid this will break horribly down the road. Any custom To see this actually causing trouble (maybe I'm reading the code wrong, after all), please try adding a testcase with such overridden |
Hello! First of all, thank you for your detailed comment. From what I understand, I don’t believe there’s anything wrong with the code I wrote to address the issue. However, based on your feedback, it seems you’re suggesting that instead of returning None, it would be better to explicitly fail when a custom init is detected—something like: (This is my first PR, and English is not my first language, so I really appreciate your understanding in case I misunderstood anything) |
Huh, not exactly, raising a However, on second thought we usually avoid producing error messages when some construct is not supported or cannot be expressed statically. It might be wiser to fall back to Any in that case and accept the call as-is, even if the arguments do not match. I'm not sure which of the options is better. To explain my point about "potential problems" caused by overloaded or even just manually defined from typing import overload
import attrs
@attrs.frozen(init=False)
class C:
x: "int | str"
@overload
def __init__(self, x: int) -> None: ...
@overload
def __init__(self, x: str) -> None: ...
def __init__(self, x: "int | str") -> None:
self.__attrs_init__(x)
obj = C(1)
attrs.evolve(obj, x=2)
attrs.evolve(obj, x="2") # E: ... - False positive import attrs
@attrs.frozen(init=False)
class C:
x: "int | str"
def __init__(self, x: "int | str", y: bool) -> None:
self.__attrs_init__(x)
obj = C(1, False)
attrs.evolve(obj, x=2) # False negative, error at runtime |
Thank you so much for the detailed explanation. It was really helpful and I believe it will greatly assist me in resolving the issue. Among the approaches you suggested, I feel that using I'll revise the code accordingly and push the changes soon. |
for more information, see https://pre-commit.ci
This comment has been minimized.
This comment has been minimized.
|
I understand you may be busy, but I would really appreciate it if you could take a moment to review my latest commit. Thank you! |
I'm not sure I love the idea of returning |
Thank you for the review. I will update and upload the test cases within today. Have a great day :) |
…init__ methods in attrs classes
for more information, see https://pre-commit.ci
This comment has been minimized.
This comment has been minimized.
…init__ methods in attrs classes
for more information, see https://pre-commit.ci
This comment has been minimized.
This comment has been minimized.
@sterliakov Hello, After several attempts, I was able to add the test case. |
After I committed the changes to attrs.py, there were no issues reported by mypy_primer. However, the error appeared only after I committed the test cases. Based on this, I believe it might be a false positive. When comparing the importance of mypy issue #19003 with the reported error in xarray, I think resolving issue #19003 should take priority and is more critical at this point. If it turns out that the error reported in xarray is actually a valid detection — due to an argument not matching the expected type — then after this PR is merged, I will either modify the xarray source code to ignore the case where the function receives an object type, or open an issue in the xarray repository to address it. All in all, it seems that the error is an expected outcome of the changes made in this PR, and I believe it's something that should be fixed within the xarray project |
Ignore the |
This comment has been minimized.
This comment has been minimized.
@sterliakov Hello, However, I'm now seeing an error from the GitHub bot that wasn't occurring before. From my investigation, this issue doesn’t appear to be caused by my changes. Could you please help verify whether this is a problem with the bot or something unrelated to my patch? |
This comment has been minimized.
This comment has been minimized.
The |
According to mypy_primer, this change doesn't affect type check results on a corpus of open source code. ✅ |
@sterliakov Hi, the updated changes are now working correctly. Could you please review my PR to see if it’s ready to be merged? |
Hello! I haven't received a response regarding my recent commits for a few days, so I just wanted to send a quick ping. Apologies for bothering you during your busy schedule! @sterliakov @JukkaL |
@@ -812,6 +813,7 @@ def __init__( | ||
body: Block | None = None, | ||
typ: mypy.types.FunctionLike | None = None, | ||
type_args: list[TypeParam] | None = None, | ||
plugin_generated: bool | None = None, |
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.
Apologies for any confusion I might have caused by my previous comment, but by saying that " it should be looked up on a different object" I didn't mean defining it on another node in addition...
return init_method.type | ||
# case 1: normal FuncDef | ||
if isinstance(init_method, FuncDef) and isinstance(init_method.type, CallableType): | ||
if init_method.plugin_generated: |
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.
typ.type.get
returns a SymbolTableNode
that already has plugin_generated
attribute. get_method
is a higher-level wrapper that returns a function. I'd probably do something like
if init_method.plugin_generated: | |
init_node = typ.type.get("__init__") or typ.type.get(ATTRS_INIT_NAME) | |
if init_node.plugin_generated: |
and then it won't be necessary to propagate that attribute down to FuncDef
. This function isn't hot (this part is only reached when we have evolve
call on some actual attrs
class), so we can afford simply looking up twice to avoid uwrapping init_node
manually.
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'll update that part using the approach you recommended! (I expect to make the changes and push them within a day or two.)
Is there anything else I should take care of?
This is my first time contributing to mypy, so I know there were some shortcomings.
Thank you so much for your kind and thorough support :)
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.
If there are no additional requests, do you think this PR could be ready for merging?
I’d appreciate any feedback you might have.
Fixes #19003
This PR fixes the issue by handling the case where the init method can be an OverloadedFuncDef with CallableType items.