Is there are a way to replace python import with a

2019-09-20 01:36发布

问题:

I am having python files with the import statements which I would like to replace into the actual code placed in the foo.py.

For instance, with the in file:

from foo import Bar

bar = Bar()
print bar

I would like to out file below:

# source of Bar class.

bar = Bar()
print bar

How can I perform such imports replacement ?

回答1:

I suggest you to use the ast.NodeTransformer in order to accomplish such import replacement.

AST provides way to interact with the python code as with the trees of the Python abstract syntax grammar.

The ast.NodeTransformer can be used to traverse through your code and identifying ImportFrom node ( the code parsed with ast is represented as the tree of nodes). After identifying ImportFrom node you can replace it with group of nodes which correspond to the source code of the Bar class, which lead to your goal.

Please see code below which describes approach described below:

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)

NOTE 1: I suggest you to use the exec in order to compile sources with correct globals and locals dict.

NOTE 2: Take into account that you will need to handle nested imports ( if foo file stores imports you wish to replace to).

NOTE 3: I've used astor to convert code from ast tree into the python code.