python / python/mypy

Union of `Never` can't be used

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

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

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

説明

Bug Report

Functions which optionally take a value of Never type have impossible requirements placed on usages of that optional value.

To Reproduce

https://gist.github.com/mypy-play/a49d72bdacc179ffda5f69d8b66f41ff

from typing import Never


def blah(s: Never | str) -> None:
    print(s + "hi")

Expected Behavior

The code type-checks. Since it is impossible for any variable to take a value of type Never, the type signature of blah is equivalent to str -> None. The function's body is valid when s is annotated with type str, so it should be valid when annotated with Never | str.

Actual Behavior

main.py:5: error: Unsupported left operand type for + ("Never")  [operator]
main.py:5: note: Left operand is of type "Never | str"
Found 1 error in 1 file (checked 1 source file)

Your Environment

  • Python 3.12
  • MyPy 1.15.0, invocation as performed in the Playground

Background

Pyright appears to do the right thing here: it accepts this code.

I ran into this when implementing this pattern, which is me placing types around something I found untyped in the wild:

T = TypeVar("T", contravariant=True)
class _MyProtocol(Protocol[T]):
  def _foo(self, arg: T | IO[str]) -> None: ...

try:
    import foo
    class _MyImpl(_MyProtocol[foo.Foo]):
      def _foo(self, arg: foo.Foo | IO[str]) -> None: 
        # do something here
        pass

    MyType = _MyImpl

except ImportError:
    class _MyImplNone(_MyProtocol[Never]):
      def _foo(self, arg: Never | IO[str]) -> None:
        # correctly assume arg is an IO[str] here
        pass

    MyType = _MyImplNone

That way, MyType has type _MyProtocol[foo.Foo] | _MyProtocol[Never], allowing a type-level discrimination of whether the foo functionality is present or not.

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

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

はじめの一歩

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

調査の方向性

Issue またはリンクされた mypy-play の例にある最小限の Python 再現コードから始め、報告された演算子エラーを、期待される str 相当の動作と比較します。型チェック中に Never を含むユニオンがどのように扱われるかを追跡し、その後、示された関数のカバレッジを追加して、Never オペランドエラーなしで mypy が受け入れることを確認します。

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

評価

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

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

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