python / python/mypy

"INTERNAL_ERROR": generic fun w/ Callable param w/ constrained return type followed by `*args` typed as `*Tuple[int, float]` crashes mypy

Offen
#21,907 3 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

crash
Vorherrschende Sprache
Python
Sterne
20.6k
Forks
3.3k
PR-Merge-Kennzahlen
PR-Kennzahlen ausstehend

Beschreibung

Crash Report

  • Create crash_example.py as follows:
from typing import *

# mypy latest from master branch crashes (mypy 2.4.0+dev.b974556f84bd4ff5280b66bce1413fa942d1261e) (and earlier prod releases as well)
def generic_fun[
   TypeVarWithConstraints: (str, bytes),
](
   a: Callable[..., TypeVarWithConstraints],
   *args: *Tuple[int, float]
): pass
  • run mypy 2.3.1 or latest master on Github (2.4.0+dev) and observe a crash with "INTERNAL_ERROR":
[liveuser@localhost-live ~]$ mypy crash_example.py --show-traceback
crash_example.py:4: error: INTERNAL ERROR -- Please try using mypy master on GitHub:
https://mypy.readthedocs.io/en/stable/common_issues.html#using-a-development-mypy-build
Please report a bug at https://github.com/python/mypy/issues
version: 2.4.0+dev.b974556f84bd4ff5280b66bce1413fa942d1261e
[--show-traceback output is included further down]

Traceback

Traceback (most recent call last):
  File "/home/liveuser/.local/bin/mypy", line 8, in <module>
    sys.exit(console_entry())
  File "/home/liveuser/.local/lib/python3.13/site-packages/mypy/__main__.py", line 16, in console_entry
    main()
  File "/home/liveuser/.local/lib/python3.13/site-packages/mypy/main.py", line 154, in main
    res, messages, blockers = run_build(sources, options, fscache, t0, stdout, stderr)
  File "/home/liveuser/.local/lib/python3.13/site-packages/mypy/main.py", line 244, in run_build
    res = build.build(sources, options, None, flush_errors, fscache, stdout, stderr)
  File "/home/liveuser/.local/lib/python3.13/site-packages/mypy/build.py", line 422, in build
    result = build_inner(
  File "/home/liveuser/.local/lib/python3.13/site-packages/mypy/build.py", line 537, in build_inner
    graph = dispatch(sources, manager, stdout, connect_threads)
  File "/home/liveuser/.local/lib/python3.13/site-packages/mypy/build.py", line 4150, in dispatch
    process_graph(graph, manager)
  File "/home/liveuser/.local/lib/python3.13/site-packages/mypy/build.py", line 4618, in process_graph
    done, still_working, results = manager.wait_for_done(graph)
  File "/home/liveuser/.local/lib/python3.13/site-packages/mypy/build.py", line 1484, in wait_for_done
    process_stale_scc(graph, next_scc, self)
  File "/home/liveuser/.local/lib/python3.13/site-packages/mypy/build.py", line 4793, in process_stale_scc
    graph[id].type_check_first_pass()
  File "/home/liveuser/.local/lib/python3.13/site-packages/mypy/build.py", line 3410, in type_check_first_pass
    self.type_checker().check_first_pass(recurse_into_functions=recurse_into_functions)
  File "/home/liveuser/.local/lib/python3.13/site-packages/mypy/checker.py", line 632, in check_first_pass
    self.accept(d)
  File "/home/liveuser/.local/lib/python3.13/site-packages/mypy/checker.py", line 779, in accept
    stmt.accept(self)
    ~~~~~~~~~~~^^^^^^
  File "/home/liveuser/.local/lib/python3.13/site-packages/mypy/nodes.py", line 1165, in accept
    return visitor.visit_func_def(self)
           ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/home/liveuser/.local/lib/python3.13/site-packages/mypy/checker.py", line 1346, in visit_func_def
    self.visit_func_def_impl(defn)
    ~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/home/liveuser/.local/lib/python3.13/site-packages/mypy/checker.py", line 1350, in visit_func_def_impl
    self.check_func_item(defn, name=defn.name)
    ~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
  File "/home/liveuser/.local/lib/python3.13/site-packages/mypy/checker.py", line 1383, in check_func_item
    self.check_func_def(defn, typ, name, allow_empty)
    ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/liveuser/.local/lib/python3.13/site-packages/mypy/checker.py", line 1514, in check_func_def
    store_argument_type(item, i, typ, self.named_generic_type)
    ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/liveuser/.local/lib/python3.13/site-packages/mypy/types_utils.py", line 183, in store_argument_type
    defn.arguments[i].variable.type = arg_type
    ~~~~~~~~~~~~~~^^^
IndexError: list index out of range

crash_example.py:4: note: use --pdb to drop into pdb

Context/motivation

In PEP-0646 ( https://peps.python.org/pep-0646/ ), it is shown how an unpacked Tuple can be used to specify the type of *args:

# example from PEP-0646
def foo(*args: *Tuple[int, str]) -> None: pass

foo(1, "hello")  # OK

In https://docs.python.org/3.13/reference/compound_stmts.html#type-parameter-lists
(separate from the SyntaxError in their overly_generic example which I have reported to the python team and am working with them to fix),
saying

A parenthesized tuple of expressions after the colon indicates a set of constraints (e.g. T: (str, bytes)). Each member of the tuple should be a type (again, this is not enforced at runtime). Constrained type variables can only take on one of the types in the list of constraints.
e.g.

from typing import *

def generic_fun_takes_a_callable_that_returns_either_str_or_bytes[
        TypeVarWithConstraints: (str, bytes),
](a: Callable[..., TypeVarWithConstraints]):
    pass

def some_fun_returns_str() -> str:
    return 'abc'

def some_fun_returns_bytes() -> bytes:
    return b'abc'

def some_fun_returns_int() -> int:
    return 1

generic_fun_takes_a_callable_that_returns_either_str_or_bytes(some_fun_returns_str) # ok

generic_fun_takes_a_callable_that_returns_either_str_or_bytes(some_fun_returns_bytes) # ok

# not ok:
# error: Value of type variable "TypeVarWithConstraints" of "generic_fun_takes_a_callable_that_returns_either_str_or_bytes" cannot be "int"  [type-var]
# generic_fun_takes_a_callable_that_returns_either_str_or_bytes(some_fun_returns_int)

So given

 def generic_fun_takes_a_callable_that_returns_either_str_or_bytes[
        TypeVarWithConstraints: (str, bytes),
](a: Callable[..., TypeVarWithConstraints]):
    pass

is ok and

# example from PEP-0646
def foo(*args: *Tuple[int, str]) -> None: pass

is ok,
what about a function that has the arguments of the 1st followed by the arguments of the 2nd example, which both work fine with mypy on their own? (note PEP-0646 gives examples of *args being typed by an unpacked tuple even when preceded by other arguments)

def generic_fun[
   TypeVarWithConstraints: (str, bytes),
](
   a: Callable[..., TypeVarWithConstraints],
   *args: *Tuple[int, float]
): pass

It turns out that the above crashes mypy unexpectedly in a way that causes the problem to tell me to file a bug, so I am doing so (see traceback towards top of ticket).


Your Environment

  • Fedora Linux 42
  • mypy 2.3.1 and mypy 2.4.0+dev.b974556f84bd4ff5280b66bce1413fa942d1261e
  • python 3.13.2 in this case

Thanks very much!

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Rechercherichtung

Reproduziere den Absturz mit der crash_example.py des Issues unter Verwendung von mypy 2.3.1 oder des Entwicklungs-Builds. Beginne in mypy/checker.py und verfolge den Aufruf bis zu mypy/types_utils.py, wo der Traceback den IndexError zeigt. Erledigt ist die Aufgabe, wenn diese gültige Kombination aus einem eingeschränkten Callable-Parameter und entpackten *args nicht mehr abstürzt; füge eine Regressionstestabdeckung hinzu, wenn die vorhandenen Tests des Projekts dafür einen geeigneten Ort bieten.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
python
Bereich
devtools
Issue-Typ
Bug
Schwierigkeit
3/5
Geschätzter Aufwand
1-2 Tage
Aktivitätsstatus
Aktiv
Klarheit
Klar beschrieben
Anfängerfreundlichkeit
70/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.