Есть ли способ заменить импорт Python на реальные источники? - PullRequest
0 голосов
/ 04 июня 2019

У меня есть файлы Python с инструкциями импорта, которые я хотел бы заменить на фактический код, помещенный в файл foo.py.

Например, с файлом in:

from foo import Bar

bar = Bar()
print bar

Я хотел бы out файл ниже:

# source of Bar class.

bar = Bar()
print bar

Как я могу выполнить такую ​​замену импорта?

1 Ответ

0 голосов
/ 04 июня 2019

Я предлагаю вам использовать ast.NodeTransformer для выполнения такой замены импорта.

AST предоставляет способ взаимодействия с кодом Python, как с деревьями грамматики абстрактного синтаксиса Python.

ast.NodeTransformer может использоваться для обхода вашего кода и идентификации узла ImportFrom (код, проанализированный с помощью ast, представлен в виде дерева узлов). После идентификации узла ImportFrom вы можете заменить его группой узлов, которые соответствуют исходному коду класса Bar класса , который ведет к вашей цели.

Пожалуйста, смотрите код ниже, который описывает подход, описанный ниже:

from ast import NodeTransformer, parse, fix_missing_locations

import astor


class FromImportTransformer(NodeTransformer):
    """ General from imports transformer. """


    def visit_ImportFrom(self, node):
        new_node = self.get_sources(node)
        # Replace node.
        fix_missing_locations(node)
        return node

    def get_sources(self, node):
        """ Accepts importFrom node and build new ast tree from the sources described in import. """
        raise NotImplemented


def transform_imports(self, source_file):
    with open(source_file) as original_sources:
        sources = original_sources.read()
    root = parse(sources, source_file)
    try:
        root = FromImportTransformer().visit(root)
    except Exception as exc:
        raise exc
    sources = astor.to_source(root, indent_with=' ' * 4, add_line_information=False)
    return processed_sources


path_to_in_sources = '/tmp/in.py'
path_to_out_sources = '/tmp/out.py'
processed_sources = transform_imports(path_to_in_sources)


with open(path_to_out_sources, 'wb+') as out:
    out.write(processed_sources)

ПРИМЕЧАНИЕ 1 : Я предлагаю вам использовать exec , чтобы скомпилировать источники с правильными глобальными и локальными данными.

ПРИМЕЧАНИЕ 2 : Учтите, что вам нужно будет обрабатывать вложенные операции импорта (если в хранилище файлов foo импортируются файлы, которые вы хотите заменить).

ПРИМЕЧАНИЕ 3 : Я использовал astor для преобразования кода из дерева ast в код Python.

...