Saya ingin mengedit kode sumber python secara terprogram. Pada dasarnya saya ingin membaca .py
file, menghasilkan AST , dan kemudian menulis kembali kode sumber python yang dimodifikasi (yaitu .py
file lain ).
Ada cara untuk mengurai / mengkompilasi kode sumber python menggunakan modul python standar, seperti ast
atau compiler
. Namun, saya rasa mereka tidak mendukung cara untuk memodifikasi kode sumber (mis. Hapus deklarasi fungsi ini) dan kemudian tulis kembali kode sumber python yang dimodifikasi.
UPDATE: Alasan saya ingin melakukan ini adalah saya ingin menulis perpustakaan pengujian mutasi untuk python, kebanyakan dengan menghapus pernyataan / ekspresi, tes rerunning dan melihat apa yang istirahat.
Jawaban:
Pythoscope melakukan ini untuk menguji kasus-kasus yang secara otomatis dihasilkan seperti halnya alat 2to3 untuk python 2.6 (itu mengubah sumber python 2.x menjadi sumber python 3.x).
Kedua alat ini menggunakan lib2to3 library yang merupakan implementasi dari mesin python parser / compiler yang dapat menyimpan komentar dalam sumber ketika itu bulat tersandung dari sumber -> AST -> sumber.
Proyek tali dapat memenuhi kebutuhan Anda jika Anda ingin melakukan lebih banyak refactoring seperti transformasi.
The ast modul pilihan lain, dan ada contoh yang lebih tua bagaimana pohon sintaks "unparse" kembali ke dalam kode (menggunakan modul parser). Tetapi
ast
modul ini lebih berguna ketika melakukan transformasi AST pada kode yang kemudian diubah menjadi objek kode.Proyek redbaron juga mungkin cocok (ht Xavier Combelle)
sumber
unparse.py
skrip - mungkin sangat sulit untuk menggunakannya dari skrip lain. Tapi, ada paket yang disebut astunparse ( di github , di pypi ) yang pada dasarnya merupakan versi paket yang benarunparse.py
.Modul bawaan sepertinya tidak memiliki metode untuk mengkonversi kembali ke sumber. Namun, modul codegen di sini menyediakan printer cantik untuk ast yang memungkinkan Anda melakukannya. misalnya.
Ini akan mencetak:
Perhatikan bahwa Anda mungkin kehilangan format dan komentar yang tepat, karena ini tidak dipertahankan.
Namun, Anda mungkin tidak perlu melakukannya. Jika semua yang Anda butuhkan adalah menjalankan AST yang diganti, Anda dapat melakukannya hanya dengan memanggil kompilasi () pada ast, dan mengeksekusi objek kode yang dihasilkan.
sumber
Dalam jawaban yang berbeda saya menyarankan menggunakan
astor
paket, tetapi sejak itu saya menemukan paket AST un-parsing yang lebih mutakhir bernamaastunparse
:Saya telah menguji ini di Python 3.5.
sumber
Anda mungkin tidak perlu membuat ulang kode sumber. Itu agak berbahaya bagi saya untuk mengatakan, tentu saja, karena Anda belum benar-benar menjelaskan mengapa Anda pikir Anda perlu menghasilkan file .py penuh kode; tapi:
Jika Anda ingin membuat file .py yang sebenarnya akan digunakan orang, mungkin sehingga mereka dapat mengisi formulir dan mendapatkan file .py yang berguna untuk dimasukkan ke dalam proyek mereka, maka Anda tidak ingin mengubahnya menjadi AST dan kembali karena Anda akan kehilangan
semua pemformatan (pikirkan baris kosong yang membuat Python begitu mudah dibaca dengan mengelompokkan kumpulan garis yang terkait bersama-sama)( komentar yang dimiliki nodelineno
dancol_offset
atribut ). Sebagai gantinya, Anda mungkin ingin menggunakan mesin templating ( bahasa template Django , misalnya, dirancang untuk membuat templating bahkan file teks mudah) untuk menyesuaikan file .py, atau menggunakan ekstensi MetaPython Rick Copeland .Jika Anda mencoba membuat perubahan selama kompilasi modul, perhatikan bahwa Anda tidak harus kembali ke teks; Anda bisa langsung mengkompilasi AST alih-alih mengubahnya kembali menjadi file .py.
Tetapi di hampir semua kasus, Anda mungkin mencoba melakukan sesuatu yang dinamis yang membuat bahasa seperti Python menjadi sangat mudah, tanpa menulis file .py baru! Jika Anda memperluas pertanyaan untuk memberi tahu kami apa yang sebenarnya ingin Anda capai, file .py baru mungkin tidak akan terlibat dalam jawaban sama sekali; Saya telah melihat ratusan proyek Python melakukan ratusan hal di dunia nyata, dan tidak satu pun dari mereka yang perlu membuat file .py. Jadi, saya harus akui, saya agak skeptis bahwa Anda telah menemukan kasus penggunaan pertama yang bagus. :-)
Perbarui: sekarang setelah Anda menjelaskan apa yang Anda coba lakukan, saya akan tergoda untuk hanya beroperasi di AST. Anda ingin bermutasi dengan menghapus, bukan baris file (yang bisa menghasilkan setengah pernyataan yang mati dengan SyntaxError), tetapi seluruh pernyataan - dan tempat apa yang lebih baik untuk melakukan itu daripada di AST?
sumber
Mem-parsing dan memodifikasi struktur kode tentu dimungkinkan dengan bantuan
ast
modul dan saya akan menunjukkannya dalam sebuah contoh sebentar lagi. Namun, menulis kembali kode sumber yang dimodifikasi tidak dimungkinkan hanya denganast
modul. Ada modul lain yang tersedia untuk pekerjaan ini seperti yang ada di sini .CATATAN: Contoh di bawah ini dapat diperlakukan sebagai tutorial pengantar tentang penggunaan
ast
modul tetapi panduan yang lebih komprehensif tentang penggunaanast
modul tersedia di sini di tutorial ular Pohon Hijau dan dokumentasi resmi tentangast
modul .Pengantar
ast
:Anda dapat menguraikan kode python (direpresentasikan dalam string) hanya dengan memanggil API
ast.parse()
. Ini mengembalikan pegangan ke struktur Pohon Sintaksis Abstrak (AST). Menariknya Anda dapat mengkompilasi kembali struktur ini dan menjalankannya seperti yang ditunjukkan di atas.API lain yang sangat berguna adalah
ast.dump()
yang membuang seluruh AST dalam bentuk string. Ini dapat digunakan untuk memeriksa struktur pohon dan sangat membantu dalam debugging. Sebagai contoh,Pada Python 2.7:
Pada Python 3.5:
Perhatikan perbedaan sintaks untuk pernyataan cetak dalam Python 2.7 vs Python 3.5 dan perbedaan jenis AST node di pohon masing-masing.
Cara memodifikasi kode menggunakan
ast
:Sekarang, mari kita lihat contoh modifikasi kode python oleh
ast
modul. Alat utama untuk memodifikasi struktur AST adalahast.NodeTransformer
kelas. Setiap kali seseorang perlu memodifikasi AST, dia perlu subkelas darinya dan menulis Node Transformation (s) yang sesuai.Sebagai contoh kita, mari kita coba menulis sebuah utilitas sederhana yang mengubah Python 2, mencetak pernyataan ke panggilan fungsi Python 3.
Pernyataan cetak ke Utilitas konverter panggilan menyenangkan: print2to3.py:
Utilitas ini dapat dicoba pada file contoh kecil, seperti yang di bawah ini, dan itu akan berfungsi dengan baik.
File Input Uji: py2.py
Harap dicatat bahwa transformasi di atas hanya untuk
ast
tujuan tutorial dan dalam skenario nyata seseorang harus melihat semua skenario yang berbeda sepertiprint " x is %s" % ("Hello Python")
.sumber
Saya telah membuat baru-baru ini cukup stabil (inti diuji dengan sangat baik) dan sepotong kode yang dapat dikembangkan yang menghasilkan kode dari
ast
pohon: https://github.com/paluh/code-formatter .Saya menggunakan proyek saya sebagai basis untuk plugin vim kecil (yang saya gunakan setiap hari), jadi tujuan saya adalah untuk menghasilkan kode python yang benar-benar bagus dan dapat dibaca.
PS Saya sudah mencoba untuk memperluas
codegen
tetapi arsitekturnya didasarkan padaast.NodeVisitor
antarmuka, jadi formatters (visitor_
metode) hanyalah fungsi. Saya telah menemukan struktur ini sangat terbatas dan sulit untuk dioptimalkan (dalam kasus ekspresi panjang dan bersarang lebih mudah untuk menjaga pohon objek dan cache beberapa hasil parsial - dengan cara lain Anda dapat menekan kompleksitas eksponensial jika Anda ingin mencari tata letak terbaik). TETAPIcodegen
karena setiap karya mitsuhiko (yang saya baca) ditulis dengan sangat baik dan ringkas.sumber
Salah satu jawaban lain merekomendasikan
codegen
, yang tampaknya telah digantikan olehastor
. Versiastor
pada PyPI (versi 0.5 pada tulisan ini) tampaknya agak ketinggalan jaman juga, sehingga Anda dapat menginstal versi pengembanganastor
sebagai berikut.Kemudian Anda dapat menggunakan
astor.to_source
untuk mengonversi Python AST ke kode sumber Python yang dapat dibaca manusia:Saya telah menguji ini di Python 3.5.
sumber
Jika Anda melihat ini pada 2019, maka Anda dapat menggunakan paket libcst ini . Ini memiliki sintaks mirip dengan ast. Ini berfungsi seperti pesona, dan melestarikan struktur kode. Ini pada dasarnya bermanfaat untuk proyek di mana Anda harus menyimpan komentar, spasi, baris baru dll.
Jika Anda tidak perlu peduli dengan komentar yang melestarikan, spasi putih, dan lainnya, maka kombinasi ast dan astor berfungsi dengan baik.
sumber
Kami memiliki kebutuhan serupa, yang tidak diselesaikan oleh jawaban lain di sini. Jadi kami membuat perpustakaan untuk ini, ASTTokens , yang mengambil pohon AST yang diproduksi dengan modul ast atau astroid , dan menandainya dengan rentang teks dalam kode sumber asli.
Itu tidak melakukan modifikasi kode secara langsung, tetapi itu tidak sulit untuk ditambahkan di atas, karena itu memberi tahu Anda kisaran teks yang perlu Anda modifikasi.
Misalnya, ini membungkus panggilan fungsi
WRAP(...)
, menjaga komentar dan yang lainnya:Menghasilkan:
Semoga ini membantu!
sumber
Sebuah Program Transformasi Sistem adalah alat yang mem-parsing teks sumber, membangun AST, memungkinkan Anda untuk mengubah mereka menggunakan sumber-to-sumber transformasi ( "jika melihat pola ini, menggantinya dengan pola yang"). Alat-alat seperti itu ideal untuk melakukan mutasi kode sumber yang ada, yang hanya "jika Anda melihat pola ini, ganti dengan varian pola".
Tentu saja, Anda memerlukan mesin program transformasi yang dapat mengurai bahasa yang menarik bagi Anda, dan masih melakukan transformasi yang diarahkan pola. Perangkat Rekayasa Ulang Perangkat Lunak DMS kami adalah sistem yang dapat melakukan itu, dan menangani Python, serta berbagai bahasa lainnya.
Lihat jawaban SO ini untuk contoh AST parsing DMS untuk Python menangkap komentar secara akurat. DMS dapat membuat perubahan pada AST, dan membuat ulang teks yang valid, termasuk komentar. Anda dapat memintanya untuk mencetak awal AST, menggunakan konvensi pemformatan sendiri (Anda dapat mengubahnya), atau melakukan "pencetakan kesetiaan", yang menggunakan informasi baris dan kolom asli untuk secara maksimal mempertahankan tata letak asli (beberapa perubahan dalam tata letak tempat kode baru dimasukkan tidak dapat dihindari).
Untuk menerapkan aturan "mutasi" untuk Python dengan DMS, Anda bisa menulis yang berikut:
Aturan ini menggantikan "+" dengan "-" dengan cara yang benar secara sintaksis; ini beroperasi di AST dan karenanya tidak akan menyentuh string atau komentar yang kelihatannya benar. Kondisi tambahan pada "mutate_this_place" adalah membiarkan Anda mengontrol seberapa sering ini terjadi; Anda tidak ingin bermutasi di setiap tempat dalam program.
Anda tentu ingin lebih banyak aturan seperti ini yang mendeteksi berbagai struktur kode, dan menggantinya dengan versi yang dimutasi. DMS senang menerapkan seperangkat aturan. AST yang termutasi kemudian dicetak ulang.
sumber
Saya dulu menggunakan baron untuk ini, tetapi sekarang telah beralih ke parso karena itu up to date dengan python modern. Ini bekerja dengan baik.
Saya juga membutuhkan ini untuk tester mutasi. Sangat sederhana untuk membuatnya dengan parso, periksa kode saya di https://github.com/boxed/mutmut
sumber