Encodingprobleme - Eclipse

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.
Antworten
Lonestar
User
Beiträge: 147
Registriert: Samstag 9. August 2008, 08:31

Hi, ich hab vor einiger Zeit schon mal eure Hilfe in anspruch genommen beim basteln eines kleinen TCP-Servers. Eigentlich war ich der Meinung das ich alles erledigt hätte und mein Spielzeug seinen Dienst ordentlich versieht, zumindest tat er das als ich ihn getestet hatte. Aber erst mal langsam an:

Ich habe das Project mit Eclipse entwickelt (war das erste mal das ich mit Eclipse/Pydev was gemacht habe). Gestartet habe ich das Projekt auch immer aus Eclipse heraus. Auf die Weise lief auch alles immer hervoragend und ich hatte keine Encoding Probleme. Letztens fiel mir auf wenn ich mein Project nicht aus Eclipse starte sondern die Datei direkt starte bekommt mein TCP-Servermodul probleme mit Umlauten. Allerdings nur wenn ich Umlaute senden möchte. Empfangen macht keine Probleme. Scheinbar habe ich das mit dem encoding in Python noch nicht so recht verstanden. Nur hab ich keine Ahnung wo ich Anfangen soll zu suchen (vor allem wunderts mich das Eclipse das Problem nicht kennt)
Ich hab schon euer [wiki=Unicode]Wiki[/wiki] überflogen und auch der LINK im Wiki war ganz interessant. Allerdings fehlt mir im Moment echt die Idee wo ich anfangen soll zu suchen.

hier erst mal mein Traceback den ich beim senden von Umlauten bekomme:

Code: Alles auswählen

----------------------------------------
Exception happened during processing of request from ('192.168.68.1', 2039)
Traceback (most recent call last):
  File "E:\Eigene Dateien\Projekte\Client-ServerP900\Working\eclipse\src\SocketS
erver.py", line 281, in _handle_request_noblock
    self.process_request(request, client_address)
  File "E:\Eigene Dateien\Projekte\Client-ServerP900\Working\eclipse\src\SocketS
erver.py", line 307, in process_request
    self.finish_request(request, client_address)
  File "E:\Eigene Dateien\Projekte\Client-ServerP900\Working\eclipse\src\SocketS
erver.py", line 320, in finish_request
    self.RequestHandlerClass(request, client_address, self)
  File "E:\Eigene Dateien\Projekte\Client-ServerP900\Working\eclipse\src\SocketS
erver.py", line 615, in __init__
    self.handle()
  File "E:\Eigene Dateien\Projekte\Client-ServerP900\Working\eclipse\src\TCPServ
er.py", line 122, in handle
    self.wfile.write(ClientAufgabe)
  File "E:\Programme\Python2_5\lib\socket.py", line 255, in write
    data = str(data) # XXX Should really reject non-string non-buffers
UnicodeEncodeError: 'ascii' codec can't encode character u'\xfc' in position 75:
 ordinal not in range(128)
----------------------------------------
Den zugehörigen Code für die Datei 'TCPServer.py' hab ich mal hierhin gepackt. Und bitte nicht wundern die Zeile 122 im Trace ist im hochgeladenen Code die Zeile 62 (ich neige dazu die Historie von meinem Modulen am anfang der Datei zu kommentieren... das muss sich nicht jeder antun)
wenn mir mal jemand nen Hinweis zur Fehlersuche geben könnte wäre ich echt dankbar :roll:
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Das Problem ist im Traceback in der Zeile ``self.wfile.write(ClientAufgabe)``. Was für ein Typ ist ``ClientAufgabe``? Das scheint ein Unicode-Objekt zu sein, also musst du es vor der Ausgabe enkodieren.

Ansonsten empfehle ich noch meine Unicode-Folien (findest du auch im Wiki), vielleicht helfen sie dir etwas (ich habe gehört, dass sie einigen auch ohne zugehörigen Vortrag geholfen haben).
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Lonestar
User
Beiträge: 147
Registriert: Samstag 9. August 2008, 08:31

Also 'ClientAufgabe' sollte ursprünglich ein 'normaler' string sein. Um das encoding habe ich mir bisher überhaupt keine Gedanken gemacht. Der String wird aus einem wxPython TextCtrl ausgelesen. Da ich ganz zu Anfang wie ich mit wxPython angefangen habe etwas hier im Forum gestöbert habe habe ich in meine GUI die Zeile
wx.SetDefaultPyEncoding("iso-8859-15")
für das encoding eingebaut ohne mir Gedanken darüber zu machen. Wenn mein Verständnis bis hierhin richtig ist, so bekomme ich aus meinem TextCtrl auch einen String mit unicode encoding zurück.
Soweit richtig?

Wenn dem so ist, dann muss ich also lediglich alle Strings die ich der Methode 'self.wfile.write()' übergebe passend encodieren. Die Methode kommt nicht von mir, wenn ich den Traceback aber richtig verstanden habe wird versucht meinen Unicode- String nach ascii zu encodieren. Was wegen der Umlaute allerdings misslingt. Wenn ich das encodieren selber nach ascii mit übernehme
self.wfile.write(ClientAufgabe.encode('ascii', 'replace'))
gibt es schon mal keine Fehlermeldung mehr. Allerdings bleiben auch meine Umlaute auf der Strecke.
Wohin muss ich also encodieren? Stehe gerade ein wenig auf dem Schlauch.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Lonestar hat geschrieben:Wenn ich das encodieren selber nach ascii mit übernehme
self.wfile.write(ClientAufgabe.encode('ascii', 'replace'))
gibt es schon mal keine Fehlermeldung mehr. Allerdings bleiben auch meine Umlaute auf der Strecke.
Du weißt aber schon, das ASCII keine Umlaute enthält? Also wenn du enkodierst, so dass ASCII raus kommt, wie erwartest du dann auch Umlaute? Du musst schon ein Encoding nehmen, das Umlaute enthält, also etwa UTF-8 oder ISO-8859-1/15.

Wobei ich allerdings inzwischen generell von ISO-8859-* so ziemlich überall abrate. Inzwischen sollte UTF-8 in den meisten Fällen die beste Möglichkeit sein.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Lonestar
User
Beiträge: 147
Registriert: Samstag 9. August 2008, 08:31

Moin, ja das ASCII keine Umlaute enthält war mir schon klar. Deswegen werden ja auch meine Umlaute beim encodieren durch Platzhlater erstetzt - das bewirkt doch das 'replace' bei encode(), oder nicht?. Irgendwie war das so ziemlich der erste Traceback bei dem ich mit der Fehlermeldung nicht so richtig was anfangen konnte - das liegt sicher hautpsächlich am mangelnden Verständnis meierseits.

Ich habe jetzt mal beide von dir vorgeschlagenen Codierungen ausprobiert.
nach utf-8 codiert wird ein 'äöü' zu 'ÀöÌ' - Progrämmsche läuft aber weiter
nach 'iso-8859-15' codiert bleibt ein 'äöü' auch ein 'äöü'

Mein Problem scheint somit gelöst - allerdings hab ich noch einige Fragen offfen.

Wie weiss ich denn welches Encoding ein Modul wie in diesem Fall socket.py von mir verlangt? Ich kann mir nicht vorstellen das ich das jedesmal ausprobieren muss. ACIII sollte eigentlich immer gehen, ist aber keine wirkliche Lösung.

Wieso gebe ich denn wx ein DefaultPyEncoding mit, und bekomme wenn ich einen String weiterreiche der mir von einem wx- Objekt geliefert wird anscheinend ein ein anderes Encoding? Oder wurde das Encoding anderweitig umgestellt? Schliesslich übergebe ich die Strings mit einer Queue, und füge anschliessend in einer Methode noch etwas and den String an. Ich kann mir nicht vorstellen das das Modul Queue an den übergebenen Objekten rumdoktort...

Und zuletzt noch - warum gibt es kein Encoding- Problem wenn ich das Projekt über Eclipse starte? Kann ich noch irgendwo Startparameter für das Encoding setzen die ich übersehen habe?

erst schon einmal vielen Dank für deine Hilfe Leonidas
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Lonestar hat geschrieben:Ich habe jetzt mal beide von dir vorgeschlagenen Codierungen ausprobiert.
nach utf-8 codiert wird ein 'äöü' zu 'ÀöÌ' - Progrämmsche läuft aber weiter
nach 'iso-8859-15' codiert bleibt ein 'äöü' auch ein 'äöü'
Falsch. Das ist die Darstellung. Du schickst UTF-8 über die Leitung und dekodierst es dann als ISO-8859-15. Du schickst also einen Apfel über die Leitung und nimmst an dass auf der anderen seite eine Birne rauskommt.

Schau, die Ausgabe lässt sich mit diesem einfachen Code reproduzieren (bin der Konsole):

Code: Alles auswählen

print u"äöü".encode('utf-8').decode('iso-8859-15')
Da wird erstmal äöü in UTF-8 kodiert (das schickst du dann über die Leitung) und auf der anderen Seite als Latin-9, dekodiert, wobei dann ÀöÌ rauskommt.

Warum es mit Latin-9 bei dir geht ist dann auch klar:

Code: Alles auswählen

print u"äöü".encode('iso-8859-15').decode('iso-8859-15')
Wenn man es mit dem gleichen Encoding de und enkodiert, kommt da auch das richtige raus.

Wesentlich besser aber, wenn du dein Programm *komplett* auf UTF-8 umstellst. Also deinem Editor sagst, dass die Datei UTF-8 ist und im Magic Cookie UTF-8 als Kodierung angibst und wenn du Bytestrings brauchst, sie auch als UTF-8 enkodierst.

Code: Alles auswählen

print u"äöü".encode('utf-8').decode('utf-8')
Lonestar hat geschrieben:Wie weiss ich denn welches Encoding ein Modul wie in diesem Fall socket.py von mir verlangt? Ich kann mir nicht vorstellen das ich das jedesmal ausprobieren muss. ACIII sollte eigentlich immer gehen, ist aber keine wirkliche Lösung.
``socket`` verlangt gar kein Encoding, ``socket`` schickt Bytes. Ob das nun die Bytes 0xc3 0xa4 0xc3 0xb6 0xc3 0xbc (äöü in UTF-8) oder 0xe4 0xf6 0xfc (äöü in ISO-8859-15) sind, ist ``socket`` dabei völlig egal, es weiß ja nicht einmal was diese Daten bedeuten.
Lonestar hat geschrieben:Wieso gebe ich denn wx ein DefaultPyEncoding mit, und bekomme wenn ich einen String weiterreiche der mir von einem wx- Objekt geliefert wird anscheinend ein ein anderes Encoding?
Ich würde ja erwarten, dass man von wx Unicode-Objekte zurückgibt und überall wo man Strings übergibt auch Unicode-Objekte nutzen kann. Somit hast du gar kein Problem mit Encodings. SetDefaultPyEncoding scheint mir jetzt gar nicht mal nötig zu sein, da ich schätze, dass es automatisch bereits das richtige Encoding hat.
Lonestar hat geschrieben:Oder wurde das Encoding anderweitig umgestellt? Schliesslich übergebe ich die Strings mit einer Queue, und füge anschliessend in einer Methode noch etwas and den String an. Ich kann mir nicht vorstellen das das Modul Queue an den übergebenen Objekten rumdoktort...
Du solltest überall Unicode-Objekte übergeben, da wird auch keiner daran rumfuhrwerken.
Lonestar hat geschrieben:Und zuletzt noch - warum gibt es kein Encoding- Problem wenn ich das Projekt über Eclipse starte? Kann ich noch irgendwo Startparameter für das Encoding setzen die ich übersehen habe?
Kann sein, dass Eclipse ein Default-Encoding setzt so dass bei der Ausgabe von Unicode versucht wird in etwas anderes als ASCII zu enkodieren. Da gibt es vermutlich irgendwo Einstellungen dazu. Ich selbst nutze keine IDE.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Lonestar
User
Beiträge: 147
Registriert: Samstag 9. August 2008, 08:31

Leonidas hat geschrieben: Schau, die Ausgabe lässt sich mit diesem einfachen Code reproduzieren (bin der Konsole):

Code: Alles auswählen

print u"äöü".encode('utf-8').decode('iso-8859-15')
Da wird erstmal äöü in UTF-8 kodiert (das schickst du dann über die Leitung) und auf der anderen Seite als Latin-9, dekodiert, wobei dann ÀöÌ rauskommt.

Warum es mit Latin-9 bei dir geht ist dann auch klar:

Code: Alles auswählen

print u"äöü".encode('iso-8859-15').decode('iso-8859-15')
Wenn man es mit dem gleichen Encoding de und enkodiert, kommt da auch das richtige raus.

Wesentlich besser aber, wenn du dein Programm *komplett* auf UTF-8 umstellst. Also deinem Editor sagst, dass die Datei UTF-8 ist und im Magic Cookie UTF-8 als Kodierung angibst und wenn du Bytestrings brauchst, sie auch als UTF-8 enkodierst.

Code: Alles auswählen

print u"äöü".encode('utf-8').decode('utf-8')
Ok die Erklärung ist echt mal einfach zu verstehen- supi. Da gingen mir gerade so einige Lichter auf. Aber irgendwie habe ich sobald ich das eine Verstanden habe schon die nächsten Verständnisprobleme. Warum Eclipse anders reagiert soll mir erst mal egal sein.

Am vernünftigsten ist es wohl wirklich alles auf UTF-8 umzustellen. So wie du es ja auch in deinen Folien geschrieben hast - Enkodiere früh, Unicode überall einsetzen, dekodiere so spät wie möglich. Mit dem Thema hätte ich mich mal direkt beim Einstieg in Python beschäftigen sollen - egal. Da stellt sich mir aber nu immer noch mindestens eine Frage. Warum bekomme ich in meiner ursprünglichen Version meine Exeption UnicodeEncodeError? Wer versucht denn da aus meinem Latin-9 ASCII zu machen? Du sagst ja das es 'socket.py' egal ist was ich ihm gebe. Da hab ich doch mal wieder irgendwas völlig falsch verstanden.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Lonestar hat geschrieben:Da stellt sich mir aber nu immer noch mindestens eine Frage. Warum bekomme ich in meiner ursprünglichen Version meine Exeption UnicodeEncodeError? Wer versucht denn da aus meinem Latin-9 ASCII zu machen? Du sagst ja das es 'socket.py' egal ist was ich ihm gebe. Da hab ich doch mal wieder irgendwas völlig falsch verstanden.
Ein UnicodeEncodeError wird geworfen, wenn du versuchst einen Unicode-String in ein Encoding zu konvertieren, dass keine Repräsentation der Codepoints/Buchstaben besitzt. Also etwa Umlaute in ASCII, Kyrillische Zeichen in ISO-8859-15, Euro in ISO-8859-1, Japanische Zeichen in KOI8-R. Nun kann man Unicode aber nicht einfach so ausgeben (abstrakt, wie in den Folien geschrieben), also versucht Python zu raten. Bei der Konsolenausgabe haut es oft noch hin, aber bei sockets weiß Python nicht was es für ein Encoding nehmen soll, also wird implizit in ASCII enkodiert. Und das kracht.

Du solltest also sichergehen, dass du beim Ausgeben von Strings den Unicode in Bytestrings umwandelst. In Python 3 wird das an einigen Ecken und Enden einfacher.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Lonestar
User
Beiträge: 147
Registriert: Samstag 9. August 2008, 08:31

jut, nachdem ja nun bei mir alle Klarheiten beseitigt sind werde ich mich heute Abend mal daran begeben mein kleines Projekt komplett auf UTF-8 umzustellen. Da sind mittlerweile doch schon so einige Dateien zusammengekommen.
Als wäre das nicht schon genug Bastelei speichert mein Projekt auch noch einiges an Daten in normalen Textdateien ab. Gespeichert wird ganz einfach mit

datei = open(dateiname,'w')
datei.write(string)

Somit wird ja, da kein Encoding für die Datei angegeben wurde, laut [wiki=Von_Umlauten,_Unicode_und_Encodings]Wiki[/wiki] das Encoding Betriebssystemspezifisch gesetzt. Wäre das evtl die Gelenheit auch alles in UTF-8 codierte Dateien abzulegen? Oder wäre das überflüssig/übertrieben?
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Lonestar hat geschrieben: Als wäre das nicht schon genug Bastelei speichert mein Projekt auch noch einiges an Daten in normalen Textdateien ab. Gespeichert wird ganz einfach mit

datei = open(dateiname,'w')
datei.write(string)

Somit wird ja, da kein Encoding für die Datei angegeben wurde, laut [wiki=Von_Umlauten,_Unicode_und_Encodings]Wiki[/wiki] das Encoding Betriebssystemspezifisch gesetzt. Wäre das evtl die Gelenheit auch alles in UTF-8 codierte Dateien abzulegen? Oder wäre das überflüssig/übertrieben?
Naja, wenn Du selber die Dateien später einliest um damit weiterzuarbeiten, ist es doch nur von Vorteil die auch in utf-8 zu codieren. Somit kannst Du davon ausgehen, dass Dein Output immer und überall im Projekt eben utf-8 ist.

Werden die Dateien dann von anderen User (z.B. externen Programmen) genutzt, so kannst Du auch in der Doku vermerken, dass es sich um utf-8 handelt und gut ist. Dann kann sich der später Nutzende wenigstens sicher sein und damit umgehen.

Die Frage ist doch: Wieso auf explizite Codierung verzichten? Damit weißt Du nicht zu 100%, was denn da nun abgelegt wird und ein späterer Nutzer noch weniger.
Lonestar
User
Beiträge: 147
Registriert: Samstag 9. August 2008, 08:31

Hyperion hat geschrieben: Die Frage ist doch: Wieso auf explizite Codierung verzichten? Damit weißt Du nicht zu 100%, was denn da nun abgelegt wird und ein späterer Nutzer noch weniger.
Genau das war auch meine Überlegung. Ich war mir nur nicht sicher ob ich da richtig liege - ich beschäftige mich mit dem Thema Codierung halt erst seit gestern Abend... da kann man nicht wirklich auf viel Erfahrung zurückblicken :wink:
Eine andere Überlegung war eine Plattformunabhängigkeit die dadurch selbst für meine Dateien die Gespeichert wurden gilt. Wenn ich es richtig verstanden habe dann bestimmt das Betriebssystem auf dem ich gerade Python laufen lasse mit welchem Codec gespeichert und gelesen wird wenn ich es nicht explizit mit 'codecs.open()' bestimme. Ist das richtig, oder befinde ich mich da auf dem Holzweg und das wäre eigentlich leichter/anders zu erreichen?
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Lonestar hat geschrieben:Gespeichert wird ganz einfach mit

datei = open(dateiname,'w')
datei.write(string)

Somit wird ja, da kein Encoding für die Datei angegeben wurde, laut [wiki=Von_Umlauten,_Unicode_und_Encodings]Wiki[/wiki] das Encoding Betriebssystemspezifisch gesetzt. Wäre das evtl die Gelenheit auch alles in UTF-8 codierte Dateien abzulegen? Oder wäre das überflüssig/übertrieben?
Sinnvoll. ``codecs.open()`` wird ja in den Folien erwähnt; das ``open()`` in Python 3.0 nimmt nun auch einen Encoding-Parameter.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Antworten