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 :

Comment récupérer dans le code l'encodage de la page (ligne coding)?


Sujet :

Python

  1. #1
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 461
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 461
    Points : 9 248
    Points
    9 248
    Billets dans le blog
    6
    Par défaut Comment récupérer dans le code l'encodage de la page (ligne coding)?
    Bonjour,

    En haut de toutes les pages de code python, je place la ligne coding classique. Et comme je travaille en utf-8, je mets:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    # -*- coding: utf-8 -*-
    Cela renseigne Python sur l'encodage des chaines codées en dur dans la page (page éditée et enregistrée avec cet encodage, bien entendu!).

    Je cherche à récupérer cet encodage (ici 'utf-8') dans le code Python. Actuellement, je crée une variable globale qui répète l'encodage, et je ne trouve pas ça élégant (en plus, c'est un risque d'erreur).

    Quelqu'un sait-il comment faire?

    Merci d'avance.

    Tyrtamos
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

  2. #2
    Membre habitué
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    141
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mai 2008
    Messages : 141
    Points : 184
    Points
    184
    Par défaut
    Salut !

    Une regexp qui lit la ligne de l'encodage et te retourne la valeur qui va bien (pas de problème de lock, le code tourne depuis "spam.pyc" et parse le fichier "spam.py"... un peut tortueux, toutefois).

    Sinon, j'ai vu que les objets fichiers disposent d'un attribut encoding, mais mon premier test ne s'avère pas concluant (ce qui ne veut pas dire que la piste n'est pas bonne, juste que je ne l'ai pas approfondie).

    Je sais aussi qu'on peut récupérer l'encodage du shell (sys.stdout.encoding), mais ça m'étonnerait que ça te serve.

  3. #3
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 461
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 461
    Points : 9 248
    Points
    9 248
    Billets dans le blog
    6
    Par défaut
    Bonjour.

    Merci de la réponse!

    Citation Envoyé par nardo47 Voir le message
    Une regexp qui lit la ligne de l'encodage et te retourne la valeur qui va bien (pas de problème de lock, le code tourne depuis "spam.pyc" et parse le fichier "spam.py"... un peut tortueux, toutefois).
    Ah oui, pas mal l'idée de faire relire le code pendant son exécution. Mais ce n'est guère plus élégant que ma variable globale...

    Citation Envoyé par nardo47 Voir le message
    Je sais aussi qu'on peut récupérer l'encodage du shell (sys.stdout.encoding), mais ça m'étonnerait que ça te serve.
    Eh oui, contrairement à ce qu'on peut lire ici ou là (y compris dans la FAQ), l'encodage de la console d'affichage ne renseigne pas sur l'encodage de la page du code Python.


    Je viens de trouver une idée de solution, limitée à la découverte de l'un ou l'autre des encodages courants: iso-8859-1/latin1, iso-8859-15, cp1252, cp850, utf-8. C'est adaptable à d'autres encodages à condition de trouver un caractère qui permet la distinction. Et si le code déclenche une exception, c'est que l'encodage ne supporte pas autre chose que l'ASCII.

    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
     
    def quelcoding():
        """Trouve l'encodage de la page contenant le script Python"""
        try:
            if "é" == u"é".encode('iso-8859-1'):
                try:
                    if "€" == u"€".encode('iso-8859-15'):
                        coding = 'iso-8859-15'
                    else:
                        coding = 'cp1252'
                except:
                    # le sigle euro n'existe pas: c'est donc l'iso-8859-1'
                    coding = 'iso-8859-1'    # idem latin1
            elif "é" == u"é".encode('cp850'):
                coding = 'cp850'
            elif "é" == u"é".encode('utf-8'):
                coding = 'utf-8'
            else:
                # Encodage de la page non trouvé
                coding =  'iso-8859-1'  # encodage arbitraire: on peut mettre autre chose!    except:
        except:
            coding = 'ASCII'    
        return coding
    Utilisation:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    coding = quelcoding()
    Exemples de résultat (attention: les pages doivent être éditées et enregistrées avec le même encodage que celui marqué dans la ligne de coding du début de la page!):

    - avec "# -*- coding: utf-8 -*-" => renvoie utf-8

    - avec "# -*- coding: cp1252 -*-" => renvoie cp1252

    - etc... (je ne l'ai pas testé dans tous les cas possibles, et il est possible qu'il y ait encore des bugs!)


    Mais bon. Je préfèrerais accéder à une variable Python qui donne le même résultat...

    Je laisse le fil ouvert: j'aimerais une solution plus simple!

    Tyrtamos
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

  4. #4
    Membre habitué
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    141
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mai 2008
    Messages : 141
    Points : 184
    Points
    184
    Par défaut
    Woaw !

    Toujours pas d'idée + précise, mais un conseil sur ta fonction : essaie de placer tes caractères et tes encoding dans un dictionnaires, sur lequel tu itéreras.
    Ca devrait alléger le code, et surtout le rendre facilement extensible (pour peu que l'on ne doive pas changer l'enchaînement des tests).
    Attention, je n'ai pas dit que c'était évident ou facile !
    Cela dit, c'est vraiment un voeu pieux, étant donné qu'on a des exceptions à gérer. Tu peux oublier, sauf si tu veux vraiment te prendre la tête.

    Vu que j'ai ma casquette d'inspecteur des travaux finis, j'en profite aussi pour te faire remarquer que tu dois réécrire (le copier/coller, c'est le mal ) cette fonction dans chaque fichier que tu veux tester ainsi.
    C'eut été mieux d'avoir cette fonction dans un module à part, mais je ne vois pas comment faire, vu la façon dont la fonction est écrite.

    Troisième remarque du gusse qui n'en fous pas 1 mais qui critique :
    le except tout seul, c'est le mal (bis repetitae)

    Bon, je reviens sur mon idée de regexp : il me semble que les commentaires ne sont pas conservés dans le fichier .pyc.
    Par contre, les docstrings sont conservés, il serait possible d'indiquer l'encodage la-dedans (mais c'est encore une redondance dont on se passerait bien).

    ...
    ...
    ...
    On me crie dans l'oreillette que je dis n'importe quoi sur les commentaires

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    >>> with open('spam.py', mode='w') as f:
    ...     f.write('# -*- coding: utf-8 -*-\n')
    ...     f.write('\n')
    ...     f.write('#A useless comment\n')
    ...     f.write('def myfunction(): pass\n')
    ...
    >>> import spam
    >>> import inspect
    >>> inspect.getcomments(spam.myfunction)
    'A useless comment\n'
    >>> inspect.getcomments(spam)
    '# -*- coding: utf-8 -*-\n'
    Problème : je ne vois pas comment passer le module en argument de la fonction getcomments depuis l'intérieur du module. J'ai bien pensé à l'attribut __name__, mais comme cet attribut est une string, ...

    ...
    ...

    Bon, je crois que c'est foutu => lu dans le Unicode HOWTO officiel : Python looks for "coding: name" or "coding=name" in the comment.
    CQFD.

    Je crois que ta méthode est la meilleure pour le cas qui t'intéresse.

  5. #5
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 461
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 461
    Points : 9 248
    Points
    9 248
    Billets dans le blog
    6
    Par défaut
    Comme ton idée du module "inspect" m'amusait, j'ai creusé un peu, ce qui m'a amené au code suivant (oui, j'ai honte ):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    #!/usr/bin/python
    # -*- coding:utf-8 -*-
    import sys
    import os
     
    import inspect
    nf = os.path.splitext(os.path.basename(sys.argv[0]))[0]
    exec("import " + nf)
    com = eval("inspect.getcomments(" + nf + ")")
    coding = com.split(' ')[2].split(':')[1]
    print coding
    Ce qui affiche bien l'utf-8!!! et les autres coding lorsqu'ils sont cités à la place.

    Mais ce qui ne marche pas, c'est que l'importation du script déclenche une première exécution du script lui-même qui s'exécutera donc 2 fois!!!


    Sinon, merci pour tes autres idées:

    - la solution du dictionnaire serait ok si tous les tests étaient de 1er niveau.

    - ok pour le except tout seul =

    - etc...

    Finalement, ma solution avec la variable globale n'était pas si mauvaise que ça (même si c'est aussi)

    En résumé, soit quelqu'un me donne une variable cachée de Python qui me fournit le coding, soit je continue avec ma variable globale.

    Une idée?

    Tyrtamos
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

  6. #6
    Membre habitué
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    141
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mai 2008
    Messages : 141
    Points : 184
    Points
    184
    Par défaut
    Citation Envoyé par tyrtamos Voir le message
    Comme ton idée du module "inspect" m'amusait, j'ai creusé un peu, ce qui m'a amené au code suivant (oui, j'ai honte ):
    Pas de quoi avoir honte, je trouve ça intéressant comme démarche. L'imagination n'a pas de limite...
    En prime, j'ai enfin vu un cas d'utilisation de eval que je comprends (càd, avec un contexte).

    Citation Envoyé par tyrtamos Voir le message
    Mais ce qui ne marche pas, c'est que l'importation du script déclenche une première exécution du script lui-même qui s'exécutera donc 2 fois!!!
    Ca, c'est pas glop du tout. Tant pis.

    Citation Envoyé par tyrtamos Voir le message
    Finalement, ma solution avec la variable globale n'était pas si mauvaise que ça (même si c'est aussi)
    Mais finalement, la variable globale, c'est comme tout "quand il y en a 1, ça va. C'est quand il y en a beaucoup qu'il y a des problèmes".

    Trêve de citations, les variables globales ne sont pas interdites. Elles existent, on peut les utiliser.
    Après, c'est toujours une tâche en + en cas de modification : changer l'encoding ET la globale, pfff... l'informatique, c'est censé automatiser les tâches répétitives, pourtant.

    Remarque : placer un test dans la docstring du module permet de ne pas oublier (ou plutôt, de se faire rappeler) qu'il y a 2 choses à changer.
    C'est la meilleure soluce que j'ai, mais si quelqu'un a une autre idée, je suis preneur aussi.

  7. #7
    Membre habitué
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    141
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mai 2008
    Messages : 141
    Points : 184
    Points
    184
    Par défaut
    Pendant ma lecture du chapitre sur la portée des variables dans "Learning Python", j'ai vu ça:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    sys.modules['nomdupackage']
    ce qui m'a donné envie de faire ça:

    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
     
    # codage.py
    # -*- coding: utf-8 -*-
    # TODO: récupérer l'encodage
     
    import sys, os, inspect
     
    if __name__ != '__main__':
        module = sys.modules[__name__]
        comment = inspect.getcomments(module)
        print comment
    # fin codage.py
     
    $ python codage.py
    $ python
    >>> import codage
    # -*- coding: utf-8 -*-
    # TODO: récupérer l'encodage
    Ce qui est certes intéressant, mais ça ne marche que quand le fichier est importé, pas quand il est exécuté directement. D'ailleurs, dans ce dernier cas, on est obligé de récupérer le nom de module comme tu l'as fait et en +, il n'est pas considéré comme chargé dans le dictionnaire sys.modules.
    Mais je trouvais ce code intéressant.

    Pendant que j'y suis, ce chapitre sur les globales m'a permis de clarifier mon point de vue sur les globales :
    Les globales c'est le mal quand on les modifie !

  8. #8
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 461
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 461
    Points : 9 248
    Points
    9 248
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    On peut ajouter des variables qui soient accessibles à tout le code sans être "globales". Voilà ci-dessous un code qui initialise tous les encodages utiles (on peut en ajouter d'autres):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    #!/usr/bin/python
    # -*- coding:utf-8 -*-
    import sys
     
    class Cod(object):
        def __init__(self):
            self.coding = 'utf-8'  # idem ligne coding en haut de page
            self.codin = sys.stdin.encoding
            self.codout = sys.stdout.encoding
            self.codisk = sys.getfilesystemencoding()
     
    cod = Cod()
    Utilisation:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    print cod.coding
    print cod.codin
    print cod.codout
    print cod.codisk
    Ce qui, dans une console DOS de Windows donne:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    utf-8
    cp850
    cp850
    mbcs
    Un des avantages de cette solution, c'est qu'on peut instancier une autre variable avec d'autres valeurs pour coller avec un autre contexte, sans perdre pour autant ce qu'on a défini au départ. On peut aussi passer facilement la variable comme paramètre d'une fonction pour transmettre d'un seul coup le contexte des encodage E/S.

    Cette solution est, bien entendu, généralisable à n'importe quelles autres variables que l'on veut accessibles à tout le code.

    Tyrtamos
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

  9. #9
    Expert confirmé Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Points : 4 005
    Points
    4 005
    Par défaut
    Bonjour,

    Et un simple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #!/usr/bin/python
    # -*- coding:cp850 -*-
    import sys
    import os.path
     
    f = open(os.path.join(os.getcwd(), sys.argv[0]))
    for ligne in (result for result in f if 'coding' in result):
            coding = ligne.split(' ')[2].split(':')[1]
            print coding
            f.close()
            break
    ?

    @+
    Merci d'utiliser le forum pour les questions techniques.

  10. #10
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 461
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 461
    Points : 9 248
    Points
    9 248
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    Ah oui, tant qu'à lire le script qui est en train de s'exécuter...

    Voilà la même en une ligne:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    coding = [ligne for ligne in open(os.path.abspath(sys.argv[0])) if 'coding' in ligne][0].split(' ')[2].split(':')[1]
    Pour que ça marche, il ne faut pas qu'il y ait un espace entre 'coding:' et l'encodage. Sinon, il faudrait changer la formule.

    Cela suppose aussi que le code .py est là, même si c'est le .pyc qui s'exécute.

    Et, bien sûr, l'absence de la ligne coding plante le programme.

    En l'absence d'une variable système Python qui donnerait le résultat, c'est probablement la meilleure solution (en plus de la variable globale).

    Merci!

    Tyrtamos
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

  11. #11
    Expert confirmé Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Points : 4 005
    Points
    4 005
    Par défaut
    Citation Envoyé par tyrtamos Voir le message
    Pour que ça marche, il ne faut pas qu'il y ait un espace entre 'coding:' et l'encodage. Sinon, il faudrait changer la formule.
    Il suffit de tester les deux cas, c'est les seuls possibles.

    Citation Envoyé par tyrtamos Voir le message
    Et, bien sûr, l'absence de la ligne coding plante le programme.
    Se limiter à la lecture de la deuxième ligne de code (la seule possible) évite le plantage.

    Citation Envoyé par tyrtamos Voir le message
    Cela suppose aussi que le code .py est là, même si c'est le .pyc qui s'exécute.
    Pas de réponse

    @+
    Merci d'utiliser le forum pour les questions techniques.

Discussions similaires

  1. Réponses: 4
    Dernier message: 13/02/2018, 14h47
  2. Réponses: 0
    Dernier message: 20/05/2010, 17h13
  3. Réponses: 5
    Dernier message: 08/03/2010, 14h09
  4. [VB.Net] Comment récupérer dans un textbox une donnée BDD ?
    Par zzzmoi dans le forum Accès aux données
    Réponses: 10
    Dernier message: 08/07/2007, 02h08
  5. Réponses: 2
    Dernier message: 11/12/2006, 12h38

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