python / python/mypy

Dataclasses: `No overload variant of "asdict" matches argument type "Self" [call-overload]` when deciding decorator conditionally

Open
#17,242 3 comments 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

feature topic-dataclasses
Dominant language
Python
Stars
20.6k
Forks
3.3k
PR merge metrics
PR metrics pending

Description

Bug Report

Mypy raises a false positive for dataclass.asdict (No overload variant of "asdict" matches argument type "Self" [call-overload]) on the very specific circumstances:

  1. The specific decorator for dataclass is decided based on a condition (e.g. Python version)
  2. The datalcasses.asdict method is called from a method that uses PEP 673's Self Type.

I also noted a similar problem occurs for dataclasses.replace: Value of type variable "_DataclassT" of "replace" cannot be "Self" [type-var].

To Reproduce

import sys
import dataclasses
import json
from typing import Self

if sys.version_info >= (3, 10):
    dataclass = dataclasses.dataclass(kw_only=True)
else:
    dataclass = dataclasses.dataclass


@dataclass
class HelloWorld:
    a: int = 1
    b: int = 2
    c: int = 3

    def double(self) -> Self:
        fields = dataclasses.asdict(self)
        return self.__class__(**{k: v*2 for k, v in fields.items()})

    def json_overwrite(self, text: str) -> Self:
        new = json.loads(text)
        return dataclasses.replace(self, **new)

x = HelloWorld().double()
y = HelloWorld().json_overwrite('{"c": 42}')
assert x.b == 4
assert y.c == 42
print(f"{x=}")
print(f"{y=}")

Gist URL: https://gist.github.com/mypy-play/70b801fbe15391f0750be8f6c403fdf4
Playground URL: https://mypy-play.net/?mypy=latest&python=3.12&flags=show-error-context%2Cstrict&gist=70b801fbe15391f0750be8f6c403fdf4

Expected Behavior

There should be no false negative.
The program works fine in runtime:

$ python3.12 main.py
x=HelloWorld(a=2, b=4, c=6)
y=HelloWorld(a=1, b=2, c=42)

Actual Behavior

main.py: note: In member "double" of class "HelloWorld":
main.py:19: error: No overload variant of "asdict" matches argument type "Self"  [call-overload]
main.py:19: note: Possible overload variants:
main.py:19: note:     def asdict(obj: DataclassInstance) -> dict[str, Any]
main.py:19: note:     def [_T] asdict(obj: DataclassInstance, *, dict_factory: Callable[[list[tuple[str, Any]]], _T]) -> _T
main.py: note: In member "json_overwrite" of class "HelloWorld":
main.py:24: error: Value of type variable "_DataclassT" of "replace" cannot be "Self"  [type-var]
Found 2 errors in 1 file (checked 1 source file)

Your Environment

  • Mypy version used: 1.10.0
  • Mypy command-line flags: --show-error-context, --strict
  • Mypy configuration options from mypy.ini (and other config files):
  • Python version used: 3.12

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Run the supplied Python 3.12 example with mypy 1.10.0 and --show-error-context --strict to reproduce the errors for dataclasses.asdict and dataclasses.replace. Start by tracing handling of the conditional dataclass decorator, Self, and the reported overload and type-variable checks. Done means the example type-checks without these false positives while preserving the runtime behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
devtools
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.