Blogeintrag zu WSGI und Python3 von Mitsuhiko

Django, Flask, Bottle, WSGI, CGI…
Antworten
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Ich habe gerade mal wieder Zeit und Muße gehabt, in Mitsuhikos Blog die letzten Einträge zu lesen und stieß auf eine schöne Erklärung der "Misere" von WSGI unter Python3.

Dabei fiel mir folgende Stelle ins Auge:
Here a list of web related libraries operating on unicode (just a small pick): Django, Pylons, TurboGears 2, WebOb, Werkzeug, Jinja, SQLAlchemy, Genshi, simplejson, feedparser and the list goes on.

What these libraries can have, what a protocol like WSGI does not, is having the knowledge of the encoding used. Why? Because in practice (not on the paper) encodings on the web are very simple and driven by the application: the encoding the application sends out is the encoding that comes back. It's as simple as that. However WSGI does not have that knowledge because how would you tell WSGI what encoding to assume? There is no configuration for WSGI so the only thing we could do is forcing a specific charset for WSGI applications on Python 3 if we want to get unicode onto that layer. Like utf-8 for everything except headers which should be latin1 for RFC compliance.
Nun frage ich mich doch einfach naiv: Wieso eigentlich kann / darf WSGI keine Konfiguration haben? Wo liegt da das Problem? Bei einem SQLAlchemy muss ich das Encoding der Datenbank ja auch explizit angeben. Inwiefern wäre das problematisch, ein solches "Durchreichen" auch für Libs zu definieren, die einen WSGI Layer implementieren? Vielleicht ist die Erklärung ja trivial, aber im Moment erschließt sie sich mir nicht.

Da auf diesem Gebiet ja keine Idioten tätig sind, muss es ja einen guten Grund geben, wieso so eine einfache Idee nicht umsetzbar ist!

(Dies wurd auch schon in der Diskussion angesprochen, wie ich grad gelesen habe)

Vielleicht kann mir das einer der Kenner hier versuchen zu erklären :-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
Defnull
User
Beiträge: 778
Registriert: Donnerstag 18. Juni 2009, 22:09
Wohnort: Göttingen
Kontaktdaten:

Das Problem ist: Aus dem Netzwerk kommen bytes. HTTP kennt nun mal kein unicode. Wenn WSGI auf Unicode auf baut, muss der Webserver die Daten dekodieren, bevor er sie an die WSGI Applikation weiter reichen kann. Aber mit welchem Codec? Die WSGI Applikation entscheidet nämlich selbst, in welchem Format sie z.B. HTML-Seiten ausliefert und damit auch, mit welchem Encoding der typische Browser Formular-Daten oder Cookies zurück schickt. Der Webserver muss den richtige Codec raten, denn WSGI bietet keine Möglichkeit, das Unicode-Verhalten des Webservers zu beeinflussen. Das ist mit "There is no configuration for WSGI" gemeint.

Ein Trick wäre nun, für alles latin9 zu nehmen, da dieser Zeichensatz die vollen 8bit eines Bytes abbildet und damit jede beliebigen binären Daten ohne Verlust codieren kann. Dann könnte die WSGI App im Notfall wieder Bytes daraus machen und die Daten anschließend richtig decodieren. Das ist allerdings ziemlich umständlich.

Eine andere Alternative wäre, WSGI mit Byte-Strings zu füllen, wie bisher. Schließlich basiert HTTP auf Bytes und nicht auf irgendeinem Encoding. Da Python3 aber Bytes eher stiefmütterlich behandelt und praktische Dinge wie zum Beispiel .format() für Bytes nicht implementiert (obwohl das kein Problem wäre), würde das WSGI Applikationen ziemlich umständlich und den Großteil der stdlib nahezu nutzlos machen.

Zusammenfassend kann man sagen: Python3 hat in Hinsicht auf Bytes- und Text-Strings ordentlich gepatzt. Die stdlib ist in vielen Bereichen einfach kaputt (cgi, mail parsing, urllib, ...), da sich die Entwickler auf 2to3 verlassen und stumpf alles auf Unicode umgemünzt haben, ganz egal ob es Sinn macht oder nicht. Ich vermute auch, das ist der Grund warum von der offiziellen Seite nichts mehr im Bereich WSGI kommt: Weil sie es selbst nicht besser wissen und warten, bis die Community ne einigermaßen funktionierende Notlösung erdenkt (was so oder so auf eine neu-Implementierung von Teilen der stdlib hinaus läuft). Schade, aber damit werden wir noch eine ganze Weile leben müssen.
Bottle: Micro Web Framework + Development Blog
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Ich denke momentan ist das Hauptproblem erstmal dass die stdlib kaputt ist, wer etwas mit Python 3 arbeitet merkt das. Ich glaube dass das generelle Interesse am einem Wechsel dadurch stark gesunken ist.
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

Weiß irgendwer wie da jetzt die Situation konkret ist? Gibt es ernsthafte Bestrebungen Python3 zu fixen? http://bugs.python.org/issue3982 wurde ja abgelehnt und geschlossen. Dann gibts noch den Feature-Freeze, der imo gar keinen Sinn macht, so lange Python3 broken ist. Ich frage mich, warum überhaupt 3.1 rausgekommen ist. Vor Armin Post war mit die Python3-Situation gar nicht so bewusst, da ich Python3 mangels Libs nicht benutzte. Ich hatte mich eher drauf verlassen, dass die Python-Devs schon wissen was sie tun, scheint ja nicht der Fall gewesen zu sein. Irgendwie sehe ich da schwarz für Python…
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Darii hat geschrieben:Weiß irgendwer wie da jetzt die Situation konkret ist? Gibt es ernsthafte Bestrebungen Python3 zu fixen?
Es muss nichts gefixt werden, weil nichts kaputt ist.

Der Punkt ist doch, dass ausschließlich einige Netzwerkprogrammierer schreien weil sie nicht vom ASCII-Encoding nach Unicode und zurück wollen. Dann sollen sie sich doch irgendeine Bibliothek anflanschen die direkt mit ASCII umgeht. Auf meiner Seite des Frameworks hätte ich aber dann gerne wieder Unicode.
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

/me hat geschrieben:Der Punkt ist doch, dass ausschließlich einige Netzwerkprogrammierer schreien weil sie nicht vom ASCII-Encoding nach Unicode und zurück wollen. Dann sollen sie sich doch irgendeine Bibliothek anflanschen die direkt mit ASCII umgeht.
Das ist aber genau das Problem. Die „einige Netzwerkprogrammierer“ wollen eben nicht mit ASCII umgehen. Es gibt fälle da braucht man Bytes. Kein Unicode. Kein ASCII. Kaputt ist, dass Unicode da verwendet wird, wo es nicht zu suchen hat. Da ist es keine Lösung was „anzuflanschen“. So lange noch niemand Python3 verwendet besteht schließlich noch die Möglichkeit das vernünftig zu machen.

Verwirrend/Kaputt ist, das bytes kein String ist, aber doch durch etwas erstellt werden, das wie ein String-Literal aussieht. Das macht das ganze unnötig kompliziert. Python 3 braucht einfach echte Bytestrings.
Benutzeravatar
Defnull
User
Beiträge: 778
Registriert: Donnerstag 18. Juni 2009, 22:09
Wohnort: Göttingen
Kontaktdaten:

Darii hat geschrieben:
/me hat geschrieben:Der Punkt ist doch, dass ausschließlich einige Netzwerkprogrammierer schreien weil sie nicht vom ASCII-Encoding nach Unicode und zurück wollen. Dann sollen sie sich doch irgendeine Bibliothek anflanschen die direkt mit ASCII umgeht.
Aus HTTP kommen Bytes. Kein Unicode. Kein ASCII. Kaputt ist, dass Unicode da verwendet wird, wo es nicht zu suchen hat.
Genau das. Es wäre ja noch in Ordnung, wenn die stdlib mit unicode wenigstens sauber umgehen würde, dann könnte man ja zur Not auch um-dekodieren. Aber auch das klappt nicht: Zeilenumbrüche sind nämlich plötzlich etwas komplett schwammiges. Der Multipart-Parser aus email zum Beispiel, der auch von cgi.FieldStorage und einigen Web Framework (Werkezug mal ausgenommen) verwendet wird, verschluckt Zeilenumbrüche am Ende von Datenblöcken. Er ist kaputt. Warum? Weil selbst ein JPEG-Bild als Unicode-Text verarbeitet wird. WTF soll das?

Nächstes Beispiel: urllib.parse

HTTP Anfragen bestehen per Definition aus Bytes. Anfragen kommen nun mal als Bytes aus dem Netzwerkkabel. Ein Python-Webserver, der das HTTP Protokoll parsen möchte, kann urllib.parse nicht benutzen. Warum nicht? Weil es aus unerfindlichen Gründen Unicode haben will! Und warum ist das ein Problem? Weil HTTP für den request path kein Encoding deklariert. Der Webserver muss raten. Und was dabei passiert, sieht man hier:

Code: Alles auswählen

>>> urllib.parse.urlparse('http://www.google.de/q?öäü'.encode('utf8').decode('latin9')).query
'öÃĊÃỳ'
>>> urllib.parse.urlparse('http://www.google.de/q?öäü'.encode('latin9').decode('utf8')).query
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.1/encodings/utf_8.py", line 16, in decode
    return codecs.utf_8_decode(input, errors, True)
UnicodeDecodeError: 'utf8' codec can't decode bytes in position 23-25: unexpected end of data
Erklärung: Der Browser kodiert GET Formular-Daten mit dem Encoding der HTML-Seite, in der das Formular ausgeliefert wurde. Das kann prinzipiell alles sein. Der Webserver weiß davon aber nichts. HTTP ist stateless. Er muss also raten, was das richtige wäre. Nimmt er latin9 (weil es verlustfrei ist) liegt er damit für alle utf8-Seiten falsch, was den Großteil der modernen Webseiten aus macht. Nimmt er utf-8, explodiert er bei latin9 Daten. Er kann es also gar nicht richtig machen. Schon aus Prinzip nicht. Und das nur, weil eine Bibliothek gerne unicode hätte, wo bytes hin gehören.
Bottle: Micro Web Framework + Development Blog
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

/me hat geschrieben:Der Punkt ist doch, dass ausschließlich einige Netzwerkprogrammierer schreien weil sie nicht vom ASCII-Encoding nach Unicode und zurück wollen.
Alles was nicht mit Strings zu tun hat funktioniert. Unicode strings sind nativ das ist gut, byte strings sind kaputt und die Verwendung der Strings ist im großen und ganzen ebenfalls überall kaputt wie z.B. bei Pfaden.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Darii hat geschrieben:Gibt es ernsthafte Bestrebungen Python3 zu fixen? http://bugs.python.org/issue3982 wurde ja abgelehnt und geschlossen.
Habe das gefunden:
http://bugs.python.org/issue4953
http://bugs.python.org/issue3991
http://bugs.python.org/issue1599329
http://bugs.python.org/issue4733

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Antworten