non-ASCII in django management command ausgeben...

Django, Flask, Bottle, WSGI, CGI…
Antworten
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

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.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
apollo13
User
Beiträge: 827
Registriert: Samstag 5. Februar 2005, 17:53

Wie wäre es utf-8 einfach zu verlangen? (Man muss imo nicht für jedes Problem ne technische Lösung suchen)
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

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)

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

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.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Das Problem habe ich auf dem Server, auf dem dieses Forum läuft ;)

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
Damaskus
Administrator
Beiträge: 995
Registriert: Sonntag 6. März 2005, 20:08
Wohnort: Schwabenländle

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...
Benutzeravatar
Damaskus
Administrator
Beiträge: 995
Registriert: Sonntag 6. März 2005, 20:08
Wohnort: Schwabenländle

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--
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

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"

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