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

Mypy does not infer that a dataclass field is optional when None is assigned #13934

Closed
Kentzo opened this issue Oct 22, 2022 · 9 comments
Closed
Labels
bug mypy got something wrong

Comments

@Kentzo
Copy link

Kentzo commented Oct 22, 2022

Bug Report

It's documented that a dataclass field can be declared as optional without Optional or | None by simply assigning None as a default value.

However, mypy fails to infer this.

To Reproduce

import dataclasses as dc


@dc.dataclass
class C:
    j: int = None

Expected Behavior

No errors

Actual Behavior

test.py:6: error: Incompatible types in assignment (expression has type "None", variable has type "int")

Your Environment

  • Mypy version used: 0.982
  • Python version used: 3.10.7
@Kentzo Kentzo added the bug mypy got something wrong label Oct 22, 2022
@binbjz
Copy link

binbjz commented Oct 23, 2022

import dataclasses as dc
from typing import Optional


@dc.dataclass
class C:
    j: Optional[int] = None

Actual Results

  • Success: no issues found in 1 source file.

mypy version: 0.982 (compiled: yes). This is not a bug, please close it.

@Kentzo
Copy link
Author

Kentzo commented Oct 23, 2022

My point is dataclass’s ivars are documented to be seen as optional without explicit Optional, akin to function parameters with a default value of None. Shouldn’t mypy respect that?

FWIW, PyCharm recognizes it and reports no error.

@erictraut
Copy link

Earlier versions of PEP 484 indicated that function parameters with a default value of None should be treated as implicitly Optional. Mypy (and PyCharm) implemented this earlier behavior. A couple of years ago, PEP 484 was updated to clarify that this behavior is no longer recommended and that type checkers should not treat function parameters as implicitly Optional. See this section for details.

Mypy has a flag called --no-implicit-optional which currently defaults to False, but it is being changed to default to True. I don't know if PyCharm plans to make a similar change. Pyright made this change about a year ago.

While PEP 484 was talking about function parameters, I would think that dataclass fields should likewise not support implicit Optional behavior. If a dataclass field is intended to accept None values, the field's declared type should explicitly include None.

The Python docs that you mentioned should probably be updated accordingly so they don't lead users to assume that implicit Optional behavior is recommended or supported by static type checkers.

@AlexWaygood
Copy link
Member

Yes, what @erictraut said. PEP 484 was revised to recommend against "implicit Optional behaviour in July 2018, in python/peps@0630155. The example in the dataclasses docs was added in May 2018, in python/cpython@98d50cb, so predates the revision to PEP 484. It is out of date, and should be changed. (If pycharm does not emit an error here, that means that pycharm is also using deprecated typing semantics here.)

TL;DR: the bugs are in the CPython docs and pycharm, not mypy.

@AlexWaygood AlexWaygood closed this as not planned Won't fix, can't repro, duplicate, stale Oct 23, 2022
@Kentzo
Copy link
Author

Kentzo commented Oct 23, 2022

Dataclass has been a part of stdlib for a long time now. The chance this behavior will change are slim. For all intents and purposes it is a documented feature.

I understand the default behavior of mypy, my request was limited in scope by instances of dataclass only.

@erictraut
Copy link

The behavior we're discussing here pertains to static type checking, not to the runtime behavior of dataclass. There is no need for the dataclass runtime behavior to change. It does not enforce any runtime typing. It ignores whatever expression you specify in the type annotation, so you could enter a completely nonsensical type like j: 0 = None, and it wouldn't matter to the dataclass runtime implementation.

It's up to mypy and other static type checkers to interpret the meaning of the type annotation and report any type violations. Your code sample has a type violation because you're attempting to assign None to a dataclass field that has a declared type of int. If you want mypy to accept this, you can declare the field's type as Optional[int] or int | None.

@Kentzo
Copy link
Author

Kentzo commented Oct 23, 2022

The practical outcome is that valid code per stdlib documentation will be flagged as erroneous. I will forward the issue with the stdlib maintainers.

@AlexWaygood
Copy link
Member

The practical outcome is that valid code per stdlib documentation will be flagged as erroneous. I will forward the issue with the stdlib maintainers.

Looks like @hauntsaninja's beaten you to it.

@AlexWaygood
Copy link
Member

The stdlib documentation has now been revised, and the revisions have been backported to the 3.11 and 3.10 branches. See python/cpython#98576 for details!

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

No branches or pull requests

4 participants