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 :

Hybride pour récupérer les docstrings d'un fichier Python


Sujet :

Python

  1. #1
    Membre éprouvé

    Profil pro
    Account Manager
    Inscrit en
    Décembre 2006
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Account Manager

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 301
    Par défaut Hybride pour récupérer les docstrings d'un fichier Python
    Bonjour,
    pour le plaisir, mais aussi par nécessité, je me suis lancé dans la création d'un outil pour récupérer les docstrings d'un fichier Python. Voici un 1er brouillon qui montre les grandes lignes :
    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
    51
    #! /usr/bin/env python3
     
    # Source :
    #    http://docs.python.org/py3k/library/ast.html
    #    http://pypi.python.org/pypi/pyRegurgitator/0.1.1
     
    import ast
     
    IaNDENT_INCREASE = 4
     
    def astStupidPrint(oneNode):
        """To quickly see what is done by the module "ast"."""
        for oneNode in ast.iter_child_nodes(astTree):
            print('--', oneNode._fields, ast.dump(oneNode), sep="\n")
     
    def docstringPrint(oneNode, indentLevel = -INDENT_INCREASE, className = '', infoToPrint = ''):
        #print(type(oneNode))
     
        if isinstance(oneNode, ast.Expr) and isinstance(oneNode.value, ast.Str):
            print(' '*indentLevel + '=== DOCSTRING {} ==='.format(infoToPrint),
                  ' '*(indentLevel + INDENT_INCREASE) + oneNode.value.s.replace('\n',
                                                                          '\n' + ' '*(indentLevel + INDENT_INCREASE)),
                  sep="\n")
     
        elif 'body' in oneNode._fields:
            if isinstance(oneNode, ast.FunctionDef):
                if className:
                    infoToPrint = 'METHOD OF "{0}" :: {1}'.format(className,
                                                                  oneNode.name)
                else:
                    infoToPrint = 'FUNCTION :: ' + oneNode.name
            elif isinstance(oneNode, ast.ClassDef):
                infoToPrint = 'CLASS :: ' + oneNode.name
                className = oneNode.name
            else:
                infoToPrint = 'CURRENT MODULE OR FILE'
     
            content = getattr(oneNode, 'body')
            if content:
                for onePiece in content:
                    docstringPrint(oneNode = onePiece,
                                   indentLevel = indentLevel + INDENT_INCREASE,
                                   className = className,
                                   infoToPrint = infoToPrint)
     
    if __name__ == '__main__':
        file = open('test.py')
        astTree = ast.parse(file.read())
    #    astStupidPrint(astTree)
    #    print()
        docstringPrint(astTree)
    Le fichier test.py est le suivant :
    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
    #! /usr/bin/env python3
     
    """1ère doc du fichier
    sur deux lignes"""
     
    def myFunction(x=0, y="1"):
        """Doc de la fonction nommée myFunction"""
        x=3
    # Un commentaire.
        z = x+y
        return z
     
    """2nde docstring mal placée..."""
     
    print(myFunction(5,6))
     
    class bidon():
        """Doc de la classe bidon"""
     
        def __init__(self):
            """1ère doc de la méthode __init__ de la classe bidon"""
            ...
            """2ème doc mal placée de la méthode __init__"""
    Ceci me renvoie :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    === DOCSTRING CURRENT MODULE OR FILE ===
        1ère doc du fichier
        sur deux lignes
        === DOCSTRING FUNCTION :: myFunction ===
            Doc de la fonction nommée myFunction
    === DOCSTRING CURRENT MODULE OR FILE ===
        2nde docstring mal placée...
        === DOCSTRING CLASS :: bidon ===
            Doc de la classe bidon
            === DOCSTRING METHOD OF "bidon" :: __init__ ===
                1ère doc de la méthode __init__ de la classe bidon
            === DOCSTRING METHOD OF "bidon" :: __init__ ===
                2ème doc mal placée de la méthode __init__
    J'essaierais d'améliorer ceci pour obtenir un mini outil de documentation à la sauce epydoc mais en plus facile à personnaliser.

    De plus en ayant toutes les docstrings, on peut envisager un moyen de faire des tutos qui affichent le code morcelé avec entre chaque morceau des commentaires en ayant juste à taper quelque chose comme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    for i in range(5):
        print(i)
    """ Nous avons ici une première façon de taper une boucle..."""
    i = 0
    while(i < 5):
        print(i)
    """Voici une autre méthode pour obtenir le même résultat que précédemment..."""
    Ensuite un petit prog. Python donnerait la mise en forme suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    for i in range(5):
        print(i)
    Nous avons ici une première façon de taper une boucle...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    i = 0
    while(i < 5):
        print(i)
    Voici une autre méthode pour obtenir le même résultat que précédemment...
    PS : merci à nardo47 de m'avoir dirigé vers ast.

  2. #2
    Membre éprouvé

    Profil pro
    Account Manager
    Inscrit en
    Décembre 2006
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Account Manager

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 301
    Par défaut
    Pour la seconde fonctionnalité, en fait ast ne va pas être très utile car il ne grade pas la trace des numéros de ligne.

    Vous semble-t-il possible de faire cela quitte à surclasser quelque chose du module ast ? A défaut, ou puis-je proposer que cette fonctionnalité soit ajoutée ?

    Au pire, je peux toujours parser le fichier à la recherche des docstrings pour couper le fichier en parties à imprimer.

  3. #3
    Membre Expert
    Homme Profil pro
    Inscrit en
    Mars 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2007
    Messages : 941
    Par défaut
    Citation Envoyé par rambc Voir le message
    Pour la seconde fonctionnalité, en fait ast ne va pas être très utile car il ne grade pas la trace des numéros de ligne.
    Euh...
    Instances of ast.expr and ast.stmt subclasses have lineno and col_offset attributes. The lineno is the line number of source text (1-indexed so the first line is line 1) and the col_offset is the UTF-8 byte offset of the first token that generated the node.

  4. #4
    Membre éprouvé

    Profil pro
    Account Manager
    Inscrit en
    Décembre 2006
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Account Manager

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 301
    Par défaut
    Miam, miam... Merci d'avoir pointé mon ignorance. Je n'ai pas lu attentivement la doc, et je pensais que la méthode astStupidPrint affichait tout, comme quoi je l'ai bien nommée.

    Voici une version avec les numéros de ligne.
    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
    51
    52
    #! /usr/bin/env python3
     
    # Source :
    #    http://docs.python.org/py3k/library/ast.html
    #    http://pypi.python.org/pypi/pyRegurgitator/0.1.1
     
    import ast
     
    INDENT_INCREASE = 4
     
    def astStupidPrint(oneNode):
        """To quickly see what is done by the module "ast"."""
        for oneNode in ast.iter_child_nodes(astTree):
            print('--', oneNode._fields, ast.dump(oneNode), sep="\n")
     
    def docstringPrint(oneNode, indentLevel = -INDENT_INCREASE, className = '', infoToPrint = ''):
        #print(type(oneNode))
     
        if isinstance(oneNode, ast.Expr) and isinstance(oneNode.value, ast.Str):
            print(' '*indentLevel + '=== DOCSTRING {0} === Line :: {1}'.format(infoToPrint,
                                                                               oneNode.lineno),
                  ' '*(indentLevel + INDENT_INCREASE) + oneNode.value.s.replace('\n',
                                                                          '\n' + ' '*(indentLevel + INDENT_INCREASE)),
                  sep="\n")
     
        elif 'body' in oneNode._fields:
            if isinstance(oneNode, ast.FunctionDef):
                if className:
                    infoToPrint = 'METHOD OF "{0}" :: {1}'.format(className,
                                                                  oneNode.name)
                else:
                    infoToPrint = 'FUNCTION :: ' + oneNode.name
            elif isinstance(oneNode, ast.ClassDef):
                infoToPrint = 'CLASS :: ' + oneNode.name
                className = oneNode.name
            else:
                infoToPrint = 'CURRENT MODULE OR FILE'
     
            content = getattr(oneNode, 'body')
            if content:
                for onePiece in content:
                    docstringPrint(oneNode = onePiece,
                                   indentLevel = indentLevel + INDENT_INCREASE,
                                   className = className,
                                   infoToPrint = infoToPrint)
     
    if __name__ == '__main__':
        file = open('test.py')
        astTree = ast.parse(file.read())
    #    astStupidPrint(astTree)
    #    print()
        docstringPrint(astTree)

  5. #5
    Membre éprouvé

    Profil pro
    Account Manager
    Inscrit en
    Décembre 2006
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Account Manager

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 301
    Par défaut
    En fait,
    il faut quand même faire gaffe au fait que c'est la dernière ligne de la DocString et non la 1ère qui est choisie pour le numéro : en comptant le nombre de retour à la ligne on a le numéro de la ligne de départ.

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

Discussions similaires

  1. Réponses: 11
    Dernier message: 15/05/2014, 15h44
  2. Récupérer les contacts d'une fichier Excel pour l'envoi d'un Email
    Par taureau dans le forum Macros et VBA Excel
    Réponses: 0
    Dernier message: 17/03/2011, 22h19
  3. [XL-97] Comment récupérer les données d'un fichier PDF pour renseigner un tableau Excel
    Par jehhej dans le forum Macros et VBA Excel
    Réponses: 2
    Dernier message: 24/02/2010, 09h04
  4. Réponses: 1
    Dernier message: 30/04/2008, 15h09
  5. Réponses: 21
    Dernier message: 16/04/2008, 10h06

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