IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

UnicodeDecodeError avec CGI [Python 3.X]


Sujet :

Python

  1. #1
    Membre du Club
    Homme Profil pro
    Apprenti
    Inscrit en
    Mars 2018
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Apprenti
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2018
    Messages : 7
    Par défaut UnicodeDecodeError avec CGI
    Bonjour à tous,
    J'ai un projet dont le but est d'importer un planning (fichier csv au format .txt) dans une base de données.
    J'ai donc réalisé un script qui modifie le fichier, car il est par défaut en utf-16 et des informations inutiles peuvent êtres enlevées. Ce script fonctionne à merveille sur Windows ou même Linux (Raspbian ou Ubuntu) mais lorsque que j'execute via CGI j'ai l'erreur "UnicodeDecodeError".
    Nom : Sans titre.png
Affichages : 365
Taille : 58,0 Ko
    Le script py est hébergé sur ma Raspberry Pi 3, et un serveur Apache2 est utilisé.
    J'ai changé l'endroit où était situé le planning pour éviter les problèmes de droit de Linux mais rien ne change.
    Lors de l’exécution du code, les fichiers sont créés comme prévu mais le fichier final (qui doit contenir le planning modifié) est vide alors que les fichiers temporaires eux sont remplis.
    Comment faire pour contourner ce problème ?
    Voici le script "delete.py" :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
     
    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    import cgi
    import cgitb
    import os
    import datetime
    import codecs
    import csv
    import sys
     
    cgitb.enable()
    cgi.test()
     
    repertoire = "/home/pi/Documents/GebPlannings/"
     
    fichier_txt = repertoire + "planning" + str(datetime.date.today().year) + "tmp.csv"
    fichier_temporaire = repertoire + "Classeur1.csv"
    fichier_temporaire2 = repertoire + "Classeur2.csv"
    fichier_csv = repertoire + "planning" + str(datetime.date.today().year) + ".csv"
     
    with codecs.open(fichier_txt, "r", "utf-16") as fichierSource:
      with codecs.open(fichier_temporaire, "w", "utf-8") as fichierCible:
        while True:
          contenu = fichierSource.read()
          if not contenu:
            break
          fichierCible.write(contenu)
    fichierSource.close()
    fichierCible.close()
     
    with open(fichier_temporaire, "rb") as fichierTemporaire1:
      with open(fichier_temporaire2, "wb") as fichierTemporaire2:
        row = 1
        for ligne in fichierTemporaire1:
          if row > 1:
            fichierTemporaire2.write(ligne)
          row += 1
    fichierTemporaire1.close()
    fichierTemporaire2.close()
     
    with open(fichier_temporaire2, "r") as source:
      lecteur = csv.reader(source, delimiter = '\t')
      with open(fichier_csv, "w") as result:
        ecriture = csv.writer(result, delimiter = ';')
        for col in lecteur:
          ecriture.writerow((col[0], col[1].replace('h', ':'), col[3], col[4], col[5], col[6].replace('h', ':')))
          #ecriture.writerow((col[0], col[1].replace('h', ':'), col[3], col[4], col[5], col[6].replace('h', ':')))
    lecteur.close()
    ecriture.close()
    Le planning ressemble à ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    NUMERO	DUREE	FREQUENCE	SALLE	ALTERNANCE	JOUR	H.DEBUT	EFFECTIF
    1	2h00	H	1	H	lundi	08h00	16
    2	2h00	H	2	H	lundi	08h00	36
    3	2h00	H	3	H	lundi	08h00	26
    4	2h00	H	4	H	lundi	08h00	31
    5	2h00	H	5 (tbi)	H	lundi	08h00	31
    6	1h00	Q2	6	Q2	lundi	08h00	30

  2. #2
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 827
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 827
    Billets dans le blog
    1
    Par défaut
    Bonjour

    Difficile de te répondre car je n'arrive pas à reproduire.
    J'ai récupéré ton script et ton planning, généré un fichier en utf-16 contenant ledit planning et ton script l'a bien bouffé sans erreur (sauf en lignes 49 et 50 car apparemment les csv n'ont pas de méthode "close()"). A ce sujet d'ailleurs c'est inutile de demander à spécifier le "close()" car c'est fait automatiquement quand tu quittes le with. De plus tu peux combiner deux with en un seul en écrivant with open(...) as truc, open(...) as chose ce qui te fait gagner un niveau d'indentation.

    Il y a un truc que tu peux tester: c'est exécuter ton script en le redirigeant (style python3 toto.py >xxx) car moi j'ai déjà eu des UnicodeError dans ce cas là (le script s'exécutait bien à l'écran mais impossible de le rediriger vers un fichier). Et pour solutionner le souci j'ai dû rajouter
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    import codecs
    import locale
    import sys
    sys.stdout=codecs.getwriter(locale.getpreferredencoding())(sys.stdout)

    Mais bon, j'ai peu d'espoir car ça m'arrivait en Python2 et ça ne le fait plus en Python3 (or je vois que tu bosses en Python3). Essaye aussi un planning test sans aucun accent pour vérifier que ça vient bien de là.

    PS: il existe la méthode os.path.join() pour générer des noms de fichiers de façon un peu plus propre...
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    repertoire = "/home/pi/Documents/GebPlannings"   # Plus besoin de finir le nom par un "/"
    fichier_txt = os.path.join(
    	repertoire,
    	"planning{0}tmp.csv".format(datetime.date.today().year),
    )
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  3. #3
    Membre du Club
    Homme Profil pro
    Apprenti
    Inscrit en
    Mars 2018
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Apprenti
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2018
    Messages : 7
    Par défaut
    Bonjour,
    Merci pour la réponse.

    J'ai donc essayé de rajouter ce code après les import:
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    sys.stdout=codecs.getwriter(locale.getpreferredencoding())(sys.stdout)
    Mais cette ligne bloque l'affichage des erreurs affichées par :Je l'ai donc mis après, le code affiche bien les erreur (comme avant) mais rien de plus (ou de moins) ne se passe.

    J'ai aussi essayé un fichier sans accents et ça à l'air d'être ça le problème . Y a t-il un moyen de faire enlever les accents par python automatiquement (é, É, ç...), ou même de les garder mais contourner cette "limitation"?

    Par contre je n'ai pas compris l'histoire de la redirection :
    Citation Envoyé par Sve@r
    Il y a un truc que tu peux tester: c'est exécuter ton script en le redirigeant (style python3 toto.py >xxx)
    Après l'upload du fichier sur la Raspberry, la page d'envoi PHP exécute une redirection
    Code html : Sélectionner tout - Visualiser dans une fenêtre à part
    <meta http-equiv="refresh" content="0; url=cgi-bin/delete.sh" />
    vers un fichier .sh
    Code bash : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    #!/bin/bash
    python3 /usr/lib/cgi-bin/delete.py
    qui lui exécute le script python.
    J'avais aussi essayé le code ci dessous, sans grand succès.
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    shell_exec('/usr/lib/cgi-bin/delete.sh');

  4. #4
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 827
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 827
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par alex420 Voir le message
    Y a t-il un moyen de faire enlever les accents par python automatiquement (é, É, ç...)
    Ca pourrait être l'utf-16 le souci. Surtout que Python3 travaille par défaut en utf-8. D'ailleurs je me demande le pourquoi de cet utf-16 et si t'en as vraiment besoin...

    Mais bon, je ne peux pas remettre en cause tes choix que je ne maitrise pas donc je peux te proposer de générer un fichier en utf-8 à partir de ton fichier en utf-16.
    Tu ouvres ton premier fichier via f1=codecs.open(fichier, "r", encoding="utf-16"). Tu ouvres ton second via f2=open() classique puis tu recopies les données du premier dans le second via un simple for lig in f1: f2.write(lig). Je viens de tester et ça a fonctionné (j'ai créé un premier fichier classique utf-8, l'ai recopié en utf-16 via "iconv" puis ai généré un 3° fichier via ce petit bout de code qui utilise le second et le 3° fichier est identique au premier).
    Et tu peux même importer la librairie "fs" qui te donne certains outils pour manipuler les filesystems dont un qui me plait beaucoup: le MemoryFS qui permet de créer un filesystem en RAM. Sympa. Tu crées tes fichiers de travail, puis tu les traites de façon classique mais quand le programme s'arrête, les fichiers de travail disparaissent car ils étaient dans la RAM du process...

    Citation Envoyé par alex420 Voir le message
    Par contre je n'ai pas compris l'histoire de la redirection :
    Ben sur Unix/Linux, tu peux soit exécuter un programme en natif (et tout ce qu'il affiche va alors à l'écran), soit l'exécuter en redirigeant ses sorties vers un fichier (ex: ls -l >/tmp/result et tout ce qui s'affiche va alors dans le fichier.
    Théoriquement ça fonctionne quel que soit le programme que tu exécutes (lui il n'est même pas au courant que tu le rediriges, c'est le noyau Unix qui gère ça). Sauf que quand j'ai commencé à coder en python2 et que j'ai commencé à me forcer à bosser en utf-8, je ne pouvais plus rediriger mes scripts vers un fichier. Même un simple print(u"ééé") fonctionnait à l'écran mais me sortait un UnicodeError dès que je demandais une redirection.
    Jusqu'à ce que je trouve sur le net quelqu'un qui parle de ce souci et donne ce petit bout de code pour le résoudre.
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  5. #5
    Membre du Club
    Homme Profil pro
    Apprenti
    Inscrit en
    Mars 2018
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Apprenti
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2018
    Messages : 7
    Par défaut
    En fait le fichier que je doit traiter est donné en utf-16 (ce fichier est généré par un logiciel sur lequel je n'ai pas la main) et j'ai le droit de le modifier qu'à l'aide un script.
    J'avais déjà convertit le fichier en utf-8 avec ce code :
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    with codecs.open(fichier_txt, "r", "utf-16") as fichierSource, codecs.open(fichier_temporaire, "w", "utf-8") as fichierCible:
      while True:
        contenu = fichierSource.read()
        if not contenu:
          break
        fichierCible.write(contenu)
    Je l'ai donc remplacé par ce code pour voir si il y avait une différence :
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    with codecs.open(fichier_txt, "r", encoding="utf-16") as fichierSource, open(fichier_temporaire, "w") as fichierCible:
      for ligne in fichierSource:
        fichierCible.write(ligne)
    J'obtient cette erreur :
    Code erreur : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
     Error in sys.excepthook: Traceback (most recent call last): File "/usr/lib/python3.4/cgitb.py", line 268, in __call__ self.handle((etype, evalue, etb)) File "/usr/lib/python3.4/cgitb.py", line 288, in handle self.file.write(doc + '\n') UnicodeEncodeError: 'ascii' codec can't encode character '\xe9' in position 2540: ordinal not in range(128) Original exception was: Traceback (most recent call last): File "/usr/lib/cgi-bin/delete.py", line 34, in fichierCible.write(ligne) UnicodeEncodeError: 'ascii' codec can't encode character '\xe9' in position 28: ordinal not in range(128)
    Le fichier utilisé ne contient que le caractère "é". Même le fichier convertit en utf-8, le programme bloque sur les accents.

    Si j'ai bien compris, les redirections sont là pour afficher les messages (d'erreurs, print() ou trucs du genre) ou enregistrer ces messages dans un fichier. Je débute avec Linux donc j'ai du mal avec ces points techniques.
    Au final je n'ai pas besoin d'afficher quoi que ce soit, c'est juste lors du test de l'application.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. utiliser django avec cgi
    Par andtwoturtles dans le forum Django
    Réponses: 12
    Dernier message: 13/01/2010, 17h36
  2. Utiliser le resultat d'une <FORM> avec CGI
    Par jmricatt dans le forum Web
    Réponses: 3
    Dernier message: 12/12/2009, 15h18
  3. Réponses: 0
    Dernier message: 16/04/2009, 11h18
  4. probleme avec CGI script
    Par keith166 dans le forum Apache
    Réponses: 3
    Dernier message: 16/08/2008, 20h48
  5. Erreur 500 avec CGI
    Par Neuromancien2 dans le forum Apache
    Réponses: 2
    Dernier message: 09/08/2008, 20h40

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo