Method overloads ignored when dispatched via protocols
まだ誰も着手していません。
- 主要言語
- Python
- スター
- 20.6k
- フォーク
- 3.3k
- 平均マージ
- 1日 18時間
- マージ済み PR(30日)
- 54
説明
Bug Report
At the moment I'm dealing with a number of numpy functions which, effectively, serve as wrappers
around a set of matching ndarray methods. Taking a simplified version of argmax as example,
a custom SupportsArgmax Protocol is herein used for dispatching the internals of the argmax
function to the ndarray.argmax method.
As it turns out, this works perfectly fine when the ndarray.argmax mods does not contain any
overloads, but when it does then any overloads beyond the first are ignored.
from typing import Protocol, overload, TypeVar
# Step 1: Define the class
class ndarray:
@overload
def argmax(self, axis: None) -> int: ...
@overload
def argmax(self, axis: int) -> ndarray: ...
# Step 2: Define a Protocol for describing the classes' argmax method
T_contra = TypeVar("T_contra", contravariant=True)
T_co = TypeVar("T_co", covariant=True)
class SupportsArgmax(Protocol[T_contra, T_co]):
def argmax(self, axis: T_contra) -> T_co: ...
# Step 3: Define a wrapper function around the classes' argmax method
T1 = TypeVar("T1")
T2 = TypeVar("T2")
def argmax(a: SupportsArgmax[T1, T2], axis: T1) -> T2: ...
Now, when an ndarray instance is passed to the argmax function I'd expect the
return type to be int if axis=None and ndarray if axis=int(...), just as is
described in the ndarray.argmax method:
array: ndarray
# note: Revealed type is 'builtins.int*'
reveal_type(argmax(array, axis=None))
# error: Cannot infer type argument 1 of "argmax"
# note: Revealed type is 'Any'
reveal_type(argmax(array, axis=0))
As can be seen above, the expected behavior is indeed observed when passing
through the first ndarray.argmax overload, but the presence of any subsequent
overloads seems to be ignored. Swapping the two overloads in the original
ndarray.argmax method only serves to reverse the issue.
Expected Behavior
Mypy successfully infers the return type, regardless of whether the protocol should
extract it from the methods' first overload or any subsequent ones.
Actual Behavior
Mypy fails for any method overload overload beyond the first.
Your Environment
- Mypy version used: mypy 0.782
- Mypy command-line flags: --show-error-codes (including or excluding --strict makes no difference here)
- Mypy configuration options from
mypy.ini(and other config files): n.a. - Python version used: Python 3.8.5
- Operating system and version: macOS 10.15.6
コントリビューションガイド
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
調査の方向性
まず、issue にある最小の Protocol とオーバーロードされた ndarray.argmax の例を mypy で再現し、両方の reveal_type 呼び出しと報告されている推論エラーを確認します。Protocol メソッドの互換性とオーバーロードされたメソッドの選択について、型チェックの経路を追跡します。axis=None の呼び出しと整数軸の呼び出しの両方で、overload に記述された戻り値の型が推論されれば完了です。
索引モデルが issue の本文から書いたものです。
評価
- 技術スタック
- python
- 領域
- devtools
- issue の種類
- バグ
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 活発さ
- 停滞
- 明瞭さ
- おおむね明確
- 初心者へのやさしさ
- 35/100