Python脚本执行:工具管理Python脚本执行系统
背景
在现代的软件开发和测试过程中,自动化工具和脚本的管理变得至关重要。为了更高效地管理工具、关联文件、提取执行参数并支持动态执行Python代码,我们设计并实现了一套基于Django框架的工具管理和执行系统。
该系统旨在实现以下目标:
- 提供对工具及其关联文件的集中化管理。
- 动态提取工具文件中的参数。
- 支持在线执行工具并记录执行历史。
- 确保工具与其关联文件之间的关系清晰,避免文件冲突和错误。
系统设计与实现
数据模型
系统包含以下主要模型:
-
Tool
表示一个工具,记录工具的基本信息(如名称、参数等)。
字段:id
: 工具唯一标识。name
: 工具名称。parameters
: JSON格式的参数集合,用于存储从文件中提取的参数。
-
ToolFile
表示与工具关联的文件,可以是工具的主文件或者辅助文件。
字段:id
: 文件唯一标识。tool
: 外键,关联的工具。file_name
: 文件名。code_content
: 文件内容。is_main
: 是否为主文件。
-
PythonExecutionRecord
用于记录工具执行的历史记录,包括输入参数、执行结果和日志。
字段:id
: 记录唯一标识。tool
: 外键,执行的工具。executor
: 执行人。parameters
: 执行时的输入参数。output
: 执行输出结果。log
: 执行日志。started_at
: 执行开始时间。ended_at
: 执行结束时间。execution_time
: 执行时长。
-
ToolToolFileRelation
用于表示工具与文件之间的多对多关系,支持多工具共享文件。
实现过程
1. 工具参数提取逻辑
在 PythonExecutionRecordViewSet
中实现了以下方法:
-
extract_parameters
使用正则表达式提取代码内容中以$
开头的变量(如$param1
),并将其解析为参数列表。 -
save_tool_files_and_extract_parameters
遍历工具的所有关联文件,调用extract_parameters
提取参数并保存到Tool
的parameters
字段中。
2. 工具与文件的关联管理
在 ToolFileViewSet
中处理了以下场景:
-
创建文件
检查是否设置为主文件。如果已存在主文件,则禁止重复创建主文件。 -
更新文件
同样检查主文件冲突情况,并在文件更新后重新提取工具的参数。
3. 工具执行逻辑
在 PythonExecutionRecordViewSet
中实现了工具执行的核心逻辑:
-
参数校验
比对用户输入的参数和工具中提取的参数,提示缺失的参数信息。 -
执行主文件
将工具的主文件及其关联文件写入临时目录,替换参数占位符后执行主文件代码。 -
执行记录
将执行的输入参数、输出结果、执行日志等信息保存为一条记录。
表之间的关系
-
Tool 与 ToolFile
Tool 通过一对多关系关联多个 ToolFile,每个 ToolFile 可以指定是否为主文件。主文件是执行的核心,其它文件为辅助文件。 -
Tool 与 PythonExecutionRecord
Tool 通过一对多关系关联多个执行记录,每次执行都会创建一条新的记录。 -
Tool 与 ToolToolFileRelation
通过 ToolToolFileRelation 实现了工具与文件的多对多关系,从而支持文件的复用。
执行 脚本 详细流程说明
在 PythonExecutionRecordViewSet
中,核心功能是处理工具的执行逻辑,以下是执行过程的详细说明:
1. 参数校验阶段
-
接收请求数据
用户在前端选择工具并输入执行参数后,系统通过 API 接收这些信息,包括:- 工具 ID
- 用户输入的参数集合
-
验证工具有效性
根据工具 ID 检查工具是否存在,并确认其是否具有主文件。如果工具不存在或没有主文件,立即返回错误响应。 -
比对参数完整性
从工具的parameters
字段中读取该工具所需的全部参数,然后与用户提供的参数集合进行对比:- 如果存在缺失参数:返回缺失参数的详细信息,提示用户补充。
- 如果参数齐全:进入执行阶段。
2. 准备执行环境阶段
-
创建临时目录
在服务器中为当前执行请求创建一个独立的临时目录,用于存储该工具的主文件和辅助文件,确保执行过程互不干扰。 -
提取并保存文件
遍历该工具关联的所有文件,将ToolFile
表中的文件内容写入临时目录,并按文件名进行命名。- 确保工具的主文件被正确识别,并单独保存到特定路径。
- 将辅助文件保存在相同目录中,以供主文件在执行时调用。
-
替换参数占位符
在文件内容中查找以$
开头的参数占位符,并用用户输入的实际参数值进行替换。此步骤确保生成的代码是可以正常执行的。
3. 执行工具阶段
-
执行主文件
使用 Python 的子进程管理工具在创建的临时目录中执行主文件。执行时:- 主文件及其辅助文件都在同一目录下,确保文件间的依赖关系可以被正确解析。
- 捕获执行的标准输出、标准错误输出,以及返回状态码。
-
设置超时限制
每次执行都设置了最大超时时间(如 5 分钟)。如果执行超过时间,子进程会被强制终止,并记录超时错误。 -
记录执行日志
- 如果执行成功:记录标准输出内容。
- 如果执行失败:捕获标准错误内容和异常信息,并记录执行失败原因。
4. 记录执行结果阶段
-
计算执行时间
根据执行开始和结束时间计算总耗时,便于后续性能分析。 -
保存执行记录
将以下信息保存到PythonExecutionRecord
表中:- 执行的工具 ID
- 用户输入的参数集合
- 执行的标准输出内容(或错误日志)
- 执行开始和结束时间
- 总执行时长
-
清理临时文件
执行完成后,删除临时目录中的所有文件,避免占用服务器存储空间。
5. 返回结果阶段
-
构造响应
系统根据执行结果构造响应数据:- 如果执行成功:返回执行的输出结果和执行时间。
- 如果执行失败:返回错误日志和失败原因。
-
发送响应
系统将构造好的响应数据通过 API 返回给前端,提示用户执行状态(成功或失败)。
总结执行流程
- 接收前端的工具和参数请求。
- 校验工具是否有效,以及用户参数是否完整。
- 创建临时执行环境,准备并替换工具文件内容中的参数。
- 执行工具的主文件,并捕获输出或错误日志。
- 保存执行结果到数据库,包括详细的日志和执行时间。
- 清理执行过程中的临时文件,返回执行结果给前端。
技术亮点
-
参数提取与校验
提取文件中动态参数的功能使工具能够更灵活地适配不同场景的执行需求。 -
主文件管理
主文件的唯一性检查逻辑避免了执行时因文件冲突导致的问题。 -
执行过程隔离
通过临时目录存储和执行代码,确保每次执行相互独立,减少对系统环境的污染。 -
执行记录的完整性
每次执行均记录详细的日志、输入和输出信息,便于后续问题定位和性能分析。
示例代码片段
提取参数
def extract_parameters(self, file_content):pattern = r'\$(\w+)'parameter_names = re.findall(pattern, file_content)return {param: None for param in set(parameter_names)}
工具执行
process = subprocess.run([sys.executable, main_file_path],capture_output=True,text=True,cwd=temp_dir,timeout=300,
)
页面展示:
1. 文件列表页面
2. 添加和更新文件
我添加了两个文件 一个 main文件 如下:
from test import bubble_sortarr_example = $listData# 调用函数并开始排序
bubble_sort(arr_example)# 打印最终排序结果
print(f"最终排序结果: {arr_example}")
test 方法文件:
def bubble_sort(arr):n = len(arr)for i in range(n):# 标记是否发生了交换,如果没有发生交换说明列表已经有序swapped = Falsefor j in range(0, n-i-1):if arr[j] > arr[j+1]:# 交换元素arr[j], arr[j+1] = arr[j+1], arr[j]swapped = Trueprint(f"第{i+1}轮排序后,数组状态为: {arr}")# 如果没有发生任何交换,则提前结束循环if not swapped:break# 示例数组
3. 工具列表 注释:一个工具可以关联多个文件
4. 编辑和更新工具,添加删除关联的文件, 必须有一个main文件
5. 在列表页点击执行会跳转执行页面 如下:
点击文件的名称会自动跳转文件的详情页。
解释下: 参数配置, 是从文件自动提取出来的, 比如 在文件里 $listData, 就会被识别 ,然后添加到配置区域,输入参数。
点击执行后会校验是否有main 文件, 会从main文件开始入口执行, 然后会返回日志
6. 执行成功的报告如下:
执行失败如下:
7. 在执行页面可以查看执行的历史
点击展开可以看到日志详情:
后边的规划
- 要有模块的概念, 一个功能模块可以关联多个工具
- 文件,工具 ,和模块都要有 项目的概念, 项目组之间可以隔离数据
- 要有权限管理, 自己创建的不允许别人修改,要修改要授权
点赞大于 10 我把代码贴出来 ,感谢大家支持