UnicodeDecodeError avec MySQLDb

Le
jean-michel bain-cornu
Bonjour,

Lorsque l'on fait une requête SQL avec MySQLDb, on peut dans certains
cas lever involontairement une exception UnicodeDecodeError.

Ceci se produit si la base est connectée par exemple avec :
import MySQLdb
c=MySQLdb.connect(host,user,pw,db,use_unicodeúlse,charset='latin1')

L'exception se produit dans cursors.py à la ligne 146 :
query = query.encode(charset)
si query contient des caractères accentués.
On pourrait utiliser systématiquement une chaîne unicode pour la
requête, mais ce n'est pas faisable si l'application est déjà écrite
avec des chaînes de requêtes qui ne sont pas unicodées (il faudrait
alors modifier le code de toute l'application).

La solution est de modifier cursors.py avec :
query = unicode(query,charset).encode(charset)

Je trouve ça embêtant de toucher à MySQLDb, et je souhaiterais savoir si
l'un d'entre vous a déjà rencontré ce problème et s'il l'a réglé d'une
autre façon.

Merci
jm

PS: python 2.4.4, MySQL-python 1.2.1
Vidéos High-Tech et Jeu Vidéo
Téléchargements
Vos réponses
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
Laurent Pointal
Le #589953
Bonjour,

Lorsque l'on fait une requête SQL avec MySQLDb, on peut dans certains
cas lever involontairement une exception UnicodeDecodeError.

Ceci se produit si la base est connectée par exemple avec :
import MySQLdb
c=MySQLdb.connect(host,user,pw,db,use_unicodeúlse,charset='latin1')

L'exception se produit dans cursors.py à la ligne 146 :
query = query.encode(charset)
si query contient des caractères accentués.
On pourrait utiliser systématiquement une chaîne unicode pour la
requête, mais ce n'est pas faisable si l'application est déjà écrite
avec des chaînes de requêtes qui ne sont pas unicodées (il faudrait
alors modifier le code de toute l'application).

La solution est de modifier cursors.py avec :
query = unicode(query,charset).encode(charset)

Je trouve ça embêtant de toucher à MySQLDb, et je souhaiterais savoir si
l'un d'entre vous a déjà rencontré ce problème et s'il l'a réglé d'une
autre façon.


Pas d'idée pour ton problème de solution propre. Par contre, y'a un truc
que je ne comprend pas:
query = unicode(query,charset).encode(charset)
C'est comme
query = query
...

Ou alors il faut faire un cas particulier du genre:
if isinstance(query,unicode) : query = query.encode(charset)
Sinon, si tu lui passe une chaine unicode à un moment, tu vas avoir:
TypeError: decoding Unicode is not supported

Et en tout cas, il faut être sûr que les chaînes qui ne sont pas en
unicode sont bien encodées avec ton charset, sinon, il faudrais jouer à:
query = unicode(query,charset_original).encode(charset_db)
Ca deviens lourd...

jean-michel bain-cornu
Le #589952
Pas d'idée pour ton problème de solution propre. Par contre, y'a un truc
que je ne comprend pas:
query = unicode(query,charset).encode(charset)
C'est comme
query = query
Hum... C'était pour voir si quelqu'un suivait...

Tout à fait d'accord ! En fait, il y a juste à retirer la ligne
query = query.encode(charset)
pour que ça marche.
Merci pour la correction.

Et en tout cas, il faut être sûr que les chaînes qui ne sont pas en
unicode sont bien encodées avec ton charset, sinon, il faudrais jouer à:
query = unicode(query,charset_original).encode(charset_db)
Si l'on supporte plusieurs charset, il faut se connecter avec

"use_unicode=True", auquel cas il faut passer les requêtes dans des
chaînes unicode.
En fait la solution correcte serait plutôt quelque chose comme :
if self.use_unicode:
query = query.encode(charset)
pour passer une chaîne correctement encodée au client MySQL.

Laurent Pointal
Le #589951

En fait la solution correcte serait plutôt quelque chose comme :
if self.use_unicode:
query = query.encode(charset)
pour passer une chaîne correctement encodée au client MySQL.


Et hop, une demande de correction au mainteneur du module...

Q? [je n'ai jamais utilisé le module Python MySQL]
Le use_unicode=True/False en option dans connect(), c'est pour dire que
toi tu vas fournir des chaînes en unicode, ou bien c'est pour dire au
client qu'il faut qu'il communique avec le serveur en utilisant unicode
(quoi que pour ça il semble y avoir l'option charset='...')?

Parce que le fait que tu fournisses une chaîne unicode dans une requête
pourrait être détecté à l'exécution via isinstance(query,unicode), ça
éviterais les surprises sans avoir besoin de préciser quoi que ce soit.

jean-michel bain-cornu
Le #589950
En fait la solution correcte serait plutôt quelque chose comme :
if self.use_unicode:
query = query.encode(charset)
pour passer une chaîne correctement encodée au client MySQL.


Et hop, une demande de correction au mainteneur du module...
Je crois que je vais expérimenter un petit plus avant de proposer le

correctif...

Q? [je n'ai jamais utilisé le module Python MySQL]
Le use_unicode=True/False en option dans connect(), c'est pour dire que
toi tu vas fournir des chaînes en unicode, ou bien c'est pour dire au
client qu'il faut qu'il communique avec le serveur en utilisant unicode
(quoi que pour ça il semble y avoir l'option charset='...')?
D'après la doc, ça concerne uniquement les chaînes retournées au

programme client (cf si après).

Parce que le fait que tu fournisses une chaîne unicode dans une requête
pourrait être détecté à l'exécution via isinstance(query,unicode), ça
ou une exception

éviterais les surprises sans avoir besoin de préciser quoi que ce soit.
C'est sûr.

Je n'ai rien vu à ce sujet dans la doc. Ce serait utile de hacker un peu
pour voir ce qui se passe, d'autant plus que les gens qui ont programmé
ça ne se soucient peut-être pas vraiment des jeux de caractères (c'est
fréquent chez les anglophones).
Je ne sais pas non plus si le module python tient compte du jeu de
caractères de la table.
Bref, il y a un peu de travail en perspective pour avoir les idées plus
claires là-dessus. Je ferai un envoi si jamais je m'y attaque.


Extrait de la doc :

use_unicode

If True, CHAR and VARCHAR and TEXT columns are returned as Unicode
strings, using the configured character set. It is best to set the
default encoding in the server configuration, or client configuration
(read with read_default_file). If you change the character set after
connecting (MySQL-4.1 and later), you'll need to put the correct
character set name in connection.charset.

If False, text-like columns are returned as normal strings, but you
can always write Unicode strings.

This must be a keyword parameter.

charset

If present, the connection character set will be changed to this
character set, if they are not equal. Support for changing the character
set requires MySQL-4.1 and later server; if the server is too old,
UnsupportedError will be raised. This option implies use_unicode=True,
but you can override this with use_unicodeúlse, though you probably
shouldn't.

If not present, the default character set is used.

This must be a keyword parameter.


Publicité
Poster une réponse
Anonyme