python / python/mypy

Binding of Generic decorators on Union variables

オープン
#11,037 コメント 1 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

bug
主要言語
Python
スター
20.6k
フォーク
3.3k
PR マージ指標
PR 指標を取得中

説明

Bug Report

Mypy seems to bind the TypeVar of a Generic decorator incorrectly when a variable is annotated as a Union.

To Reproduce
This example is based on this untyped cython code.

from typing import Callable, Generic, Optional, TypeVar, Union, overload

F = TypeVar("F")
G = TypeVar("G")


class cache_readonly(Generic[F, G]):
    def __init__(self, func: Callable[[F], G]) -> None:
        self.func = func
        self.name = func.__name__
        self.__doc__ = getattr(func, "__doc__", None)

    @overload
    def __get__(self, obj: F, typ) -> G:
        ...

    @overload
    def __get__(self, obj: None, typ) -> "cache_readonly[F, G]":
        ...

    def __get__(self, obj: Optional[F], typ) -> Union[G, "cache_readonly[F, G]"]:
        if obj is None:
            # accessed on the class, not the instance
            return self

        # Get the cache or set a default one if needed
        cache = getattr(obj, "_cache", None)
        if cache is None:
            cache = obj._cache = {}  # type: ignore

        if self.name in cache:
            val = cache[self.name]
        else:
            val = self.func(obj)
            cache[self.name] = val
        return val

    def __set__(self, obj: F, value: G) -> None:
        raise AttributeError("Can't set attribute")


class TestA:
    @cache_readonly
    def x(self) -> str:
        return "A"


class TestB:
    @cache_readonly
    def x(self) -> str:
        return "B"


def test(obj: Union[TestA, TestB]) -> str:
    return obj.x

Expected Behavior
Mypy and pyright are happy with the code :)

Actual Behavior
mypy

test.py:55: error: Argument 1 to "__get__" of "cache_readonly" has incompatible type "Union[TestA, TestB]"; expected "TestA"
test.py:55: error: Argument 1 to "__get__" of "cache_readonly" has incompatible type "Union[TestA, TestB]"; expected "TestB"

Pyright doesn't complain (except for the __doc__ line).

Your Environment

  • Mypy version used: 0.910
  • Mypy command-line flags: -
  • Mypy configuration options from mypy.ini (and other config files): -
  • Python version used: 3.9.6
  • Operating system and version: CentOS 3.10.0-693.5.2.el7.x86_64

コントリビューションガイド

コントリビューションガイドを開く

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

調査の方向性

mypy 0.910 を使用して test.py の例で報告を再現し、その診断結果を期待される動作および pyright の結果と比較してください。Union[TestA, TestB] へのアクセスで互換性のない get 引数のエラーが発生しなくなり、示されているデコレーターの動作が維持されていれば完了です。

索引モデルが issue の本文から書いたものです。

評価

技術スタック
python
領域
devtools
issue の種類
バグ
難易度
4/5
見積もり時間
3〜5日
活発さ
停滞
明瞭さ
おおむね明確
初心者へのやさしさ
35/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。