Skip to content

gh-119581: Add a test of InitVar with name shadowing #119582

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

Merged
merged 2 commits into from
May 28, 2024

Conversation

stroxler
Copy link
Contributor

@stroxler stroxler commented May 26, 2024

As originally discussed in python/mypy#17219,
MyPy has had a false-positive bug report because it errors when a dataclass has methods that shadow an InitVar field.

It is actually a bit surprising that this works, it turns out that __annotations__ "remembers" field assignments even if the bound names are later overwritten by methods; it will not work to provide a default value.

There have been multiple bug reports on MyPy so we know people are actually relying on this in practice; most likely it comes up when a dataclass wants to take a "raw" value as an InitVar and transform it somehow in __post_init__ into a different value before assigning it to a field; in that case they may choose to make the actual field private and provide a property for access.

I currently provide a test of the happy path where there is no default value provided, but no tests of the behavior when no default is provided (in which case the property will override the default) and no documentation (because I'm not sure we want to consider this behavior officially supported).

The main goal is to have a regression test since it would be easy for a refactor to break this.

As originally discussed in
python/mypy#17219,
MyPy has had a false-positive bug report because it errors when a
dataclass has methods that shadow an `InitVar` field.

It is actually a bit surprising that this works, it turns out
that `__annotations__` "remembers" field assignments even if the
bound names are later overwritten by methods; it will *not* work
to provide a default value.

There have been multiple bug reports on MyPy so we know people are
actually relying on this in practice; most likely it comes up when
a dataclass wants to take a "raw" value as an InitVar and transform
it somehow in `__post_init__` into a different value before assigning
it to a field; in that case they may choose to make the actual field
private and provide a property for access.

I currently provide a test of the happy path where there is no default
value provided, but no tests of the behavior when no default is
provided (in which case the property will override the default) and no
documentation (because I'm not sure we want to consider this behavior
officially supported).

The main goal is to have a regression test since it would be easy for a
refactor to break this.
Copy link
Member

@AlexWaygood AlexWaygood left a comment

Choose a reason for hiding this comment

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

Thanks! It seems likely to me that this probably only worked "by accident" rather than being something that was deliberately designed. But nonetheless, it seems like useful behaviour that's worth preserving; and as you say, it seems like lots of people are relying on it now. So, I agree that this is a useful test to add.

(Whether or not type checkers support this pattern is irrelevant to whether it should be supported at runtime: lots of people use dataclasses without running a type checker on their code.)

Copy link
Member

@AlexWaygood AlexWaygood left a comment

Choose a reason for hiding this comment

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

LGTM, thanks! (I'll wait a few days before merging, in case Eric or Carl have any objections)

@AlexWaygood AlexWaygood added needs backport to 3.12 only security fixes needs backport to 3.13 bugs and security fixes tests Tests in the Lib/test dir labels May 28, 2024
Copy link
Member

@ericvsmith ericvsmith left a comment

Choose a reason for hiding this comment

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

This looks good to me. I was actually unaware of this behavior, but it does indeed look useful.

@AlexWaygood AlexWaygood merged commit 6ec3712 into python:main May 28, 2024
35 of 36 checks passed
@miss-islington-app
Copy link

Thanks @stroxler for the PR, and @AlexWaygood for merging it 🌮🎉.. I'm working now to backport this PR to: 3.12, 3.13.
🐍🍒⛏🤖

miss-islington pushed a commit to miss-islington/cpython that referenced this pull request May 28, 2024
miss-islington pushed a commit to miss-islington/cpython that referenced this pull request May 28, 2024
@bedevere-app
Copy link

bedevere-app bot commented May 28, 2024

GH-119672 is a backport of this pull request to the 3.13 branch.

@bedevere-app bedevere-app bot removed the needs backport to 3.13 bugs and security fixes label May 28, 2024
@bedevere-app
Copy link

bedevere-app bot commented May 28, 2024

GH-119673 is a backport of this pull request to the 3.12 branch.

@bedevere-app bedevere-app bot removed the needs backport to 3.12 only security fixes label May 28, 2024
AlexWaygood pushed a commit that referenced this pull request May 28, 2024
… (#119672)

gh-119581: Add a test of InitVar with name shadowing (GH-119582)
(cherry picked from commit 6ec3712)

Co-authored-by: Steven Troxler <[email protected]>
AlexWaygood pushed a commit that referenced this pull request May 28, 2024
… (#119673)

gh-119581: Add a test of InitVar with name shadowing (GH-119582)
(cherry picked from commit 6ec3712)

Co-authored-by: Steven Troxler <[email protected]>
@stroxler stroxler deleted the gh-119581-new-dataclasses-test branch May 28, 2024 21:08
estyxx pushed a commit to estyxx/cpython that referenced this pull request Jul 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
skip news tests Tests in the Lib/test dir
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants