Ich möchte den Python-Quellcode programmgesteuert bearbeiten. Grundsätzlich möchte ich eine .py
Datei lesen , den AST generieren und dann den geänderten Python-Quellcode (dh eine andere .py
Datei) zurückschreiben .
Es gibt Möglichkeiten, Python-Quellcode mithilfe von Standard-Python-Modulen wie ast
oder zu analysieren / kompilieren compiler
. Ich glaube jedoch nicht, dass einer von ihnen Möglichkeiten unterstützt, den Quellcode zu ändern (z. B. diese Funktionsdeklaration zu löschen) und dann den modifizierenden Python-Quellcode zurückzuschreiben.
UPDATE: Der Grund, warum ich dies tun möchte, ist, dass ich eine Mutationstestbibliothek für Python schreiben möchte , hauptsächlich indem ich Anweisungen / Ausdrücke lösche, Tests erneut ausführe und sehe, was kaputt geht.
Antworten:
Pythoscope führt dies für die Testfälle aus, die automatisch generiert werden, ebenso wie das 2to3- Tool für Python 2.6 (es konvertiert die Python 2.x-Quelle in die Python 3.x-Quelle).
Beide Tools verwenden die lib2to3- Bibliothek, eine Implementierung der Python-Parser / Compiler-Maschinerie, mit der Kommentare in der Quelle beibehalten werden können, wenn sie aus der Quelle -> AST -> Quelle ausgelöst wird.
Das Seilprojekt kann Ihren Anforderungen entsprechen, wenn Sie mehr Refactoring wie Transformationen durchführen möchten.
Das ast- Modul ist Ihre andere Option, und es gibt ein älteres Beispiel dafür, wie Syntaxbäume (mithilfe des Parser-Moduls) wieder in Code "analysiert" werden . Das
ast
Modul ist jedoch nützlicher, wenn eine AST-Transformation für Code durchgeführt wird, der dann in ein Codeobjekt umgewandelt wird.Das Redbaron- Projekt könnte auch gut passen (ht Xavier Combelle)
quelle
unparse.py
Skript kann es sehr umständlich sein, es aus einem anderen Skript zu verwenden. Aber es gibt ein Paket namens Astunparse ( auf Github , auf Pypi ), das im Grunde eine richtig verpackte Version von istunparse.py
.Das eingebaute Ast-Modul scheint keine Methode zum Zurückkonvertieren in die Quelle zu haben. Das Codegen- Modul hier bietet jedoch einen hübschen Drucker für den Ast, mit dem Sie dies tun können. z.B.
Dies wird gedruckt:
Beachten Sie, dass Sie möglicherweise die genaue Formatierung und die Kommentare verlieren, da diese nicht erhalten bleiben.
Möglicherweise müssen Sie dies jedoch nicht. Wenn Sie lediglich den ersetzten AST ausführen müssen, können Sie dies einfach tun, indem Sie compile () auf dem ast aufrufen und das resultierende Codeobjekt ausführen.
quelle
Möglicherweise müssen Sie den Quellcode nicht neu generieren. Das ist natürlich ein bisschen gefährlich für mich, da Sie nicht erklärt haben, warum Sie denken, dass Sie eine .py-Datei voller Code generieren müssen. aber:
Wenn Sie eine .py-Datei generieren möchten, die tatsächlich verwendet wird, damit sie möglicherweise ein Formular ausfüllen und eine nützliche .py-Datei zum Einfügen in ihr Projekt erhalten können, möchten Sie sie nicht in eine AST- und eine AST-Datei ändern zurück, weil Sie
alle Formatierungenverlieren(denken Sie an die Leerzeilen, die Python so lesbar machen, indem Sie verwandte Zeilensätze zusammen gruppieren)( Astknoten habenlineno
undcol_offset
Attribute ). Stattdessen möchten Sie wahrscheinlich eine Vorlagen- Engine verwenden (die Django-Vorlagensprache soll beispielsweise das Vorlagen - Erstellen von Textdateien vereinfachen), um die .py-Datei anzupassen, oder die MetaPython- Erweiterung von Rick Copeland verwenden .Wenn Sie versuchen, während der Kompilierung eines Moduls Änderungen vorzunehmen, müssen Sie nicht vollständig zum Text zurückkehren. Sie können den AST einfach direkt kompilieren, anstatt ihn wieder in eine .py-Datei umzuwandeln.
Aber in fast jedem Fall versuchen Sie wahrscheinlich, etwas Dynamisches zu tun, das eine Sprache wie Python tatsächlich sehr einfach macht, ohne neue .py-Dateien zu schreiben! Wenn Sie Ihre Frage erweitern, um uns mitzuteilen, was Sie tatsächlich erreichen möchten, werden neue .py-Dateien wahrscheinlich überhaupt nicht in die Antwort einbezogen. Ich habe Hunderte von Python-Projekten gesehen, die Hunderte von realen Dingen ausgeführt haben, und kein einziges von ihnen musste jemals eine .py-Datei schreiben. Ich muss zugeben, ich bin ein bisschen skeptisch, dass Sie den ersten guten Anwendungsfall gefunden haben. :-)
Update: Nachdem Sie erklärt haben, was Sie tun möchten, wäre ich ohnehin versucht, nur mit dem AST zu arbeiten. Sie möchten mutieren, indem Sie nicht Zeilen einer Datei entfernen (was zu Halbanweisungen führen kann, die einfach mit einem SyntaxError sterben), sondern ganze Anweisungen - und wo kann man das besser tun als im AST?
quelle
In einer anderen Antwort schlug ich vor, das
astor
Paket zu verwenden, aber seitdem habe ich ein aktuelleres AST-Entparsing-Paket mit dem Namen gefundenastunparse
:Ich habe dies auf Python 3.5 getestet.
quelle
Das Parsen und Ändern der Codestruktur ist sicherlich mit Hilfe des
ast
Moduls möglich, und ich werde es gleich in einem Beispiel zeigen. Das Zurückschreiben des geänderten Quellcodes ist jedoch nicht nur mit demast
Modul möglich . Für diesen Job stehen andere Module zur Verfügung, z. B. eines hier .HINWEIS: Das folgende Beispiel kann als einführendes Tutorial zur Verwendung des
ast
Moduls behandelt werden. Eine umfassendere Anleitung zur Verwendung desast
Moduls finden Sie hier im Tutorial zu Green Tree Snakes und in der offiziellen Dokumentation zumast
Modul .Einführung in
ast
:Sie können den Python-Code (in Zeichenfolge dargestellt) analysieren, indem Sie einfach die API aufrufen
ast.parse()
. Dadurch wird das Handle an die AST-Struktur (Abstract Syntax Tree) zurückgegeben. Interessanterweise können Sie diese Struktur zurückkompilieren und wie oben gezeigt ausführen.Eine weitere sehr nützliche API ist die,
ast.dump()
die den gesamten AST in einer Zeichenfolgenform ausgibt. Es kann zur Überprüfung der Baumstruktur verwendet werden und ist beim Debuggen sehr hilfreich. Beispielsweise,Auf Python 2.7:
Auf Python 3.5:
Beachten Sie den Unterschied in der Syntax für die Druckanweisung in Python 2.7 gegenüber Python 3.5 und den Unterschied im Typ des AST-Knotens in den jeweiligen Bäumen.
So ändern Sie Code mithilfe von
ast
:Schauen wir uns nun ein Beispiel für die Änderung des Python-Codes nach
ast
Modulen an. Das Hauptwerkzeug zum Ändern der AST-Struktur istast.NodeTransformer
class. Wann immer jemand den AST ändern muss, muss er eine Unterklasse daraus erstellen und die Knotenumwandlung (en) entsprechend schreiben.In unserem Beispiel versuchen wir, ein einfaches Dienstprogramm zu schreiben, das die Python 2-Druckanweisungen in Python 3-Funktionsaufrufe umwandelt.
Dienstprogramm Print to Fun Call Converter drucken: print2to3.py:
Dieses Dienstprogramm kann für kleine Beispieldateien wie die folgende ausprobiert werden und sollte einwandfrei funktionieren.
Testeingabedatei: py2.py.
Bitte beachten Sie, dass die obige Transformation nur zu
ast
Lernzwecken dient und im realen Fall alle verschiedenen Szenarien betrachtet werden müssen, wie zprint " x is %s" % ("Hello Python")
.quelle
Ich habe kürzlich einen ziemlich stabilen (Kern ist wirklich gut getestet) und erweiterbaren Code erstellt, der Code aus dem
ast
Baum generiert : https://github.com/paluh/code-formatter .Ich verwende mein Projekt als Basis für ein kleines Vim-Plugin (das ich jeden Tag verwende), daher ist es mein Ziel, wirklich schönen und lesbaren Python-Code zu generieren.
PS Ich habe versucht zu erweitern,
codegen
aber die Architektur basiert auf derast.NodeVisitor
Schnittstelle, daher sind Formatierer (visitor_
Methoden) nur Funktionen. Ich fand diese Struktur ziemlich einschränkend und schwer zu optimieren (bei langen und verschachtelten Ausdrücken ist es einfacher, den Objektbaum beizubehalten und einige Teilergebnisse zwischenzuspeichern - auf andere Weise können Sie die exponentielle Komplexität erreichen, wenn Sie nach dem besten Layout suchen möchten). ABERcodegen
da jedes Stück von Mitsuhikos Werk (das ich gelesen habe) sehr gut geschrieben und prägnant ist.quelle
Eine der anderen Antworten empfiehlt
codegen
, die von abgelöst worden zu sein scheintastor
. Die Version vonastor
on PyPI (Version 0.5 zum Zeitpunkt dieses Schreibens) scheint ebenfalls etwas veraltet zu sein, sodass Sie die Entwicklungsversion vonastor
wie folgt installieren können .Anschließend können Sie
astor.to_source
einen Python AST in lesbaren Python-Quellcode konvertieren:Ich habe dies auf Python 3.5 getestet.
quelle
Wenn Sie sich dies 2019 ansehen, können Sie dieses libcst- Paket verwenden. Es hat eine ähnliche Syntax wie ast. Dies funktioniert wie ein Zauber und behält die Codestruktur bei. Es ist grundsätzlich hilfreich für das Projekt, bei dem Sie Kommentare, Leerzeichen, Zeilenumbrüche usw. beibehalten müssen.
Wenn Sie sich nicht um die Beibehaltung von Kommentaren, Leerzeichen und anderen kümmern müssen, funktioniert die Kombination von Ast und Astor gut.
quelle
Wir hatten ein ähnliches Bedürfnis, das durch andere Antworten hier nicht gelöst wurde. Deshalb haben wir hierfür eine Bibliothek erstellt, ASTTokens , die einen mit den Ast- oder Astroid- Modulen erstellten AST-Baum verwendet und ihn mit den Textbereichen im ursprünglichen Quellcode markiert.
Code wird nicht direkt geändert, aber das ist nicht schwer hinzuzufügen, da es Ihnen den Textbereich angibt, den Sie ändern müssen.
Dies schließt beispielsweise einen Funktionsaufruf ein
WRAP(...)
, wobei Kommentare und alles andere erhalten bleiben:Produziert:
Hoffe das hilft!
quelle
Ein Programmtransformationssystem ist ein Tool, das Quelltext analysiert, ASTs erstellt und es Ihnen ermöglicht, sie mithilfe von Quell-zu-Quell-Transformationen zu ändern ("Wenn Sie dieses Muster sehen, ersetzen Sie es durch dieses Muster"). Solche Tools sind ideal für die Mutation vorhandener Quellcodes, die nur "Wenn Sie dieses Muster sehen, durch eine Mustervariante ersetzen" sind.
Natürlich benötigen Sie eine Programmtransformations-Engine, die die für Sie interessante Sprache analysieren und dennoch die mustergesteuerten Transformationen durchführen kann. Unser DMS Software Reengineering Toolkit ist ein System, das dies kann und Python und eine Vielzahl anderer Sprachen verarbeitet.
In dieser SO-Antwort finden Sie ein Beispiel für einen DMS-analysierten AST für Python, der Kommentare genau erfasst . DMS kann Änderungen am AST vornehmen und gültigen Text einschließlich der Kommentare neu generieren. Sie können ihn bitten, den AST mit seinen eigenen Formatierungskonventionen zu drucken (Sie können diese ändern) oder "Fidelity Printing" ausführen, bei dem die ursprünglichen Zeilen- und Spalteninformationen verwendet werden, um das ursprüngliche Layout maximal beizubehalten (einige Änderungen im Layout, wenn neuer Code verwendet wird) eingefügt ist unvermeidlich).
Um eine "Mutations" -Regel für Python mit DMS zu implementieren, können Sie Folgendes schreiben:
Diese Regel ersetzt "+" syntaktisch korrekt durch "-". Es arbeitet mit dem AST und berührt daher keine Zeichenfolgen oder Kommentare, die zufällig richtig aussehen. Die zusätzliche Bedingung für "mutate_this_place" besteht darin, dass Sie steuern können, wie oft dies auftritt. Sie möchten nicht jeden Ort im Programm mutieren .
Offensichtlich möchten Sie eine Reihe weiterer Regeln wie diese, die verschiedene Codestrukturen erkennen und durch mutierte Versionen ersetzen. DMS wendet gerne eine Reihe von Regeln an. Der mutierte AST wird dann hübsch gedruckt.
quelle
Ich habe früher Baron dafür verwendet, bin jetzt aber zu Parso gewechselt, weil es mit modernem Python auf dem neuesten Stand ist. Es funktioniert großartig.
Ich brauchte das auch für einen Mutationstester. Es ist wirklich ganz einfach, eine mit parso zu erstellen. Schauen Sie sich meinen Code unter https://github.com/boxed/mutmut an
quelle