Я хочу программно редактировать исходный код Python. По сути, я хочу прочитать .py
файл, сгенерировать AST , а затем записать обратно измененный исходный код Python (т. Е. Другой .py
файл).
Существуют способы синтаксического анализа / компиляции исходного кода Python с использованием стандартных модулей Python, таких как ast
или compiler
. Однако я не думаю, что кто-либо из них поддерживает способы изменения исходного кода (например, удаление объявления этой функции), а затем записывает обратно модифицирующий исходный код Python.
ОБНОВЛЕНИЕ: причина, по которой я хочу это сделать, заключается в том, что я хотел бы написать библиотеку тестирования мутаций для python, в основном путем удаления операторов / выражений, повторного запуска тестов и просмотра ошибок.
Ответы:
Pythoscope делает это с тестовыми примерами , которые он генерирует автоматически, как и инструмент 2to3 для python 2.6 (он конвертирует исходный код python 2.x в исходный код python 3.x).
Оба эти инструмента используют библиотеку lib2to3, которая является реализацией механизма синтаксического анализатора / компилятора python, который может сохранять комментарии в источнике, когда он округляется из источника -> AST -> источник.
Проект веревки может удовлетворить ваши потребности , если вы хотите сделать больше рефакторинга , как преобразования.
Модуль ast - это ваша другая опция, и есть более старый пример того, как «разбирать» синтаксические деревья обратно в код (используя модуль синтаксического анализа). Но
ast
модуль более полезен при выполнении преобразования AST для кода, который затем преобразуется в объект кода.Проект RedBaron также может подойти (Ксавье Комбель)
источник
unparse.py
скрипта - это может быть очень неудобно использовать из другого скрипта. Но есть пакет под названием astunparse ( на github , на pypi ), который в основном представляет собой правильно упакованную версиюunparse.py
.Кажется, что встроенный модуль ast не имеет метода для преобразования обратно в исходный код. Тем не менее, модуль codegen здесь предоставляет симпатичный принтер для ast, который позволит вам сделать это. например.
Это напечатает:
Обратите внимание, что вы можете потерять точное форматирование и комментарии, так как они не сохраняются.
Однако вам может и не понадобиться. Если все, что вам требуется, это выполнить замененный AST, вы можете сделать это, просто вызвав compile () в ast и выполнив полученный объект кода.
источник
В другом ответе я предложил использовать
astor
пакет, но с тех пор я нашел более современный пакет для анализа AST, который называетсяastunparse
:Я проверил это на Python 3.5.
источник
Возможно, вам не нужно повторно генерировать исходный код. Конечно, мне немного опасно говорить, поскольку вы на самом деле не объяснили, почему вы думаете, что вам нужно сгенерировать файл .py, полный кода; но:
Если вы хотите сгенерировать файл .py, который люди фактически будут использовать, возможно, чтобы они могли заполнить форму и получить полезный файл .py для вставки в свой проект, то вам не нужно менять его на AST и назад , потому что вы потеряете
все форматирование (вспомнит пустые строки , которые делают Python так читаемыми группировки связанных наборов линий вместе)( AST узлы имеютlineno
иcol_offset
атрибуты ) комментарии. Вместо этого вы, вероятно, захотите использовать шаблонизатор ( например, язык шаблонов Django предназначен для упрощения шаблонизации даже текстовых файлов) для настройки файла .py или использовать расширение MetaPython Рика Копленда .Если вы пытаетесь внести изменения во время компиляции модуля, обратите внимание, что вам не нужно возвращаться к тексту; Вы можете просто скомпилировать AST напрямую, а не превращать его обратно в файл .py.
Но почти в любом случае вы, вероятно, пытаетесь сделать что-то динамическое, что на самом деле делает такой язык, как Python, без написания новых файлов .py! Если вы расширите свой вопрос, чтобы сообщить нам, чего вы на самом деле хотите достичь, новые файлы .py, вероятно, вообще не будут участвовать в ответе; Я видел сотни проектов Python, выполняющих сотни реальных вещей, и ни один из них не нуждался в написании файла .py. Итак, я должен признать, я немного скептик, что вы нашли первый хороший вариант использования. :-)
Обновление: теперь, когда вы объяснили, что вы пытаетесь сделать, я все равно хотел бы просто поработать с AST. Вы захотите изменить его, удалив не строки файла (что может привести к полу-операторам, которые просто умирают с SyntaxError), а целые операторы - и что может быть лучше для этого, чем в AST?
источник
Разбор и изменение структуры кода, безусловно, возможны с помощью
ast
модуля, и я покажу это на примере ниже. Однако запись измененного исходного кода невозможна только сast
одним модулем. Для этой работы доступны и другие модули, например, один здесь .ПРИМЕЧАНИЕ. Пример, приведенный ниже, можно рассматривать как вводное руководство по использованию
ast
модуля, но более полное руководство по использованиюast
модуля доступно здесь, в руководстве Green Tree snakes и официальной документации поast
модулю .Введение в
ast
:Вы можете проанализировать код Python (представленный в виде строки), просто вызвав API
ast.parse()
. Это возвращает дескриптор в структуру абстрактного синтаксического дерева (AST). Интересно, что вы можете скомпилировать эту структуру и выполнить ее, как показано выше.Другой очень полезный API -
ast.dump()
это дамп всего AST в виде строки. Он может использоваться для проверки древовидной структуры и очень полезен при отладке. Например,На Python 2.7:
На Python 3.5:
Обратите внимание на разницу в синтаксисе для оператора печати в Python 2.7 по сравнению с Python 3.5 и разницу в типе узла AST в соответствующих деревьях.
Как изменить код, используя
ast
:Теперь давайте рассмотрим пример модификации кода Python
ast
модулем. Основным инструментом для изменения структуры AST являетсяast.NodeTransformer
класс. Всякий раз, когда нужно модифицировать AST, ему / ей нужно подклассы из него и написать Node Transformation соответственно.Для нашего примера давайте попробуем написать простую утилиту, которая преобразует Python 2, операторы print в вызовы функций Python 3.
Вывести оператор в утилиту конвертирования вызовов Fun: print2to3.py:
Эту утилиту можно попробовать на небольшом примере файла, например, приведенном ниже, и она должна работать нормально.
Тестовый входной файл: py2.py
Обратите внимание, что приведенное выше преобразование предназначено только для
ast
целей обучения, и в реальном случае нужно будет рассмотреть все различные сценарии, такие какprint " x is %s" % ("Hello Python")
.источник
Недавно я создал довольно стабильный (ядро действительно хорошо протестировано) и расширяемый кусок кода, который генерирует код из
ast
дерева: https://github.com/paluh/code-formatter .Я использую свой проект в качестве основы для небольшого плагина vim (который я использую каждый день), поэтому моя цель - генерировать действительно хороший и читаемый код на Python.
PS Я пытался расширить,
codegen
но его архитектура основана наast.NodeVisitor
интерфейсе, поэтому средства форматирования (visitor_
методы) - это просто функции. Я обнаружил, что эта структура довольно ограничена и ее трудно оптимизировать (в случае длинных и вложенных выражений легче сохранять дерево объектов и кэшировать некоторые частичные результаты - иначе вы можете столкнуться с экспоненциальной сложностью, если хотите найти лучший макет). НОcodegen
как каждая часть работы Мицухико (которую я прочитал) очень хорошо написана и лаконична.источник
Один из других ответов рекомендует
codegen
, который, кажется, был замененastor
. Версияastor
PyPI (версия 0.5 на момент написания статьи) также выглядит несколько устаревшей, поэтому вы можете установить версию для разработкиastor
следующим образом.Затем вы можете использовать
astor.to_source
для преобразования Python AST в читаемый исходный код Python:Я проверил это на Python 3.5.
источник
Если вы посмотрите на это в 2019 году, то вы можете использовать этот пакет libcst . Синтаксис похож на аст. Это работает как очарование и сохраняет структуру кода. Это в основном полезно для проекта, где вы должны сохранить комментарии, пробелы, перевод строки и т. Д.
Если вам не нужно заботиться о сохранении комментариев, пробелов и прочего, тогда комбинация ast и astor работает хорошо.
источник
У нас была похожая потребность, которая не была решена другими ответами здесь. Поэтому мы создали для этого библиотеку ASTTokens , которая берет дерево AST, созданное с помощью модулей ast или astroid , и отмечает его диапазонами текста в исходном исходном коде.
Он не выполняет модификации кода напрямую, но его нетрудно добавить сверху, так как он говорит вам диапазон текста, который вам нужно изменить.
Например, это оборачивает вызов функции
WRAP(...)
, сохраняя комментарии и все остальное:Производит:
Надеюсь это поможет!
источник
Система преобразования программ - это инструмент, который анализирует исходный текст, создает AST, позволяет изменять их с помощью преобразований источника в источник («если вы видите этот шаблон, замените его этим шаблоном»). Такие инструменты идеально подходят для мутации существующих исходных кодов, которые просто «если вы видите этот шаблон, замените его вариантом».
Конечно, вам нужен механизм программной трансформации, который может анализировать интересующий вас язык и при этом выполнять преобразования, ориентированные на шаблоны. Наш инструментарий реинжиниринга программного обеспечения DMS - это система, которая может сделать это и обрабатывает Python и множество других языков.
Посмотрите этот SO-ответ для примера разбора DMS AST для Python для точного захвата комментариев . DMS может вносить изменения в AST и восстанавливать действительный текст, включая комментарии. Вы можете попросить его полностью распечатать AST, используя свои собственные правила форматирования (вы можете изменить их), или выполнить «печать верности», которая использует исходную информацию о строках и столбцах для максимального сохранения исходного макета (некоторые изменения в макете, где новый код) вставлено неизбежно).
Чтобы реализовать правило «мутации» для Python с DMS, вы можете написать следующее:
Это правило заменяет "+" на "-" синтаксически правильным образом; он работает с AST и поэтому не затрагивает строки или комментарии, которые выглядят правильно. Дополнительное условие для mutate_this_place - это возможность контролировать, как часто это происходит; Вы не хотите видоизменять каждое место в программе.
Очевидно, что вам нужно больше таких правил, которые бы определяли различные структуры кода и заменяли их мутированными версиями. DMS с удовольствием применяет ряд правил. Мутировавший AST затем довольно печатается.
источник
Раньше я использовал для этого барон, но теперь перешел на парсо, потому что он соответствует современным питонам. Работает отлично.
Я также нуждался в этом для тестера мутации. Это действительно довольно просто сделать с парсо, проверьте мой код на https://github.com/boxed/mutmut
источник