Verständnis zu type Literal

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Erhy
User
Beiträge: 64
Registriert: Mittwoch 2. Januar 2019, 21:09

Hallo!
Mein Script funktioniert zwar,
trotzdem möchte ich wissen, wie man mit Literals in Python kodiert.

Bei meiner Image-Bearbeitung mit dem Modul Pillow öffne ich ein Image mit

Code: Alles auswählen

from PIL import Image

origPil = Image.open( filename )
origPil_mode = origPil.mode # ist 'I;16' für ein Image mit 16-bit Auflösung
img_array = np.asarray(origPil)
nach der der Bearbeitung möchte ich das Image im selben Mode anschauen und bei Bedarf speichern:

Code: Alles auswählen

img_to_show = Image.fromarray( img_array , mode = origPil_mode ) # mode is defined as lieral ?
from PIL import ImageShow
ImageShow.show(img_to_show)
In der Zeile
img_to_show = Image.fromarray( img_array , mode = origPil_mode )
meckert mein VS Code Python:

Code: Alles auswählen

Argument of type "str" cannot be assigned to parameter 
"mode" of type
"Literal['1', 'CMYK', 'F', 'HSV', 'I', 'l', "LAB', 'P', 'RGB', 'RGBA', 'RGBX', 'YCbCr'] | None"
in function "fromarray"
   Type "str" cannot be assigned to type 
"Literal['1', "CMYK', 'F', 'HSV', 'I', 'L', 'LAB', 'P', 'RGB', 'RGBA', ''RGBX', 'YCbCr'] | None"
Nicht nur dass in der Auflistung möglicher Werte 'I;16' fehlt,
wüsste ich auch nicht, wie die Zuweisung zu kodieren wäre.

Danke für die Diskussion
Erhy
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Die Doku ist da etwas subtil. Wenn man es freundlich ausdrückt. Der Mode ist ein String, oder None. Erlaubt sind aber nur die modes, die als vollkommen unterstützt angegeben werden. Deiner ist in der Liste der nur eingeschränkt unterstützten Modi, und das du den nicht zum schreiben benutzen kannst, ist eben genau die Einschränkung.

Literal heißt hier auch nur String-Literal, warum auch immer. Ich vermute das soll eine Art String enumeration im Typsystem ausdrücken.
Erhy
User
Beiträge: 64
Registriert: Mittwoch 2. Januar 2019, 21:09

__deets__ hat geschrieben: Dienstag 7. September 2021, 17:43 Deiner ist in der Liste der nur eingeschränkt unterstützten Modi, und das du den nicht zum schreiben benutzen kannst, ist eben genau die Einschränkung.
Literal heißt hier auch nur String-Literal, warum auch immer. Ich vermute das soll eine Art String enumeration im Typsystem ausdrücken.
auch bei 'RGB' meckert VS Code.
Habe nun weiter den Debugger bemüht und gesehen, dass in Image.pyi
from typing_extensions import Literal
verwendet wird.
Die Frage ist glaube ich,
wie man aus der Liste eines Literals einen Wert auswählt, und diesen als Literal verwendet.

Erhy
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Erhy: Ich glaube eher die Frage ist warum VSCode bzw. das entsprechende Plugin hier unberechtigt meckert.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Laut deren eigenen Tests hast du nicht recht: https://github.com/python-pillow/Pillow ... ert.py#L30

Das sind Strings. Es gibt auch schlicht keine Were vom Typ Literal. Es ist lediglich eine Typannotation, um präziser zu beschrieben, welche Werte ein Argument als String konkret annehmen kann: https://www.python.org/dev/peps/pep-0586/

Warum VS Code da meckert - keine Ahnung. Es ändert aber nichts an dem, was da als Modi übergeben werden kann: Strings, aber eben nur die, die als Modi bekannt sind.
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Ich vermute mal der Typchecker den VSCode verwendet, versteht einfach `typing_extensions.Literal` nicht richtig und behandelt den wie jeden anderen Typ. Und eine Zeichenkette ist halt nicht von dem Typ. Vielleicht kann man da irgendwas aktualisieren‽
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Erhy
User
Beiträge: 64
Registriert: Mittwoch 2. Januar 2019, 21:09

der Prototype von fromarray ist:
def fromarray(obj, mode: _Mode | None = ...) -> Image: ...
und _Mode ist definiert:
_Mode = Literal["1", "CMYK", "F", "HSV", "I", "L", "LAB", "P", "RGB", "RGBA", "RGBX", "YCbCr"]
narpfel
User
Beiträge: 643
Registriert: Freitag 20. Oktober 2017, 16:10

@Erhy: Wie ist denn der tatsächliche Code? So wie gezeigt? Dann ist klar, warum VSCode da meckert: Für einen Wert vom Typ `Literal` darf nur ein literaler Wert angegeben werden, `Image.mode` ist aber kein literaler Wert. Viel mehr als ein `#type: ignore` wirst du da nicht machen können, wenn die Type Hints an der Stelle mit der Realität kollidieren.
Erhy
User
Beiträge: 64
Registriert: Mittwoch 2. Januar 2019, 21:09

hab auch bei den Pillow Leuten nachgefragt:
https://github.com/python-pillow/Pillow/issues/5707
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Erhy: Da können die Pillow-Leute nichts für oder gegen machen, die liefern keine Typ-Annotationen.

@narpfel: Also zumindest `mypy` kommt damit klar wenn `Image.mode` auch den Typ `_Mode` annotiert hätte. Hat es wahrscheinlich nicht, denn das können ja auch andere Werte sein, aber es muss nicht zwingend ein literaler Wert sein, denn man da übergibt. Es reicht wenn der Typchecker feststellen kann, das es ein erlaubter Wert ist.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

@Erhy,

Dieser Fehler ist so nicht nachzustellen.

"mode" ist ein einfacher String und das wird auch erwartet und daher funktioniert dein Script auch.

Was meinst du mit VS Code meckert?
Wo und wann wird die Fehlermeldung angezeigt?
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@rogerb: Was VS Code genau sagt, hat Erhy doch im Ausgangsbeitrag kopiert. Es gibt ein Plugin für Python (pylance) das unter anderem a) Typannotationen prüft, und b) Typannotationen für PIL benutzt, und da ist `mode` nicht irgendeine Zeichenkette, sondern muss ein Wert aus der Liste im ersten Beitrag sein.

`PIL.IMage.Image.mode` hat die Typannotation `str`, aber das `mode`-Argument von `PIL.Image.fromarray()` hat die weiter oben genannte `_Mode`-Annotation. Und das passt halt nicht.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

@__blackjack__,
Was VS Code genau sagt
?
Manchmal kommt es schon auf klare Ausdrucksweise an. Die Typeannotations von Pylance (In VSCode - Speak eine Extension und kein Plugin) dienen in erster Linie zur Codevervollständigung und zum Typehinting.
PIL.IMage.Image.mode` hat die Typannotation `str`, aber das `mode`-Argument von `PIL.Image.fromarray()` hat die weiter oben genannte `_Mode`-Annotation.
Du meinst im typeshed-repository? Oder im Quellcode von PIL?

PIL selber verwendet keine Typeannotations, daher kann die "Image.fromarray" Methode erstmal alles mögliche verarbeiten, ohne eine explizite Fehlermeldung auszugeben. Innerhalb der Methode wird aber davon ausgegangen, dass ein "mode" in Form eines Strings übergeben wurde.
"Image.mode" ist eine einfache Instanzvariable, die einen String enthält. Das heißt man kann Image.mode einfach zurück an die fromarray() Methode zurückübergeben, wie es in dem Beispielcode ja auch gemacht wird.
Von da kommt die Fehlermeldung also auch nicht. Und soweit waren wir ja auch schon.

Pylance hat im typeshed-repository für PIL in der Image.pyi eine Typeannotation für _Mode. Was ja auch der TO schon bemerkt hatte. Das ist aber auch erstmal kein Grund für eine Fehlermeldung.

Egal wieviele Linter, ich auch konfiguriere und Einstellungen in VS Code verstelle. Ich kann keine Fehlermeldung provozieren.
Daher finde ich die Frage was VS Code jetzt genau "sagt" oder "meckert" berechtigt.

Falls du den Fehler nachstellen kannst, würde mich interessieren wie du das machst.
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@rogerb: Das PIL keine Typannotationen hat, habe ich ja bereits geschrieben als Erhy dort den Bugtracker gefüttert hat.

Wenn die Typannotation von typeshed kein Grund für die Fehlermeldung ist, warum ist *das* dann genau das was die Fehlermeldung ausspuckt?

Was genau gesagt/gemeckert wird, steht doch im ersten Beitrag. Und das kann zum Beispiel passieren wenn, was immer da die Annotationen prüft, nicht weiss was `Literal` bedeutet.

Nachstellen lassen, sollte sich das mit folgendem Code:

Code: Alles auswählen

#!/usr/bin/env python3
from typing_extensions import Literal

_Mode = Literal[
    "1",
    "CMYK",
    "F",
    "HSV",
    "I",
    "l",
    "LAB",
    "P",
    "RGB",
    "RGBA",
    "RGBX",
    "YCbCr",
]


class Image:
    mode: str


def fromarray(obj, mode: _Mode) -> Image:
    ...


def main() -> None:
    original_image = Image()
    original_mode = original_image.mode
    new_image = fromarray(None, original_mode)


if __name__ == "__main__":
    main()
Verschwinden sollte die Meldung wenn man das `mode`-Attribut von `Image` auch mit `_Mode` statt mit `str` annotiert, oder `original_mode` an einen erlaubten Wert, beispielsweise ``original_mode = "RGB"`` bindet.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

Dass man das gezielt falsch programmieren kann ist klar.
Dein Beispiel entspricht nicht dem Quellcode von Pillow:

Code: Alles auswählen

PIL.Image.fromarray(obj, mode=None)

Die Frage war auch warum das Code-Schnippsel von Erhy diesen Fehler zeigt.

VS Code kann auf vielfältige Weise auf Fehler hinweisen. Außerdem gibt es zig verschiedene Einstellungen, die die Funktionsweise beeinflussen. Linter können aktiviert und deactiviert werden. Pfade können verstellt werden, usw.
Dies ist offensichtlich keine Fehlermeldung die durch Python Code entsteht, sondern durch die Funktionsweise von VS Code, installierte Extensions, Konfigurationen usw.
Daher muss man etwas gründlicher hinschauen als nur zu sagen VS Code meckert über ...
Ich finde die Frage nach wie vor berechtigt.

Abgesehen davon, haben wir ja auch noch nicht den gesamten Code gesehen...
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

@Erhy,

Mit der Einstellung:
"python.analysis.typeCheckingMode": "strict"

wird der Fehler bei mir jetzt auch angezeigt. Dazu kommen aber auch noch einige andere Probleme. Daher muss dies nicht die Ursache für die Fehlermedlung sein.
Es gibt da auch noch viele andere ähnliche Einstellungen.

Wie ja schon von allen festgestellt wurde, kann PIL eigentlich mit jedem String umgehen. Hat aber eine Sonderbehandlung für ["1", "L", "I", "P", "F", "RGB"]
In allen anderen Fällen versucht PIL.Image so gut es geht aus dem Array ein Bild zu erzeugen.
Mit "1;16" kommt PIL deswegen klar, weil das numpy Array eben sinnvolle Daten enthält.

Wenn dich die Fehlermeldung stört, müsstest du wahrscheinlich mal deine Einstellungen in VS Code prüfen. Am Code etwas zu ändern macht meiner Meinung nach keinen Sinn, da du nun mal ein "I;16" Format hast.
Wenn du statt dessen das Format "SupertollesBild" als String übergibst, wird bestimmt das gleiche dabei rauskommen.

Edit:
Mit dieser Einstellung bekomme ich genau dein Fehlerbild:
"python.analysis.typeCheckingMode": "basic"

Wie gesagt, das muss es nicht sein, sieht aber so aus. Du must dir halt überlegen wie streng du das einstellen willst.
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@rogerb: Mein Beispiel entspricht dem Code der bei Erhy zu dieser Fehlermeldung führt. Ich habe nicht „gezielt falsch programmiert“, sondern einfach nur genau das nachgestellt was in der Kombination von PIL, VS Code, und pylance, was seinerseits typeshed verwendet, Stand der Dinge ist und zu der Fehlermeldung führt.

Und all die Informationen hatte Erhy ja auch schon über mehrere Beiträge verteilt geliefert.

Was man am Code machen kann ist den Wert zu ”casten”, oder einen Kommentar hinzufügen der pylance an der Stelle ruhig stellt, oder man schaltet das mit den Typannotationen grundsätzlich aus.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Benutzeravatar
pillmuncher
User
Beiträge: 1482
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

Type Annotations in Python sollten IMO nicht für statische Typabsicherung verwendet werden. Letzteres halte ich für völlig anti-pythonisch. Man kann sie aber gut für typ-basierten dynamischen Dispatch oder Property Based Testing und ähnliche Sachen verwenden.
In specifications, Murphy's Law supersedes Ohm's.
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

@__blackjack__,

Du hast etwas programmiert was den gleichen Fehler erzeugt.
Es ist offensichtlich etwas anderes, ob die Typeannotations im Code oder in einm Stub file vom typeshed repository liegen. Denn dort unterliegen sie den Einstellungen von Pylance.
Bei deinem Codebeispiel wird der Fehler immer angezeigt. Damit kannst du zwar den gleichen Fehler erzeugen, das beantwortet aber nicht die Frage, warum der Fehler bei Erhy auftritt, bei mir aber zum Beispiel nicht.
Erhy's Code enthielt ja keine expliziten Typeannotations. Das ist nunmal der Unterschied.
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@rogerb: Ich hätte das auch in eine Stub-Datei auslagern können, das Ergebnis wäre das gleiche gewesen. Da ist kein wirklicher Unterschied was den Effekt angeht, und die Lösung ist auch in beiden Fällen gleich.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Antworten