python / python/mypy

Possible bug - mypy rejects subclassing `Any` typed `*args` entries within a function (OK in python; pyright and pyrefly say OK) though allowing the same from keyword parameters

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

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

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

説明

(No AI or LLMs were used in finding or writing up this issue.)

In Python and passing other type checkers (e.g. pyright 1.1.414 and pyrefly 1.3.1) it is ok to subclass a type passed within the *args variadic argument which is typed as Any, but mypy 2.3.1 and recent master seems to reject this.

E.g. the following Python program runs fine and typechecks via pyright 1.1.414 and pyrefly 1.3.1
(btw if you have an objection to this on the basis of the intermediate x variable, please also see the example pair at the end of the issue showing mypy will allow a keyword arg for a type to subclass but not an element of *args without an intermediate variable)

https://mypy-play.net/?gist=caa19ef606afd2b352e2e5e3fa608bca

from typing import Any

def fun_varargs_element_to_type_used_for_inherit(
   *args: *tuple[int, Any],
) -> Any:
  # not allowed by mypy but allowed by pyright and others
  x = args[1]
  class Sub(x): pass
  return Sub()

s = fun_varargs_element_to_type_used_for_inherit(1, str)
print('isinstance(s, str): ', isinstance(s, str))

Per pyright 1.1.414 and pyrefly 1.3.1 it typechecks and in python 3.13.2 (and 3.12 see gist above) runs and produces valid output:

(venv) [liveuser@localhost-live mypy]$ pyright ~/examplecomplex2.py
0 errors, 0 warnings, 0 informations
(venv) [liveuser@localhost-live mypy]$ python ~/examplecomplex2.py
isinstance(s, str):  True

But mypy 2.3.1 rejects it (see mypy playground link and associated gist https://mypy-play.net/?gist=caa19ef606afd2b352e2e5e3fa608bca ) .

Here are some unit test cases showing this behavior as well:

[case testVarargsArgumentTypeCheckingUsingArgumentTypeFromVarArgsForInheritanceExplicitCastOk]
# flags: --python-version 3.12
from typing import Any

def fun_explicit_cast_varargs_element_to_type_used_for_inherit(
   *args: *tuple[int, Any],
):
  # allowed
  x : type = args[1]
  class Sub(x): pass

fun_explicit_cast_varargs_element_to_type_used_for_inherit(1, str)

[builtins fixtures/tuple.pyi]

[case testVarargsArgumentTypeCheckingUsingArgumentTypeFromVarArgsForInheritance-xfail]
# flags: --python-version 3.12
from typing import Any

def fun_varargs_element_to_type_used_for_inherit(
   *args: *tuple[int, Any],
):
  # not allowed by mypy but allowed by pyright and others
  x = args[1]
  class Sub(x): pass

fun_varargs_element_to_type_used_for_inherit(1, str)

[builtins fixtures/tuple.pyi]

The first case passes, the second xfails (I marked it expected fail for now per current behavior) when it should pass it seems.

Note that passing a type via an Any typed keyword parameter is OK-ed by mypy:
https://mypy-play.net/?gist=9ff16e8bc2f873f3fe5d0dcb4ff8baeb

[liveuser@localhost-live mypy]$ cat ~/examplecomplex3.py
from typing import Any

def fun_keyword_parameter_to_type_used_for_inherit(
   *args: *tuple[int, Any],
   keywordarg: Any
) -> Any:
  class Sub(keywordarg): pass
  return Sub()

s = fun_keyword_parameter_to_type_used_for_inherit(1, 1, keywordarg=str)
print('isinstance(s, str): ', isinstance(s, str))

[liveuser@localhost-live mypy]$ python ~/examplecomplex3.py
isinstance(s, str):  True

[liveuser@localhost-live mypy]$ mypy ~/examplecomplex3.py
Success: no issues found in 1 source file

But using args[1] (an element of the *args tuple directly) when Any typed to pass a type for subclassing is not allowed by mypy, while it is allowed by pyright 1.1.414 and pyrefly 1.3.1 and python:
https://mypy-play.net/?gist=d12a1ef7f71677f150d09200fadf1958

[liveuser@localhost-live mypy]$ cat ~/examplecomplex4.py
from typing import Any

def fun_varargs_element_to_type_used_for_inherit(
   *args: *tuple[int, Any],
) -> Any:
  # not allowed by mypy but allowed by pyright and others
  class Sub(args[1]): pass
  return Sub()

s = fun_varargs_element_to_type_used_for_inherit(1, str)
print('isinstance(s, str): ', isinstance(s, str))

[liveuser@localhost-live mypy]$ python ~/examplecomplex4.py
isinstance(s, str):  True

[liveuser@localhost-live mypy]$ pyright ~/examplecomplex4.py
0 errors, 0 warnings, 0 informations

[liveuser@localhost-live mypy]$ mypy ~/examplecomplex4.py
/home/liveuser/examplecomplex4.py:7: error: Variable "args" is not valid as a type  [valid-type]
/home/liveuser/examplecomplex4.py:7: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
/home/liveuser/examplecomplex4.py:7: error: Invalid base class "args"  [misc]
/home/liveuser/examplecomplex4.py:7: error: Invalid type: try using Literal[1] instead?  [valid-type]
Found 3 errors in 1 file (checked 1 source file)

(Note the above typechecks fine in pyright 1.1.414 and pyrefly 1.3.1 )

  • Mypy version used: 2.3.1 (and recent master)
  • Mypy command-line flags: None
  • Mypy configuration options from mypy.ini (and other config files): defaults
  • Python version used: 3.12 and 3.13.2

Thanks so much for building this tool!

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

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

はじめの一歩

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

調査の方向性

まず、名前の挙がっている2つのユニットケース、特に testVarargsArgumentTypeCheckingUsingArgumentTypeFromVarArgsForInheritance-xfail を再現し、それらの診断結果をキーワードパラメーターの例と比較します。可変長エントリが Any の場合の args[1] の処理を追跡し、直接形式と中間変数を使う形式を確認します。xfail が成功するケースになり、明示的なキャストやキーワードの動作を退行させなければ完了です。

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

評価

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

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

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