Seite 1 von 1

non-ASCII in django management command ausgeben...

Verfasst: Mittwoch 12. September 2012, 15:39
von jens
Ich hab noch ein wenig Probleme, Sonderzeichen im phpbb2djangobb migration management command auszugeben.

Eine schöne Erklärung ist hier: https://code.djangoproject.com/ticket/5877#comment:5

Demnach ist es ja so: python nutzt für stdout das encoding von "LANG" oder "PYTHONENCODING"

Wenn alles modern und ok ist, ist es UTF-8 und im django management command kann man alles mit self.stdout.write() ausgeben. Am besten übergibt man dabei immer unicode und gut...

Doch man bekommt Probleme, wenn es kein UTF-8 ist.

Ich hab mal ein kleines Test Skript gemacht:

Code: Alles auswählen

#!/usr/bin/env python
# coding: utf-8

import os, sys

print "Encoding test"

print "LANG:", os.environ.get("LANG", "-")
print "PYTHONENCODING:", os.environ.get("PYTHONENCODING", "-")
print "sys.stdout.encoding:", sys.stdout.encoding
print "sys.getfilesystemencoding():", sys.getfilesystemencoding()

print u"test caf\u00E9!"

print "--END--"
Lokal, mit UTF-8 liefert es:

Code: Alles auswählen

Encoding test
LANG: de_DE.UTF-8
PYTHONENCODING: -
sys.stdout.encoding: UTF-8
sys.getfilesystemencoding(): UTF-8
test café!
--END--
Doch auf einem anderen Server das:

Code: Alles auswählen

Encoding test
LANG: de_DE
PYTHONENCODING: -
sys.stdout.encoding: ISO-8859-1
sys.getfilesystemencoding(): ISO-8859-1
test caf�!
--END--
Was massiert nun, wenn man ein Zeichen Ausgibt, welches nicht in ISO-8859-1 passt? Man bekommt ein UnicodeEncodeError...

Was sollte man also machen, damit man beim Aufruf eines django management command kein Fehler bekommt?
Wie wäre es smart_str() mit encoding=sys.stdout.encoding or sys.getfilesystemencoding() und errors="replace" zu nutzten? Wenn etwas nicht gezeigt werden kann, wird es ersetzt, aber das management command kann durchlaufen.

Re: non-ASCII in django management command ausgeben...

Verfasst: Donnerstag 13. September 2012, 07:36
von apollo13
Wie wäre es utf-8 einfach zu verlangen? (Man muss imo nicht für jedes Problem ne technische Lösung suchen)

Re: non-ASCII in django management command ausgeben...

Verfasst: Donnerstag 13. September 2012, 08:38
von jens
Könnte man natürlich auch. Ich denke allerdings, das viele Benutzer den Grund für einen einen UnicodeEncodeError Fehler nicht kennen werden. Bevor ich mich damit befasst hab, hätte ich es auch nicht gewusst.
Spätestens unter Windows wird man dabei Probleme bekommen. (Wobei, wer benutzt schon Django unter Windows :P )

Gut man könnte auch sowas in der Art machen:

Code: Alles auswählen

OUT_ENCODING = sys.stdout.encoding or sys.getfilesystemencoding()
assert OUT_ENCODING.lower() == "utf-8", "%s encoding not supported, please switch terminal to UTF-8" % OUT_ENCODING
Wäre zumindest hilfreicher als ein allgemeiner UnicodeEncodeError Traceback.

Wenn man allerdings eh nie non-ASCII Ausgibt, hat man das Problem natürlich überhaupt nicht.

Meine Aktuelle Lösung sind ungefähr so aus:

Code: Alles auswählen

OUT_ENCODING = sys.stdout.encoding or sys.getfilesystemencoding()

class Command(BaseCommand):
    def handle(self, *args, **options):
        self._out(u"Hello World!\n")

    def _out(self, msg):
        msg = smart_str(msg, encoding=OUT_ENCODING, errors="replace")
        self.stdout.write(msg)

    def _err(self, msg):
        msg = smart_str(msg, encoding=OUT_ENCODING, errors="replace")
        self.stderr.write(msg)

Re: non-ASCII in django management command ausgeben...

Verfasst: Sonntag 16. September 2012, 23:24
von Leonidas
jens hat geschrieben:Könnte man natürlich auch. Ich denke allerdings, das viele Benutzer den Grund für einen einen UnicodeEncodeError Fehler nicht kennen werden. Bevor ich mich damit befasst hab, hätte ich es auch nicht gewusst.
Du meinst User auf Sun OS 4 oder anderen vorsintflutlichen Systemen? Wenn ein halbwegs modernes System bei UTF-8-Ausgaben patzt, dann ist das recht klar ein Bug der Distribution. Schließe mich da apollo13 an. Um BlackJack vorrauszugreifen: Du kannst auch einen Encoding-Switch dazumachen, der die Standardeinstellung 'UTF-8' ändert ;)

Und das Filesystem-Encoding zu nutzen ist irgendwie verkehrt. Unter Linux ist das grad mal so "keines" und die IOStreams haben auch kein Encoding wenn man sie in einer Pipe verwendet.

Re: non-ASCII in django management command ausgeben...

Verfasst: Montag 17. September 2012, 09:51
von jens
Das Problem habe ich auf dem Server, auf dem dieses Forum läuft ;)

Re: non-ASCII in django management command ausgeben...

Verfasst: Montag 17. September 2012, 12:04
von Damaskus
jens hat geschrieben:Das Problem habe ich auf dem Server, auf dem dieses Forum läuft ;)
Jup der läuft auf ISO-8859-1, fällt mir gerade wieder ein :)
Da war mal irgendwas mit einem PERL Modul...

Re: non-ASCII in django management command ausgeben...

Verfasst: Montag 17. September 2012, 12:30
von Damaskus
Wobei ich folgendes Ergebnis erhalte:

Lokal auf einer VM (Debian Squeeze)

Code: Alles auswählen

Encoding test
LANG: de_DE.UTF-8
PYTHONENCODING: -
sys.stdout.encoding: UTF-8
sys.getfilesystemencoding(): UTF-8
test café!
--END--
Und auf dem Forumsserver: (Debian Squeeze)

Code: Alles auswählen

Encoding test
LANG: de_DE
PYTHONENCODING: -
sys.stdout.encoding: ISO-8859-1
sys.getfilesystemencoding(): ISO-8859-1
test café!
--END--

Re: non-ASCII in django management command ausgeben...

Verfasst: Montag 15. Oktober 2012, 11:02
von jens
Leonidas hat geschrieben:Und das Filesystem-Encoding zu nutzen ist irgendwie verkehrt. Unter Linux ist das grad mal so "keines" und die IOStreams haben auch kein Encoding wenn man sie in einer Pipe verwendet.
Hab gerade eine Lösung in ReSt gesehen. Demnach wäre das eine Idee:

Code: Alles auswählen

try:
    import locale # module missing in Jython
except ImportError, msg:
    locale_encoding = None
else:
    locale_encoding = locale.getlocale()[1] or locale.getdefaultlocale()[1]
    # locale.getpreferredencoding([do_setlocale=True|False])
    # has side-effects | might return a wrong guess.
    # (cf. Update 1 in http://stackoverflow.com/questions/4082645/using-python-2-xs-locale-module-to-format-numbers-and-currency)
    try:
        codecs.lookup(locale_encoding or '') # None -> ''
    except LookupError:
        locale_encoding = None

if not locale_encoding:
    locale_encoding = sys.stdout.encoding or sys.getfilesystemencoding()
Den fallback am Ende habe ich eingefügt. Eine Ahnung ob das Sinn macht. Besser wäre vielleicht:

Code: Alles auswählen

if not locale_encoding:
    locale_encoding = "ascii"