gpt4 book ai didi

python - 解析项目中的类和函数依赖关系

转载 作者:行者123 更新时间:2023-11-28 17:48:00 26 4
gpt4 key购买 nike

我正在尝试对 Python 代码库中的类和函数依赖项进行一些分析。我的第一步是使用 Python 的 csv 模块和正则表达式创建一个 .csv 文件以导入到 Excel 中。

我目前的版本是这样的:

import re
import os
import csv
from os.path import join


class ClassParser(object):
class_expr = re.compile(r'class (.+?)(?:\((.+?)\))?:')
python_file_expr = re.compile(r'^\w+[.]py$')

def findAllClasses(self, python_file):
""" Read in a python file and return all the class names
"""
with open(python_file) as infile:
everything = infile.read()
class_names = ClassParser.class_expr.findall(everything)
return class_names

def findAllPythonFiles(self, directory):
""" Find all the python files starting from a top level directory
"""
python_files = []
for root, dirs, files in os.walk(directory):
for file in files:
if ClassParser.python_file_expr.match(file):
python_files.append(join(root,file))
return python_files

def parse(self, directory, output_directory="classes.csv"):
""" Parse the directory and spit out a csv file
"""
with open(output_directory,'w') as csv_file:
writer = csv.writer(csv_file)
python_files = self.findAllPythonFiles(directory)
for file in python_files:
classes = self.findAllClasses(file)
for classname in classes:
writer.writerow([classname[0], classname[1], file])

if __name__=="__main__":
parser = ClassParser()
parser.parse("/path/to/my/project/main/directory")

这会生成格式为 .csv 的输出:

class name, inherited classes (also comma separated), file
class name, inherited classes (also comma separated), file
... etc. ...

除了类名之外,我还想开始解析函数声明和定义。我的问题:是否有更好的方法来获取类名、继承类名、函数名、参数名等?

注意:我考虑过使用 Python ast 模块,但我没有使用它的经验,也不知道如何使用它来获取所需的信息,或者它是否可以这样做。

编辑:响应 Martin Thurau 对更多信息的请求 - 我试图解决这个问题的原因是因为我继承了一个相当冗长(100k+ 行)的项目,没有明显的模块、类和函数的结构;它们都作为文件集合存在于单个源目录中。

一些源文件包含数十个切线相关的类,并且长达 10k+ 行,这使得它们难以维护。我开始分析使用 The Hitchhiker's Guide to Packaging 获取每个类并将其打包成更具凝聚力的结构的相对难度。作为基地。对于该分析,我关心的部分内容是一个类与其文件中的其他类的交织程度,以及特定类所依赖的导入或继承的类。

最佳答案

我已经着手实现它。将以下代码放在一个文件中,然后运行它,传递要分析的文件或目录的名称。它将打印出它找到的所有类、它所在的文件以及类的基类。它不是智能的,所以如果您在代码库中定义了两个 Foo 类,它不会告诉您正在使用哪个,但这是一个开始。

此代码使用 python ast 模块检查 .py 文件,并找到所有 ClassDef 节点。然后它使用这个 meta package将它们的一部分打印出来——你需要安装这个包。

$ pip install -e git+https://github.com/srossross/Meta.git#egg=meta

示例输出,针对 django-featured-item 运行:

$ python class-finder.py /path/to/django-featured-item/featureditem/
FeaturedField,../django-featured-item/featureditem/fields.py,models.BooleanField
SingleFeature,../django-featured-item/featureditem/tests.py,models.Model
MultipleFeature,../django-featured-item/featureditem/tests.py,models.Model
Author,../django-featured-item/featureditem/tests.py,models.Model
Book,../django-featured-item/featureditem/tests.py,models.Model
FeaturedField,../django-featured-item/featureditem/tests.py,TestCase

代码:

# class-finder.py
import ast
import csv
import meta
import os
import sys

def find_classes(node, in_file):
if isinstance(node, ast.ClassDef):
yield (node, in_file)

if hasattr(node, 'body'):
for child in node.body:
# `yield from find_classes(child)` in Python 3.x
for x in find_classes(child, in_file): yield x


def print_classes(classes, out):
writer = csv.writer(out)
for cls, in_file in classes:
writer.writerow([cls.name, in_file] +
[meta.asttools.dump_python_source(base).strip()
for base in cls.bases])


def process_file(file_path):
root = ast.parse(open(file_path, 'r').read(), file_path)
for cls in find_classes(root, file_path):
yield cls


def process_directory(dir_path):
for entry in os.listdir(dir_path):
for cls in process_file_or_directory(os.path.join(dir_path, entry)):
yield cls


def process_file_or_directory(file_or_directory):
if os.path.isdir(file_or_directory):
return process_directory(file_or_directory)
elif file_or_directory.endswith('.py'):
return process_file(file_or_directory)
else:
return []

if __name__ == '__main__':
classes = process_file_or_directory(sys.argv[1])
print_classes(classes, sys.stdout)

关于python - 解析项目中的类和函数依赖关系,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15256509/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com