Hallo allerseits,
das Python-Modul MySQLdb vermittelt zwischen Python und MySQL. Derzeit haben viele Entwickler damit Probleme.
Das Projekt ist auf Sourceforge gehostet.
http://sourceforge.net/projects/mysql-python/
Ich habe im Forum "Open Discussion" einen offenen Brief an den Entwickler gepostet.
http://sourceforge.net/forum/forum.php? ... m_id=70460
Das Folgende ist eine auszugsweise Übersetzung aus diesem Posting:
---
Es gab eine - stille? - Interface-Änderung zwischen den Versionen 1.2.1c3 und and 1.2.1_p2.
Alte Version: cursor.execute() erhält einen String als Parameter.
Neue Version: cursor.execute() erwartet ein Unicode-Objekt.
Aus diesem Grund kämpfen derzeit viele Entwickler mit nicht mehr funktionierenden Anwendungen. Oder sie haben dieses Erlebnis noch vor sich.
z. B. wenn sie von Ubuntu 6.06 auf Version 6.10 wechseln.
Derzeit scheint es keine "Produktivversion" von MySQLdb zu geben, die unter Linux UND Windows funktioniert.
Niemand ist für das Testen unter Windows verantwortlich, obwohl in der Projektzusammenfassung "32-bit MS Windows (NT/2000/XP)" als Plattformen angeführt sind.
--- Auszug Ende
Da bei vielen Leuten schon recht viel Arbeitszeit den Bach hinuntergegangen ist, rate ich aus derzeitiger Sicht zu großer Vorsicht beim Einsatz von MySQLdb.
Lest auf Sourceforge, python-forum.de, im Usenet etc. alle relevanten Postings und Bugreports und zieht Eure Schlüsse.
Testet rechtzeitig auf allen Ziel-Plattformen.
Probleme mit MySQLdb - Warnung
Ich bin nicht sicher, wie direkt da Zusammenhänge bestehen, aber ich hatte ein größeres Problem mit Encodings mit der noch aktuellen stabilen Version von MySQLdb. Auf http://homework.nwsnet.de/releases/2d1e ... e-imminent habe ich dazu ein paar Worte geschrieben und einen Weg aufgezeigt, dies mit einem einfachen Patch zu umgehen. Leider lässt 1.2.2 schon viel zu lange auf sich warten 

Zuletzt geändert von Y0Gi am Sonntag 10. Februar 2013, 00:47, insgesamt 2-mal geändert.
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
Aha! Das ist aber interessant!geraldf hat geschrieben:Interface-Änderung zwischen den Versionen 1.2.1c3 und and 1.2.1_p2.
Alte Version: cursor.execute() erhält einen String als Parameter.
Neue Version: cursor.execute() erwartet ein Unicode-Objekt.
Ich hab in PyLucid mit relativ viel Aufwand selber das de-/encoding eingebaut...
Gibt es denn wirklich einen Traceback, wenn man bei der neuen Version einen String und kein Unicode Objekt benutzt???
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
So, ich hab mal ein test Skript geschrieben: http://paste.pocoo.org/show/298/
Ich hab es getestet mit MySQLdb Version: 1.2.1g2 und 1.2.1_p2 mehr habe ich z.Z. nicht zur Verfügung...
Ich muß da aber irgendwie einen Fehler drin haben... Hier mal die Ausgaben, die eigentlich bei beiden Versionen gleich sind:
Das Skript erzeugt eine Tabelle mit einem varchar Feld.
Es wird der Test-String in den Varianten "unicode", "utf-8", "latin-1", "iso-8859-15" eingefügt und danach wieder ausgelesen.
Der ausgelesene String wird versucht mit "unicode", "utf-8", "latin-1", "iso-8859-15" zu decodieren.
Wie sich zeigt, ist es 1. egal in welchem Encoding man Daten einfügt (Was irgendwie sehr merkwürdig ist) und 2. erhält man die Daten immer mit dem Codec zurück, der beim Server eingestellt ist.
Es ist der Codec der in der Variable "character_set_server" angegeben ist. Bei MySQL in der neueren Version ist es per default "latin-1"...
Irgendwie kann ich aber nicht glauben, das man die Daten in egal welchem Code in die DB packen kann.... Da muß irgendwo ein Fehler im Skript sein.
Ich hab es getestet mit MySQLdb Version: 1.2.1g2 und 1.2.1_p2 mehr habe ich z.Z. nicht zur Verfügung...
Ich muß da aber irgendwie einen Fehler drin haben... Hier mal die Ausgaben, die eigentlich bei beiden Versionen gleich sind:
Zur Funktionsweise:-==[MySQLdb unicode test]==-
MySQLdb Version: 1.2.1_p2
MySQLdb version_info: (1, 2, 1, 'final', 2)
MySQL server encoding: latin1
-------------------------------------------------------------------------------
CREATE TABLE temp_test... OK
-------------------------------------------------------------------------------
inser the teststring in unicode!
INSERT & SELECT... OK
The String can be encoded with 'latin-1'
Test output with 'utf-8': Test äöüß
-------------------------------------------------------------------------------
insert the teststring encoded in 'utf-8'
INSERT & SELECT... OK
The String can be encoded with 'latin-1'
Test output with 'utf-8': Test äöüß
-------------------------------------------------------------------------------
insert the teststring encoded in 'latin-1'
INSERT & SELECT... OK
The String can be encoded with 'latin-1'
Test output with 'utf-8': Test äöüß
-------------------------------------------------------------------------------
insert the teststring encoded in 'iso-8859-15'
INSERT & SELECT... OK
The String can be encoded with 'latin-1'
Test output with 'utf-8': Test äöüß
DROP TABLE... OK
Close Connection... OK
Das Skript erzeugt eine Tabelle mit einem varchar Feld.
Es wird der Test-String in den Varianten "unicode", "utf-8", "latin-1", "iso-8859-15" eingefügt und danach wieder ausgelesen.
Der ausgelesene String wird versucht mit "unicode", "utf-8", "latin-1", "iso-8859-15" zu decodieren.
Wie sich zeigt, ist es 1. egal in welchem Encoding man Daten einfügt (Was irgendwie sehr merkwürdig ist) und 2. erhält man die Daten immer mit dem Codec zurück, der beim Server eingestellt ist.
Es ist der Codec der in der Variable "character_set_server" angegeben ist. Bei MySQL in der neueren Version ist es per default "latin-1"...
Irgendwie kann ich aber nicht glauben, das man die Daten in egal welchem Code in die DB packen kann.... Da muß irgendwo ein Fehler im Skript sein.
Warum versuchst Du zu raten was Du zurückbekommst? Viel interessanter wäre es doch direkt den Vergleich zu zeigen: was Du reinsteckst und was Du zurückbekommst. Beides als `repr()` damit man wirklich Byte für Byte sieht wie die Daten aussehen.jens hat geschrieben:Irgendwie kann ich aber nicht glauben, das man die Daten in egal welchem Code in die DB packen kann.... Da muß irgendwo ein Fehler im Skript sein.
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
Sehr gute Idee! Ich sollte mir endlich mal repr() merken
Aktualisiert: http://paste.pocoo.org/show/299/
Diff: http://paste.pocoo.org/compare/299/
Wie man sieht, stecke ich schon den String richtig encodiert in die DB... Und es kommt immer in "latin-1" raus und ist der selbe Test-String...
Ich werde mit mal eine Uralte MySQLdb installieren und damit mal testen...
EDIT: Gesagt, getan... Das Ergebnis ist das selbe mit MySQLdb version_info: (1, 2, 0, 'final', 1)
EDIT 2: Das gleiche bei MySQLdb version_info: (1, 0, 0, 'final', 1) ... Ist die älteste für Python 2.4... Mal sehen, wie es mit Python 2.3 aussieht!
EDIT 3: Mit Python 2.3 und MySQLdb version_info: (1, 2, 0, 'final', 1) aus das selbe...
EDIT4: Und noch Python 2.3 mit MySQLdb version_info: (0, 9, 2, 'final', 1) das selbe...

Aktualisiert: http://paste.pocoo.org/show/299/
Diff: http://paste.pocoo.org/compare/299/
Code: Alles auswählen
-==[MySQLdb unicode test]==-
MySQLdb Version: 1.2.1_p2
MySQLdb version_info: (1, 2, 1, 'final', 2)
MySQL server encoding:
MySQL variable 'character_set_server': latin1
connection.character_set_name: latin1
-------------------------------------------------------------------------------
CREATE TABLE temp_test... OK
-------------------------------------------------------------------------------
inser the teststring in unicode!
INSERT & SELECT... OK
db_input...: u'Test \xe4\xf6\xfc\xdf'
db_output..: 'Test \xe4\xf6\xfc\xdf'
The String can be encoded with 'latin-1'
Test output with 'utf-8': Test äöüß
-------------------------------------------------------------------------------
insert the teststring encoded in 'utf-8':
INSERT & SELECT... OK
db_input...: 'Test \xc3\xa4\xc3\xb6\xc3\xbc\xc3\x9f'
db_output..: 'Test \xe4\xf6\xfc\xdf'
The String can be encoded with 'latin-1'
Test output with 'utf-8': Test äöüß
-------------------------------------------------------------------------------
insert the teststring encoded in 'latin-1':
INSERT & SELECT... OK
db_input...: 'Test \xe4\xf6\xfc\xdf'
db_output..: 'Test \xe4\xf6\xfc\xdf'
The String can be encoded with 'latin-1'
Test output with 'utf-8': Test äöüß
-------------------------------------------------------------------------------
insert the teststring encoded in 'iso-8859-15':
INSERT & SELECT... OK
db_input...: 'Test \xe4\xf6\xfc\xdf'
db_output..: 'Test \xe4\xf6\xfc\xdf'
The String can be encoded with 'latin-1'
Test output with 'utf-8': Test äöüß
-------------------------------------------------------------------------------
insert the teststring encoded in 'utf_16_be':
INSERT & SELECT... OK
db_input...: '\x00T\x00e\x00s\x00t\x00 \x00\xe4\x00\xf6\x00\xfc\x00\xdf'
db_output..: 'Test \xe4\xf6\xfc\xdf'
The String can be encoded with 'latin-1'
Test output with 'utf-8': Test äöüß
DROP TABLE... OK
Close Connection... OK
Ich werde mit mal eine Uralte MySQLdb installieren und damit mal testen...
EDIT: Gesagt, getan... Das Ergebnis ist das selbe mit MySQLdb version_info: (1, 2, 0, 'final', 1)
EDIT 2: Das gleiche bei MySQLdb version_info: (1, 0, 0, 'final', 1) ... Ist die älteste für Python 2.4... Mal sehen, wie es mit Python 2.3 aussieht!
EDIT 3: Mit Python 2.3 und MySQLdb version_info: (1, 2, 0, 'final', 1) aus das selbe...
EDIT4: Und noch Python 2.3 mit MySQLdb version_info: (0, 9, 2, 'final', 1) das selbe...
Zuletzt geändert von jens am Donnerstag 7. Dezember 2006, 14:29, insgesamt 1-mal geändert.
-
- User
- Beiträge: 1790
- Registriert: Donnerstag 28. Oktober 2004, 16:33
- Wohnort: Graz, Steiermark - Österreich
- Kontaktdaten:
Ich werfe zzzeeks sqlalchemy in den Raum.
TUFKAB – the user formerly known as blackbird
-
- Python-Forum Veteran
- Beiträge: 16025
- Registriert: Freitag 20. Juni 2003, 16:30
- Kontaktdaten:
Ich schmeiß auch noch PostgreSQL ein - ein DMBS das sehr gut funktioniert und viele verschiedene teilweise auch sehr gute Python-Interfaces hat. Wird auch von SQLAlchemy unterstützt.blackbird hat geschrieben:Ich werfe zzzeeks sqlalchemy in den Raum.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
SQLAlchemy und PostgreSQL hilft mir jetzt unheimlich toll weiter...
Also: Was kann ich jetzt aus meinem Test folgern?
Das man egal in welchem Encoding Daten in die DB schmeißen kann und sie kommen immer sauber im Server Encoding (also latin-1) zurück?
Das kann doch irgendwie nicht sein, oder?

Also: Was kann ich jetzt aus meinem Test folgern?
Das man egal in welchem Encoding Daten in die DB schmeißen kann und sie kommen immer sauber im Server Encoding (also latin-1) zurück?
Das kann doch irgendwie nicht sein, oder?
Ne das kann auch nicht seinjens hat geschrieben:[...]
Das man egal in welchem Encoding Daten in die DB schmeißen kann und sie kommen immer sauber im Server Encoding (also latin-1) zurück?
Das kann doch irgendwie nicht sein, oder?

lg
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
Hm... Nagut... Wenn der Server latin-1 als encoding eingestellt hat, kann er auch IMHO nur alle Zeichen die latin-1 abbilden kann speichern... Latin-1 müßte somit alle Zeichen von 0x0000 bis 0x00FF abbilden, oder ?
Ich mache mal ein Test damit...
Ich mache mal ein Test damit...
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
Jep, so ist es...
Als Testdaten hab ich mal das genommen:
Das kann ich als "unicode" oder encodiert in "utf-8", "latin-1" oder "utf_16_be" in die DB schmeißen... Raus kommt latin-1 der decodiert genau dem Test-String entspricht...
Also ist ja schön, das MySQLdb es so macht, aber wie macht es das???
Wenn ich einen String im exotischen "utf_16_be" Encoding in die DB schreibe, wie kann das Modul wissen, das es dieser Codec ist?
Als Testdaten hab ich mal das genommen:
Code: Alles auswählen
TEST_STRING = u"".join([unichr(i) for i in xrange(0, 256)])
Also ist ja schön, das MySQLdb es so macht, aber wie macht es das???
Wenn ich einen String im exotischen "utf_16_be" Encoding in die DB schreibe, wie kann das Modul wissen, das es dieser Codec ist?
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
Hier mal der latin-1 Test: http://paste.pocoo.org/show/301/
Wirft das raus:
Ach, und noch was...
Man kann ab MySQL v4.1 das verwendete character set ändern. So:
Das scheint aber keine Gute Idee zu sein... In dem Fall sind alle Werte "defekt". Egal ob ich versuche die Ausgaben mit "latin-1" oder "utf-8" zu encodieren:
Wirft das raus:
Code: Alles auswählen
-==[MySQLdb unicode test]==-
MySQLdb Version: 1.2.0
MySQLdb version_info: (1, 2, 0, 'final', 1)
MySQL server encoding:
MySQL variable 'character_set_server': latin1
connection.character_set_name: latin1
-------------------------------------------------------------------------------
CREATE TABLE temp_test... OK
-------------------------------------------------------------------------------
inser the teststring in unicode!
INSERT & SELECT... OK
db_input...: u'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x...
db_output..: '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x1...
Encode db output with server encoding 'latin1'... OK
Is test-String == db output: True
-------------------------------------------------------------------------------
insert the teststring encoded in 'utf-8':
INSERT & SELECT... OK
db_input...: '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x1...
db_output..: '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x1...
Encode db output with server encoding 'latin1'... OK
Is test-String == db output: True
-------------------------------------------------------------------------------
insert the teststring encoded in 'latin-1':
INSERT & SELECT... OK
db_input...: '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x1...
db_output..: '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x1...
Encode db output with server encoding 'latin1'... OK
Is test-String == db output: True
-------------------------------------------------------------------------------
insert the teststring encoded in 'utf_16_be':
INSERT & SELECT... OK
db_input...: '\x00\x00\x00\x01\x00\x02\x00\x03\x00\x04\x00\x05\x00\x06\x00\x07\x00\...
db_output..: '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x1...
Encode db output with server encoding 'latin1'... OK
Is test-String == db output: True
DROP TABLE... OK
Close Connection... OK
Ach, und noch was...
Man kann ab MySQL v4.1 das verwendete character set ändern. So:
Code: Alles auswählen
cursor.execute('set character set %s;', ("utf8",))
Code: Alles auswählen
inser the teststring in unicode!
INSERT & SELECT... OK
db_input...: u'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x...
db_output..: '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x1...
Encode db output with server encoding 'latin1'... OK
Is test-String == db output: False
-------------------------------------------------------------------------------
insert the teststring encoded in 'utf-8':
INSERT & SELECT... OK
db_input...: '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x1...
db_output..: '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x1...
Encode db output with server encoding 'latin1'... OK
Is test-String == db output: False
-------------------------------------------------------------------------------
insert the teststring encoded in 'latin-1':
INSERT & SELECT... OK
db_input...: '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x1...
db_output..: '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x1...
Encode db output with server encoding 'latin1'... OK
Is test-String == db output: False
-------------------------------------------------------------------------------
insert the teststring encoded in 'utf_16_be':
INSERT & SELECT... OK
db_input...: '\x00\x00\x00\x01\x00\x02\x00\x03\x00\x04\x00\x05\x00\x06\x00\x07\x00\...
db_output..: '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x1...
Encode db output with server encoding 'latin1'... OK
Is test-String == db output: False
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
So, nach den tests habe ich jetzt auch anpassungen in PyLucid unternommen.
Mit https://pylucid.net/trac/changeset/643 wird nun folgendes gemacht bzw. nicht mehr gemacht:
btw. wie bekommt man da die Daten zurück? Direkt als unicode oder in dem encoding der DB???
Mit https://pylucid.net/trac/changeset/643 wird nun folgendes gemacht bzw. nicht mehr gemacht:
- 1. Das DB encoding wird nicht mehr mit 'set character set %s;' geändert. Es wird immer das default encoding des Servers genommen.
2. Die Daten, zur DB gehen, werden nicht mehr von in ein anderes encoding gebracht.

-
- User
- Beiträge: 1790
- Registriert: Donnerstag 28. Oktober 2004, 16:33
- Wohnort: Graz, Steiermark - Österreich
- Kontaktdaten:
Wenn du eine Column als "String" im table definierst bekommst du das encoding zurück, oder bullshit. Letzteres besonders gerne beim MySQL adapter. Das würde ich gar nicht verwenden. Wenn deine Column als "Unicode" definiert ist bekommst du, tadadada: unicodejens hat geschrieben:Und, ja, ich werde auf SQLAlchemy umsteigenbtw. wie bekommt man da die Daten zurück? Direkt als unicode oder in dem encoding der DB???

TUFKAB – the user formerly known as blackbird
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
Da hat sich wohl noch mehr geändert...geraldf hat geschrieben:Interface-Änderung zwischen den Versionen 1.2.1c3 und and 1.2.1_p2.
Alte Version: cursor.execute() erhält einen String als Parameter.
Neue Version: cursor.execute() erwartet ein Unicode-Objekt.
Beim connecten kann man einmal ein kwarg "charset" angeben, in einer älteren v1.2.1 nicht, dafür aber "use_unicode"...
Irgendwie blicke ich in den Versionnummern nicht durch. Von daher kann man auch schlecht testen, welches kwargs nun geht, wie hier:
Code: Alles auswählen
from MySQLdb import version_info
if version_info < (1, 2, 1):
# Für alte Versionen
kwargs["use_unicode"] = True
else:
# ab python-mysqldb v1.2.1
kwargs["charset"] = self.encoding

Ich frage mich dann, ob der trac-Patch auch richtig arbeitet.