at runtime dataclass special-cases FunctionType, but at type-time mypy special-cases Callable, leading to mismatches
まだ誰も着手していません。
- 主要言語
- Python
- スター
- 20.6k
- フォーク
- 3.3k
- PR マージ指標
- PR 指標を取得中
説明
Bug Report
If you declare an attribute on a dataclass to be Callable, Mypy assumes that its __get__ will not be called, even on a default attribute. But this is only true if the default is a FunctionType, not some other type of callable.
Similarly, the inverse is true: an abstract type (such as a callable Protocol) will tell mypy that __get__ will be called, even though if the concrete default value is a FunctionType, it won't be.
Specifically, the following program contains 2 type errors, but MyPy does not think so:
To Reproduce
from __future__ import annotations
from typing import Callable, Protocol, ParamSpec, TypeVar, Generic
from dataclasses import dataclass
def f() -> None:
print("hello world")
def f2(self: object) -> None:
print("bound self", self)
P = ParamSpec("P")
T = TypeVar("T")
R = TypeVar("R", covariant=True)
T_con = TypeVar("T_con", contravariant=True)
class BindableMethod(Protocol[T_con, R]):
def __get__(self, instance: T_con, owner: None | type[object]) -> Callable[[], R]:
...
def __call__(me, self: T_con) -> R:
...
class UnboundNonFunction(Generic[P, R]):
def __call__(self) -> int:
print("unbound")
return 3
def __get__(self, instance: object, owner: type | None) -> BoundNonFunction:
print("binding", instance, owner)
return BoundNonFunction(instance)
@dataclass(frozen=True)
class BoundNonFunction:
instance: object
def __call__(self) -> str:
print("bound", self.instance)
return "wat"
@dataclass
class FuncHolder():
func: Callable[[], None] = f
func2: BindableMethod[FuncHolder, None] = f2
func3: Callable[[], int] = UnboundNonFunction()
FuncHolder().func()
try:
FuncHolder().func2()
except Exception as e:
print("whoops", str(e))
try:
print(FuncHolder().func3() + 4)
except Exception as e:
print("whoops 2", str(e))
https://mypy-play.net/?mypy=latest&python=3.11&gist=1ac4e7c090774489207dfbc737de2d61
Expected Behavior
I would expect runtime and type-time behavior to be consistent here. Specifically I just don't expect __get__ to be called on things with a Callable type.
Actual Behavior
Mypy succeeds, rather than reporting the type errors.
Your Environment
- Mypy version used: mypy 1.1.1 (compiled: yes)
- Mypy command-line flags: none
- Mypy configuration options from
mypy.ini(and other config files): none - Python version used: 3.11.2 (python.org, macOS, aarch64)
コントリビューションガイド
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
調査の方向性
issue にある自己完結型の Python 再現コードから始め、リンクされた設定を使って mypy-play で実行します。実行時の dataclass ディスクリプタの動作を、Callable およびプロトコル型のデフォルトに対する mypy の扱いと比較します。mypy が 2 つの型エラーを報告しつつ、有効な FunctionType のケースを維持すれば完了です。
索引モデルが issue の本文から書いたものです。
評価
- 技術スタック
- python
- 領域
- compilers, devtools
- issue の種類
- バグ
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 活発さ
- 停滞
- 明瞭さ
- おおむね明確
- 初心者へのやさしさ
- 25/100