python / python/mypy

Passing Callable to higher-order functions expecting Type[Callable] fails

Offen
#15,593 1 Kommentar 1 Reaktion 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

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

Beschreibung

Bug Report

Mypy reports that higher-order functions with parameters of type Type[Callable] - or any subscripted variant - can't receive Callable (with compatible subscripts where needed) as arguments.

To Reproduce

Playground link (with more detail and further test cases):
https://mypy-play.net/?mypy=1.4.1&python=3.11&gist=bd6418069e6a7800eb0e2067829a2c90

def test_fn(_: Type[Callable]) -> None:
    """A higher order fn accepting some TYPE, instances of which are callable"""
    pass

test_fn(Callable)  # FAILS
test_fn(Callable[[int], None])  # FAILS

TestCase: TypeAlias = Callable[[int], None]
test_fn(TestCase)  # FAILS

Expected Behavior

From https://docs.python.org/3/library/typing.html#type-of-class-objects

A variable annotated with type[C] (or typing.Type[C]) may accept values that are classes themselves – specifically, it will accept the class object of C.

So, passing Callable to a function expecting a Type[Callable], either directly or via a TypeAlias, should work.

Actual Behavior

When a subscripted Callable expression is passed directly in the function call, mypy reports:

error: Argument 1 to "test_fn" has incompatible type "object"; expected "type[Callable[..., Any]]"  [arg-type]

When bare Callable is passed in-place, or when any Callable expression is passed via a variable, with or without a TypeAlias annotation, this becomes:

error: Argument 1 to "test_fn" has incompatible type "<typing special form>"; expected "type[Callable[..., Any]]"  [arg-type]

Your Environment

  • Mypy version used: Playground 1.4.1 (originally discovered in 1.3.0)
  • Mypy command-line flags: Playground defaults
  • Mypy configuration options from mypy.ini (and other config files): Playground defaults
  • Python version used: 3.11

Other Notes

Pylance/Pyright appears to be fine with this.

The actual use-case I have is as a (generic) factory function which, given the type of some callable, will return an appropriate version of a corresponding generic class, which manages registering and triggering callbacks of the original callable type. The constructed class preserves and forwards the function signature annotations from the callable onto its own methods, via a ParamSpec and return-type TypeVar. The function receives a type, rather than a callable instance, as when defining the callback interface I wouldn't typically have a function of the correct type to hand.

As the playgound link shows, I'm also intending that the factory fn support receiving callable Protocol classes, which while more flexible than collections.abc.Callable (kwargs!) are also much more verbose. Mypy seems happy with these.

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

Beginne damit, die drei fehlschlagenden Fälle im verlinkten mypy playground zu reproduzieren, einschließlich bare, subscripted und aliased Callable-Formen. Das Issue nennt keine Quelldatei oder keinen Test; abgeschlossen ist es, wenn kompatible Callable-Ausdrücke akzeptiert werden, wenn sie an Type[Callable]-Parameter übergeben werden, ohne die gemeldeten arg-type-Fehler.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
python
Bereich
devtools
Issue-Typ
Bug
Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Aktivitätsstatus
Veraltet
Klarheit
Größtenteils klar
Anfängerfreundlichkeit
35/100

Neue Issues direkt in Ihr Postfach

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