Unicode-Probleme: getfilesystemencoding = ascii statt utf-8

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
Benutzeravatar
redeagle
User
Beiträge: 10
Registriert: Freitag 2. November 2012, 12:25
Wohnort: Erde
Kontaktdaten:

Hi
Ich habe ein kleines Tool geschrieben das ein web-interface haben soll. Dazu lasse ich das Python-Script per Apache laufen.
Das Tool soll zunächst eine Liste mit Verzeichnissen per HTML darstellen. Das läuft soweit auch alles sehr gut. Aber sobald ein Verzeichnis ein unicode-Zeichen (z.B. "ß") im Namen hat bricht alles zusammen :)

Zum auflisten der Verzeichnisse nutze ich os.listdir.
Ausgabe im python-interpreter: "['testa', 'testb', 'scheiße']"
Ausgabe, wenn ich den code im CGI-script nutze: "['testa', 'testb', 'schei\udcc3\udc9fe']"

Offensichtlich verhält sich python in der CGI-Umgebung anders, als wenn ich den Code von der Shell aus ausführe.
Nach etwas Suchen habe ich diverse Funktionen gefunden die mir Codierungs-Settings ausgeben und ändern lassen:

Code: Alles auswählen

    os.environ["LC_ALL"] = "de_DE.UTF-8"

    print(sys.getdefaultencoding())
    print(sys.getfilesystemencoding())
    print(locale.getpreferredencoding())
    print(locale.getdefaultlocale())
Das os.environ-getue ist nötig damit getdefaultlocale nicht (None, None) zurück gibt, und getprefferedencoding nicht ANSI ist

Output im Interpreter: utf-8; utf-8; UTF-8; ('de_DE', 'UTF-8')
In der CGI-Umgebung: utf-8; ascii; UTF-8; ('de_DE', 'UTF-8')

Kurz: In der CGI-Umgebung nutzt Python 3 für das FS-Encodung ASCII statt unicode.


Wie bekomme ich das Problem gelöst? Ist da überhaupt Python das Problem, oder der Server (Apache)? Oder liegt das Problem gar an einer ganz anderen Stelle?

Versionen:
Python: 3.3.2
Apache: 2.4.3
System: Basierend auf Slackware 14
mfg.: redeagle
BlackJack

Python 3 ist halt doof. :-) Es gibt so etwas wie eine systemweite Dateinamenkodierung unter Linux nicht. Das Konzept welches Python da versucht umzusetzen ist kaputt. Dateinamen sind Byteketten und die dadurch dargestellten Zeichenketten können nicht nur auf verschiedenen Dateisystemen unterschiedlich kodiert sein, sondern auch auf ein und dem selben Dateisystem können ganz unterschiedlich kodierte Dateinamen existieren.

Unter Python 2 würde ich an der Stelle einen Dateinamentyp einführen bei dem die rohen Bytedaten des Namens und eine Darstellung als Unicode getrennt sind.
Benutzeravatar
redeagle
User
Beiträge: 10
Registriert: Freitag 2. November 2012, 12:25
Wohnort: Erde
Kontaktdaten:

Naja, aber os.listdir gibt mir ja bereits "kaputte" Daten. Ich müsste dann den Rückgabe-wert parsen und "\udcc3\udc9f" in die Bytes 0xC0, 0x9F Zerlegen.
Das ist mir zu weit weg von einer schönen Lösung :) - Da macht es fast schon Sinn den Teil des Python-Codes der mit dem Dateisystem in Kontakt kommt in C zu implementieren. (Verzeichnisse erstellen und auflisten)

Zur Dateinamen-Kodierung: Ich verwende IMMER utf-8, was nicht utf-8 ist (sondern z.B. ASCII, bekommt man von win-usern ja recht gerne) wird direkt umbenannt oder gelöscht. Ich lege sehr viel wert darauf dass alles utf-8 fähig ist und nutzt da ich recht viel mit unicodes arbeite.
Ich kann im Einsatzbereich des Skripts 100% sicher sein dass alle Dateinamen utf-8 codiert sind. Es wäre für mich also OK Python mit Gewalt dazu zu bringen in diesem Fall utf-8 zu nutzen.
mfg.: redeagle
BlackJack

@redeagle: Die Dokumentation im `os`-Modul sagt das `getfilesystemencoding()` verwendet wird, und die Dokumentation dort sagt es ist das Ergebnis von der C-Funktion ``nl_langinfo(CODESET)``. Deren ``man``-Page sagt es ist die Locale-Kategorie LC_CTYPE. Und *die* müsste man ja mit `locale.setlocale()` in Python setzen können. :-)
Benutzeravatar
redeagle
User
Beiträge: 10
Registriert: Freitag 2. November 2012, 12:25
Wohnort: Erde
Kontaktdaten:

Code: Alles auswählen

locale.setlocale(locale.LC_CTYPE, ("de_DE", "UTF-8"))
imp.reload(sys)
…ändert leider nichts an getfilesystemencoding.

Allerdings gibt locale.nl_langinfo(locale.CODESET) nun "UTF-8" statt "ANSI" aus.
Ist zumindest schonmal ein bisschen mehr unicode :D
mfg.: redeagle
Benutzeravatar
Balmung
User
Beiträge: 44
Registriert: Sonntag 17. März 2013, 18:36

Du kannst an os.listdir einen Bytestring übergeben und wirst dann als Rückgabewert die Dateinamen ebenfalls als Bytestrings erhalten.
In den Fällen, in denen Dateien nicht einheitlich kodiert sind, was ja vorkommen kann, ist das womöglich die komfortabelste Möglichkeit unter Python3 mit den Dateinamen klarzukommen.
»Honk Honk«
Benutzeravatar
redeagle
User
Beiträge: 10
Registriert: Freitag 2. November 2012, 12:25
Wohnort: Erde
Kontaktdaten:

Super, danke. So funktioniert es :)

Code: Alles auswählen

    for entry in os.listdir(PROJECTROOT.encode("utf-8")):
        entry = entry.decode("utf-8")
mfg.: redeagle
Antworten