Skip to content
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

Remove non-existing _DT from ordered dataclass #18846

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

guitvcer
Copy link

(Explain how this PR changes mypy.)

Fixes #18811

Remove _DT attribute that does not exist in runtime from ordered dataclass.

This comment has been minimized.

This comment has been minimized.

and info.get("__eq__") is None
or decorator_arguments["order"]
):
if decorator_arguments["eq"] and info.get("__eq__") is None:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Won't this still keep creating _DT on @dataclass(eq=True)? The problematic bit is actually creating a fake TypeVarExpr and putting it in dataclass' symbol table.

Furthermore, this will actually break @dataclass(eq=False, order=True) definitions, because below self._api.fail() does not abort early, we'll still create methods referencing non-existent _DT, maybe leading to some crashes down the road.

Copy link
Author

Choose a reason for hiding this comment

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

Okay, I removed _DT from @dataclass(eq=True).

But I don't actually understand about @dataclass(eq=False, order=True) definitions, newbie in mypy:)

This comment has been minimized.

@sterliakov
Copy link
Collaborator

Okay, this typevar was stored in class' symbol table since #6515. The question is how come that all our tests pass with this (rather huge) block removed, and there are zero primer hits. Note that attrs plugin and namedtuple semanal does the same, adding a typevar node to the modified class.

I feel like this will eventually fail in incremental mode, trying to consume existing __lt__ of some dataclass without corresponding TypeVar node. Using TypeVarType that doesn't have corresponding tvar node somewhere is just begging for trouble, but somehow I can't quickly create a reproducer that crashes readily. Can we really just get rid of it like this?..

Copy link
Member

@sobolevn sobolevn left a comment

Choose a reason for hiding this comment

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

I have no idea why info.names[SELF_TVAR_NAME] = should be used here. It is either a very clever hack, or just a bug.

All evidences show that this is likely the former.

@sobolevn
Copy link
Member

Tests like

[case testDataclassOrdering]
give me extra confidence.

@sobolevn sobolevn requested a review from ilevkivskyi April 11, 2025 08:39
@sobolevn
Copy link
Member

Tagging @ilevkivskyi as the code author

Copy link
Contributor

According to mypy_primer, this change doesn't affect type check results on a corpus of open source code. ✅

Copy link
Member

@ilevkivskyi ilevkivskyi left a comment

Choose a reason for hiding this comment

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

It was not a hack, and I don't think this PR is safe. This code creates a consistent structure that is identical to what would happen for a Python code generated for the dataclass:

class Example:
    _DT = TypeVar("_DT")
    def __lt__(self: _DT, other: _DT) -> bool: ...

Creating a TypeVarType out of thin air without a corresponding TypeVarExpr may cause crashes in subtle scenarios, I guess it doesn't crash immediately because we special-case plugin-generated nodes in most places, but some code paths still may rely on a consistent structure.

@sobolevn
Copy link
Member

@ilevkivskyi thank you for the explanation! Then, we need to special case this in stubtest.

@sterliakov
Copy link
Collaborator

sterliakov commented Apr 11, 2025 via email

@ilevkivskyi
Copy link
Member

ilevkivskyi commented Apr 11, 2025

can we fake per-method PEP695 type parameters instead

Those actually create TypeVarExprs as well under the hood (and add them to symbol tables), but it may be better because they are only added to the method locals IIUC. That said I don't think it is actually worth the effort, these fake type vars have been there for namedtuples, attrs, and dataclasses for years, and no-one complained.

@sterliakov
Copy link
Collaborator

Well, if someone is interested in making such a change, I think it's justified: now mypy believes that some dataclasses have a _DT attribute which would be a rather funny problem to debug. (I'm personally fine with just ignoring those typevars in stubtest too)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

stubtest invents _DT attribute on dataclasses
5 participants