Создать график импорта - PullRequest
3 голосов
/ 23 ноября 2011

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

Например, если x импортирует из y и z, а y импортирует из t и vЯ хотел бы иметь:

x -> y, z
y -> t, v

Теперь я уже определил свой крючок импорта, как показано ниже, но, запустив его в простом файле, я не получил то, что ожидал:1008 * Где simple.py фактически импортируется из study_imports.Проблема в том, что я хочу видеть «simple.py» вместо «study_imports.py», есть ли способ получить путь к файлу, фактически импортирующему другой модуль?

class CollectImports(object):
    """
    Import hook, adds each import request to the loaded set and dumps
    them to file
    """

    def __init__(self, output_file):
        self.loaded = set()
        self.output_file = output_file

    def __str__(self):
        return str(self.loaded)

    def cleanup(self):
        """Dump the loaded set to file
        """
        dumped_str = '\n'.join(x for x in self.loaded)
        open(self.output_file, 'w').write(dumped_str)

    def find_module(self, module_name, package=None):
        #TODO: try to find the name of the package which is actually
        #importing something else, and how it's doing it
        #use a defualtdict with empty sets as the storage for this job
        entry = (__file__, module_name)
        self.loaded.add(str(entry))

Ответы [ 3 ]

2 голосов
/ 23 ноября 2011

Может быть с проверять модуль.

Модуль a.py

import inspect

print inspect.stack()

Модуль b.py

import a

при запуске b.py я получил:

[
   (<frame object at 0x28a9b70>, '/path/a.py', 5, '<module>', ['print inspect.stack()\n'], 0),
   (<frame object at 0x28a9660>, 'b.py', 2, '<module>', ['import to_import\n'], 0)
]

Похоже, что второй кадр содержит то, что вам нужно.

1 голос
/ 28 ноября 2011

Итак, я выглядел немного лучше, и в итоге я переписал свой код, используя AST. Snakefood по-прежнему использует компилятор, который устарел и намного медленнее, чем использование ast.

Результат отличный, например, это посетитель:

from ast import parse, NodeVisitor


class ImportVisitor(NodeVisitor):

    def __init__(self):
        self.imported = set()
        super(ImportVisitor, self).__init__()

    def __str__(self):
        return '\n'.join(x for x in self.imported)

    def visit_Import(self, node):
        for n in node.names:
            self.imported.add(n.name)

    #that we are using
    def visit_ImportFrom(self, node):
        self.imported.add(node.module)

Что может быть использовано, например, как:

def gen_module_imports(mod):
    try:
        at = parse(open(mod).read())
    except SyntaxError:
        print("file %s has a syntax error, please fix it" % mod)
        return []
    else:
        v = ImportVisitor()
        v.visit(at)
        return v.imported
0 голосов
/ 23 ноября 2011

Уловка проверки, кажется, работает нормально :) Я получаю что-то вроде simple.py: set (['study_imports']) в файле import.log.

Class CollectImports(object):
    """
    Import hook, adds each import request to the loaded set and dumps
    them to file
    """

    def __init__(self, output_file):
        self.loaded = defaultdict(lambda: set())
        self.output_file = output_file

    def __str__(self):
        return str(self.loaded)

    def cleanup(self):
        """Dump the loaded set to file
        """
        dumped_str = '\n'.join(('%s: %s' % (k, v)) for k, v in self.loaded.items())
        open(self.output_file, 'w').write(dumped_str)

    def find_module(self, module_name, package=None):
        st = inspect.stack()
        self.loaded[st[1][1]].add(module_name)
...