python / python/mypy

`@overload` incorrectly reports error if overload param would go to different params of implementation depending on positional vs keyword calling style

Offen
#16,626 0 Kommentare 3 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

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

Beschreibung

Bug Report

Type-checking on the @overload decorator incorrectly reports an error in the implementation function's signature when an argument would go to different parameters of an implementation function depending on whether that argument is passed as a positional or keyword argument, even if both outcomes are still valid.

To Reproduce

Here's a minimal possible example:

from typing import overload

@overload
def func(value: int):
    ...

def func(positional_only: int | None = None, /, value: int | None = None):
    pass

func can be correctly called with either of these signatures:

func(1)  # results in call with parameters(1, None)
func(value=1)  # results in call with parameters (None, 1)

Either of these calls is valid.

Expected Behavior

The type-checker considers the code valid. (Excluding the error that there's only one overload, which is expected in this minimal example).

Actual Behavior

type_test.py:8: error: Overloaded function implementation does not accept all possible arguments of signature 1  [misc]

Your Environment

  • Mypy version used: mypy 1.7.1 (compiled: yes)
  • Mypy command-line flags: python3 -m mypy ./type_test_2.py
  • Mypy configuration options from mypy.ini (and other config files): Not changed from the default
  • Python version used: Python 3.11.6

A motivating example

I wanted to define a lookup function that can lookup an object by id (an int) or name (a str), something like this:

from typing import overload

@overload
def lookup(id: int):
    ...

@overload
def lookup(name: str):
    ...

def lookup(id_or_name: int | str | None = None, /, id: int | None = None, name: str | None = None):
    if id is None and name is None:
        if isinstance(id_or_name, int): id = id_or_name
        else: name = id_or_name  # name is str

    if id is not None:
        return _lookup_by_id(id)
    else:
        return _lookup_by_name(name)


## Possible calls:

lookup(1)  # integer positional
lookup(id=1)  # integer keyword

lookup("foo")  # string positional
lookup(name="foo")  # string keyword

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

Führe zunächst den gemeldeten Befehl python3 -m mypy ./type_test_2.py mit dem minimalen Overload-Beispiel aus und bestätige den Fehler der Implementierungssignatur. Verfolge die Kompatibilitätsprüfung der Overload-Implementierung und füge Abdeckung für Positions- und Schlüsselwortaufrufe hinzu, die verschiedene Implementierungsparameter erreichen. Die Aufgabe ist erledigt, wenn gültige Aufrufe nicht mehr den gemeldeten Fehler erzeugen, während ungültige Overload-Implementierungen weiterhin abgelehnt werden.

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
Klar beschrieben
Anfängerfreundlichkeit
45/100

Neue Issues direkt in Ihr Postfach

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