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

Fix __post_init__() internal error #16080

Merged
merged 4 commits into from Sep 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 4 additions & 1 deletion mypy/checker.py
Expand Up @@ -1076,6 +1076,8 @@ def check_func_item(

if name == "__exit__":
self.check__exit__return_type(defn)
# TODO: the following logic should move to the dataclasses plugin
# https://github.com/python/mypy/issues/15515
if name == "__post_init__":
if dataclasses_plugin.is_processed_dataclass(defn.info):
dataclasses_plugin.check_post_init(self, defn, defn.info)
Expand Down Expand Up @@ -2882,7 +2884,8 @@ def check_assignment(
typ = self.expr_checker.accept(rvalue)
self.check_match_args(inferred, typ, lvalue)
if name == "__post_init__":
if dataclasses_plugin.is_processed_dataclass(self.scope.active_class()):
active_class = self.scope.active_class()
if active_class and dataclasses_plugin.is_processed_dataclass(active_class):
self.fail(message_registry.DATACLASS_POST_INIT_MUST_BE_A_FUNCTION, rvalue)

# Defer PartialType's super type checking.
Expand Down
1 change: 0 additions & 1 deletion mypy/nodes.py
Expand Up @@ -515,7 +515,6 @@ def __init__(self) -> None:
# Original, not semantically analyzed type (used for reprocessing)
self.unanalyzed_type: mypy.types.ProperType | None = None
# If method, reference to TypeInfo
# TODO: Type should be Optional[TypeInfo]
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This comment was added in 2018 in #4438.

FakeInfo was added in 2017, and the following comment seems to be at odds:

mypy/mypy/nodes.py

Lines 3366 to 3370 in fdc7914

# 'None' is not used as a dummy value for two reasons:
# 1. This will require around 80-100 asserts to make 'mypy --strict-optional mypy'
# pass cleanly.
# 2. If NOT_READY value is accidentally used somewhere, it will be obvious where the value
# is from, whereas a 'None' value could come from anywhere.

self.info = FUNC_NO_INFO
self.is_property = False
self.is_class = False
Expand Down
4 changes: 2 additions & 2 deletions mypy/plugins/dataclasses.py
Expand Up @@ -1070,8 +1070,8 @@ def replace_function_sig_callback(ctx: FunctionSigContext) -> CallableType:
)


def is_processed_dataclass(info: TypeInfo | None) -> bool:
return info is not None and "dataclass" in info.metadata
def is_processed_dataclass(info: TypeInfo) -> bool:
return bool(info) and "dataclass" in info.metadata


def check_post_init(api: TypeChecker, defn: FuncItem, info: TypeInfo) -> None:
Expand Down
4 changes: 4 additions & 0 deletions test-data/unit/check-dataclasses.test
Expand Up @@ -2280,6 +2280,10 @@ reveal_type(a2) # N: Revealed type is "__main__.A[builtins.int]"

[builtins fixtures/tuple.pyi]

[case testPostInitNotMethod]
def __post_init__() -> None:
pass

[case testPostInitCorrectSignature]
from typing import Any, Generic, TypeVar, Callable, Self
from dataclasses import dataclass, InitVar
Expand Down