python / python/mypy

sorted() loses information about namedtuple elements

Offen
#17,602 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

bug topic-join-v-union
Vorherrschende Sprache
Python
Sterne
20.6k
Forks
3.3k
PR-Merge-Kennzahlen
PR-Kennzahlen ausstehend

Beschreibung

Bug Report

it seems that running sorted() on an union of iterables of named tuple, create some missing information

To Reproduce

playground url

from typing import NamedTuple
from typing import reveal_type


class NamedTupleA(NamedTuple):
    field_a: str


class NamedTupleB(NamedTuple):
    field_b: str


def my_fun(my_list: list[NamedTupleA] | list[NamedTupleB]) -> None:
    reveal_type(my_list)
    # Revealed type is "Union[builtins.list[tuple[builtins.str, fallback=__main__.NamedTupleA]], builtins.list[tuple[builtins.str, fallback=__main__.NamedTupleB]]]"

    for nt in my_list:
        if isinstance(nt, NamedTupleA):
            print(nt.field_a)
        else:
            # here nt is recognized of `NamedTupleB` type, I can access field_b
            print(nt.field_b)

    reveal_type(sorted(my_list))
    # Revealed type is "builtins.list[tuple[builtins.str]]"

    for sorted_nt in sorted(my_list):
        if isinstance(sorted_nt, NamedTupleA):
            print(sorted_nt.field_a)
        else:
            # here I expected nt to be recognized of `NamedTupleB` type
            print(sorted_nt.field_b)

if __name__ == '__main__':
    my_fun([NamedTupleA('value_1')])
    my_fun([NamedTupleB('value_2')])
    # this error is expected: I cannot mix NamedTupleA and NamedTupleB
    my_fun([NamedTupleA('value_1'), NamedTupleB('value_2')])

basically I have 2 list of NamedTuples.
my_fun must accept either one.
Ideally I could write a User-Defined Type Guards, but let's say that I'm just checking (with isinstance) each element type.

If I loop directly over the list, the check works for both the if and the else branch (there shouldn't be any other case, the union is between two types)

If I loop directly over the sorted list, the type of the element is different, so in the else branch mypy gives me an error

Expected Behavior

I expect no errors on print(sorted_nt.field_b)

Actual Behavior

main.py:32: error: "tuple[str]" has no attribute "field_b" [attr-defined]

Your Environment

linux, python3.12, mypy 1.10.1

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

Beginnen Sie mit der verknüpften mypy-playground-Reproduktion unter Python 3.12 und mypy 1.10.1 und vergleichen Sie anschließend die angezeigten Typen vor und nach sorted() in main.py. Die Korrektur ist vollständig, wenn das Ergebnis von sorted() die NamedTuple-Alternativen beibehält, sodass die isinstance-Zweige sorted_nt.field_a und sorted_nt.field_b ohne einen attr-defined-Fehler akzeptieren.

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
48/100

Neue Issues direkt in Ihr Postfach

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