[gelöst]Decoding Problem mit MySQLdb

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
ebel
User
Beiträge: 9
Registriert: Donnerstag 30. März 2006, 17:22

Hallo Python-Forumianer,

Habe folgende Tabelle

CREATE TABLE `tablename` (
`name` varchar(3) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
INSERT INTO `tablename` VALUES ('—');

Versuche nun folgendes

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: utf-8 -*-
import MySQLdb
c=MySQLdb.connect("localhost","user","passwort","databank").cursor()
c.execute("Select name from tablename")
name=c.fetchone()[0]
print type(name)
# ergibt: <type 'str'>
sql="Select '%s'" % (name)
print sql
# ergibt: Select '—'
# ACHTUNG: Dies ist ein langer Gedankenstrich
c.execute(sql)
Fehlerausgabe:
Traceback (most recent call last):
File "/home/ceb/temp/test.py", line 13, in <module>
c.execute(sql)
File "/usr/lib/python2.5/site-packages/MySQLdb/cursors.py", line 146, in execute
query = query.encode(charset)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 8: ordinal not in range(128)

Wie muss man decoden um das SQL statement ausführen zu können? Oder ist das ein ganz anderes Probelm was ich bisher übersehen habe?

Schon mal vielen Dank im voraus

Gruss
ebel
Zuletzt geändert von ebel am Freitag 9. Februar 2007, 12:02, insgesamt 1-mal geändert.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Im connect solltest du am besten das kwarg charset nutzten und z.B. auf "utf8" stellen.

Dann fütterst du MySQL mit unicode Strings... Das sollte gehen...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Welche Version von MySQLdb verwendest du? Vermutlich nicht die AFAIK aktuellste 1.2.2b1, denn da sollte das Problem behoben sein. Alternativ kannst du eine 1.2.1_p1 (vermutlich auch andere) mit dem hier beschriebenen Patch anpassen.

Vielleicht reicht es aber auch schon, nicht printf-%-Formatierung zu benutzen, sondern die Variablen als Parameter an .execute() zu übergeben. Genau das hat Andy Dustman (der Entwickler) nämlich auch sehr oft bei solchen Problemen entgegnet.
ebel
User
Beiträge: 9
Registriert: Donnerstag 30. März 2006, 17:22

LieberY0Gi,

vielen, vielen Dank für den nützlichen Verweis auf hier beschriebenen Patch. Ungaublich einfach die Lösung.

Also, kurz zusammen gefasst:
Das Problem betrifft anscheinend nur MySQLdb version 1.2.1_p2

Lösung:
in "/usr/lib/python2.5/site-packages/MySQLdb/cursors.py", line 146

Code: Alles auswählen

query = query.encode(charset)
austauschen gegen:

Code: Alles auswählen

if isinstance(query, unicode):
    query = query.encode(charset)
Das wars.

Gruss
ebel
Zuletzt geändert von ebel am Freitag 9. Februar 2007, 14:54, insgesamt 1-mal geändert.
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Aber bitte. Hat mich selbst genug Nerven gekostet...

Mir ist ein Rätsel, warum 1.2.2 immer noch nicht stable geworden ist, 1.2.1_p1 ist praktisch IMHO unbrauchbar.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

ebel hat geschrieben:Also, kurz zusammen gefasst:
Das Problem betrifft anscheinend nur MySQLdb version 1.2.1_p2

Lösung:
in "/usr/lib/python2.5/site-packages/MySQLdb/cursors.py", line 146

Code: Alles auswählen

query = query.encode(charset)
austauschen gegen:

Code: Alles auswählen

if isinstance(query, unicode):
    query = query.encode(charset)
Ich weiß nicht ob du damit glück haben wirst.

Ich mache es anders: Ich baue den connect mit "charset=utf8" oder "use_unicode=True" auf. Danach setzte ich den SQL-Befehl "SET NAMES 'utf8';" ab.
Das scheint gut zu funktionieren. Das ist im Prinzip auch das selbe wie der trac Patch: http://trac.edgewall.org/attachment/tic ... ysql.patch

Siehe auch: http://www.python-forum.de/post-52110.html#52110

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
ebel
User
Beiträge: 9
Registriert: Donnerstag 30. März 2006, 17:22

Hallo Jens,

vielen Dank für Deinen zusätzlichen Hinweis. Mehrere Lösungen sind immer gut!!!

Also im Moment bin ich glücklich mit der Lösung, da ich meine Programme nicht ändern muss und alles wie bisher wunderbar funktioniert. Ist aber vielleicht keine saubere Lösung und zieht Folgefehler nach sich. Sieht Du da eine Gefahr?

Gruss
ebel

Edit (jens): FULL QUOTES bitte unterlassen, siehe: http://www.python-forum.de/topic-9352.html
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Naja, ich würde es ehr vermeiden in den Quellentexten von MySQLdb rum zu patchen. Wenn du das kannst, solltest du auch einfach eine neue Version installieren können, oder nicht?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
ebel
User
Beiträge: 9
Registriert: Donnerstag 30. März 2006, 17:22

Hallo Jens,

Du hast sicherlich recht: Im Quelltext rumfummeln ist immer ein bisschen gefährlich. Wenn man aber den Quelltext genauer anschaut so sieht es als ob der Entwickler Andy Dustman an allen anderen Stellen in cursors.py eben genau das macht.

Ok, nicht genau das selbe, denn er macht folgendes:

Code: Alles auswählen

from types import UnicodeType
if type(q) is UnicodeType:
    q = q.encode(charset)
Wobei das aber das selbe bedeutet.

Ich werde aber 1.2.2 sofort installieren sobald es stable ist.

Gruß und nochmals vielen Dank für Deinen Hinweis
ebel
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Aha! Ich frage mich warum er nicht if isinstance(q, unicode) macht...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

jens hat geschrieben:Naja, ich würde es ehr vermeiden in den Quellentexten von MySQLdb rum zu patchen. Wenn du das kannst, solltest du auch einfach eine neue Version installieren können, oder nicht?
Da fallen mir mehrere Gründe ein:
* Ich möchte meinen Quelltext nicht ändern, wenn es mit der nächsten Version ohne diese Änderungen funktionieren würde und ich nur auf mein eigenen bzw. von mir betreuten Environments achten muss oder die Version 1.2.2x für andere als Requirement festlegen kann.
* Ich möchte über die Update-Möglichkeiten meiner Paketverwaltung informiert werden, wenn eine neue Version des Pakets vorhanden ist. Dazu lasse ich es installiert anstatt es zu deinstallieren und direkt den Quellcode zu verwenden, weil es noch kein Paket für meine Distribution gibt, ich keines machen oder aus einem RPM konvertieren will etc.

Sicher auch nicht der heilige Gral, aber das sind MySQL-spezifische Workarounds über SQL-Kommandos für ältere MySQLdb-Pakete IMHO auch nicht.
ebel
User
Beiträge: 9
Registriert: Donnerstag 30. März 2006, 17:22

Jens schrieb: Aha! Ich frage mich warum er nicht if isinstance(q, unicode) macht...


Hmmm, echt gesagt keine Ahnung
Man kann das natürlich auch so fixen wie Andy Dustman, muss dann aber

Code: Alles auswählen

from types import UnicodeType
vor Zeile 146 in den Quelltext mit in die class BaseCursor einbinden. Wird bei ihm aber erst in Zeile 250 gemacht.

Gruss
ebel
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

jens hat geschrieben:Ich mache es anders: Ich baue den connect mit "charset=utf8" oder "use_unicode=True" auf. Danach setzte ich den SQL-Befehl "SET NAMES 'utf8';" ab.
Das mit dem "SET NAMES 'utf8';" ist vielleicht doch keine so gute Idee. Zumindest dann nicht, wenn man bestehende DB Daten hat.
Ich hab nämlich eine DB, die per default auf latin1 läuft. Nach dem "SET NAMES 'utf8';" sind die Umlaute defekt.

Ich werde mal versuchen einen DUMP zu ziehen (mit deaktivieren utf8), dann auf utf8 umstellen und den DUMP wieder einspielen... Mal sehen...

EDIT: Ne, das ist ja unfug. Wenn ich z.B. mit phpMyAdmin den dump einspiele, ist ja doch wieder das default encoding aktiv. Also wird der dump wieder in latin1 eingespielt.

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

@jens: was das dumpen betrifft: es ist am einfachsten mit phpmyadmin einen dump ziehen, der dir das nicht als datei speichert, sondern anzeigt. Das angezeigte schreibst du dann in eine Datei und speicherst es als Utf-8 ab (charsets die noch im dump rumgurken rauslöschen!). Dann leerst du die db (bzw. drop) und stellst das charset auf utf-8 um. Dann importierst du dein File :)
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Ja, das Verfahren kenne ich... Aber ich weiß nicht ob ich den PyLucid Nutzer das zumuten sollte ;)

Wenn ich "SET NAMES" nicht in einer neueren Version fest auf 'utf8' stelle, gibt es keine Probleme. Auch wenn der Server evtl. mit latin-1 läuft...

Naja, mal sehen, vielleicht sollte ich das optional machen oder so...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
thelittlebug
User
Beiträge: 188
Registriert: Donnerstag 20. Juli 2006, 20:46
Wohnort: Wien
Kontaktdaten:

Bissal spät aber doch :

Du solltest das Encoding auch nachträglich mit "alter table ......" ändern können. Das Encoding lässt sich gesondert einstellen für:
Den ganzen Datenbankserver, wird als default genutzt wenn neue Datenbanken angelegt werden.
Eine Datenbank, wird als default genutzt wenn neue Tabellen angelegt werden.
Eine Tabelle, wird als default genutzt wenn neue Spalten angelegt werden.
Eine Spalte, hier kann nachträglich umgestellt werden wobei dann die DB die Daten konvertiert.

lgherby

p.s. häng auch grad beim Thema MySQL mit SQLAlchemy und Unicode rum. Scheint aber jetzt alles gelöst zu sein.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

MySQLdb und encoding... Da gibt es überall Probleme mit, siehe auch: http://www.python-forum.de/topic-8002.html

In django gibt es auch ein paar Tickets zum Thema... Ich hoffe das alle zukünftigen Versionen vom Modul das besser machen als bisher ;)

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
thelittlebug
User
Beiträge: 188
Registriert: Donnerstag 20. Juli 2006, 20:46
Wohnort: Wien
Kontaktdaten:

Also Probleme hab ich keine mehr und auch die Lösung war eigentlich sehr angenehm nur hab ich mir zuerst ein paar Unicode Grundlagen durchlesen müssen um zu verstehen wie Python damit umgeht.

Im großen und ganzen habe ich nur folgendes gemacht:
1. SQLAlchemy alle Spalten auch als Unicode deklariert. ( z.b. Unicode(50) )
2. MySQL (war eine bestehende DB) alle Spalten auf utf8_unicode_ci umgestellt. Vorsichtshalber auch die Vorgaben für Tabellen und die DB falls neue Tabellen oder Spalten erstellt werden.
3. Connection String für SQLAlchemy mit den 2 Parametern versehen so wie es auch hier in diesem Thread beschrieben wurde.
4. Templatekonfiguration lt. Mako Doku.

Seitdem klappts auch mit dem bösen Unicode :)
Teilweise werden einem ja schauerhafte Märchen erzählt, was man nicht alles ersetzen und patchen muss, ich hab nur recht wenig davon mitbekommen.

lgherby
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

Die Mär vom "bösen Unicode" kommt daher, dass die Leute weder verstehen, dass Unicodestrings eine Sequenz von Codepoints sind (und nicht etwa "UTF-8-Strings", was man sich darunter auch immer vorstellen soll), noch dass man sich das Leben enorm durch das `codecs`-Modul erleichtern kann.
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
Antworten