Table of Contents
Contexte
Lors de l’exécution d’un script Python pour générer un fichier CSV à partir de données extraites d’une base MySQL, une erreur bloquante a été rencontrée :
UnicodeEncodeError: 'ascii' codec can't encode characters in position 4-5: ordinal not in range(128)
Cette erreur survenait lorsque le script tentait d’écrire des données contenant des caractères accentués ou non-ASCII dans le fichier CSV. Les journaux du script ne fournissaient initialement pas suffisamment d’informations pour identifier la source du problème.
Analyse initiale du problème
- Nature de l’erreur :
L’exceptionUnicodeEncodeError
est typique en Python 2 lorsque des données Unicode contiennent des caractères en dehors de la plage ASCII (0-127). Par défaut, Python 2 tente d’utiliser l’encodage ASCII pour écrire ces données, ce qui provoque une erreur si des caractères non pris en charge sont présents. - Source potentielle :
L’erreur se produisait lors de l’écriture dans un fichier CSV. Elle était due à des caractères non-ASCII présents dans la colonnename
de la base de données MySQL. - Logs insuffisants :
Les journaux n’identifiaient pas clairement la ligne problématique, compliquant la localisation de la donnée à l’origine de l’erreur.
Déroulement de la résolution
Identification des données problématiques
Pour localiser rapidement les entrées contenant des caractères non-ASCII, une requête SQL a été exécutée :
SELECT name FROM users WHERE name REGEXP '[^ -~]';
- Cette requête utilise une expression régulière pour filtrer les noms contenant des caractères en dehors de la plage ASCII imprimable.
- Le résultat a permis d’identifier un utilisateur dont le prénom contenait un accent.
Correction des données
Une fois l’utilisateur identifié, son nom a été corrigé dans la base de données pour éliminer les caractères accentués :
UPDATE users SET name = 'Nom Sans Accent' WHERE name = 'Nom Avec Accent';
Validation de la correction
Le script a été réexécuté avec succès, confirmant que le problème était lié à des données non conformes.
Enseignements
- Vérification des données en amont :
Avant de traiter ou d’écrire des données provenant d’une base, il est utile d’implémenter une vérification des caractères spéciaux ou non-ASCII. - Amélioration des journaux :
Les journaux devraient inclure des informations détaillées sur les exceptions, y compris la ligne de données traitée, pour faciliter le diagnostic.
Exemple de journalisation enrichie :
except Exception as e:
logger.error("Erreur lors du traitement de la ligne : {}".format(ligne), exc_info=True)
- Utilisation d’un encodage compatible :
Si des caractères non-ASCII sont attendus, il est recommandé d’utiliser un encodage comme UTF-8 pour les fichiers de sortie.
Exemple :
import codecs
csv = codecs.open(CSV_ANNUAIRE, "w", encoding='utf-8')
csv.write(u"{};{};{};{}\n".format(prenom, nom, numero_interne_tiret, numero_externe))
Prévention à l’avenir
- Requêtes SQL de validation :
Implémentez des requêtes périodiques pour vérifier la conformité des données dans les bases :
SELECT name FROM users WHERE name REGEXP '[^ -~]';
- Encodage des bases de données :
Assurez-vous que la base utilise un encodage UTF-8 (ou UTF-8-MB4 pour les emojis et caractères spéciaux) pour éviter les problèmes d’encodage. Commande pour vérifier :
SHOW FULL COLUMNS FROM users;
Conversion si nécessaire :
ALTER TABLE users CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
- Configuration de Python :
Configurez votre environnement Python pour utiliser UTF-8 par défaut. Ajoutez cette variable d’environnement :
export PYTHONIOENCODING=utf-8
- Traitement robuste des exceptions :
Ajoutez des blocstry...except
pour capturer et loguer les exceptions sans interrompre l’exécution du script.
Conclusion
Cette expérience illustre l’importance d’une gestion proactive des caractères non conformes dans les bases de données et les scripts Python. Avec des journaux enrichis, une validation des données en amont et l’utilisation d’encodages compatibles, il est possible de prévenir et de résoudre efficacement ce type de problèmes.