217 votes

Analyser un fichier .py, lire l'AST, le modifier, puis réécrire le code source modifié.

Je veux éditer de façon programmatique le code source de python. En gros, je veux lire un .py génère le fichier AST puis retranscrire le code source python modifié (c'est-à-dire un autre .py ).

Il existe des moyens d'analyser/compiler le code source python en utilisant les modules python standard, tels que ast o compiler . Cependant, je ne pense pas qu'aucun d'entre eux permette de modifier le code source (par exemple, supprimer cette déclaration de fonction) et de réécrire ensuite le code source python modifié.

UPDATE : La raison pour laquelle je veux faire cela est que j'aimerais écrire un Bibliothèque de tests de mutation pour python, principalement en supprimant les déclarations/expressions, en relançant les tests et en voyant ce qui se casse.

5 votes

Déclassé depuis la version 2.6 : le paquetage du compilateur a été supprimé dans Python 3.0.

1 votes

Pourquoi ne pouvez-vous pas modifier la source ? Pourquoi ne pouvez-vous pas écrire un décorateur ?

3 votes

La vache ! Je voulais faire un testeur de mutation pour python en utilisant la même technique (spécifiquement en créant un plugin de nez), prévois-tu de le mettre en open sourcing ?

86voto

Ryan Points 7423

Pythoscope le fait pour les scénarios de test qu'il génère automatiquement, tout comme le fait le programme 2 à 3 pour python 2.6 (il convertit les sources de python 2.x en sources de python 3.x).

Ces deux outils utilisent le lib2to3 qui est une implémentation de la machinerie de l'analyseur/compilateur de python qui peut préserver les commentaires dans la source lorsqu'il y a un aller-retour de la source -> AST -> source.

El projet de corde peut répondre à vos besoins si vous voulez faire plus de refactoring comme les transformations.

El ast est votre autre option, et Il existe un exemple plus ancien de la façon de "décortiquer" les arbres syntaxiques pour les retranscrire en code. (en utilisant le module d'analyse syntaxique). Mais le ast est plus utile lorsqu'on effectue une transformation AST sur du code qui est ensuite transformé en un objet code.

El redbaron peut également être un bon choix (ht Xavier Combelle)

6 votes

L'exemple unparse est toujours maintenu, voici la version py3k mise à jour : hg.python.org/cpython/log/tip/Tools/parser/unparse.py

2 votes

En ce qui concerne unparse.py script - il peut être vraiment encombrant de l'utiliser à partir d'un autre script. Mais, il existe un paquetage appelé astunparse ( sur github , sur pypi ) qui est en fait une version correctement emballée de unparse.py .

0 votes

Pourriez-vous peut-être mettre à jour votre réponse en ajoutant parso comme option préférée ? C'est très bien et mis à jour.

63voto

Brian Points 48423

Le module ast intégré ne semble pas disposer d'une méthode de conversion en source. Cependant, le module codegen Ce module fournit une jolie imprimante pour l'ast qui vous permettrait de le faire. par exemple.

import ast
import codegen

expr="""
def foo():
   print("hello world")
"""
p=ast.parse(expr)

p.body[0].body = [ ast.parse("return 42").body[0] ] # Replace function body with "return 42"

print(codegen.to_source(p))

Cela va s'imprimer :

def foo():
    return 42

Notez que vous risquez de perdre le formatage et les commentaires exacts, car ceux-ci ne sont pas conservés.

Cependant, il se peut que vous n'en ayez pas besoin. Si tout ce dont vous avez besoin est d'exécuter l'AST remplacé, vous pouvez le faire simplement en appelant compile() sur l'ast, et en exécutant l'objet de code résultant.

21 votes

Pour tous ceux qui l'utiliseront à l'avenir, codegen est largement dépassé et comporte quelques bogues. J'en ai corrigé quelques-uns ; j'ai mis cela sous forme de gist sur github : gist.github.com/791312

0 votes

Remarquez que le dernier codegen est mis à jour en 2012, ce qui est après le commentaire ci-dessus, donc je suppose que le codegen est mis à jour. @mattbasta

6 votes

astor semble être un successeur maintenu de codegen

19voto

Brandon Rhodes Points 21188

Vous n'aurez peut-être pas besoin de générer à nouveau le code source. C'est un peu dangereux pour moi de dire cela, bien sûr, puisque vous n'avez pas expliqué pourquoi vous pensez avoir besoin de générer un fichier .py plein de code, mais.. :

  • Si vous voulez générer un fichier .py que les gens utiliseront réellement, peut-être pour qu'ils puissent remplir un formulaire et obtenir un fichier .py utile à insérer dans leur projet, alors vous ne voulez pas le changer en AST et inversement parce que vous perdrez tout le formatage (pensez aux lignes vides qui rendent Python si lisible en regroupant des ensembles de lignes apparentées) ( es nœuds ont lineno y col_offset attributs ). Au lieu de cela, vous voudrez probablement utiliser un moteur de modèles (la fonction Langage de template Django par exemple, est conçu pour faciliter la création de modèles, même pour les fichiers texte) pour personnaliser le fichier .py, ou bien utiliser le logiciel de Rick Copeland MetaPython extension.

  • Si vous essayez d'apporter une modification pendant la compilation d'un module, notez que vous n'avez pas besoin de revenir au texte ; vous pouvez simplement compiler l'AST directement au lieu de le transformer en un fichier .py.

  • Mais dans presque tous les cas, vous essayez probablement de faire quelque chose de dynamique qu'un langage comme Python rend très facile, sans écrire de nouveaux fichiers .py ! Si vous élargissez votre question pour nous faire savoir ce que vous voulez réellement accomplir, les nouveaux fichiers .py ne seront probablement pas du tout impliqués dans la réponse ; j'ai vu des centaines de projets Python faire des centaines de choses dans le monde réel, et pas un seul d'entre eux n'a eu besoin d'écrire un fichier .py. Je dois donc admettre que je suis un peu sceptique quant au fait que vous ayez trouvé le premier bon cas d'utilisation :-)

Mise à jour : maintenant que vous avez expliqué ce que vous essayez de faire, je serais tenté d'opérer simplement sur l'AST de toute façon. Vous voudrez muter en supprimant, non pas des lignes d'un fichier (ce qui pourrait aboutir à des demi-affirmations qui mourraient simplement avec une SyntaxError), mais des affirmations entières - et quel meilleur endroit pour le faire que dans l'AST ?

0 votes

Bon aperçu de la solution possible et des alternatives probables.

1 votes

Un cas réel d'utilisation pour la génération de code : Kid et Genshi (je crois) génèrent du Python à partir de modèles XML pour accélérer le rendu des pages dynamiques.

6voto

paluh Points 469

J'ai créé récemment un morceau de code assez stable (le noyau est vraiment bien testé) et extensible qui génère du code à partir des éléments suivants ast arbre : https://github.com/paluh/code-formatter .

J'utilise mon projet comme base pour un petit plugin vim (que j'utilise tous les jours), donc mon but est de générer un code python vraiment agréable et lisible.

P.S. J'ai essayé d'étendre codegen mais son architecture est basée sur ast.NodeVisitor de sorte que les formateurs ( visitor_ méthodes) ne sont que des fonctions. J'ai trouvé cette structure assez contraignante et difficile à optimiser (dans le cas d'expressions longues et imbriquées, il est plus facile de conserver l'arbre des objets et de mettre en cache certains résultats partiels - d'une autre manière, on peut atteindre une complexité exponentielle si l'on veut rechercher la meilleure disposition). MAIS codegen car tous les travaux de Mitsuhiko (que j'ai lus) sont très bien écrits et concis.

1voto

Ira Baxter Points 48153

A Système de transformation des programmes est un outil qui analyse le texte source, construit des AST, vous permet de les modifier en utilisant des transformations de source à source ("si vous voyez ce motif, remplacez-le par ce motif"). De tels outils sont idéaux pour effectuer des mutations de codes sources existants, qui sont simplement "si vous voyez ce motif, remplacez-le par une variante de motif".

Bien entendu, vous avez besoin d'un moteur de transformation de programmes capable d'analyser le langage qui vous intéresse, tout en effectuant les transformations dirigées par les motifs. Notre site Boîte à outils de réingénierie du logiciel DMS est un système qui peut faire cela, et qui gère Python, et une variété d'autres langages.

Voir ceci Réponse SO pour un exemple d'une AST analysée par DMS pour Python capturant des commentaires. avec précision. DMS peut apporter des modifications à l'AST, et régénérer un texte valide, y compris les commentaires. Vous pouvez lui demander d'imprimer l'AST en utilisant ses propres conventions de formatage (vous pouvez les modifier), ou de faire une "impression de fidélité", qui utilise les informations de ligne et de colonne d'origine pour préserver au maximum la mise en page d'origine (certains changements de mise en page sont inévitables lorsqu'un nouveau code est inséré).

Pour mettre en œuvre une règle de "mutation" pour Python avec DMS, vous pourriez écrire ce qui suit :

rule mutate_addition(s:sum, p:product):sum->sum =
  " \s + \p " -> " \s - \p"
 if mutate_this_place(s);

Cette règle remplace "+" par "-" d'une manière syntaxiquement correcte ; elle opère sur l'AST et ne touchera donc pas aux chaînes ou aux commentaires qui se trouvent être corrects. La condition supplémentaire sur "mutate_this_place" vous permet de contrôler la fréquence à laquelle cela se produit ; vous ne voulez pas muter les éléments suivants chaque place dans le programme.

Il est évident que vous voudriez un tas d'autres règles comme celle-ci qui détectent les différentes structures de code et les remplacent par les versions mutées. DMS est heureux d'appliquer un ensemble de règles. L'AST muté est alors prettyprinted.

0 votes

Je n'ai pas regardé cette réponse depuis 4 ans. Wow, elle a été rétrogradée plusieurs fois. C'est vraiment stupéfiant, car elle répond directement à la question du PO, et montre même comment faire les mutations qu'il veut faire. Je suppose qu'aucun de ceux qui ont été descendus ne souhaite expliquer pourquoi ils ont rétrogradé.

4 votes

Parce qu'elle fait la promotion d'un outil très coûteux et fermé.

0 votes

@ZoranPavlovic : Vous n'avez donc aucune objection quant à sa précision technique ou son utilité ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X