Forum Programmation.python str et encodage ASCII, unicode...

Posté par  . Licence CC By‑SA.
Étiquettes : aucune
0
15
août
2017

Je ne suis pas développeur Python, ni objet. Mais je dois rectifier un bug d'encodage assez simple et courant en Python 2.7 (suffit de parcourir Google). Il s'agit de ce genre de ligne qui reçoit un caractère unicode et plante (ordinal not in range):

values.update({'name':str(res.product_id.name)+" - "+str(xpak.pack_pro_id.name),})

C'est du Python 2.7. Je sais qu'il ne faut pas utiliser str et qu'il faudrait corriger en un truc avec encode('utf-8'), mais quand j'essaie ça provoque le même genre d'erreur (ascii demandé mais on reçoit unicode). Bref, j'ai essayé mais je ne sais pas faire…

  • # Besoin de plus de détails

    Posté par  . Évalué à 2.

    Il y a 2 types de données pour du texte en Python, str et unicode.
    encode('utf-8') va transformer un str en unicode (en assumant que la source est bien au format unicode), et decode('utf-8') va faire le contraire.

    Est-ce que tu sais de quel type sont res.product_id.name et xpak.pack_pro_id.name ? Et quel type tu attend dans ton objet values ?

    Est-ce que tu peux nous fournir l'erreur précise que tu reçoit ?

    • [^] # Re: Besoin de plus de détails

      Posté par  . Évalué à 2. Dernière modification le 15 août 2017 à 17:40.

      Merci pour ton aide.
      Non je ne sais pas de quel type ils sont. Le code ne l'indique pas. Comme ce sont des identifiants, je pense qu'ils ne sont pas unicode. Si je te comprend bien, il faut employer decode('utf-8')

      Voilà le message d'erreur avec str :

      UnicodeEncodeError: 'ascii' codec can't encode character u'\xee' in position 21: ordinal not in range(128)
      J'ai compris que c'était assez semblable à cette question sur Stackoverflow
      https://stackoverflow.com/questions/9942594/unicodeencodeerror-ascii-codec-cant-encode-character-u-xa0-in-position-20

      "La liberté est à l'homme ce que les ailes sont à l'oiseau" Jean-Pierre Rosnay

      • [^] # Re: Besoin de plus de détails

        Posté par  . Évalué à 2.

        Si les variables sont de type str contenant de l'UTF-8, c'est bien decode('utf-8') qu'il faut utiliser. Tu peux essayer:

        values.update({'name': res.product_id.name.decode('utf-8') + " - " + xpak.pack_pro_id.name.decode('utf-8')})
        
        # ou plus simple à écrire (code équivalent):
        values['name'] = res.product_id.name.decode('utf-8') + " - " + xpak.pack_pro_id.name.decode('utf-8')

        Mais au vu de l'erreur, je pense qu'elles sont déjà en unicode (et le cast en str() n'aime pas les caractères unicodes). Dans ce cas, si values['name'] attend bien de l'unicode, il ne devrait pas y avoir besoin de transformation.

        values['name'] = res.product_id.name + " - " + xpak.pack_pro_id.name

        Si les variables d'entrées sont en unicode mais values['name'] doit être en str, je te proposes ça:

        values['name'] = (res.product_id.name + " - " + xpak.pack_pro_id.name).encode('utf-8')

        Note que tout ces exemples ne fonctionneront qu'en Python 2.


        Tu peux admirer ici l'enfer de la gestion de l'encoding en Python. Certaines libs prennent uniquement des str en paramètre de leurs fonctions, d'autres uniquement des unicode. Pareil pour les valeurs de retour, le type varie suivant les libs, et parfois même les deux types peuvent être retournés. Dans 80% des cas, ça n'est pas documenté.

        • [^] # Re: Besoin de plus de détails

          Posté par  . Évalué à 2.

          C'est bizarre aucun de tes exemples ne résoud le problème. POurtant ça colle assez avec ce que j'ai lu par ailleurs.
          J'ai pensé à une faute de frappe pour le dernier et j'ai aussi essayé avec decode().

          "La liberté est à l'homme ce que les ailes sont à l'oiseau" Jean-Pierre Rosnay

          • [^] # Re: Besoin de plus de détails

            Posté par  . Évalué à 2.

            Il est possible que les données en entrée ne soient pas en UTF-8, ou bien qu'il y ait un bug ailleurs qui ne soit pas apparu avant. Sinon, je ne voit pas.
            L'un des gros inconvénients de l'unicode en Python, c'est que les exceptions n'apparaissent que quand on commence à utiliser des caractères non-ascii, c'est peut-être le 1er produit à avoir un nom avec des symboles non-ascii ?

            Est-ce que tu as un moyen d'afficher une valeur quelque part ? tu peux faire un print(type(res.product_id.name)) pour afficher le type réel.

            Si tu as un lien vers le code en question, je peux y jeter un coup d’œil.

            • [^] # Re: Besoin de plus de détails

              Posté par  . Évalué à 2.

              Si, je pense que les données d'entrées sont en utf-8 pance que ce sont des noms d'articles que j'ai rentrés.
              Voilà le lien pour le code, c'et un module Odoo, j'ai arrangé qq petites choses par rapport au truc original. Mais ça reste assez mal codé.
              https://github.com/zeroheure/odoo_pack_10
              Le fichier est models/pack.py, les problèmes commencent ligne 65.

              Et un gros MERCI, je n'en espérais pas tant!

              "La liberté est à l'homme ce que les ailes sont à l'oiseau" Jean-Pierre Rosnay

              • [^] # Re: Besoin de plus de détails

                Posté par  . Évalué à 2.

                J'ai regardé un peu, et j'avoue que je ne vois pas d’où peut venir le problème.
                Tu es sûr que tu as remplacé toutes les occurrences à chaque fois, sait-on jamais ? D'ailleurs, le code gagnerait fortement à être fortement à être refactorisé, on doit pouvoir le réduire de 3/4 facilement, mais je suppose que tu le sais.

                Ta meilleure chance est d'afficher toutes les valeurs (et leurs types) dans un try: ... except ... pour voir ce qu'il se passe.

                • [^] # Re: Besoin de plus de détails

                  Posté par  . Évalué à 2.

                  Je viens de faire un diff avec le code original (sur https://github.com/GaboSnader/odoo_pack_10/tree/master/odoo_pack), les différences viennent de la traduction que j'ai faite en anglais. Je n'ai rien touché d'autre.

                  Je sais bien que c'est un code pas terrible, venu d'un étudiant je crois, mais c'est le seul module libre pour Odoo 10 qui fasse ça. On utilise actuellement un module propriétaire beaucoup plus poussé, mais ce petit module rendrait service à pas mal de monde je pense, c'est pourquoi je l'ai testé, traduit et restructuré.

                  Merci pour ton aide en tout cas, je vais regarder les types.
                  Va falloir que je me mette à Python (10 ans que je le dis!).

                  "La liberté est à l'homme ce que les ailes sont à l'oiseau" Jean-Pierre Rosnay

                  • [^] # Re: Besoin de plus de détails

                    Posté par  . Évalué à 3.

                    Va falloir que je me mette à Python (10 ans que je le dis!).

                    Tu as essayé les formations sur coursera ou autres plateformes en ligne? C'est bien foutu pour démarrer.

                    Si tu travailles beaucoup avec odoo j'imagine que ca va bien t'aider de connaitre un peu de python.

  • # la bible

    Posté par  (site web personnel) . Évalué à 7.

  • # Voir les types

    Posté par  (site web personnel) . Évalué à 2.

    Afin de savoir ce que tu manipules, ajoutes temporairement un

    print type(res.product_id.name), type(xpak.pack_pro_id.name)

    Pour les fonctions d'encodage/décodage, en prenant une chaîne str (sans accent pour simplifier) et une chaîne unicode (avec un accent):

    >>> s = "chaine str"
    >>> s.decode('utf8')
    u'chaine str'
    
    >>> u = u"chaîne unicode"
    >>> u.encode('utf8')
    'cha\xc3\xaene unicode'
    
    

    À toi de voir si tes valeurs doivent être sous la forme de str encodant de l'utf8, ou bien d'unicode contenant directement les caractères accentués (ça dépend de l'usage que tu en as après).

    Une bonne raison de passer à Python3 :-)

    Votez les 30 juin et 7 juillet, en connaissance de cause. http://www.pointal.net/VotesDeputesRN

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.