Использование AST для получения информации о переменных и их типах - PullRequest
0 голосов
/ 05 апреля 2019

Я делаю парсинг исходного кода Python с GitHub, используя модуль AST, чтобы увидеть, как часто используются различные функции и библиотеки. Мне удалось успешно проанализировать вызовы функций и импорт библиотек, так что я могу перехватывать такие вещи, как import numpy as np и np.array([1, 2, 3]), и документировать, что был вызван numpy.array (я также могу обрабатывать операции импорта).

Проблема, с которой я сталкиваюсь, заключается в перехвате таких вызовов, как

x = [1, 1, 2, 1, 3]
x.count(1)

Я могу извлечь x.count(1), но поскольку я не знаю тип x (списки и строки имеют метод подсчета), я не могу полностью проанализировать и записать эти вызовы функций.

Есть идеи, как к этому подойти? Должен ли я попытаться сохранить рабочее пространство имен переменных и их содержимое / типы, а затем попытаться выяснить, какой библиотеке соответствует функция? Просто кажется, что здесь слишком много сложности, так как вы можете иметь такие выражения, как x, y = (len (a), str (b)), поэтому я надеюсь, что есть более простой способ. Спасибо!

Вот как я подошел к нему для других частей. Код адаптирован из другого поста StackOverflow.

class ParseCall(ast.NodeVisitor):
    def __init__(self):
        self.ls = []
    def visit_Attribute(self, node):
        ast.NodeVisitor.generic_visit(self, node)
        self.ls.append(node.attr)
    def visit_Name(self, node):
        self.ls.append(node.id)

class FindFuncs(ast.NodeVisitor):
    def __init__(self):
        self.funcs = []
    def visit_Call(self, node):
        p = ParseCall()
        p.visit(node.func)
        self.funcs.append(".".join(p.ls))
        ast.NodeVisitor.generic_visit(self, node)

class FindImports(ast.NodeVisitor):
    def __init__(self):
        self.imports = {}
    def visit_Import(self, node):
        for x in node.names:
            if(x.asname): self.imports[x.asname] = x.name
            else: self.imports[x.name] = x.name
    def visit_ImportFrom(self, node):
        for x in node.names:
            if(x.asname): self.imports[x.asname] = f"{node.module}.{x.name}"
            else: self.imports[x.name] = f"{node.module}.{x.name}"
...