pysql utf-8

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
Benutzeravatar
DatenMetzgerX
User
Beiträge: 398
Registriert: Freitag 28. April 2006, 06:28
Wohnort: Zürich Seebach (CH)

Ich und coding ^^

Code: Alles auswählen

    def sql(self, strSql, dicMulti =None):
        if dicMulti:
            self.cur.executemany(strSql, dicMulti)
        else:
            self.cur.execute(strSql)
        
        result = self.cur.fetchall()
Wenn jetzt das resultat ein Text mit öäü ist, stürzt das Programm bei fetchall ab.

Code: Alles auswählen

OperationalError: Could not decode to UTF-8 column 'tooltip' with text 'Ausgewählte Textgruppe editieren'
Sicher wieder was einfaches ;)
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

DatenMetzgerX hat geschrieben:

Code: Alles auswählen

OperationalError: Could not decode to UTF-8 column 'tooltip' with text 'Ausgewählte Textgruppe editieren'
Sicher wieder was einfaches ;)
Hi DatenMetzgerX!

Nein, so einfach ist das gar nicht. Ich halte das für einen der größten Schwachpunkte von Python. Statt wie Visual Basic, nur mit Unicode zu arbeiten, gibt es bei Python immer ein Hin und Her zwischen den verschiedensten Encodings. So auch im Zusammenspiel mit Datenbanken.

Ich gehe jetzt einfach mal davon aus, dass du pySQLite meinst, da es "pysql" nicht gibt.

Die für mich derzeit einfachste Möglichkeit, dem ganzen Encoding-Schlamassel aus dem Weg zu gehen, ist zwar etwas umständlich, aber sie funktioniert. --> Alles Unicode.

Was ich damit meine? Fülle die Datenbank nur mit Unicode-Strings und erwarte im Gegenzug Unicode-Strings. Leider kümmert sich Python nicht von selbst darum, dass beim Ausgeben der Daten an die Konsole auch das richtige Encoding verwendet wird. Deshalb habe ich im folgenden Beispiel auch noch einen kleinen Hack dafür eingebaut.

Die Angabe des Codings im Kopf des Moduls ist essentiell. Dass das angegebene Coding auch mit dem der Datei zusammenstimmt -- davon gehe ich aus. Siehe: http://www.python-forum.de/topic-5095.html

Und hier das Beispiel mit Unicode (man beachte die vielen u vor den Strings):

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-

import sys
import codecs
import os
try:
    import sqlite3 # Ab Python 2.5
except ImportError:
    from pysqlite2 import dbapi2 as sqlite3


# STDOUT-Encoding herausfinden und StdOut umleiten (für print-Anweisungen)
# Streamwriter mit korrektem Encoding (!!!funktioniert so nicht im IDLE!!!)
out_enc = sys.stdout.encoding or sys.getfilesystemencoding()
sys.stdout = codecs.getwriter(out_enc)(sys.__stdout__)


#
# Schreiben
#

# Nur zum Testen: Alte Datei vorher loeschen
try:
    os.remove("dateiname.s3db")
except:
    pass

# Verbindung herstellen
conn = sqlite3.connect(
    "dateiname.s3db",
    isolation_level = None, # Autocommit
)
cur = conn.cursor()

# Tabelle erstellen
sql = u"""
CREATE TABLE adressen (
    first_name varchar,
    last_name varchar,
    age int
)
"""
cur.execute(sql)

# Werte in die Tabelle schreiben
personen = [
    {"first_name": u"Geroldä", "last_name": u"Penzö", "age": "31"},
    {"first_name": u"Ludwigü", "last_name": u"Bucherä", "age": "29"},
]
sql = u"""
INSERT INTO adressen (
    first_name,
    last_name,
    age
)
VALUES (
    :first_name,
    :last_name,
    :age
)
"""
cur.executemany(sql, personen)

# Verbindung schliessen (nur zum Testen)
cur.close()
conn.close()

#
# Lesen
#

# Verbindung herstellen
conn = sqlite3.connect("dateiname.s3db")
cur = conn.cursor()

sql = u"""
SELECT
    first_name, last_name, age
FROM
    adressen
"""
cur.execute(sql)
rows = cur.fetchall()

for row in rows:
    vorname, nachname, alter = row
    print "Datensatz:", row
    print "Vorname:  ", vorname, "==>", type(vorname)
    print "Nachname: ", nachname, "==>", type(nachname)
    print "Alter:    ", alter, "==>", type(alter)
    print

# Verbindung schliessen
cur.close()
conn.close()
Hier noch zwei interessante Links zu diesem Thema:
http://initd.org/tracker/pysqlite/wiki/ ... orTEXTdata
http://initd.org/tracker/pysqlite/ticket/139

lg
Gerold
:-)

Stichwoerte: sqlite pysqlite umlaute unicode
Zuletzt geändert von gerold am Dienstag 25. Juli 2006, 20:16, insgesamt 2-mal geändert.
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
BlackJack

gerold hat geschrieben:Nein, so einfach ist das gar nicht. Ich halte das für einen der größten Schwachpunkte von Python. Statt wie Visual Basic, nur mit Unicode zu arbeiten, gibt es bei Python immer ein Hin und Her zwischen den verschiedensten Encodings. So auch im Zusammenspiel mit Datenbanken.
Wieso ist das ein Schwachpunkt von Python? Sowie Daten von aussen kommen oder nach aussen gehen müssen sie irgendwie kodiert werden. Das ist in jeder Sprache so, auch wenn der Zeichenkettentyp intern per Vorgabe Unicode ist.

Python weigert sich halt zu "raten" welche Kodierung es ist, sobald das nicht sicher ist und ASCII nicht funktioniert.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

BlackJack hat geschrieben:Wieso ist das ein Schwachpunkt von Python? Sowie Daten von aussen kommen oder nach aussen gehen müssen sie irgendwie kodiert werden. Das ist in jeder Sprache so, auch wenn der Zeichenkettentyp intern per Vorgabe Unicode ist.

Python weigert sich halt zu "raten" welche Kodierung es ist, sobald das nicht sicher ist und ASCII nicht funktioniert.
Hi BlackJack!

Ich zähle mal auf:

- Um in einem Modul einen Unicode-String zu erzeugen muss vor den String ein "u" gesetzt werden. Oder man muss den String mit decode() umwandeln. Statt einfach alle Strings automatisch als Unicode-Strings zu betrachten.

- Der Befehl "print" produziert einen Fehler wenn Umlaute ausgegeben werden müssen. Stattdessen könnte doch (automatisch) nachgesehen werden, welches Encoding für STDOUT vorgegeben ist und dieses automatisch verwendet werden. Warum wird das Betriebssystem nicht nach dem Encoding gefragt und dieses automatisch verwendet? Nein, man muss sich selber darum kümmern.

- Wie mit Umlauten umgegangen wird -- das ist ein Thema, das in den wenigsten Python-Büchern drinnen steht. So tauchen ständig die gleichen Fragen und Probleme zum Thema Umlaute und Encodings auf.

Alles was ich mir wünsche ist, dass das was automatisch erledigt werden könnte -- auch automatisch von Python erledigt wird.

- Unicode (oder ein anderes geeignetes Encoding) als automatisch vorgegebene Basis für Python-Code.

- Beim Lesen von STDIN und sys.argv oder beim Schreiben nach STDOUT oder STDERR sollte automatisch von Unicode und nach Unicode umgewandelt werden. Wenn Python das Encoding nicht raus finden kann, dann kann ja der Programmierer eingreifen.

Das wars. Deshalb zähle ich dieses Thema zu einem oder sogar zu dem größten Schwachpunkt von Python. Zumindest außerhalb der englischsprachigen Länder.

lg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
BlackJack

gerold hat geschrieben: Ich zähle mal auf:

- Um in einem Modul einen Unicode-String zu erzeugen muss vor den String ein "u" gesetzt werden. Oder man muss den String mit decode() umwandeln. Statt einfach alle Strings automatisch als Unicode-Strings zu betrachten.
Okay. Aber ein 'u' davor zu schreiben ist nun nicht wirklich sooo schwer.
- Der Befehl "print" produziert einen Fehler wenn Umlaute ausgegeben werden müssen. Stattdessen könnte doch (automatisch) nachgesehen werden, welches Encoding für STDOUT vorgegeben ist und dieses automatisch verwendet werden. Warum wird das Betriebssystem nicht nach dem Encoding gefragt und dieses automatisch verwendet? Nein, man muss sich selber darum kümmern.
Das stimmt nicht! Es wird nachgeschaut welche Kodierung `sys.stdout` benutzt, wenn Unicode Zeichenketten ausgegeben werden. Bei Byte Zeichenketten stellt sich die Frage nicht, die werden einfach so ausgegeben.
Alles was ich mir wünsche ist, dass das was automatisch erledigt werden könnte -- auch automatisch von Python erledigt wird.
Wird es doch.
- Beim Lesen von STDIN und sys.argv oder beim Schreiben nach STDOUT oder STDERR sollte automatisch von Unicode und nach Unicode umgewandelt werden. Wenn Python das Encoding nicht raus finden kann, dann kann ja der Programmierer eingreifen.
Da hält sich Python halt an die "Zen"s `Refuse the temptation to guess` und `Errors should never pass silently`.

Wenn STDIN und STDOUT umgeleitete Dateien sind, dann weiss man nicht was die richtige Kodierung ist. Das gleiche gilt für `sys.argv`. Wenn das Skript nicht direkt auf der Kommandozeile aufgerufen wird, sondern aus einem anderen Skript, dann gilt für Zeichen ausserhalb von ASCII die Kodierung dieser Textdatei. Diese Kodierung kennt Python nicht, also wird auch nicht geraten.

Diese Probleme werden auch nicht gelöst wenn Zeichenketten intern grundsätzlich Unicode repräsentieren, auf den Wegen in und aus dem dem Programm muss man diese wieder irgendwie kodieren.
Benutzeravatar
DatenMetzgerX
User
Beiträge: 398
Registriert: Freitag 28. April 2006, 06:28
Wohnort: Zürich Seebach (CH)

Merci.. geht bestens ;)
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Hi BlackJack!
BlackJack hat geschrieben:Okay. Aber ein 'u' davor zu schreiben ist nun nicht wirklich sooo schwer.
Es bleibt ja nicht bei einem "u". Es geht bei mir öfter in die hunderte...

Code: Alles auswählen

message = (
    u"Das ist eine Zeile. Das ist eine Zeile mit Umlauten. äüö Eine Zeile. "
    u"Das ist eine Zeile. Das ist eine Zeile mit Umlauten. äüö Eine Zeile. "
    u"Das ist eine Zeile. Das ist eine Zeile mit Umlauten. äüö Eine Zeile. "
)
Für solche Fälle wünsche ich mir so etwas:

Code: Alles auswählen

# -*- coding: iso-8859-1; all-unicode -*-
BlackJack hat geschrieben:Das stimmt nicht! Es wird nachgeschaut welche Kodierung `sys.stdout` benutzt, wenn Unicode Zeichenketten ausgegeben werden. Bei Byte Zeichenketten stellt sich die Frage nicht, die werden einfach so ausgegeben.
Das wusste ich nicht. Nur schade, dass da noch ein Paar IDEs nicht mitspielen und das Coding beim Umleiten nicht mit angeben.
BlackJack hat geschrieben:
- Beim Lesen von STDIN und sys.argv oder beim Schreiben nach STDOUT oder STDERR sollte automatisch von Unicode und nach Unicode umgewandelt werden. Wenn Python das Encoding nicht raus finden kann, dann kann ja der Programmierer eingreifen.
Da hält sich Python halt an die "Zen"s `Refuse the temptation to guess` und `Errors should never pass silently`.
Da stimme ich dir zu. Fehler sollten nicht im Hintergrund passieren. Aber, damit wollte ich auch sagen, dass ich mir doch z.B. auch von sys.argv Unicode-Strings erwarten könnte. Aber nein, es steht irgendwo in den Sternen welches Coding dafür benötigt wird. Einfach alles, was rein kommt und wo eine realistische Chance existiert, dass Python mir diese Strings nach Unicode umwandeln könnte, könnten doch umgewandelt werden. Nur dann, wenn Python den String nicht umwandeln kann, nur dann einen Fehler auszulösen, fände ich nicht schlecht.

Wie schön wäre eine reine UTF-8- oder Unicode-Welt :roll:

lg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
CrackPod
User
Beiträge: 205
Registriert: Freitag 30. Juni 2006, 12:56

und wenn ich einfach

Code: Alles auswählen

# -*- coding: utf-8 -*-
nehmt?
Da is doch fast alles an Zeichen drinnen?!
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

CrackPod hat geschrieben:und wenn ich einfach

Code: Alles auswählen

# -*- coding: utf-8 -*-
nehmt?
Da is doch fast alles an Zeichen drinnen?!
Hi CrackPod!

Das löst leider nicht alle Probleme.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
dcc
User
Beiträge: 3
Registriert: Sonntag 2. Juli 2006, 16:16

gerold hat geschrieben: Hi CrackPod!

Das löst leider nicht alle Probleme.

mfg
Gerold
:-)
Oh, Gerold!

Du hast so recht! Ich habe viele, viele Stunden meines Lebens mit unsauber kodierten XML und dem was Python daraus macht verbracht. In einer perfekten Welt gäbe es in der Tat nur einen Zeichensatz (wahrscheintlich dann UTF-32-NextGeneration). Einen sie alle zu einen, einen sie alle zu...

Gruß,

dcc
BlackJack

gerold hat geschrieben:Hi BlackJack!
BlackJack hat geschrieben:Okay. Aber ein 'u' davor zu schreiben ist nun nicht wirklich sooo schwer.
Es bleibt ja nicht bei einem "u". Es geht bei mir öfter in die hunderte...

Code: Alles auswählen

message = (
    u"Das ist eine Zeile. Das ist eine Zeile mit Umlauten. äüö Eine Zeile. "
    u"Das ist eine Zeile. Das ist eine Zeile mit Umlauten. äüö Eine Zeile. "
    u"Das ist eine Zeile. Das ist eine Zeile mit Umlauten. äüö Eine Zeile. "
)
Für solche Fälle wünsche ich mir so etwas:

Code: Alles auswählen

# -*- coding: iso-8859-1; all-unicode -*-
Wäre eine Idee. Aber suchen/ersetzen im Editor sollte auch fix gehen.
BlackJack hat geschrieben:Einfach alles, was rein kommt und wo eine realistische Chance existiert, dass Python mir diese Strings nach Unicode umwandeln könnte, könnten doch umgewandelt werden. Nur dann, wenn Python den String nicht umwandeln kann, nur dann einen Fehler auszulösen, fände ich nicht schlecht.
Das führt dann zu dem Phänomen das bei Dir alles läuft und dann bei jemand anderem ein Fehler ausgelöst wird, weil der eine andere Umgebung hat. Dann müsstest Du doch wieder eine Fehlerbehandlung und explizite Umkodierung in den Code schreiben. So musst Du es eben sofort machen.
Wie schön wäre eine reine UTF-8- oder Unicode-Welt :roll:
Ja, das würde in der Tat einiges vereinfachen. :-)
Andy
User
Beiträge: 196
Registriert: Sonntag 1. Januar 2006, 20:12
Wohnort: aus dem hohen Norden....

Hi Gerold!

Entweder ich mach was falsch, oder Dein Code funzt nicht in Windows?!?

Erstmal meine Versionsangaben:

Python 2.4
pysqlite 2.3.2
SQLite Administrator 0.8.2.5

Wenn ich Deinen Code verarbeite, dann bekomme ich z. B. dass hier :( :
Geroldä

Testweise habe ich es hiermit versucht: # -*- coding: cp1252 -*-.
Keine Veränderung.

Wo dran mag dass liegen? ich tippe mal auf SQLite Administrator 0.8.2.5.

Gruss andy
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Andy hat geschrieben:Wenn ich Deinen Code verarbeite, dann bekomme ich z. B. dass hier :( :
Geroldä
[...]
Wo dran mag dass liegen? ich tippe mal auf SQLite Administrator 0.8.2.5.
Hi Andy!

Du hast recht. Es liegt am "SQLite Administrator". Der kodiert die Ausgabe im Windows-Standardformat und nicht im SQLite-Standard **UTF-8**.

Der *SQLite Database Browser* zeigt die Umlaute korrekt an. Es gilt, in meinen Augen, weiterhin als beste Regel für pySQLite:
Unicode --> pySQLite --> Unicode

Intern wird alles nach UTF-8 umgewandelt, aber darum musst du dich nicht kümmern.

lg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Andy
User
Beiträge: 196
Registriert: Sonntag 1. Januar 2006, 20:12
Wohnort: aus dem hohen Norden....

gerold hat geschrieben: Du hast recht. Es liegt am "SQLite Administrator". Der kodiert die Ausgabe im Windows-Standardformat und nicht im SQLite-Standard **UTF-8**.
Der *SQLite Database Browser* zeigt die Umlaute korrekt an.
Juhu, super! :lol: Hab´mir jetzt den SQLite Database Browser runtergeladen.
Damit´s funzt wunderbar.

Vielen Dank Gerold!

Gruss Andy
Benutzeravatar
DatenMetzgerX
User
Beiträge: 398
Registriert: Freitag 28. April 2006, 06:28
Wohnort: Zürich Seebach (CH)

gerold hat geschrieben:Hi BlackJack!
BlackJack hat geschrieben:Okay. Aber ein 'u' davor zu schreiben ist nun nicht wirklich sooo schwer.
Es bleibt ja nicht bei einem "u". Es geht bei mir öfter in die hunderte...
Dieses Problem habe ich gelöst, in dem ich ein Modul geschrieben habe, das für alle Abfragen verantwortlich ist.

Da habe ich eine Funktion Query(strSql, Values)

und da transformiere ich vor und nach der abfrage alles in unicode ;)
Antworten