python работа - Разберите файл .py, прочитайте AST, измените его, а затем запишите измененный исходный код




5 Answers

Pythoscope делает это для тестовых случаев, которые он автоматически генерирует, как и инструмент 2to3 для python 2.6 (он преобразует источник python 2.x в источник python 3.x).

Оба эти средства используют библиотеку lib2to3 которая представляет собой реализацию механизма анализатора / компилятора python, который может сохранять комментарии в источнике, когда он округляется из источника -> AST -> source.

Проект каната может удовлетворить ваши потребности, если вы хотите сделать больше рефакторинга, например преобразований.

Модуль ast - это ваш другой вариант, и есть более старый пример того, как «разглядеть» синтаксические деревья обратно в код (используя модуль парсера). Но модуль ast более полезен при выполнении преобразования AST на коде, который затем преобразуется в объект кода.

Проект redbaron также может быть хорошо подходит (ht Xavier Combelle)

xml-файлами создать

Я хочу программно редактировать исходный код python. В основном я хочу прочитать .py файл, сгенерировать AST , а затем записать измененный исходный код python (т. .py Другой .py файл).

Есть способы проанализировать / скомпилировать исходный код python с использованием стандартных модулей python, таких как ast или compiler . Тем не менее, я не думаю, что любой из них поддерживает способы изменения исходного кода (например, удалить это объявление функции), а затем записать обратно модифицирующий исходный код python.

ОБНОВЛЕНИЕ. Причина, по которой я хочу это сделать, - это написать библиотеку тестирования мутаций для python, в основном путем удаления операторов / выражений, повторных тестов и просмотра разрывов.




Возможно, вам не понадобится повторно генерировать исходный код. Это немного опасно для меня, конечно, потому что вы на самом деле не объяснили, почему вы думаете, что вам нужно создать файл .py с полным кодом; но:

  • Если вы хотите сгенерировать файл .py, который люди фактически будут использовать, возможно, чтобы они могли заполнить форму и получить полезный .py-файл для вставки в свой проект, то вы не хотите изменять его в AST и назад, потому что вы потеряете все форматирование (подумайте о пустых строках, которые делают Python настолько удобочитаемым, группируя связанные множества строк вместе) ( узлы ast имеют lineno и col_offset ). Вместо этого вы, вероятно, захотите использовать механизм шаблонов (например, язык шаблонов Django , чтобы упростить создание шаблонов даже текстовых файлов), чтобы настроить файл .py, или использовать расширение MetaPython Рика Коупленда.

  • Если вы пытаетесь внести изменения во время компиляции модуля, обратите внимание, что вам не нужно полностью возвращаться к тексту; вы можете просто скомпилировать AST вместо того, чтобы превратить его в файл .py.

  • Но почти в любом случае вы, вероятно, пытаетесь сделать что-то динамическое, что язык, такой как Python, на самом деле делает очень легко, не записывая новые .py-файлы! Если вы развернете свой вопрос, чтобы сообщить нам, чего вы на самом деле хотите достичь, новые .py-файлы, вероятно, вообще не будут задействованы в ответе; Я видел сотни проектов на Python, которые делали сотни реальных вещей, и ни один из них не нуждался в создании файла .py. Итак, я должен признать, что я немного скептик, что вы нашли первый хороший вариант использования. :-)

Обновление: теперь, когда вы объяснили, что вы пытаетесь сделать, у меня возникнет соблазн просто работать с AST. Вам нужно будет мутировать, удалив, а не строки файла (что может привести к полу-операторам, которые просто умирают с помощью SyntaxError), но целые утверждения - и какое лучшее место для этого сделать, чем в AST?




Я недавно создал довольно стабильный (ядро действительно хорошо протестировано) и расширяемый фрагмент кода, который генерирует код из дерева ast : https://github.com/paluh/code-formatter .

Я использую мой проект как основу для небольшого плагина vim (который я использую каждый день), поэтому моя цель - создать действительно хороший и читаемый код на Python.

PS Я пытался расширить codegen но его архитектура основана на интерфейсе ast.NodeVisitor , поэтому visitor_ ( visitor_ methods) - это просто функции. Я нашел эту структуру довольно ограниченной и трудно оптимизированной (в случае длинных и вложенных выражений легче сохранить дерево объектов и кешировать некоторые частичные результаты - иначе вы можете столкнуться с экспоненциальной сложностью, если хотите найти лучший макет). BUT codegen как каждая часть работы мицухико (которую я прочитал) очень хорошо написана и кратким.




share рекомендует codegen , который, судя по всему, astor . Версия astor на PyPI (версия 0.5 на момент написания этой статьи), похоже, немного устарела, поэтому вы можете установить версию развития astor следующим образом.

pip install git+https://github.com/berkerpeksag/astor.git#egg=astor

Затем вы можете использовать astor.to_source для преобразования Python AST в удобочитаемый Python исходный код:

>>> import ast
>>> import astor
>>> print(astor.to_source(ast.parse('def foo(x): return 2 * x')))
def foo(x):
    return 2 * x

Я тестировал это на Python 3.5.




У нас была аналогичная потребность, которая не была решена другими ответами здесь. Поэтому мы создали для этого библиотеку ASTTokens , которая берет дерево AST, созданное с помощью модулей ast или astroid , и маркирует его диапазонами текста в исходном исходном коде.

Он не делает модификаций кода напрямую, но это не сложно добавить сверху, так как он сообщает вам диапазон текста, который вам нужно изменить.

Например, это завершает вызов функции в WRAP(...) , сохраняя комментарии и все остальное:

example = """
def foo(): # Test
  '''My func'''
  log("hello world")  # Print
"""

import ast, asttokens
atok = asttokens.ASTTokens(example, parse=True)

call = next(n for n in ast.walk(atok.tree) if isinstance(n, ast.Call))
start, end = atok.get_text_range(call)
print(atok.text[:start] + ('WRAP(%s)' % atok.text[start:end])  + atok.text[end:])

Производит:

def foo(): # Test
  '''My func'''
  WRAP(log("hello world"))  # Print

Надеюсь это поможет!




Related

python compiler-construction abstract-syntax-tree