Probleme mit cxfreeze und Python 3.1

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.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Ja, dass es ein Unicode-String ist.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
heiliga horsd

Ich dachte Python 3 verwendet von sich aus Unicode?
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Oh, upps. Hab den Teil mit Python 3 übersehen. Dann kannst du es tatsächlich weglassen.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
heiliga horsd

Ich habe die Vermutung, dass ich irgendwie zu blöd für so etwas bin :/
Also, ich habe die Variable encoding mit "850" belegt (das ist ja die entsprechende Kodierung für die cmd.exe, oder?) und folgenden Codeschnipsel für die Formatierte Ausgabe:

Code: Alles auswählen

print(str(Ausgabeformat.format(questiontext[x],
                                           questionvars[x])).encode(encoding))
Leider ist dann die Ausgabe nicht mehr formatiert (d.h. manche Werte fallen aus der Reihe) und Umlaute sehen nun noch grässlicher aus (H\x94he )

Ausschnitt aus der (eigentlich formatierten) Ausgabe:

Code: Alles auswählen

b'Rechtwinkligkeit \x81berpr\x81fen              3'
b'H\x94he berechnen                           4
Benutzeravatar
Masaru
User
Beiträge: 425
Registriert: Mittwoch 4. August 2004, 22:17

heiliga horsd hat geschrieben:... Also, ich habe die Variable encoding mit "850" belegt (das ist ja die entsprechende Kodierung für die cmd.exe, oder?)...

Nö ... das Encoding der (Windows) Eingabeaufforderung (via: cmd.exe) ist abhängig von Deiner Windows-Version.

>>Masaru<<
fhoech
User
Beiträge: 143
Registriert: Montag 9. April 2007, 18:26

Nö ... das Encoding der (Windows) Eingabeaufforderung (via: cmd.exe) ist abhängig von Deiner Windows-Version.
Mit Version meinst du wahrscheinlich Sprachversion :) Ausserdem kann man in der Windows-Eingabeaufforderung mit chcp das Encoding ändern.

In Python kommt man mit sys.stdout.encoding an das richtige für stdout, aber nur falls nicht mit locale.setlocale ein anderes Encoding festgelegt wurde (der Wert von sys.stdout.encoding ändert sich dadurch nämlich nicht, das eigentliche Encoding aber sehr wohl. Falls in der Anwendung nirgends setlocale benutzt wird, kann man natürlich direkt sys.stdout.encoding nehmen).

Das funktioniert dann für Python 2.6:

Code: Alles auswählen

>>> import locale, sys
>>> print u'\u00e4\u00f6\u00fc\ufffe'.encode(locale.getlocale()[1] or sys.stdout.encoding, 'replace')
äöü?
Aber Python 3.1 verhält sich anders:

Code: Alles auswählen

>>> import locale, sys
>>> print('\u00e4\u00f6\u00fc\ufffe'.encode(encoding, 'replace'))
b'\x84\x94\x81?'
Da fällt mir jetzt kein guter Workaround ein. Folgendes funktioniert, ist aber irgendwie umständlich:

Code: Alles auswählen

>>> import locale, sys
>>> print('\u00e4\u00f6\u00fc\ufffe'.encode(locale.getlocale()[1] or sys.stdout.encoding, 
                                            'replace').decode(sys.stdout.encoding, 'replace'))
äöü?
BlackJack

@fhoech: `sys.stdout.encoding` geht aber auch nur, wenn Python die Kodierung irgendwie herausfinden konnte. Leitet man die Ausgabe in eine Datei um, dann ist das zum Beispiel `None`.
heiliga horsd

Hmm, die Lösung ist ziemlich unpraktisch vom Aufwand her, außerdem werden manche Ausgaben tatsächlich in eine Datei geschrieben.... ich werds lieber hier gut sein lassen und euch für eure Hilfe danken! Ich bin inzwischen der Meinung, dass ich meine Programme nicht an die alte Software des Microsoftmonopols anpassen muss, dafür werden Leute bezahlt.
fhoech
User
Beiträge: 143
Registriert: Montag 9. April 2007, 18:26

BlackJack hat geschrieben:@fhoech: `sys.stdout.encoding` geht aber auch nur, wenn Python die Kodierung irgendwie herausfinden konnte. Leitet man die Ausgabe in eine Datei um, dann ist das zum Beispiel `None`.
Stimmt, da müsste in meinen Beispielen noch ein `or sys.getdefaultencoding()`o.ä. hintendran.
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

könnte man nicht str überschreiben und dann in die __init__ einfach ein self.decode(xyz) ?
the more they change the more they stay the same
BlackJack

@Dav1d: "einfach" `str` "überschreiben"? Wie das? Was soll das bringen? Und dann müsste man überall das neue `str` verwenden, man kommt aber wohl kaum an allen Code heran, der das Original verwendet.
Benutzeravatar
Trundle
User
Beiträge: 591
Registriert: Dienstag 3. Juli 2007, 16:45

@BlackJack: Mit become.py natürlich.

Tut mir leid für den unqualifizierten Beitrag, ich konnte nicht widerstehen.
"Der Dumme erwartet viel. Der Denkende sagt wenig." ("Herr Keuner" -- Bertolt Brecht)
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

Mir tuts auch Leid, ich hab nicht mitgedacht
the more they change the more they stay the same
fhoech
User
Beiträge: 143
Registriert: Montag 9. April 2007, 18:26

Hmm. Eher würde ich eine eigene print-Funktion verwenden:

Code: Alles auswählen

import locale
import sys

def myprint(*args, **kwargs):
	stream = kwargs.get('file', sys.stdout)
	sep = kwargs.get('sep', ' ')
	end = kwargs.get('end', '\n')
	enc_in = enc_out = getattr(stream, 'encoding', locale.getpreferredencoding())
	if stream == sys.stdout:
		enc_out = locale.getlocale()[1] or enc_out
	if 'b' in stream.mode:
		sep, end = (char.encode(enc_out, 'replace') for char in (sep, end))
		stream.write(sep.join(arg if isinstance(arg, bytes) else (arg if isinstance(arg, str) else repr(arg)).encode(enc_out, 'replace') for arg in args))
	else:
		stream.write(sep.join((arg if isinstance(arg, str) else repr(arg)).encode(enc_out, 'replace').decode(enc_in, 'replace') for arg in args))
	stream.write(end)
(das geht bestimmt hübscher?)
Dieses 'print' beachtet ein eventuell per locale.setlocale geändertes Encoding von sys.stdout, wirft keine UnicodeError-Ausnahmen sondern ersetzt nicht darstellbare Zeichen mit einem Platzhalter ('\ufffe' oder '?'), kann übergebene Byte-Strings direkt in einen Stream schreiben, falls dieser im Binärmodus geöffnet wurde, und sollte sich ansonsten wie das Standard-'print' verhalten.

*edit* hatte noch einen Fehler drin, jetzt behoben.
Benutzeravatar
snafu
User
Beiträge: 6744
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

codecs.EncodedFile() mit `replace` als Wert für `error` dürfte die Anforderungen doch eigentlich erfüllen, oder? Man müsste sich nur noch eine kleine Wrapperfunktion schreiben, die immer in das gewünschte Encoding übersetzt. Dies kann man z.B. auch als Datenstrom an `print()` übergeben, so dass man die Funktion nicht komplett neu implementieren muss...
fhoech
User
Beiträge: 143
Registriert: Montag 9. April 2007, 18:26

snafu hat geschrieben:codecs.EncodedFile() mit `replace` als Wert für `error` dürfte die Anforderungen doch eigentlich erfüllen, oder? Man müsste sich nur noch eine kleine Wrapperfunktion schreiben, die immer in das gewünschte Encoding übersetzt. Dies kann man z.B. auch als Datenstrom an `print()` übergeben, so dass man die Funktion nicht komplett neu implementieren muss...
Ja, daran dachte ich auch, aber es funktionierte nicht so, wie ich erwartet hatte. Kann aber gut sein, dass ich auf dem Schlauch stehe. Hier z.B.

Code: Alles auswählen

>>> import sys, codecs
>>> stdout = codecs.EncodedFile(sys.stdout, 'cp850', errors='replace')
>>> print('test', file=stdout)
TypeError: must be bytes or buffer, not str
>>> print(b'test', file=stdout)
TypeError: must be bytes or buffer, not str
Benutzeravatar
snafu
User
Beiträge: 6744
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Nee, ich hätte jetzt das selbe geschrieben wenn ich nicht vorher F5 gedrückt hätte. ;)

Code: Alles auswählen

>>> import sys, locale, codecs
>>> f = codecs.EncodedFile(sys.stdout, locale.getpreferredencoding())
>>> f.write('bla')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.1/codecs.py", line 806, in write
    data, bytesdecoded = self.decode(data, self.errors)
  File "/usr/lib/python3.1/encodings/utf_8.py", line 16, in decode
    return codecs.utf_8_decode(input, errors, True)
TypeError: must be bytes or buffer, not str
>>> f.write(b'bla')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.1/codecs.py", line 807, in write
    return self.writer.write(data)
  File "/usr/lib/python3.1/codecs.py", line 356, in write
    self.stream.write(data)
TypeError: must be str, not bytes
Es gibt 3 Möglichkeiten:
1. Ich bin zu dumm, die Funktion zu verstehen
2. Die Python-Entwickler wollen einen verarschen
3. Die Funktion ist leider kaputt
heiliga horsd

Wie gesagt, die Nutzer meines Programms ohne eine Python-Installation werden mit diesem Schönheitsfehler leben müssen. Ihr müsst euch also hier nicht weiter den Kopf über solche Lapalien zerbrechen! :wink:
Mein cxfreeze funktioniert wieder und ich bin ansonsten recht glücklich :)
Benutzeravatar
snafu
User
Beiträge: 6744
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Nun ja, diese ganze Encoding-Sch*** finde ich weitaus mehr als eine Lapalie, aber sei's drum.
Antworten