commit 0fc08732f13c3b5adc3c0c3f08d6943da6865cea
Author: chenjunyi <314298729@qq.com>
Date: Wed Jan 28 16:57:46 2026 +0800
v0.19
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..9e4d72a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,163 @@
+# ---> Python
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+output
+wheels/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+*.py,cover
+.hypothesis/
+.pytest_cache/
+cover/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+.pybuilder/
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+# For a library or package, you might want to ignore these files since the code is
+# intended to run in multiple environments; otherwise, check them in:
+# .python-version
+
+# pipenv
+# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+# However, in case of collaboration, if having platform-specific dependencies or dependencies
+# having no cross-platform support, pipenv may install dependencies that don't work, or not
+# install all needed dependencies.
+#Pipfile.lock
+
+# poetry
+# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
+# This is especially recommended for binary packages to ensure reproducibility, and is more
+# commonly ignored for libraries.
+# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
+#poetry.lock
+
+# pdm
+# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
+#pdm.lock
+# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
+# in version control.
+# https://pdm.fming.dev/#use-with-ide
+.pdm.toml
+
+# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
+__pypackages__/
+
+# Celery stuff
+celerybeat-schedule
+celerybeat.pid
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+# pytype static type analyzer
+.pytype/
+
+# Cython debug symbols
+cython_debug/
+
+# PyCharm
+# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
+# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
+# and can be added to the global gitignore or merged into this file. For a more nuclear
+# option (not recommended) you can uncomment the following to ignore the entire idea folder.
+#.idea/
+
diff --git a/.pylintrc b/.pylintrc
new file mode 100644
index 0000000..e749d6b
--- /dev/null
+++ b/.pylintrc
@@ -0,0 +1 @@
+extension-pkg-whitelist=PyQt5
\ No newline at end of file
diff --git a/.python-version b/.python-version
new file mode 100644
index 0000000..d20cc2b
--- /dev/null
+++ b/.python-version
@@ -0,0 +1 @@
+3.8.10
diff --git a/GUI.ui b/GUI.ui
new file mode 100644
index 0000000..0943cfe
--- /dev/null
+++ b/GUI.ui
@@ -0,0 +1,790 @@
+
+
+ MainWindow
+
+
+
+ 0
+ 0
+ 826
+ 619
+
+
+
+ MainWindow
+
+
+
+ -
+
+
-
+
+
+
+ 微软雅黑
+ 10
+ 50
+ false
+
+
+
+ 3
+
+
+
+ 文档生产工具
+
+
+
-
+
+
-
+
+
+
+ 微软雅黑
+ 10
+ 50
+ false
+
+
+
+ 大纲转说明-鉴定模板
+
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
+
+
+ false
+
+
+
-
+
+
+ 选择大纲文档
+
+
+
+ -
+
+
-
+
+
+ 设计人员:
+
+
+
+ -
+
+
+
+
+ -
+
+
+ 测试记录转说明
+
+
+
+ -
+
+
+ 开始转换
+
+
+
+
+
+
+ -
+
+
+
+ 微软雅黑
+ 10
+ 50
+ false
+
+
+
+ 追踪关系填写
+
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
+
+
+ false
+
+
+
-
+
+
+ 选择文件
+
+
+
+ -
+
+
+ 大纲追踪关系填写(依据大纲文件)
+
+
+
+ -
+
+
+ 测试说明追踪填写(依据说明文件)
+
+
+
+ -
+
+
+ 测试报告追踪填写(依据记录文件)
+
+
+
+
+
+
+ -
+
+
+
+ 微软雅黑
+ 10
+ 50
+ false
+
+
+
+ 根据说明生成测试记录
+
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
+
+
+ false
+
+
+
-
+
+
+ 选择文件
+
+
+
+ -
+
+
-
+
+
+ 测试人员:
+
+
+ Qt::AutoText
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+
+ -
+
+
-
+
+
+ 监测人员:
+
+
+ Qt::AutoText
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+
+ -
+
+
-
+
+
+ 测试时间:
+
+
+ Qt::AutoText
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+
+ -
+
+
-
+
+
+ 说明生成记录
+
+
+
+ -
+
+
+ 记录反向生成说明
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 文档小工具
+
+
+ -
+
+
-
+
+
+
+ 微软雅黑
+ 10
+ 50
+ false
+
+
+
+ UAS单元测试转换
+
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
+
+
+ false
+
+
+
-
+
+
-
+
+
+ 被测软件名:
+
+
+
+ -
+
+
+ -
+
+
+ 被测软件标识:
+
+
+
+ -
+
+
+ -
+
+
+ 请选择SAU报告文档
+
+
+
+ -
+
+
+ 开始转换
+
+
+
+
+
+
+
+
+ -
+
+
+
+ 微软雅黑
+ 10
+ 50
+ false
+
+
+
+ 自动填充
+
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
+
+
+ false
+
+
+
-
+
+
-
+
+
+ 选择文档
+
+
+
+ -
+
+
-
+
+
+ 单元格左侧:
+
+
+
+ -
+
+
+
+
+ -
+
+
-
+
+
+ 填充的内容:
+
+
+
+ -
+
+
+
+
+ -
+
+
-
+
+
+ 填充的数量:
+
+
+
+ -
+
+
+
+
+ -
+
+
-
+
+
+ 清空单元格
+
+
+
+ -
+
+
+ 填充
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+ 微软雅黑
+ 10
+ 50
+ false
+
+
+
+ 提取单元格标题右侧的单元格内容
+
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
+
+
+ false
+
+
+
-
+
+
-
+
+
+ 选择文档
+
+
+
+ -
+
+
-
+
+
+ 单元格标题:
+
+
+
+ -
+
+
+
+
+ -
+
+
-
+
+
+ 单元格标题:
+
+
+
+ -
+
+
+
+
+ -
+
+
-
+
+
+ 单元格标题:
+
+
+
+ -
+
+
+
+
+ -
+
+
+ 点击提取
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 报告生成工具
+
+
+
+
+ 5
+ 5
+ 161
+ 211
+
+
+
+ 部件测试表格
+
+
+ -
+
+
+ 选择UAS文件
+
+
+
+ -
+
+
+ 点击生成
+
+
+
+
+
+
+
+
+ FPGA工具
+
+
+
+
+ 5
+ 5
+ 246
+ 211
+
+
+
+ FPGA记录自动填写
+
+
+ -
+
+
+ 选择FPGA记录文件
+
+
+
+ -
+
+
-
+
+
-
+
+
+ 测试时间
+
+
+
+ -
+
+
+
+
+ -
+
+
-
+
+
+ 测试人员
+
+
+
+ -
+
+
+
+
+ -
+
+
-
+
+
+ 监测人员
+
+
+
+ -
+
+
+
+
+ -
+
+
-
+
+
+ 项目编号
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+ 自动填写开始
+
+
+
+
+
+
+
+
+ 255
+ 5
+ 191
+ 211
+
+
+
+ FPGA记录转说明
+
+
+ -
+
+
+ 请选择完整FPGA记录文件
+
+
+
+ -
+
+
-
+
+
+ 设计人员
+
+
+
+ -
+
+
+
+
+ -
+
+
+ 点击生成说明
+
+
+
+
+
+
+
+
+ -
+
+
+ -
+
+
-
+
+
+ Qt::Horizontal
+
+
+
+ 618
+ 20
+
+
+
+
+ -
+
+
+ 清空消息
+
+
+
+ -
+
+
+ 显示帮助
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ 0
+
+
+
+
+
+
+
+
+
+
+
+ 打开文件
+
+
+
+
+ close
+
+
+
+
+ 关于工具
+
+
+
+
+ 退出
+
+
+
+
+ IEEE转换工具
+
+
+
+
+
+
diff --git a/Icon.png b/Icon.png
new file mode 100644
index 0000000..81564da
Binary files /dev/null and b/Icon.png differ
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..9d52199
--- /dev/null
+++ b/README.md
@@ -0,0 +1,2 @@
+# newToolforTest
+一个使用QT框架写的脚本工具集合,已弃用
\ No newline at end of file
diff --git a/Ui_GUI.py b/Ui_GUI.py
new file mode 100644
index 0000000..ef6977d
--- /dev/null
+++ b/Ui_GUI.py
@@ -0,0 +1,510 @@
+# -*- coding: utf-8 -*-
+
+# Form implementation generated from reading ui file 'GUI.ui'
+#
+# Created by: PyQt5 UI code generator 5.15.4
+#
+# WARNING: Any manual changes made to this file will be lost when pyuic5 is
+# run again. Do not edit this file unless you know what you are doing.
+
+
+from PyQt5 import QtCore, QtGui, QtWidgets
+
+
+class Ui_MainWindow(object):
+ def setupUi(self, MainWindow):
+ MainWindow.setObjectName("MainWindow")
+ MainWindow.resize(826, 619)
+ self.centralwidget = QtWidgets.QWidget(MainWindow)
+ self.centralwidget.setObjectName("centralwidget")
+ self.verticalLayout_8 = QtWidgets.QVBoxLayout(self.centralwidget)
+ self.verticalLayout_8.setObjectName("verticalLayout_8")
+ self.verticalLayout_7 = QtWidgets.QVBoxLayout()
+ self.verticalLayout_7.setObjectName("verticalLayout_7")
+ self.tabWidget = QtWidgets.QTabWidget(self.centralwidget)
+ font = QtGui.QFont()
+ font.setFamily("微软雅黑")
+ font.setPointSize(10)
+ font.setBold(False)
+ font.setWeight(50)
+ self.tabWidget.setFont(font)
+ self.tabWidget.setObjectName("tabWidget")
+ self.tab = QtWidgets.QWidget()
+ self.tab.setObjectName("tab")
+ self.gridLayout = QtWidgets.QGridLayout(self.tab)
+ self.gridLayout.setObjectName("gridLayout")
+ self.horizontalLayout_15 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_15.setObjectName("horizontalLayout_15")
+ self.groupBox = QtWidgets.QGroupBox(self.tab)
+ font = QtGui.QFont()
+ font.setFamily("微软雅黑")
+ font.setPointSize(10)
+ font.setBold(False)
+ font.setWeight(50)
+ self.groupBox.setFont(font)
+ self.groupBox.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter)
+ self.groupBox.setFlat(False)
+ self.groupBox.setObjectName("groupBox")
+ self.verticalLayout = QtWidgets.QVBoxLayout(self.groupBox)
+ self.verticalLayout.setObjectName("verticalLayout")
+ self.pushButton = QtWidgets.QPushButton(self.groupBox)
+ self.pushButton.setObjectName("pushButton")
+ self.verticalLayout.addWidget(self.pushButton)
+ self.horizontalLayout = QtWidgets.QHBoxLayout()
+ self.horizontalLayout.setObjectName("horizontalLayout")
+ self.label = QtWidgets.QLabel(self.groupBox)
+ self.label.setObjectName("label")
+ self.horizontalLayout.addWidget(self.label)
+ self.lineEdit = QtWidgets.QLineEdit(self.groupBox)
+ self.lineEdit.setObjectName("lineEdit")
+ self.horizontalLayout.addWidget(self.lineEdit)
+ self.verticalLayout.addLayout(self.horizontalLayout)
+ self.pushButton_3 = QtWidgets.QPushButton(self.groupBox)
+ self.pushButton_3.setObjectName("pushButton_3")
+ self.verticalLayout.addWidget(self.pushButton_3)
+ self.pushButton_2 = QtWidgets.QPushButton(self.groupBox)
+ self.pushButton_2.setObjectName("pushButton_2")
+ self.verticalLayout.addWidget(self.pushButton_2)
+ self.horizontalLayout_15.addWidget(self.groupBox)
+ self.groupBox_2 = QtWidgets.QGroupBox(self.tab)
+ font = QtGui.QFont()
+ font.setFamily("微软雅黑")
+ font.setPointSize(10)
+ font.setBold(False)
+ font.setWeight(50)
+ self.groupBox_2.setFont(font)
+ self.groupBox_2.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter)
+ self.groupBox_2.setFlat(False)
+ self.groupBox_2.setObjectName("groupBox_2")
+ self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.groupBox_2)
+ self.verticalLayout_2.setObjectName("verticalLayout_2")
+ self.pushButton_4 = QtWidgets.QPushButton(self.groupBox_2)
+ self.pushButton_4.setObjectName("pushButton_4")
+ self.verticalLayout_2.addWidget(self.pushButton_4)
+ self.pushButton_6 = QtWidgets.QPushButton(self.groupBox_2)
+ self.pushButton_6.setObjectName("pushButton_6")
+ self.verticalLayout_2.addWidget(self.pushButton_6)
+ self.pushButton_5 = QtWidgets.QPushButton(self.groupBox_2)
+ self.pushButton_5.setObjectName("pushButton_5")
+ self.verticalLayout_2.addWidget(self.pushButton_5)
+ self.pushButton_18 = QtWidgets.QPushButton(self.groupBox_2)
+ self.pushButton_18.setObjectName("pushButton_18")
+ self.verticalLayout_2.addWidget(self.pushButton_18)
+ self.horizontalLayout_15.addWidget(self.groupBox_2)
+ self.groupBox_4 = QtWidgets.QGroupBox(self.tab)
+ font = QtGui.QFont()
+ font.setFamily("微软雅黑")
+ font.setPointSize(10)
+ font.setBold(False)
+ font.setWeight(50)
+ self.groupBox_4.setFont(font)
+ self.groupBox_4.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter)
+ self.groupBox_4.setFlat(False)
+ self.groupBox_4.setObjectName("groupBox_4")
+ self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.groupBox_4)
+ self.verticalLayout_4.setObjectName("verticalLayout_4")
+ self.pushButton_11 = QtWidgets.QPushButton(self.groupBox_4)
+ self.pushButton_11.setObjectName("pushButton_11")
+ self.verticalLayout_4.addWidget(self.pushButton_11)
+ self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_2.setObjectName("horizontalLayout_2")
+ self.label_4 = QtWidgets.QLabel(self.groupBox_4)
+ self.label_4.setTextFormat(QtCore.Qt.AutoText)
+ self.label_4.setAlignment(QtCore.Qt.AlignCenter)
+ self.label_4.setObjectName("label_4")
+ self.horizontalLayout_2.addWidget(self.label_4)
+ self.lineEdit_4 = QtWidgets.QLineEdit(self.groupBox_4)
+ self.lineEdit_4.setObjectName("lineEdit_4")
+ self.horizontalLayout_2.addWidget(self.lineEdit_4)
+ self.verticalLayout_4.addLayout(self.horizontalLayout_2)
+ self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_3.setObjectName("horizontalLayout_3")
+ self.label_5 = QtWidgets.QLabel(self.groupBox_4)
+ self.label_5.setTextFormat(QtCore.Qt.AutoText)
+ self.label_5.setAlignment(QtCore.Qt.AlignCenter)
+ self.label_5.setObjectName("label_5")
+ self.horizontalLayout_3.addWidget(self.label_5)
+ self.lineEdit_5 = QtWidgets.QLineEdit(self.groupBox_4)
+ self.lineEdit_5.setObjectName("lineEdit_5")
+ self.horizontalLayout_3.addWidget(self.lineEdit_5)
+ self.verticalLayout_4.addLayout(self.horizontalLayout_3)
+ self.horizontalLayout_4 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_4.setObjectName("horizontalLayout_4")
+ self.label_6 = QtWidgets.QLabel(self.groupBox_4)
+ self.label_6.setTextFormat(QtCore.Qt.AutoText)
+ self.label_6.setAlignment(QtCore.Qt.AlignCenter)
+ self.label_6.setObjectName("label_6")
+ self.horizontalLayout_4.addWidget(self.label_6)
+ self.lineEdit_6 = QtWidgets.QLineEdit(self.groupBox_4)
+ self.lineEdit_6.setObjectName("lineEdit_6")
+ self.horizontalLayout_4.addWidget(self.lineEdit_6)
+ self.verticalLayout_4.addLayout(self.horizontalLayout_4)
+ self.horizontalLayout_5 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_5.setObjectName("horizontalLayout_5")
+ self.pushButton_12 = QtWidgets.QPushButton(self.groupBox_4)
+ self.pushButton_12.setObjectName("pushButton_12")
+ self.horizontalLayout_5.addWidget(self.pushButton_12)
+ self.pushButton_13 = QtWidgets.QPushButton(self.groupBox_4)
+ self.pushButton_13.setObjectName("pushButton_13")
+ self.horizontalLayout_5.addWidget(self.pushButton_13)
+ self.verticalLayout_4.addLayout(self.horizontalLayout_5)
+ self.horizontalLayout_15.addWidget(self.groupBox_4)
+ self.gridLayout.addLayout(self.horizontalLayout_15, 0, 0, 1, 1)
+ self.tabWidget.addTab(self.tab, "")
+ self.tab_2 = QtWidgets.QWidget()
+ self.tab_2.setObjectName("tab_2")
+ self.verticalLayout_12 = QtWidgets.QVBoxLayout(self.tab_2)
+ self.verticalLayout_12.setObjectName("verticalLayout_12")
+ self.horizontalLayout_13 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_13.setObjectName("horizontalLayout_13")
+ self.groupBox_3 = QtWidgets.QGroupBox(self.tab_2)
+ font = QtGui.QFont()
+ font.setFamily("微软雅黑")
+ font.setPointSize(10)
+ font.setBold(False)
+ font.setWeight(50)
+ self.groupBox_3.setFont(font)
+ self.groupBox_3.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter)
+ self.groupBox_3.setFlat(False)
+ self.groupBox_3.setObjectName("groupBox_3")
+ self.verticalLayout_9 = QtWidgets.QVBoxLayout(self.groupBox_3)
+ self.verticalLayout_9.setObjectName("verticalLayout_9")
+ self.verticalLayout_3 = QtWidgets.QVBoxLayout()
+ self.verticalLayout_3.setObjectName("verticalLayout_3")
+ self.label_2 = QtWidgets.QLabel(self.groupBox_3)
+ self.label_2.setObjectName("label_2")
+ self.verticalLayout_3.addWidget(self.label_2)
+ self.lineEdit_2 = QtWidgets.QLineEdit(self.groupBox_3)
+ self.lineEdit_2.setObjectName("lineEdit_2")
+ self.verticalLayout_3.addWidget(self.lineEdit_2)
+ self.label_3 = QtWidgets.QLabel(self.groupBox_3)
+ self.label_3.setObjectName("label_3")
+ self.verticalLayout_3.addWidget(self.label_3)
+ self.lineEdit_3 = QtWidgets.QLineEdit(self.groupBox_3)
+ self.lineEdit_3.setObjectName("lineEdit_3")
+ self.verticalLayout_3.addWidget(self.lineEdit_3)
+ self.pushButton_7 = QtWidgets.QPushButton(self.groupBox_3)
+ self.pushButton_7.setObjectName("pushButton_7")
+ self.verticalLayout_3.addWidget(self.pushButton_7)
+ self.pushButton_8 = QtWidgets.QPushButton(self.groupBox_3)
+ self.pushButton_8.setObjectName("pushButton_8")
+ self.verticalLayout_3.addWidget(self.pushButton_8)
+ self.verticalLayout_9.addLayout(self.verticalLayout_3)
+ self.horizontalLayout_13.addWidget(self.groupBox_3)
+ self.groupBox_5 = QtWidgets.QGroupBox(self.tab_2)
+ font = QtGui.QFont()
+ font.setFamily("微软雅黑")
+ font.setPointSize(10)
+ font.setBold(False)
+ font.setWeight(50)
+ self.groupBox_5.setFont(font)
+ self.groupBox_5.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter)
+ self.groupBox_5.setFlat(False)
+ self.groupBox_5.setObjectName("groupBox_5")
+ self.verticalLayout_10 = QtWidgets.QVBoxLayout(self.groupBox_5)
+ self.verticalLayout_10.setObjectName("verticalLayout_10")
+ self.verticalLayout_5 = QtWidgets.QVBoxLayout()
+ self.verticalLayout_5.setObjectName("verticalLayout_5")
+ self.pushButton_16 = QtWidgets.QPushButton(self.groupBox_5)
+ self.pushButton_16.setObjectName("pushButton_16")
+ self.verticalLayout_5.addWidget(self.pushButton_16)
+ self.horizontalLayout_6 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_6.setObjectName("horizontalLayout_6")
+ self.label_7 = QtWidgets.QLabel(self.groupBox_5)
+ self.label_7.setObjectName("label_7")
+ self.horizontalLayout_6.addWidget(self.label_7)
+ self.lineEdit_9 = QtWidgets.QLineEdit(self.groupBox_5)
+ self.lineEdit_9.setObjectName("lineEdit_9")
+ self.horizontalLayout_6.addWidget(self.lineEdit_9)
+ self.verticalLayout_5.addLayout(self.horizontalLayout_6)
+ self.horizontalLayout_7 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_7.setObjectName("horizontalLayout_7")
+ self.label_9 = QtWidgets.QLabel(self.groupBox_5)
+ self.label_9.setObjectName("label_9")
+ self.horizontalLayout_7.addWidget(self.label_9)
+ self.lineEdit_10 = QtWidgets.QLineEdit(self.groupBox_5)
+ self.lineEdit_10.setObjectName("lineEdit_10")
+ self.horizontalLayout_7.addWidget(self.lineEdit_10)
+ self.verticalLayout_5.addLayout(self.horizontalLayout_7)
+ self.horizontalLayout_8 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_8.setObjectName("horizontalLayout_8")
+ self.label_10 = QtWidgets.QLabel(self.groupBox_5)
+ self.label_10.setObjectName("label_10")
+ self.horizontalLayout_8.addWidget(self.label_10)
+ self.lineEdit_11 = QtWidgets.QLineEdit(self.groupBox_5)
+ self.lineEdit_11.setObjectName("lineEdit_11")
+ self.horizontalLayout_8.addWidget(self.lineEdit_11)
+ self.verticalLayout_5.addLayout(self.horizontalLayout_8)
+ self.horizontalLayout_9 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_9.setObjectName("horizontalLayout_9")
+ self.pushButton_14 = QtWidgets.QPushButton(self.groupBox_5)
+ self.pushButton_14.setObjectName("pushButton_14")
+ self.horizontalLayout_9.addWidget(self.pushButton_14)
+ self.pushButton_15 = QtWidgets.QPushButton(self.groupBox_5)
+ self.pushButton_15.setObjectName("pushButton_15")
+ self.horizontalLayout_9.addWidget(self.pushButton_15)
+ self.verticalLayout_5.addLayout(self.horizontalLayout_9)
+ self.verticalLayout_10.addLayout(self.verticalLayout_5)
+ self.horizontalLayout_13.addWidget(self.groupBox_5)
+ self.groupBox_6 = QtWidgets.QGroupBox(self.tab_2)
+ font = QtGui.QFont()
+ font.setFamily("微软雅黑")
+ font.setPointSize(10)
+ font.setBold(False)
+ font.setWeight(50)
+ self.groupBox_6.setFont(font)
+ self.groupBox_6.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter)
+ self.groupBox_6.setFlat(False)
+ self.groupBox_6.setObjectName("groupBox_6")
+ self.verticalLayout_11 = QtWidgets.QVBoxLayout(self.groupBox_6)
+ self.verticalLayout_11.setObjectName("verticalLayout_11")
+ self.verticalLayout_6 = QtWidgets.QVBoxLayout()
+ self.verticalLayout_6.setObjectName("verticalLayout_6")
+ self.pushButton_17 = QtWidgets.QPushButton(self.groupBox_6)
+ self.pushButton_17.setObjectName("pushButton_17")
+ self.verticalLayout_6.addWidget(self.pushButton_17)
+ self.horizontalLayout_10 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_10.setObjectName("horizontalLayout_10")
+ self.label_8 = QtWidgets.QLabel(self.groupBox_6)
+ self.label_8.setObjectName("label_8")
+ self.horizontalLayout_10.addWidget(self.label_8)
+ self.lineEdit_12 = QtWidgets.QLineEdit(self.groupBox_6)
+ self.lineEdit_12.setObjectName("lineEdit_12")
+ self.horizontalLayout_10.addWidget(self.lineEdit_12)
+ self.verticalLayout_6.addLayout(self.horizontalLayout_10)
+ self.horizontalLayout_11 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_11.setObjectName("horizontalLayout_11")
+ self.label_11 = QtWidgets.QLabel(self.groupBox_6)
+ self.label_11.setObjectName("label_11")
+ self.horizontalLayout_11.addWidget(self.label_11)
+ self.lineEdit_13 = QtWidgets.QLineEdit(self.groupBox_6)
+ self.lineEdit_13.setObjectName("lineEdit_13")
+ self.horizontalLayout_11.addWidget(self.lineEdit_13)
+ self.verticalLayout_6.addLayout(self.horizontalLayout_11)
+ self.horizontalLayout_12 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_12.setObjectName("horizontalLayout_12")
+ self.label_12 = QtWidgets.QLabel(self.groupBox_6)
+ self.label_12.setObjectName("label_12")
+ self.horizontalLayout_12.addWidget(self.label_12)
+ self.lineEdit_14 = QtWidgets.QLineEdit(self.groupBox_6)
+ self.lineEdit_14.setObjectName("lineEdit_14")
+ self.horizontalLayout_12.addWidget(self.lineEdit_14)
+ self.verticalLayout_6.addLayout(self.horizontalLayout_12)
+ self.pushButton_19 = QtWidgets.QPushButton(self.groupBox_6)
+ self.pushButton_19.setObjectName("pushButton_19")
+ self.verticalLayout_6.addWidget(self.pushButton_19)
+ self.verticalLayout_11.addLayout(self.verticalLayout_6)
+ self.horizontalLayout_13.addWidget(self.groupBox_6)
+ self.verticalLayout_12.addLayout(self.horizontalLayout_13)
+ self.tabWidget.addTab(self.tab_2, "")
+ self.tab_3 = QtWidgets.QWidget()
+ self.tab_3.setObjectName("tab_3")
+ self.groupBox_10 = QtWidgets.QGroupBox(self.tab_3)
+ self.groupBox_10.setGeometry(QtCore.QRect(5, 5, 161, 211))
+ self.groupBox_10.setObjectName("groupBox_10")
+ self.verticalLayout_19 = QtWidgets.QVBoxLayout(self.groupBox_10)
+ self.verticalLayout_19.setObjectName("verticalLayout_19")
+ self.pushButton_27 = QtWidgets.QPushButton(self.groupBox_10)
+ self.pushButton_27.setObjectName("pushButton_27")
+ self.verticalLayout_19.addWidget(self.pushButton_27)
+ self.pushButton_28 = QtWidgets.QPushButton(self.groupBox_10)
+ self.pushButton_28.setObjectName("pushButton_28")
+ self.verticalLayout_19.addWidget(self.pushButton_28)
+ self.tabWidget.addTab(self.tab_3, "")
+ self.tab_4 = QtWidgets.QWidget()
+ self.tab_4.setObjectName("tab_4")
+ self.groupBox_11 = QtWidgets.QGroupBox(self.tab_4)
+ self.groupBox_11.setGeometry(QtCore.QRect(5, 5, 246, 211))
+ self.groupBox_11.setObjectName("groupBox_11")
+ self.verticalLayout_20 = QtWidgets.QVBoxLayout(self.groupBox_11)
+ self.verticalLayout_20.setObjectName("verticalLayout_20")
+ self.pushButton_29 = QtWidgets.QPushButton(self.groupBox_11)
+ self.pushButton_29.setObjectName("pushButton_29")
+ self.verticalLayout_20.addWidget(self.pushButton_29)
+ self.verticalLayout_13 = QtWidgets.QVBoxLayout()
+ self.verticalLayout_13.setObjectName("verticalLayout_13")
+ self.horizontalLayout_16 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_16.setObjectName("horizontalLayout_16")
+ self.label_13 = QtWidgets.QLabel(self.groupBox_11)
+ self.label_13.setObjectName("label_13")
+ self.horizontalLayout_16.addWidget(self.label_13)
+ self.lineEdit_7 = QtWidgets.QLineEdit(self.groupBox_11)
+ self.lineEdit_7.setObjectName("lineEdit_7")
+ self.horizontalLayout_16.addWidget(self.lineEdit_7)
+ self.verticalLayout_13.addLayout(self.horizontalLayout_16)
+ self.horizontalLayout_17 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_17.setObjectName("horizontalLayout_17")
+ self.label_14 = QtWidgets.QLabel(self.groupBox_11)
+ self.label_14.setObjectName("label_14")
+ self.horizontalLayout_17.addWidget(self.label_14)
+ self.lineEdit_8 = QtWidgets.QLineEdit(self.groupBox_11)
+ self.lineEdit_8.setObjectName("lineEdit_8")
+ self.horizontalLayout_17.addWidget(self.lineEdit_8)
+ self.verticalLayout_13.addLayout(self.horizontalLayout_17)
+ self.horizontalLayout_18 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_18.setObjectName("horizontalLayout_18")
+ self.label_15 = QtWidgets.QLabel(self.groupBox_11)
+ self.label_15.setObjectName("label_15")
+ self.horizontalLayout_18.addWidget(self.label_15)
+ self.lineEdit_15 = QtWidgets.QLineEdit(self.groupBox_11)
+ self.lineEdit_15.setObjectName("lineEdit_15")
+ self.horizontalLayout_18.addWidget(self.lineEdit_15)
+ self.verticalLayout_13.addLayout(self.horizontalLayout_18)
+ self.horizontalLayout_19 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_19.setObjectName("horizontalLayout_19")
+ self.label_16 = QtWidgets.QLabel(self.groupBox_11)
+ self.label_16.setObjectName("label_16")
+ self.horizontalLayout_19.addWidget(self.label_16)
+ self.lineEdit_16 = QtWidgets.QLineEdit(self.groupBox_11)
+ self.lineEdit_16.setObjectName("lineEdit_16")
+ self.horizontalLayout_19.addWidget(self.lineEdit_16)
+ self.verticalLayout_13.addLayout(self.horizontalLayout_19)
+ self.verticalLayout_20.addLayout(self.verticalLayout_13)
+ self.pushButton_30 = QtWidgets.QPushButton(self.groupBox_11)
+ self.pushButton_30.setObjectName("pushButton_30")
+ self.verticalLayout_20.addWidget(self.pushButton_30)
+ self.groupBox_12 = QtWidgets.QGroupBox(self.tab_4)
+ self.groupBox_12.setGeometry(QtCore.QRect(255, 5, 191, 211))
+ self.groupBox_12.setObjectName("groupBox_12")
+ self.verticalLayout_21 = QtWidgets.QVBoxLayout(self.groupBox_12)
+ self.verticalLayout_21.setObjectName("verticalLayout_21")
+ self.pushButton_31 = QtWidgets.QPushButton(self.groupBox_12)
+ self.pushButton_31.setObjectName("pushButton_31")
+ self.verticalLayout_21.addWidget(self.pushButton_31)
+ self.horizontalLayout_20 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_20.setObjectName("horizontalLayout_20")
+ self.label_17 = QtWidgets.QLabel(self.groupBox_12)
+ self.label_17.setObjectName("label_17")
+ self.horizontalLayout_20.addWidget(self.label_17)
+ self.lineEdit_17 = QtWidgets.QLineEdit(self.groupBox_12)
+ self.lineEdit_17.setObjectName("lineEdit_17")
+ self.horizontalLayout_20.addWidget(self.lineEdit_17)
+ self.verticalLayout_21.addLayout(self.horizontalLayout_20)
+ self.pushButton_32 = QtWidgets.QPushButton(self.groupBox_12)
+ self.pushButton_32.setObjectName("pushButton_32")
+ self.verticalLayout_21.addWidget(self.pushButton_32)
+ self.tabWidget.addTab(self.tab_4, "")
+ self.verticalLayout_7.addWidget(self.tabWidget)
+ self.textBrowser = QtWidgets.QTextBrowser(self.centralwidget)
+ self.textBrowser.setObjectName("textBrowser")
+ self.verticalLayout_7.addWidget(self.textBrowser)
+ self.horizontalLayout_14 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_14.setObjectName("horizontalLayout_14")
+ spacerItem = QtWidgets.QSpacerItem(618, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
+ self.horizontalLayout_14.addItem(spacerItem)
+ self.pushButton_9 = QtWidgets.QPushButton(self.centralwidget)
+ self.pushButton_9.setObjectName("pushButton_9")
+ self.horizontalLayout_14.addWidget(self.pushButton_9)
+ self.pushButton_10 = QtWidgets.QPushButton(self.centralwidget)
+ self.pushButton_10.setObjectName("pushButton_10")
+ self.horizontalLayout_14.addWidget(self.pushButton_10)
+ self.verticalLayout_7.addLayout(self.horizontalLayout_14)
+ self.progressBar = QtWidgets.QProgressBar(self.centralwidget)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.progressBar.sizePolicy().hasHeightForWidth())
+ self.progressBar.setSizePolicy(sizePolicy)
+ self.progressBar.setProperty("value", 0)
+ self.progressBar.setObjectName("progressBar")
+ self.verticalLayout_7.addWidget(self.progressBar)
+ self.verticalLayout_8.addLayout(self.verticalLayout_7)
+ MainWindow.setCentralWidget(self.centralwidget)
+ self.menubar = QtWidgets.QMenuBar(MainWindow)
+ self.menubar.setGeometry(QtCore.QRect(0, 0, 826, 22))
+ self.menubar.setObjectName("menubar")
+ self.menu = QtWidgets.QMenu(self.menubar)
+ self.menu.setObjectName("menu")
+ self.menu_2 = QtWidgets.QMenu(self.menubar)
+ self.menu_2.setObjectName("menu_2")
+ MainWindow.setMenuBar(self.menubar)
+ self.statusbar = QtWidgets.QStatusBar(MainWindow)
+ self.statusbar.setObjectName("statusbar")
+ MainWindow.setStatusBar(self.statusbar)
+ self.actionopen = QtWidgets.QAction(MainWindow)
+ self.actionopen.setObjectName("actionopen")
+ self.actionclose = QtWidgets.QAction(MainWindow)
+ self.actionclose.setObjectName("actionclose")
+ self.actionAbout = QtWidgets.QAction(MainWindow)
+ self.actionAbout.setObjectName("actionAbout")
+ self.action_3 = QtWidgets.QAction(MainWindow)
+ self.action_3.setObjectName("action_3")
+ self.actionIEEE754 = QtWidgets.QAction(MainWindow)
+ self.actionIEEE754.setObjectName("actionIEEE754")
+ self.menu.addAction(self.actionopen)
+ self.menu.addSeparator()
+ self.menu.addAction(self.action_3)
+ self.menu_2.addAction(self.actionAbout)
+ self.menu_2.addAction(self.actionIEEE754)
+ self.menubar.addAction(self.menu.menuAction())
+ self.menubar.addAction(self.menu_2.menuAction())
+
+ self.retranslateUi(MainWindow)
+ self.tabWidget.setCurrentIndex(3)
+ QtCore.QMetaObject.connectSlotsByName(MainWindow)
+
+ def retranslateUi(self, MainWindow):
+ _translate = QtCore.QCoreApplication.translate
+ MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
+ self.groupBox.setTitle(_translate("MainWindow", "大纲转说明-鉴定模板"))
+ self.pushButton.setText(_translate("MainWindow", "选择大纲文档"))
+ self.label.setText(_translate("MainWindow", "设计人员:"))
+ self.pushButton_3.setText(_translate("MainWindow", "测试记录转说明"))
+ self.pushButton_2.setText(_translate("MainWindow", "开始转换"))
+ self.groupBox_2.setTitle(_translate("MainWindow", "追踪关系填写"))
+ self.pushButton_4.setText(_translate("MainWindow", "选择文件"))
+ self.pushButton_6.setText(_translate("MainWindow", "大纲追踪关系填写(依据大纲文件)"))
+ self.pushButton_5.setText(_translate("MainWindow", "测试说明追踪填写(依据说明文件)"))
+ self.pushButton_18.setText(_translate("MainWindow", "测试报告追踪填写(依据记录文件)"))
+ self.groupBox_4.setTitle(_translate("MainWindow", "根据说明生成测试记录"))
+ self.pushButton_11.setText(_translate("MainWindow", "选择文件"))
+ self.label_4.setText(_translate("MainWindow", "测试人员:"))
+ self.label_5.setText(_translate("MainWindow", "监测人员:"))
+ self.label_6.setText(_translate("MainWindow", "测试时间:"))
+ self.pushButton_12.setText(_translate("MainWindow", "说明生成记录"))
+ self.pushButton_13.setText(_translate("MainWindow", "记录反向生成说明"))
+ self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("MainWindow", "文档生产工具"))
+ self.groupBox_3.setTitle(_translate("MainWindow", "UAS单元测试转换"))
+ self.label_2.setText(_translate("MainWindow", "被测软件名:"))
+ self.label_3.setText(_translate("MainWindow", "被测软件标识:"))
+ self.pushButton_7.setText(_translate("MainWindow", "请选择SAU报告文档"))
+ self.pushButton_8.setText(_translate("MainWindow", "开始转换"))
+ self.groupBox_5.setTitle(_translate("MainWindow", "自动填充"))
+ self.pushButton_16.setText(_translate("MainWindow", "选择文档"))
+ self.label_7.setText(_translate("MainWindow", "单元格左侧:"))
+ self.label_9.setText(_translate("MainWindow", "填充的内容:"))
+ self.label_10.setText(_translate("MainWindow", "填充的数量:"))
+ self.pushButton_14.setText(_translate("MainWindow", "清空单元格"))
+ self.pushButton_15.setText(_translate("MainWindow", "填充"))
+ self.groupBox_6.setTitle(_translate("MainWindow", "提取单元格标题右侧的单元格内容"))
+ self.pushButton_17.setText(_translate("MainWindow", "选择文档"))
+ self.label_8.setText(_translate("MainWindow", "单元格标题:"))
+ self.label_11.setText(_translate("MainWindow", "单元格标题:"))
+ self.label_12.setText(_translate("MainWindow", "单元格标题:"))
+ self.pushButton_19.setText(_translate("MainWindow", "点击提取"))
+ self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), _translate("MainWindow", "文档小工具"))
+ self.groupBox_10.setTitle(_translate("MainWindow", "部件测试表格"))
+ self.pushButton_27.setText(_translate("MainWindow", "选择UAS文件"))
+ self.pushButton_28.setText(_translate("MainWindow", "点击生成"))
+ self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_3), _translate("MainWindow", "报告生成工具"))
+ self.groupBox_11.setTitle(_translate("MainWindow", "FPGA记录自动填写"))
+ self.pushButton_29.setText(_translate("MainWindow", "选择FPGA记录文件"))
+ self.label_13.setText(_translate("MainWindow", "测试时间"))
+ self.label_14.setText(_translate("MainWindow", "测试人员"))
+ self.label_15.setText(_translate("MainWindow", "监测人员"))
+ self.label_16.setText(_translate("MainWindow", "项目编号"))
+ self.pushButton_30.setText(_translate("MainWindow", "自动填写开始"))
+ self.groupBox_12.setTitle(_translate("MainWindow", "FPGA记录转说明"))
+ self.pushButton_31.setText(_translate("MainWindow", "请选择完整FPGA记录文件"))
+ self.label_17.setText(_translate("MainWindow", "设计人员"))
+ self.pushButton_32.setText(_translate("MainWindow", "点击生成说明"))
+ self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_4), _translate("MainWindow", "FPGA工具"))
+ self.pushButton_9.setText(_translate("MainWindow", "清空消息"))
+ self.pushButton_10.setText(_translate("MainWindow", "显示帮助"))
+ self.menu.setTitle(_translate("MainWindow", "文件"))
+ self.menu_2.setTitle(_translate("MainWindow", "工具"))
+ self.actionopen.setText(_translate("MainWindow", "打开文件"))
+ self.actionclose.setText(_translate("MainWindow", "close"))
+ self.actionAbout.setText(_translate("MainWindow", "关于工具"))
+ self.action_3.setText(_translate("MainWindow", "退出"))
+ self.actionIEEE754.setText(_translate("MainWindow", "IEEE转换工具"))
diff --git a/__init__.py b/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/bak/FPGA记录to说明模板.docx b/bak/FPGA记录to说明模板.docx
new file mode 100644
index 0000000..f36e67f
Binary files /dev/null and b/bak/FPGA记录to说明模板.docx differ
diff --git a/bak/fpga_JtoS.py b/bak/fpga_JtoS.py
new file mode 100644
index 0000000..377e5bc
--- /dev/null
+++ b/bak/fpga_JtoS.py
@@ -0,0 +1,117 @@
+from PyQt5 import QtCore
+from PyQt5.QtCore import pyqtSignal
+from pathlib import *
+from PyQt5.QtWidgets import QMessageBox
+from docxtpl import DocxTemplate,InlineImage
+from docx import Document
+import io
+
+
+class create_FPGA_JtoS(QtCore.QThread):
+ sin_out = pyqtSignal(str)
+
+ def __init__(self,parent):
+ super().__init__()
+ self.parent = parent
+
+ def run(self):
+ self.sin_out.emit("进入测试记录转说明线程......")
+ self.sin_out.emit("开始转换......")
+ #如果没有选择文件路径则退出
+ if not self.parent.open_file_name:
+ self.sin_out.emit('nofile')
+ self.parent.tabWidget.setEnabled(True)
+ return
+
+ #打开模板文件进行渲染,然后就是用docxtpl生成用例
+ try:
+ tpl_path = Path.cwd() / "need" / "document_templates" / "FPGA记录to说明模板.docx"
+ self.sin_out.emit('导入模板文件路径为:' + str(tpl_path))
+ tpl = DocxTemplate(tpl_path) #模板导入成功
+
+ except:
+ QMessageBox.warning(self.parent,"出错了","导入模板出错请检查模板文件是否存在或名字不正确")
+ return
+
+
+ try:
+ doc = Document(self.parent.open_file_name[0])
+ self.sin_out.emit('已识别到FPGA测试记录文件...')
+ except:
+ self.sin_out.emit('open failed:选择的文档')
+ self.parent.tabWidget.setEnabled(True)
+ return
+
+ self.sin_out.emit('复制测试说明文档模板到本程序所在目录...')
+ curpath = Path.cwd() / 'need'
+ shuoming_path_tmp = curpath / 'document_templates' / 'FPGA记录to说明模板.docx'
+ print(shuoming_path_tmp)
+ if shuoming_path_tmp.is_file():
+ self.sin_out.emit('已检测到有说明模板文件...')
+ else:
+ self.sin_out.emit('open failed:选择的文档')
+ return
+
+ #创建一个字典来储存单个用例
+ data_list = []
+ #获取表格数量
+ tables = doc.tables
+ tb_count = len(tables)
+ self.sin_out.emit('total:'+ str(tb_count))
+
+ for i in range(tb_count):
+ if tables[i].cell(0,0).text == '测试用例名称':
+ try:
+ data = {'name':'','biaoshi':'','zhuizong':'','zongsu':'','init':'','qianti':'','step':[]}
+ self.sin_out.emit(str(i+1))
+ self.sin_out.emit(f'正在处理第{i+1}个表格')
+ # 1、获取测试用例名称
+ data['name'] = tables[i].cell(0,3).text
+ # 2、获取用例标识
+ data['biaoshi'] = tables[i].cell(0,8).text
+ # 3、获取追踪关系 注意word中换行为\r\x07
+ temp = tables[i].cell(1,3).text
+ data['zhuizong'] = temp.replace("\n", "\r\x07")
+ # 4、获取综述
+ data['zongsu'] = tables[i].cell(2,3).text
+ # 5、初始化
+ data['init'] = tables[i].cell(3,3).text
+ # 6、获取前提与约束
+ data['qianti'] = tables[i].cell(4,3).text
+ # 7、获取步骤信息-总行数减去12为步骤行数
+ row_count = len(tables[i].rows)
+ step_count = row_count - 12
+ for j in range(step_count):
+ buzhou = {'shuru':'','yuqi':'','num':'','image':'','is_image':'0'}
+ buzhou['num'] = tables[i].rows[7+j].cells[0].text
+ buzhou['shuru'] = tables[i].rows[7+j].cells[2].text
+ cel = tables[i].rows[7+j].cells[2]
+ if len(cel._element.findall('.//{http://schemas.openxmlformats.org/wordprocessingml/2006/main}drawing'))>0:
+ img_ele = cel._element.xpath('.//pic:pic')[0]
+ embed = img_ele.xpath('.//a:blip/@r:embed')[0]
+ related_part = doc.part.related_parts[embed]
+ image = related_part.image
+ image_bytes = image.blob
+ buzhou['image'] = InlineImage(tpl, io.BytesIO(image_bytes))
+ buzhou['is_image'] = '1'
+ buzhou['yuqi'] = tables[i].rows[7+j].cells[4].text
+ data['step'].append(buzhou)
+ # 8、最后加入data_list
+ data_list.append(data)
+ except:
+ self.sin_out.emit(f'第{i}个表格处理错误!')
+ pass
+
+
+ #开始渲染模板文件-有2层循环
+ try:
+ context = {
+ "tables":data_list,
+ "renyuan":self.parent.lineEdit_17.text(),
+ }
+ tpl.render(context)
+ tpl.save("FPGA反向生成的说明文档.docx")
+ self.sin_out.emit('stopsuccess')
+ except:
+ self.sin_out.emit('stoperror')
+ return
\ No newline at end of file
diff --git a/demo/XXFPGA测试记录.doc b/demo/XXFPGA测试记录.doc
new file mode 100644
index 0000000..0d8bb57
Binary files /dev/null and b/demo/XXFPGA测试记录.doc differ
diff --git a/demo/XXFPGA测试记录.docx b/demo/XXFPGA测试记录.docx
new file mode 100644
index 0000000..96f9a49
Binary files /dev/null and b/demo/XXFPGA测试记录.docx differ
diff --git a/demo/XXPGA测试说明.doc b/demo/XXPGA测试说明.doc
new file mode 100644
index 0000000..3479203
Binary files /dev/null and b/demo/XXPGA测试说明.doc differ
diff --git a/demo/单元测试记录demo.docx b/demo/单元测试记录demo.docx
new file mode 100644
index 0000000..29a4d78
Binary files /dev/null and b/demo/单元测试记录demo.docx differ
diff --git a/index.py b/index.py
new file mode 100644
index 0000000..1c342b5
--- /dev/null
+++ b/index.py
@@ -0,0 +1,45 @@
+# -*- coding: utf-8 -*-
+import sys
+from PyQt5.QtWidgets import QApplication
+from PyQt5 import QtCore, QtGui
+from need.main import userMain
+import qtmodern.styles
+import qtmodern.windows
+# from qt_material import apply_stylesheet
+#以下导入为打包导入所需-使用软件
+import os
+import sys
+import json
+import docx
+import docxtpl
+import six
+import docxcompose
+import lxml
+import markupsafe
+import win32api
+import win32com
+
+if __name__ == "__main__":
+ pyqt5_path = os.path.join(sys.prefix, 'Lib', 'site-packages', 'PyQt5', 'Qt5', 'plugins', 'platforms')
+ if os.path.exists(pyqt5_path) and os.path.exists(os.path.join(pyqt5_path, 'qwindows.dll')):
+ os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = pyqt5_path
+
+ QtCore.QCoreApplication.setAttribute(QtCore.Qt.ApplicationAttribute.AA_EnableHighDpiScaling)
+ app = QApplication(sys.argv)
+ # 设置任务栏软件图标
+ app.setWindowIcon(QtGui.QIcon('Icon.png'))
+ win = userMain()
+ ##以下是qt_material样式加载
+ # apply_stylesheet(app,theme = 'dark_teal.xml')
+ # win.show()
+
+ qtmodern.styles.light(app) #还有dark可以选择
+ mw = qtmodern.windows.ModernWindow(win)
+ mw.show()
+ '''
+ #设置窗口有边框可拖动,但删除标题栏
+ self.setWindowFlags(
+ Qt.Window | Qt.CustomizeWindowHint | Qt.WindowSystemMenuHint)
+ # win.show()
+ '''
+ sys.exit(app.exec_())
diff --git a/need/Ui_GUI.py b/need/Ui_GUI.py
new file mode 100644
index 0000000..ef6977d
--- /dev/null
+++ b/need/Ui_GUI.py
@@ -0,0 +1,510 @@
+# -*- coding: utf-8 -*-
+
+# Form implementation generated from reading ui file 'GUI.ui'
+#
+# Created by: PyQt5 UI code generator 5.15.4
+#
+# WARNING: Any manual changes made to this file will be lost when pyuic5 is
+# run again. Do not edit this file unless you know what you are doing.
+
+
+from PyQt5 import QtCore, QtGui, QtWidgets
+
+
+class Ui_MainWindow(object):
+ def setupUi(self, MainWindow):
+ MainWindow.setObjectName("MainWindow")
+ MainWindow.resize(826, 619)
+ self.centralwidget = QtWidgets.QWidget(MainWindow)
+ self.centralwidget.setObjectName("centralwidget")
+ self.verticalLayout_8 = QtWidgets.QVBoxLayout(self.centralwidget)
+ self.verticalLayout_8.setObjectName("verticalLayout_8")
+ self.verticalLayout_7 = QtWidgets.QVBoxLayout()
+ self.verticalLayout_7.setObjectName("verticalLayout_7")
+ self.tabWidget = QtWidgets.QTabWidget(self.centralwidget)
+ font = QtGui.QFont()
+ font.setFamily("微软雅黑")
+ font.setPointSize(10)
+ font.setBold(False)
+ font.setWeight(50)
+ self.tabWidget.setFont(font)
+ self.tabWidget.setObjectName("tabWidget")
+ self.tab = QtWidgets.QWidget()
+ self.tab.setObjectName("tab")
+ self.gridLayout = QtWidgets.QGridLayout(self.tab)
+ self.gridLayout.setObjectName("gridLayout")
+ self.horizontalLayout_15 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_15.setObjectName("horizontalLayout_15")
+ self.groupBox = QtWidgets.QGroupBox(self.tab)
+ font = QtGui.QFont()
+ font.setFamily("微软雅黑")
+ font.setPointSize(10)
+ font.setBold(False)
+ font.setWeight(50)
+ self.groupBox.setFont(font)
+ self.groupBox.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter)
+ self.groupBox.setFlat(False)
+ self.groupBox.setObjectName("groupBox")
+ self.verticalLayout = QtWidgets.QVBoxLayout(self.groupBox)
+ self.verticalLayout.setObjectName("verticalLayout")
+ self.pushButton = QtWidgets.QPushButton(self.groupBox)
+ self.pushButton.setObjectName("pushButton")
+ self.verticalLayout.addWidget(self.pushButton)
+ self.horizontalLayout = QtWidgets.QHBoxLayout()
+ self.horizontalLayout.setObjectName("horizontalLayout")
+ self.label = QtWidgets.QLabel(self.groupBox)
+ self.label.setObjectName("label")
+ self.horizontalLayout.addWidget(self.label)
+ self.lineEdit = QtWidgets.QLineEdit(self.groupBox)
+ self.lineEdit.setObjectName("lineEdit")
+ self.horizontalLayout.addWidget(self.lineEdit)
+ self.verticalLayout.addLayout(self.horizontalLayout)
+ self.pushButton_3 = QtWidgets.QPushButton(self.groupBox)
+ self.pushButton_3.setObjectName("pushButton_3")
+ self.verticalLayout.addWidget(self.pushButton_3)
+ self.pushButton_2 = QtWidgets.QPushButton(self.groupBox)
+ self.pushButton_2.setObjectName("pushButton_2")
+ self.verticalLayout.addWidget(self.pushButton_2)
+ self.horizontalLayout_15.addWidget(self.groupBox)
+ self.groupBox_2 = QtWidgets.QGroupBox(self.tab)
+ font = QtGui.QFont()
+ font.setFamily("微软雅黑")
+ font.setPointSize(10)
+ font.setBold(False)
+ font.setWeight(50)
+ self.groupBox_2.setFont(font)
+ self.groupBox_2.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter)
+ self.groupBox_2.setFlat(False)
+ self.groupBox_2.setObjectName("groupBox_2")
+ self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.groupBox_2)
+ self.verticalLayout_2.setObjectName("verticalLayout_2")
+ self.pushButton_4 = QtWidgets.QPushButton(self.groupBox_2)
+ self.pushButton_4.setObjectName("pushButton_4")
+ self.verticalLayout_2.addWidget(self.pushButton_4)
+ self.pushButton_6 = QtWidgets.QPushButton(self.groupBox_2)
+ self.pushButton_6.setObjectName("pushButton_6")
+ self.verticalLayout_2.addWidget(self.pushButton_6)
+ self.pushButton_5 = QtWidgets.QPushButton(self.groupBox_2)
+ self.pushButton_5.setObjectName("pushButton_5")
+ self.verticalLayout_2.addWidget(self.pushButton_5)
+ self.pushButton_18 = QtWidgets.QPushButton(self.groupBox_2)
+ self.pushButton_18.setObjectName("pushButton_18")
+ self.verticalLayout_2.addWidget(self.pushButton_18)
+ self.horizontalLayout_15.addWidget(self.groupBox_2)
+ self.groupBox_4 = QtWidgets.QGroupBox(self.tab)
+ font = QtGui.QFont()
+ font.setFamily("微软雅黑")
+ font.setPointSize(10)
+ font.setBold(False)
+ font.setWeight(50)
+ self.groupBox_4.setFont(font)
+ self.groupBox_4.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter)
+ self.groupBox_4.setFlat(False)
+ self.groupBox_4.setObjectName("groupBox_4")
+ self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.groupBox_4)
+ self.verticalLayout_4.setObjectName("verticalLayout_4")
+ self.pushButton_11 = QtWidgets.QPushButton(self.groupBox_4)
+ self.pushButton_11.setObjectName("pushButton_11")
+ self.verticalLayout_4.addWidget(self.pushButton_11)
+ self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_2.setObjectName("horizontalLayout_2")
+ self.label_4 = QtWidgets.QLabel(self.groupBox_4)
+ self.label_4.setTextFormat(QtCore.Qt.AutoText)
+ self.label_4.setAlignment(QtCore.Qt.AlignCenter)
+ self.label_4.setObjectName("label_4")
+ self.horizontalLayout_2.addWidget(self.label_4)
+ self.lineEdit_4 = QtWidgets.QLineEdit(self.groupBox_4)
+ self.lineEdit_4.setObjectName("lineEdit_4")
+ self.horizontalLayout_2.addWidget(self.lineEdit_4)
+ self.verticalLayout_4.addLayout(self.horizontalLayout_2)
+ self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_3.setObjectName("horizontalLayout_3")
+ self.label_5 = QtWidgets.QLabel(self.groupBox_4)
+ self.label_5.setTextFormat(QtCore.Qt.AutoText)
+ self.label_5.setAlignment(QtCore.Qt.AlignCenter)
+ self.label_5.setObjectName("label_5")
+ self.horizontalLayout_3.addWidget(self.label_5)
+ self.lineEdit_5 = QtWidgets.QLineEdit(self.groupBox_4)
+ self.lineEdit_5.setObjectName("lineEdit_5")
+ self.horizontalLayout_3.addWidget(self.lineEdit_5)
+ self.verticalLayout_4.addLayout(self.horizontalLayout_3)
+ self.horizontalLayout_4 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_4.setObjectName("horizontalLayout_4")
+ self.label_6 = QtWidgets.QLabel(self.groupBox_4)
+ self.label_6.setTextFormat(QtCore.Qt.AutoText)
+ self.label_6.setAlignment(QtCore.Qt.AlignCenter)
+ self.label_6.setObjectName("label_6")
+ self.horizontalLayout_4.addWidget(self.label_6)
+ self.lineEdit_6 = QtWidgets.QLineEdit(self.groupBox_4)
+ self.lineEdit_6.setObjectName("lineEdit_6")
+ self.horizontalLayout_4.addWidget(self.lineEdit_6)
+ self.verticalLayout_4.addLayout(self.horizontalLayout_4)
+ self.horizontalLayout_5 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_5.setObjectName("horizontalLayout_5")
+ self.pushButton_12 = QtWidgets.QPushButton(self.groupBox_4)
+ self.pushButton_12.setObjectName("pushButton_12")
+ self.horizontalLayout_5.addWidget(self.pushButton_12)
+ self.pushButton_13 = QtWidgets.QPushButton(self.groupBox_4)
+ self.pushButton_13.setObjectName("pushButton_13")
+ self.horizontalLayout_5.addWidget(self.pushButton_13)
+ self.verticalLayout_4.addLayout(self.horizontalLayout_5)
+ self.horizontalLayout_15.addWidget(self.groupBox_4)
+ self.gridLayout.addLayout(self.horizontalLayout_15, 0, 0, 1, 1)
+ self.tabWidget.addTab(self.tab, "")
+ self.tab_2 = QtWidgets.QWidget()
+ self.tab_2.setObjectName("tab_2")
+ self.verticalLayout_12 = QtWidgets.QVBoxLayout(self.tab_2)
+ self.verticalLayout_12.setObjectName("verticalLayout_12")
+ self.horizontalLayout_13 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_13.setObjectName("horizontalLayout_13")
+ self.groupBox_3 = QtWidgets.QGroupBox(self.tab_2)
+ font = QtGui.QFont()
+ font.setFamily("微软雅黑")
+ font.setPointSize(10)
+ font.setBold(False)
+ font.setWeight(50)
+ self.groupBox_3.setFont(font)
+ self.groupBox_3.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter)
+ self.groupBox_3.setFlat(False)
+ self.groupBox_3.setObjectName("groupBox_3")
+ self.verticalLayout_9 = QtWidgets.QVBoxLayout(self.groupBox_3)
+ self.verticalLayout_9.setObjectName("verticalLayout_9")
+ self.verticalLayout_3 = QtWidgets.QVBoxLayout()
+ self.verticalLayout_3.setObjectName("verticalLayout_3")
+ self.label_2 = QtWidgets.QLabel(self.groupBox_3)
+ self.label_2.setObjectName("label_2")
+ self.verticalLayout_3.addWidget(self.label_2)
+ self.lineEdit_2 = QtWidgets.QLineEdit(self.groupBox_3)
+ self.lineEdit_2.setObjectName("lineEdit_2")
+ self.verticalLayout_3.addWidget(self.lineEdit_2)
+ self.label_3 = QtWidgets.QLabel(self.groupBox_3)
+ self.label_3.setObjectName("label_3")
+ self.verticalLayout_3.addWidget(self.label_3)
+ self.lineEdit_3 = QtWidgets.QLineEdit(self.groupBox_3)
+ self.lineEdit_3.setObjectName("lineEdit_3")
+ self.verticalLayout_3.addWidget(self.lineEdit_3)
+ self.pushButton_7 = QtWidgets.QPushButton(self.groupBox_3)
+ self.pushButton_7.setObjectName("pushButton_7")
+ self.verticalLayout_3.addWidget(self.pushButton_7)
+ self.pushButton_8 = QtWidgets.QPushButton(self.groupBox_3)
+ self.pushButton_8.setObjectName("pushButton_8")
+ self.verticalLayout_3.addWidget(self.pushButton_8)
+ self.verticalLayout_9.addLayout(self.verticalLayout_3)
+ self.horizontalLayout_13.addWidget(self.groupBox_3)
+ self.groupBox_5 = QtWidgets.QGroupBox(self.tab_2)
+ font = QtGui.QFont()
+ font.setFamily("微软雅黑")
+ font.setPointSize(10)
+ font.setBold(False)
+ font.setWeight(50)
+ self.groupBox_5.setFont(font)
+ self.groupBox_5.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter)
+ self.groupBox_5.setFlat(False)
+ self.groupBox_5.setObjectName("groupBox_5")
+ self.verticalLayout_10 = QtWidgets.QVBoxLayout(self.groupBox_5)
+ self.verticalLayout_10.setObjectName("verticalLayout_10")
+ self.verticalLayout_5 = QtWidgets.QVBoxLayout()
+ self.verticalLayout_5.setObjectName("verticalLayout_5")
+ self.pushButton_16 = QtWidgets.QPushButton(self.groupBox_5)
+ self.pushButton_16.setObjectName("pushButton_16")
+ self.verticalLayout_5.addWidget(self.pushButton_16)
+ self.horizontalLayout_6 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_6.setObjectName("horizontalLayout_6")
+ self.label_7 = QtWidgets.QLabel(self.groupBox_5)
+ self.label_7.setObjectName("label_7")
+ self.horizontalLayout_6.addWidget(self.label_7)
+ self.lineEdit_9 = QtWidgets.QLineEdit(self.groupBox_5)
+ self.lineEdit_9.setObjectName("lineEdit_9")
+ self.horizontalLayout_6.addWidget(self.lineEdit_9)
+ self.verticalLayout_5.addLayout(self.horizontalLayout_6)
+ self.horizontalLayout_7 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_7.setObjectName("horizontalLayout_7")
+ self.label_9 = QtWidgets.QLabel(self.groupBox_5)
+ self.label_9.setObjectName("label_9")
+ self.horizontalLayout_7.addWidget(self.label_9)
+ self.lineEdit_10 = QtWidgets.QLineEdit(self.groupBox_5)
+ self.lineEdit_10.setObjectName("lineEdit_10")
+ self.horizontalLayout_7.addWidget(self.lineEdit_10)
+ self.verticalLayout_5.addLayout(self.horizontalLayout_7)
+ self.horizontalLayout_8 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_8.setObjectName("horizontalLayout_8")
+ self.label_10 = QtWidgets.QLabel(self.groupBox_5)
+ self.label_10.setObjectName("label_10")
+ self.horizontalLayout_8.addWidget(self.label_10)
+ self.lineEdit_11 = QtWidgets.QLineEdit(self.groupBox_5)
+ self.lineEdit_11.setObjectName("lineEdit_11")
+ self.horizontalLayout_8.addWidget(self.lineEdit_11)
+ self.verticalLayout_5.addLayout(self.horizontalLayout_8)
+ self.horizontalLayout_9 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_9.setObjectName("horizontalLayout_9")
+ self.pushButton_14 = QtWidgets.QPushButton(self.groupBox_5)
+ self.pushButton_14.setObjectName("pushButton_14")
+ self.horizontalLayout_9.addWidget(self.pushButton_14)
+ self.pushButton_15 = QtWidgets.QPushButton(self.groupBox_5)
+ self.pushButton_15.setObjectName("pushButton_15")
+ self.horizontalLayout_9.addWidget(self.pushButton_15)
+ self.verticalLayout_5.addLayout(self.horizontalLayout_9)
+ self.verticalLayout_10.addLayout(self.verticalLayout_5)
+ self.horizontalLayout_13.addWidget(self.groupBox_5)
+ self.groupBox_6 = QtWidgets.QGroupBox(self.tab_2)
+ font = QtGui.QFont()
+ font.setFamily("微软雅黑")
+ font.setPointSize(10)
+ font.setBold(False)
+ font.setWeight(50)
+ self.groupBox_6.setFont(font)
+ self.groupBox_6.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter)
+ self.groupBox_6.setFlat(False)
+ self.groupBox_6.setObjectName("groupBox_6")
+ self.verticalLayout_11 = QtWidgets.QVBoxLayout(self.groupBox_6)
+ self.verticalLayout_11.setObjectName("verticalLayout_11")
+ self.verticalLayout_6 = QtWidgets.QVBoxLayout()
+ self.verticalLayout_6.setObjectName("verticalLayout_6")
+ self.pushButton_17 = QtWidgets.QPushButton(self.groupBox_6)
+ self.pushButton_17.setObjectName("pushButton_17")
+ self.verticalLayout_6.addWidget(self.pushButton_17)
+ self.horizontalLayout_10 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_10.setObjectName("horizontalLayout_10")
+ self.label_8 = QtWidgets.QLabel(self.groupBox_6)
+ self.label_8.setObjectName("label_8")
+ self.horizontalLayout_10.addWidget(self.label_8)
+ self.lineEdit_12 = QtWidgets.QLineEdit(self.groupBox_6)
+ self.lineEdit_12.setObjectName("lineEdit_12")
+ self.horizontalLayout_10.addWidget(self.lineEdit_12)
+ self.verticalLayout_6.addLayout(self.horizontalLayout_10)
+ self.horizontalLayout_11 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_11.setObjectName("horizontalLayout_11")
+ self.label_11 = QtWidgets.QLabel(self.groupBox_6)
+ self.label_11.setObjectName("label_11")
+ self.horizontalLayout_11.addWidget(self.label_11)
+ self.lineEdit_13 = QtWidgets.QLineEdit(self.groupBox_6)
+ self.lineEdit_13.setObjectName("lineEdit_13")
+ self.horizontalLayout_11.addWidget(self.lineEdit_13)
+ self.verticalLayout_6.addLayout(self.horizontalLayout_11)
+ self.horizontalLayout_12 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_12.setObjectName("horizontalLayout_12")
+ self.label_12 = QtWidgets.QLabel(self.groupBox_6)
+ self.label_12.setObjectName("label_12")
+ self.horizontalLayout_12.addWidget(self.label_12)
+ self.lineEdit_14 = QtWidgets.QLineEdit(self.groupBox_6)
+ self.lineEdit_14.setObjectName("lineEdit_14")
+ self.horizontalLayout_12.addWidget(self.lineEdit_14)
+ self.verticalLayout_6.addLayout(self.horizontalLayout_12)
+ self.pushButton_19 = QtWidgets.QPushButton(self.groupBox_6)
+ self.pushButton_19.setObjectName("pushButton_19")
+ self.verticalLayout_6.addWidget(self.pushButton_19)
+ self.verticalLayout_11.addLayout(self.verticalLayout_6)
+ self.horizontalLayout_13.addWidget(self.groupBox_6)
+ self.verticalLayout_12.addLayout(self.horizontalLayout_13)
+ self.tabWidget.addTab(self.tab_2, "")
+ self.tab_3 = QtWidgets.QWidget()
+ self.tab_3.setObjectName("tab_3")
+ self.groupBox_10 = QtWidgets.QGroupBox(self.tab_3)
+ self.groupBox_10.setGeometry(QtCore.QRect(5, 5, 161, 211))
+ self.groupBox_10.setObjectName("groupBox_10")
+ self.verticalLayout_19 = QtWidgets.QVBoxLayout(self.groupBox_10)
+ self.verticalLayout_19.setObjectName("verticalLayout_19")
+ self.pushButton_27 = QtWidgets.QPushButton(self.groupBox_10)
+ self.pushButton_27.setObjectName("pushButton_27")
+ self.verticalLayout_19.addWidget(self.pushButton_27)
+ self.pushButton_28 = QtWidgets.QPushButton(self.groupBox_10)
+ self.pushButton_28.setObjectName("pushButton_28")
+ self.verticalLayout_19.addWidget(self.pushButton_28)
+ self.tabWidget.addTab(self.tab_3, "")
+ self.tab_4 = QtWidgets.QWidget()
+ self.tab_4.setObjectName("tab_4")
+ self.groupBox_11 = QtWidgets.QGroupBox(self.tab_4)
+ self.groupBox_11.setGeometry(QtCore.QRect(5, 5, 246, 211))
+ self.groupBox_11.setObjectName("groupBox_11")
+ self.verticalLayout_20 = QtWidgets.QVBoxLayout(self.groupBox_11)
+ self.verticalLayout_20.setObjectName("verticalLayout_20")
+ self.pushButton_29 = QtWidgets.QPushButton(self.groupBox_11)
+ self.pushButton_29.setObjectName("pushButton_29")
+ self.verticalLayout_20.addWidget(self.pushButton_29)
+ self.verticalLayout_13 = QtWidgets.QVBoxLayout()
+ self.verticalLayout_13.setObjectName("verticalLayout_13")
+ self.horizontalLayout_16 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_16.setObjectName("horizontalLayout_16")
+ self.label_13 = QtWidgets.QLabel(self.groupBox_11)
+ self.label_13.setObjectName("label_13")
+ self.horizontalLayout_16.addWidget(self.label_13)
+ self.lineEdit_7 = QtWidgets.QLineEdit(self.groupBox_11)
+ self.lineEdit_7.setObjectName("lineEdit_7")
+ self.horizontalLayout_16.addWidget(self.lineEdit_7)
+ self.verticalLayout_13.addLayout(self.horizontalLayout_16)
+ self.horizontalLayout_17 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_17.setObjectName("horizontalLayout_17")
+ self.label_14 = QtWidgets.QLabel(self.groupBox_11)
+ self.label_14.setObjectName("label_14")
+ self.horizontalLayout_17.addWidget(self.label_14)
+ self.lineEdit_8 = QtWidgets.QLineEdit(self.groupBox_11)
+ self.lineEdit_8.setObjectName("lineEdit_8")
+ self.horizontalLayout_17.addWidget(self.lineEdit_8)
+ self.verticalLayout_13.addLayout(self.horizontalLayout_17)
+ self.horizontalLayout_18 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_18.setObjectName("horizontalLayout_18")
+ self.label_15 = QtWidgets.QLabel(self.groupBox_11)
+ self.label_15.setObjectName("label_15")
+ self.horizontalLayout_18.addWidget(self.label_15)
+ self.lineEdit_15 = QtWidgets.QLineEdit(self.groupBox_11)
+ self.lineEdit_15.setObjectName("lineEdit_15")
+ self.horizontalLayout_18.addWidget(self.lineEdit_15)
+ self.verticalLayout_13.addLayout(self.horizontalLayout_18)
+ self.horizontalLayout_19 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_19.setObjectName("horizontalLayout_19")
+ self.label_16 = QtWidgets.QLabel(self.groupBox_11)
+ self.label_16.setObjectName("label_16")
+ self.horizontalLayout_19.addWidget(self.label_16)
+ self.lineEdit_16 = QtWidgets.QLineEdit(self.groupBox_11)
+ self.lineEdit_16.setObjectName("lineEdit_16")
+ self.horizontalLayout_19.addWidget(self.lineEdit_16)
+ self.verticalLayout_13.addLayout(self.horizontalLayout_19)
+ self.verticalLayout_20.addLayout(self.verticalLayout_13)
+ self.pushButton_30 = QtWidgets.QPushButton(self.groupBox_11)
+ self.pushButton_30.setObjectName("pushButton_30")
+ self.verticalLayout_20.addWidget(self.pushButton_30)
+ self.groupBox_12 = QtWidgets.QGroupBox(self.tab_4)
+ self.groupBox_12.setGeometry(QtCore.QRect(255, 5, 191, 211))
+ self.groupBox_12.setObjectName("groupBox_12")
+ self.verticalLayout_21 = QtWidgets.QVBoxLayout(self.groupBox_12)
+ self.verticalLayout_21.setObjectName("verticalLayout_21")
+ self.pushButton_31 = QtWidgets.QPushButton(self.groupBox_12)
+ self.pushButton_31.setObjectName("pushButton_31")
+ self.verticalLayout_21.addWidget(self.pushButton_31)
+ self.horizontalLayout_20 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_20.setObjectName("horizontalLayout_20")
+ self.label_17 = QtWidgets.QLabel(self.groupBox_12)
+ self.label_17.setObjectName("label_17")
+ self.horizontalLayout_20.addWidget(self.label_17)
+ self.lineEdit_17 = QtWidgets.QLineEdit(self.groupBox_12)
+ self.lineEdit_17.setObjectName("lineEdit_17")
+ self.horizontalLayout_20.addWidget(self.lineEdit_17)
+ self.verticalLayout_21.addLayout(self.horizontalLayout_20)
+ self.pushButton_32 = QtWidgets.QPushButton(self.groupBox_12)
+ self.pushButton_32.setObjectName("pushButton_32")
+ self.verticalLayout_21.addWidget(self.pushButton_32)
+ self.tabWidget.addTab(self.tab_4, "")
+ self.verticalLayout_7.addWidget(self.tabWidget)
+ self.textBrowser = QtWidgets.QTextBrowser(self.centralwidget)
+ self.textBrowser.setObjectName("textBrowser")
+ self.verticalLayout_7.addWidget(self.textBrowser)
+ self.horizontalLayout_14 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_14.setObjectName("horizontalLayout_14")
+ spacerItem = QtWidgets.QSpacerItem(618, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
+ self.horizontalLayout_14.addItem(spacerItem)
+ self.pushButton_9 = QtWidgets.QPushButton(self.centralwidget)
+ self.pushButton_9.setObjectName("pushButton_9")
+ self.horizontalLayout_14.addWidget(self.pushButton_9)
+ self.pushButton_10 = QtWidgets.QPushButton(self.centralwidget)
+ self.pushButton_10.setObjectName("pushButton_10")
+ self.horizontalLayout_14.addWidget(self.pushButton_10)
+ self.verticalLayout_7.addLayout(self.horizontalLayout_14)
+ self.progressBar = QtWidgets.QProgressBar(self.centralwidget)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.progressBar.sizePolicy().hasHeightForWidth())
+ self.progressBar.setSizePolicy(sizePolicy)
+ self.progressBar.setProperty("value", 0)
+ self.progressBar.setObjectName("progressBar")
+ self.verticalLayout_7.addWidget(self.progressBar)
+ self.verticalLayout_8.addLayout(self.verticalLayout_7)
+ MainWindow.setCentralWidget(self.centralwidget)
+ self.menubar = QtWidgets.QMenuBar(MainWindow)
+ self.menubar.setGeometry(QtCore.QRect(0, 0, 826, 22))
+ self.menubar.setObjectName("menubar")
+ self.menu = QtWidgets.QMenu(self.menubar)
+ self.menu.setObjectName("menu")
+ self.menu_2 = QtWidgets.QMenu(self.menubar)
+ self.menu_2.setObjectName("menu_2")
+ MainWindow.setMenuBar(self.menubar)
+ self.statusbar = QtWidgets.QStatusBar(MainWindow)
+ self.statusbar.setObjectName("statusbar")
+ MainWindow.setStatusBar(self.statusbar)
+ self.actionopen = QtWidgets.QAction(MainWindow)
+ self.actionopen.setObjectName("actionopen")
+ self.actionclose = QtWidgets.QAction(MainWindow)
+ self.actionclose.setObjectName("actionclose")
+ self.actionAbout = QtWidgets.QAction(MainWindow)
+ self.actionAbout.setObjectName("actionAbout")
+ self.action_3 = QtWidgets.QAction(MainWindow)
+ self.action_3.setObjectName("action_3")
+ self.actionIEEE754 = QtWidgets.QAction(MainWindow)
+ self.actionIEEE754.setObjectName("actionIEEE754")
+ self.menu.addAction(self.actionopen)
+ self.menu.addSeparator()
+ self.menu.addAction(self.action_3)
+ self.menu_2.addAction(self.actionAbout)
+ self.menu_2.addAction(self.actionIEEE754)
+ self.menubar.addAction(self.menu.menuAction())
+ self.menubar.addAction(self.menu_2.menuAction())
+
+ self.retranslateUi(MainWindow)
+ self.tabWidget.setCurrentIndex(3)
+ QtCore.QMetaObject.connectSlotsByName(MainWindow)
+
+ def retranslateUi(self, MainWindow):
+ _translate = QtCore.QCoreApplication.translate
+ MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
+ self.groupBox.setTitle(_translate("MainWindow", "大纲转说明-鉴定模板"))
+ self.pushButton.setText(_translate("MainWindow", "选择大纲文档"))
+ self.label.setText(_translate("MainWindow", "设计人员:"))
+ self.pushButton_3.setText(_translate("MainWindow", "测试记录转说明"))
+ self.pushButton_2.setText(_translate("MainWindow", "开始转换"))
+ self.groupBox_2.setTitle(_translate("MainWindow", "追踪关系填写"))
+ self.pushButton_4.setText(_translate("MainWindow", "选择文件"))
+ self.pushButton_6.setText(_translate("MainWindow", "大纲追踪关系填写(依据大纲文件)"))
+ self.pushButton_5.setText(_translate("MainWindow", "测试说明追踪填写(依据说明文件)"))
+ self.pushButton_18.setText(_translate("MainWindow", "测试报告追踪填写(依据记录文件)"))
+ self.groupBox_4.setTitle(_translate("MainWindow", "根据说明生成测试记录"))
+ self.pushButton_11.setText(_translate("MainWindow", "选择文件"))
+ self.label_4.setText(_translate("MainWindow", "测试人员:"))
+ self.label_5.setText(_translate("MainWindow", "监测人员:"))
+ self.label_6.setText(_translate("MainWindow", "测试时间:"))
+ self.pushButton_12.setText(_translate("MainWindow", "说明生成记录"))
+ self.pushButton_13.setText(_translate("MainWindow", "记录反向生成说明"))
+ self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("MainWindow", "文档生产工具"))
+ self.groupBox_3.setTitle(_translate("MainWindow", "UAS单元测试转换"))
+ self.label_2.setText(_translate("MainWindow", "被测软件名:"))
+ self.label_3.setText(_translate("MainWindow", "被测软件标识:"))
+ self.pushButton_7.setText(_translate("MainWindow", "请选择SAU报告文档"))
+ self.pushButton_8.setText(_translate("MainWindow", "开始转换"))
+ self.groupBox_5.setTitle(_translate("MainWindow", "自动填充"))
+ self.pushButton_16.setText(_translate("MainWindow", "选择文档"))
+ self.label_7.setText(_translate("MainWindow", "单元格左侧:"))
+ self.label_9.setText(_translate("MainWindow", "填充的内容:"))
+ self.label_10.setText(_translate("MainWindow", "填充的数量:"))
+ self.pushButton_14.setText(_translate("MainWindow", "清空单元格"))
+ self.pushButton_15.setText(_translate("MainWindow", "填充"))
+ self.groupBox_6.setTitle(_translate("MainWindow", "提取单元格标题右侧的单元格内容"))
+ self.pushButton_17.setText(_translate("MainWindow", "选择文档"))
+ self.label_8.setText(_translate("MainWindow", "单元格标题:"))
+ self.label_11.setText(_translate("MainWindow", "单元格标题:"))
+ self.label_12.setText(_translate("MainWindow", "单元格标题:"))
+ self.pushButton_19.setText(_translate("MainWindow", "点击提取"))
+ self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), _translate("MainWindow", "文档小工具"))
+ self.groupBox_10.setTitle(_translate("MainWindow", "部件测试表格"))
+ self.pushButton_27.setText(_translate("MainWindow", "选择UAS文件"))
+ self.pushButton_28.setText(_translate("MainWindow", "点击生成"))
+ self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_3), _translate("MainWindow", "报告生成工具"))
+ self.groupBox_11.setTitle(_translate("MainWindow", "FPGA记录自动填写"))
+ self.pushButton_29.setText(_translate("MainWindow", "选择FPGA记录文件"))
+ self.label_13.setText(_translate("MainWindow", "测试时间"))
+ self.label_14.setText(_translate("MainWindow", "测试人员"))
+ self.label_15.setText(_translate("MainWindow", "监测人员"))
+ self.label_16.setText(_translate("MainWindow", "项目编号"))
+ self.pushButton_30.setText(_translate("MainWindow", "自动填写开始"))
+ self.groupBox_12.setTitle(_translate("MainWindow", "FPGA记录转说明"))
+ self.pushButton_31.setText(_translate("MainWindow", "请选择完整FPGA记录文件"))
+ self.label_17.setText(_translate("MainWindow", "设计人员"))
+ self.pushButton_32.setText(_translate("MainWindow", "点击生成说明"))
+ self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_4), _translate("MainWindow", "FPGA工具"))
+ self.pushButton_9.setText(_translate("MainWindow", "清空消息"))
+ self.pushButton_10.setText(_translate("MainWindow", "显示帮助"))
+ self.menu.setTitle(_translate("MainWindow", "文件"))
+ self.menu_2.setTitle(_translate("MainWindow", "工具"))
+ self.actionopen.setText(_translate("MainWindow", "打开文件"))
+ self.actionclose.setText(_translate("MainWindow", "close"))
+ self.actionAbout.setText(_translate("MainWindow", "关于工具"))
+ self.action_3.setText(_translate("MainWindow", "退出"))
+ self.actionIEEE754.setText(_translate("MainWindow", "IEEE转换工具"))
diff --git a/need/about.py b/need/about.py
new file mode 100644
index 0000000..f12b1c2
--- /dev/null
+++ b/need/about.py
@@ -0,0 +1,50 @@
+# -*- coding: utf-8 -*-
+
+# Form implementation generated from reading ui file 'about.ui'
+#
+# Created by: PyQt5 UI code generator 5.12.1
+#
+# WARNING! All changes made in this file will be lost!
+
+from PyQt5 import QtCore, QtGui, QtWidgets
+
+
+class Ui_Dialog(object):
+ def setupUi(self, Dialog):
+ Dialog.setObjectName("Dialog")
+ Dialog.resize(290, 80)
+ self.horizontalLayout = QtWidgets.QHBoxLayout(Dialog)
+ self.horizontalLayout.setObjectName("horizontalLayout")
+ self.label = QtWidgets.QLabel(Dialog)
+ self.label.setText("")
+ self.label.setPixmap(QtGui.QPixmap(r'need/static/zxlogo.gif'))
+ self.label.setObjectName("label")
+ self.horizontalLayout.addWidget(self.label)
+ self.verticalLayout = QtWidgets.QVBoxLayout()
+ self.verticalLayout.setObjectName("verticalLayout")
+ self.label_2 = QtWidgets.QLabel(Dialog)
+ self.label_2.setObjectName("label_2")
+ self.verticalLayout.addWidget(self.label_2)
+ self.label_5 = QtWidgets.QLabel(Dialog)
+ self.label_5.setText("")
+ self.label_5.setObjectName("label_5")
+ self.verticalLayout.addWidget(self.label_5)
+ self.label_3 = QtWidgets.QLabel(Dialog)
+ self.label_3.setObjectName("label_3")
+ self.verticalLayout.addWidget(self.label_3)
+ self.label_4 = QtWidgets.QLabel(Dialog)
+ self.label_4.setObjectName("label_4")
+ self.verticalLayout.addWidget(self.label_4)
+ spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
+ self.verticalLayout.addItem(spacerItem)
+ self.horizontalLayout.addLayout(self.verticalLayout)
+
+ self.retranslateUi(Dialog)
+ QtCore.QMetaObject.connectSlotsByName(Dialog)
+
+ def retranslateUi(self, Dialog):
+ _translate = QtCore.QCoreApplication.translate
+ Dialog.setWindowTitle(_translate("Dialog", "关于"))
+ self.label_2.setText(_translate("Dialog", "软件名称:CTTools测试工具集合"))
+ self.label_3.setText(_translate("Dialog", "版本:V0.12/2022"))
+ self.label_4.setText(_translate("Dialog", "作者:chen/wang"))
diff --git a/need/document_templates/FPGA记录to说明模板.docx b/need/document_templates/FPGA记录to说明模板.docx
new file mode 100644
index 0000000..278740f
Binary files /dev/null and b/need/document_templates/FPGA记录to说明模板.docx differ
diff --git a/need/document_templates/SunwiseAUnit单元测试转换模板.docx b/need/document_templates/SunwiseAUnit单元测试转换模板.docx
new file mode 100644
index 0000000..92c1f54
Binary files /dev/null and b/need/document_templates/SunwiseAUnit单元测试转换模板.docx differ
diff --git a/need/document_templates/cpu新记录to说明模版.docx b/need/document_templates/cpu新记录to说明模版.docx
new file mode 100644
index 0000000..ce1b1fc
Binary files /dev/null and b/need/document_templates/cpu新记录to说明模版.docx differ
diff --git a/need/document_templates/get_content.docx b/need/document_templates/get_content.docx
new file mode 100644
index 0000000..0a9f6c2
Binary files /dev/null and b/need/document_templates/get_content.docx differ
diff --git a/need/document_templates/tpl模板文件.zip b/need/document_templates/tpl模板文件.zip
new file mode 100644
index 0000000..a3fd7dc
Binary files /dev/null and b/need/document_templates/tpl模板文件.zip differ
diff --git a/need/document_templates/~$GA记录to说明模板.docx b/need/document_templates/~$GA记录to说明模板.docx
new file mode 100644
index 0000000..3e56165
Binary files /dev/null and b/need/document_templates/~$GA记录to说明模板.docx differ
diff --git a/need/document_templates/反向测试说明模板.docx b/need/document_templates/反向测试说明模板.docx
new file mode 100644
index 0000000..1b96d04
Binary files /dev/null and b/need/document_templates/反向测试说明模板.docx differ
diff --git a/need/document_templates/大纲追踪模板.docx b/need/document_templates/大纲追踪模板.docx
new file mode 100644
index 0000000..caf4a1f
Binary files /dev/null and b/need/document_templates/大纲追踪模板.docx differ
diff --git a/need/document_templates/报告模板变量.md b/need/document_templates/报告模板变量.md
new file mode 100644
index 0000000..bd2a1df
--- /dev/null
+++ b/need/document_templates/报告模板变量.md
@@ -0,0 +1,13 @@
+# 报告模板变量
+
+## 1.判断变量
+
+- is_jianding-是否为鉴定文件变量,{% if is_jianding == ‘1’ %},string类型
+
+
+
+## 2.用户输入变量
+
+- proj_bianhao-项目编号,例如R2255
+- soft_name-软件名,例如XX图像处理软件
+-
\ No newline at end of file
diff --git a/need/document_templates/报告追踪模板.docx b/need/document_templates/报告追踪模板.docx
new file mode 100644
index 0000000..0a38754
Binary files /dev/null and b/need/document_templates/报告追踪模板.docx differ
diff --git a/need/document_templates/文档模板/测评大纲模板-2022年10月11日.docx b/need/document_templates/文档模板/测评大纲模板-2022年10月11日.docx
new file mode 100644
index 0000000..6f15cc7
Binary files /dev/null and b/need/document_templates/文档模板/测评大纲模板-2022年10月11日.docx differ
diff --git a/need/document_templates/文档模板/测评报告模板-2022年10月11日.docx b/need/document_templates/文档模板/测评报告模板-2022年10月11日.docx
new file mode 100644
index 0000000..73c8f97
Binary files /dev/null and b/need/document_templates/文档模板/测评报告模板-2022年10月11日.docx differ
diff --git a/need/document_templates/测评报告模板.docx b/need/document_templates/测评报告模板.docx
new file mode 100644
index 0000000..af8e94e
Binary files /dev/null and b/need/document_templates/测评报告模板.docx differ
diff --git a/need/document_templates/测试说明模板.docx b/need/document_templates/测试说明模板.docx
new file mode 100644
index 0000000..b161ceb
Binary files /dev/null and b/need/document_templates/测试说明模板.docx differ
diff --git a/need/document_templates/说明生成记录模板.docx b/need/document_templates/说明生成记录模板.docx
new file mode 100644
index 0000000..74f1bb8
Binary files /dev/null and b/need/document_templates/说明生成记录模板.docx differ
diff --git a/need/document_templates/说明追踪模板.docx b/need/document_templates/说明追踪模板.docx
new file mode 100644
index 0000000..1830335
Binary files /dev/null and b/need/document_templates/说明追踪模板.docx differ
diff --git a/need/document_templates/部件桩函数工具1.docx b/need/document_templates/部件桩函数工具1.docx
new file mode 100644
index 0000000..68ec32e
Binary files /dev/null and b/need/document_templates/部件桩函数工具1.docx differ
diff --git a/need/fpga_JtoS.py b/need/fpga_JtoS.py
new file mode 100644
index 0000000..7992bb3
--- /dev/null
+++ b/need/fpga_JtoS.py
@@ -0,0 +1,146 @@
+from PyQt5 import QtCore
+from PyQt5.QtCore import pyqtSignal
+from pathlib import *
+from PyQt5.QtWidgets import QMessageBox
+from docxtpl import DocxTemplate, InlineImage
+from docx import Document
+from docx.table import Table
+from docx.text.paragraph import Paragraph
+import io
+
+class create_FPGA_JtoS(QtCore.QThread):
+ sin_out = pyqtSignal(str)
+
+ def __init__(self, parent):
+ super().__init__()
+ self.parent = parent
+
+ def run(self):
+ self.sin_out.emit("进入测试记录转说明线程......")
+ self.sin_out.emit("开始转换......")
+ # 如果没有选择文件路径则退出
+ if not self.parent.open_file_name:
+ self.sin_out.emit('nofile')
+ self.parent.tabWidget.setEnabled(True)
+ return
+
+ # 打开模板文件进行渲染,然后就是用docxtpl生成用例
+ try:
+ tpl_path = Path.cwd() / "need" / "document_templates" / "FPGA记录to说明模板.docx"
+ self.sin_out.emit('导入模板文件路径为:' + str(tpl_path))
+ tpl = DocxTemplate(tpl_path) # 模板导入成功
+
+ except:
+ QMessageBox.warning(self.parent, "出错了", "导入模板出错请检查模板文件是否存在或名字不正确")
+ return
+
+ try:
+ doc = Document(self.parent.open_file_name[0])
+ self.sin_out.emit('已识别到FPGA测试记录文件...')
+ except:
+ self.sin_out.emit('open failed:选择的文档')
+ self.parent.tabWidget.setEnabled(True)
+ return
+
+ self.sin_out.emit('复制测试说明文档模板到本程序所在目录...')
+ curpath = Path.cwd() / 'need'
+ shuoming_path_tmp = curpath / 'document_templates' / 'FPGA记录to说明模板.docx'
+ print(shuoming_path_tmp)
+ if shuoming_path_tmp.is_file():
+ self.sin_out.emit('已检测到有说明模板文件...')
+ else:
+ self.sin_out.emit('open failed:选择的文档')
+ return
+
+ # 获取表格数量
+ tables = doc.tables
+ tb_count = len(tables)
+ self.sin_out.emit('total:' + str(tb_count))
+ # 创建一个字典来储存单个用例
+ data_list = []
+ table_index = 1
+ # 获取表格数量
+ for ele in doc._element.body.iter():
+ data = {'type': ''}
+ if ele.tag.endswith('}p'):
+ elePstyle = ele.findall('.//{http://schemas.openxmlformats.org/wordprocessingml/2006/main}pStyle')
+ if len(elePstyle) >= 1:
+ parag = Paragraph(ele, doc)
+ if parag.style.name.startswith("Heading") or parag.style.name.startswith("标题"):
+ rank = parag.style.name.split(" ")[-1]
+ text = parag.text
+ if text == "" or text.startswith("文档齐套性审查单") \
+ or text.startswith("软件研制任务书审查单") \
+ or text.startswith("附录") \
+ or text.startswith("附件") \
+ or text.startswith("需求文档审查单"):
+ pass
+ else:
+ data['type'] = rank
+ data['title'] = text
+ data_list.append(data)
+ elif ele.tag.endswith('}tbl'):
+ data = {'name': '', 'biaoshi': '', 'zhuizong': [], 'zongsu': '', 'init': '', 'qianti': '', 'step': []}
+ data['type'] = 'table'
+ table = Table(ele, doc)
+ if table.cell(0, 0).text == '测试用例名称':
+ self.sin_out.emit(str(table_index))
+
+ try:
+ self.sin_out.emit(str(table_index))
+ self.sin_out.emit(f'正在处理第{table_index}个表格')
+ # 1、获取测试用例名称
+ data['name'] = table.cell(0, 3).text
+ # 2、获取用例标识
+ data['biaoshi'] = table.cell(0, 9).text
+ # 3、获取追踪关系 注意word中换行为\r\x07
+ temp = table.cell(1, 3)
+ for tem in temp.paragraphs:
+ data['zhuizong'].append(tem.text)
+ # 4、获取综述
+ data['zongsu'] = table.cell(2, 3).text
+ # 5、初始化
+ data['init'] = table.cell(3, 3).text
+ # 6、获取前提与约束
+ data['qianti'] = table.cell(4, 3).text
+ # 7、获取步骤信息-总行数减去12为步骤行数
+ row_count = len(table.rows)
+ step_count = row_count - 12
+ for j in range(step_count):
+ buzhou = {'shuru': '', 'yuqi': '', 'num': '', 'image': '', 'is_image': '0'}
+ buzhou['num'] = table.rows[7 + j].cells[0].text
+ buzhou['shuru'] = table.rows[7 + j].cells[2].text
+ cel = table.rows[7 + j].cells[2]
+ if len(
+ cel._element.findall('.//{http://schemas.openxmlformats.org/wordprocessingml/2006/main}drawing')
+ ) > 0:
+ img_ele = cel._element.xpath('.//pic:pic')[0]
+ embed = img_ele.xpath('.//a:blip/@r:embed')[0]
+ related_part = doc.part.related_parts[embed]
+ image = related_part.image
+ # blob属性就是二进制图片属性
+ image_bytes = image.blob
+ buzhou['image'] = InlineImage(tpl, io.BytesIO(image_bytes))
+ buzhou['is_image'] = '1'
+ buzhou['yuqi'] = table.rows[7 + j].cells[4].text
+ data['step'].append(buzhou)
+ # 8、最后加入data_list
+ data_list.append(data)
+ table_index += 1
+ except:
+ self.sin_out.emit(f'第{table_index}个表格处理错误!')
+ table_index += 1
+ pass
+ # 开始渲染模板文件
+ try:
+ self.sin_out.emit(str(tb_count + 1))
+ context = {
+ "tables": data_list,
+ "renyuan": self.parent.lineEdit_17.text(),
+ }
+ tpl.render(context)
+ tpl.save("FPGA反向生成的说明文档.docx")
+ self.sin_out.emit('stopsuccess')
+ except:
+ self.sin_out.emit('stoperror')
+ return
diff --git a/need/fpga_record_thrend.py b/need/fpga_record_thrend.py
new file mode 100644
index 0000000..ee810ae
--- /dev/null
+++ b/need/fpga_record_thrend.py
@@ -0,0 +1,155 @@
+import pythoncom
+from PyQt5 import QtCore
+from PyQt5.QtCore import pyqtSignal
+from pathlib import *
+from docx import Document
+import re
+from docx.shared import Pt
+
+#常量
+TABLE_FONT_SIZE = Pt(10.5)
+
+class create_FPGA_record(QtCore.QThread):
+ sin_out = pyqtSignal(str)
+
+ def __init__(self,parent):
+ super().__init__()
+ self.parent = parent
+
+ def run(self):
+
+
+ self.sin_out.emit("开始填写FPGA记录......")
+ self.sin_out.emit("开始填写文档......")
+
+ #如果没有选择路径则退出
+ if not self.parent.open_file_name:
+ self.sin_out.emit('nofile')
+ self.parent.tabWidget.setEnabled(True)
+ return
+
+ #告诉windows单线程
+ pythoncom.CoInitialize()
+ #在用户选择的目录中查找UAS单位测试报告文档
+ self.sin_out.emit('打开单元测试原文件...')
+
+ try:
+ doc = Document(self.parent.open_file_name[0])
+ except:
+ self.sin_out.emit('open failed:选择的文档')
+ pythoncom.CoUninitialize()
+ self.parent.tabWidget.setEnabled(True)
+ return
+
+ table_count = len(doc.tables)
+ self.sin_out.emit('total:'+ str(table_count))
+ # 如果大纲标识一致需要累加
+ static_dagang_biaoshi = ''
+ index = 1
+ num = 0
+ for table in doc.tables:
+ num += 1
+ self.sin_out.emit(str(num))
+ self.sin_out.emit(f'正在处理第{num}个表格')
+ if table.cell(0,0).text == '测试用例名称':
+
+ try:
+ #~~~~~~~~~~~~~~~第一步处理表格中所在标题填入~~~~~~~~~~~~~~~
+ prev_para = table._element.getprevious()
+ # 如果找到前一个元素是paragraph、但没有找到子节点有pStyle节点,则再往上找
+ while prev_para is not None and prev_para.tag.endswith('}p') and \
+ len(prev_para.findall('.//{http://schemas.openxmlformats.org/wordprocessingml/2006/main}pStyle')) == 0:
+ prev_para = prev_para.getprevious()
+ if prev_para is not None and prev_para.tag.endswith('}p'):
+ t_ele = prev_para.findall('.//{http://schemas.openxmlformats.org/wordprocessingml/2006/main}t')
+ title = ''
+ for i in range(len(t_ele)):
+ title = title + t_ele[i].text
+ # 将title放入到cell(0,1)-完成第一步了
+ table.cell(0,3).text = title
+
+
+ #~~~~~~~~~~~~~~~第二步找到追踪关系中大纲标识更改后填入~~~~~~~~~~~~~~~(要求用户必须3行!)
+ temp = table.cell(1,3).text.split("\n")[-1]
+ dagang_biaoshi = re.split('[::]',temp)[-1]
+
+ # 如果大纲标识一致,则累加
+ if dagang_biaoshi != static_dagang_biaoshi:
+ static_dagang_biaoshi = dagang_biaoshi
+ yongli_biaoshi = dagang_biaoshi.replace('XQ','R1_YL') + '_001'
+ # 填入标识
+ table.cell(0,8).text = yongli_biaoshi
+ index = 1
+ else:
+ index += 1
+ if len(str(index)) <= 3:
+ str_index = (3-len(str(index)))*'0' + str(index)
+ yongli_biaoshi = dagang_biaoshi.replace('XQ','R1_YL') + '_' + str_index
+ table.cell(0,8).text = yongli_biaoshi
+
+ #~~~~~~~~~~~~~~~输出用户知道~~~~~~~~~~~~~~~
+ self.sin_out.emit(f'处理完毕测试项:{title},{yongli_biaoshi}')
+
+ #~~~~~~~~~~~~~~~第三步填写“测试用例综述”~~~~~~~~~~~~~~~
+ if title:
+ zongsu_string = f'使用功能仿真的方法,对{title}进行测试'
+ table.cell(2,3).text = zongsu_string
+ else:
+ print('注意:未识别到正确标题!,填入综述失败')
+
+ #~~~~~~~~~~~~~~~第四步“执行状态”填写为已执行、“测试时间”、“测试人员”、“监测人员”为可更改项~~~~~~~~~~~~~~~
+ #执行状态-固定!
+ table.rows[-4].cells[2].text = '已执行'
+ #测试人员
+ table.rows[-3].cells[2].text = self.parent.lineEdit_8.text()
+ table.rows[-4].cells[7].text = self.parent.lineEdit_7.text()
+ table.rows[-3].cells[7].text = self.parent.lineEdit_15.text()
+
+ #~~~~~~~~~~~~~~~第五步填写当通过与否为通过时,写"/"~~~~~~~~~~~~~~~
+ table.rows[-2].cells[2].text = '/'
+
+ # 判断有几个步骤-根据总行数判断,并循环查看是否为通过
+ flag = 1
+ for i in range(len(table.rows) - 12):
+ temp = table.rows[-6 - i].cells[-1].text
+ if temp == '不通过':
+ flag = 0
+ if temp == '未通过':
+ flag = 0
+ if flag == 1:
+ table.rows[-2].cells[2].text = '/'
+ else:
+ project_code = self.parent.lineEdit_16.text()
+ pro_biaoshi = f'PT_{project_code}_'
+ table.rows[-2].cells[2].text = pro_biaoshi
+
+ #~~~~~~~~~~~~~~~第六步截图为空填写‘/’否则不变~~~~~~~~~~~~~~~
+ cell = table.cell(-5,0)
+ has_image = False
+ for paragraph in cell.paragraphs:
+ tupian_list = paragraph._element.findall('.//{http://schemas.openxmlformats.org/wordprocessingml/2006/main}drawing')
+ if len(tupian_list) != 0:
+ has_image = True
+ if has_image:
+ pass
+ else:
+ table.cell(-5,0).text = '/'
+ except:
+ self.sin_out.emit(f'第{num}个表格处理失败,请查看!!!')
+ pass
+
+ # 设置字体
+ for row in table.rows:
+ for cell in row.cells:
+ for paragraph in cell.paragraphs:
+ for run in paragraph.runs:
+ run.font.size = TABLE_FONT_SIZE
+ # 保存文档
+ try:
+ doc.save('~新生产的fpga记录~.docx')
+ self.sin_out.emit('stopsuccess')
+ except:
+ self.sin_out.emit('stoperror')
+ return
+
+
\ No newline at end of file
diff --git a/need/main.py b/need/main.py
new file mode 100644
index 0000000..8140d14
--- /dev/null
+++ b/need/main.py
@@ -0,0 +1,2186 @@
+# -*- coding: utf-8 -*-
+import logging
+
+LOG_FORMAT = "%(asctime)s>%(levelname)s>PID:%(process)d %(thread)d>%(module)s>%(funcName)s>%(lineno)d>%(message)s"
+logging.basicConfig(
+ level=logging.DEBUG,
+ format=LOG_FORMAT,
+)
+
+# 是否打印调试信息标志
+debug = True
+if debug:
+ logging.debug("进入主程序,开始导入包...")
+
+# 导入常规库
+import sys, re, string
+from pathlib import *
+# 导入word文档操作库
+from win32com.client import DispatchEx
+from docxtpl import DocxTemplate
+import docx
+from docx import Document
+import shutil
+import pythoncom
+# 导入QT组件
+from PyQt5 import QtCore
+from PyQt5.QtWidgets import QMainWindow, QFileDialog, QMessageBox, QDialog, QToolTip
+from PyQt5.QtCore import pyqtSignal
+from PyQt5.QtGui import QFont
+# 导入UI转换PY文件
+from need.Ui_GUI import Ui_MainWindow
+from need import about, zhuan
+# 导入工具包文件-时间转换
+from need.utils import get_current_time, get_current_name, get_current_date, get_current_hour
+from need.zhuan_tool import IEEE754_16_to_float, IEEE754_float_to_16
+# 导入其他线程
+from need.threads import create_bujian
+from need.fpga_record_thrend import create_FPGA_record
+from need.fpga_JtoS import create_FPGA_JtoS
+from need.new_JtoS import create_new_JtoS
+
+
+class zhuan_dlg(QDialog, zhuan.Ui_Dialog):
+
+ def __init__(self):
+ super().__init__()
+ self.setupUi(self)
+
+ if debug:
+ logging.debug("初始化转换程序:")
+
+ #linetext信号连接
+ self.lineEdit.editingFinished.connect(self.shiliu_zhuan)
+ self.lineEdit_2.editingFinished.connect(self.shi_zhuan)
+ # 设置气泡提示信息
+ QToolTip.setFont(QFont("SansSerif", 12))
+ self.lineEdit.setToolTip("注意,编辑输入框后需要点击其他控件才进行转换,且格式不正确不转换")
+ self.lineEdit_2.setToolTip("注意,编辑输入框后需要点击其他控件才进行转换,且格式不正确不转换")
+
+ def shiliu_zhuan(self):
+ #获取当前文字
+ x = self.lineEdit.text()
+ if len(x) == 8:
+ if self.radioButton.isChecked() == True: #说明选中了32位转换
+ result = IEEE754_16_to_float(x, 32)
+ self.lineEdit_2.setText(str(result))
+ elif len(x) == 16:
+ if self.radioButton_2.isChecked() == True: #说明选中了64位转换
+ result = IEEE754_16_to_float(x, 64)
+ self.lineEdit_2.setText(str(result))
+
+ def shi_zhuan(self):
+ #获取当前文字
+ x = self.lineEdit_2.text()
+ #字符串转浮点数
+ # if str.isdigit(x):
+ # x = float(x)
+ # elif str.isdigit(x.replace(".","")):
+ try:
+ x = float(x)
+ except:
+ logging.debug('输入的内容无法转换为浮点数')
+
+ if isinstance(x, float) == True:
+ print('进入转换函数里面')
+ if self.radioButton.isChecked() == True: #说明选中了32位转换
+ result = IEEE754_float_to_16(x, 32)
+ print(result)
+ self.lineEdit.setText(str(result))
+ else:
+ result = IEEE754_float_to_16(x, 64)
+ self.lineEdit.setText(str(result))
+
+
+class userMain(QMainWindow, Ui_MainWindow):
+ #自定义信号和槽
+
+ def __init__(self):
+ super().__init__()
+ self.setupUi(self)
+ if debug:
+ logging.debug("初始化主程序:")
+
+ # 实例化翻译家
+ self.trans = QtCore.QCoreApplication.translate
+ self.setWindowTitle('测试个人工具')
+
+ #使用翻译家改变PYQT的空间名字等属性self.label_4.setText(self.trans("MainWindow", "文件名(自动识别):"))
+
+ if debug:
+ logging.debug("初始化部分全局变量...")
+ # 存放文件夹路径变量
+ self.open_dirs_name = ''
+ # 存放文件名称路径变量
+ self.open_file_name = ''
+
+ # 读取配置文件
+
+ #~~~~~~~~~~~~~~~连接线程函数~~~~~~~~~~~~~~~
+ ## 连接大纲生成说明函数
+ self.create_shuoming_trd = create_shuoming(self)
+ self.create_shuoming_trd.sin_out.connect(self.text_display)
+ self.pushButton_2.clicked.connect(self.create_shuoming_btn)
+
+ ## 连接大纲追溯
+ self.create_dagang_zhuisu_trd = create_dagang_zhuisu(self)
+ self.create_dagang_zhuisu_trd.sin_out.connect(self.text_display)
+ self.pushButton_5.clicked.connect(self.creat_shuoming_zhuisu_btn)
+
+ ## 连接说明追踪线程
+ self.create_shuoming_zhuisu_trd = create_shuoming_zhuisu(self)
+ self.create_shuoming_zhuisu_trd.sin_out.connect(self.text_display)
+ self.pushButton_6.clicked.connect(self.creat_dagang_zhuisu_btn)
+
+ ## 连接报告追踪
+ self.create_baogao_zhuisu_trd = create_baogao_zhuisu(self)
+ self.create_baogao_zhuisu_trd.sin_out.connect(self.text_display)
+ self.pushButton_18.clicked.connect(self.create_baogao_zhuisu_btn)
+
+ ## 连接单元追踪线程
+ self.create_danyuan_trd = create_danyuan(self)
+ self.create_danyuan_trd.sin_out.connect(self.text_display)
+ self.pushButton_8.clicked.connect(self.creat_danyuan_btn)
+
+ ## 连接根据测试说明生成记录线程
+ self.create_jilu_trd = create_jilu(self)
+ self.create_jilu_trd.sin_out.connect(self.text_display)
+ self.pushButton_12.clicked.connect(self.creat_jilu_btn)
+
+ ## 记录反向生成说明线程
+ self.create_shuomingfanxiang_trd = create_new_JtoS(self)
+ self.create_shuomingfanxiang_trd.sin_out.connect(self.text_display)
+ self.pushButton_13.clicked.connect(self.creat_shuomingfanxiang_btn)
+
+ ## 自动填充空白表格线程
+ self.create_zidong_trd = create_zidong(self)
+ self.create_zidong_trd.sin_out.connect(self.text_display)
+ self.pushButton_15.clicked.connect(self.creat_zidong_btn)
+
+ ## 清空单元格线程
+ self.clear_cell_trd = clear_cell(self)
+ self.clear_cell_trd.sin_out.connect(self.text_display)
+ self.pushButton_14.clicked.connect(self.clear_cell_btn)
+
+ ## 提取表格内容线程
+ self.get_content_trd = get_content(self)
+ self.get_content_trd.sin_out.connect(self.text_display)
+ self.pushButton_19.clicked.connect(self.get_content_btn)
+
+ ## 部件测试调用关系表格线程
+ self.create_bujian_trd = create_bujian(self)
+ self.create_bujian_trd.sin_out.connect(self.text_display)
+ self.pushButton_28.clicked.connect(self.create_bujian_btn)
+
+ ## FPGA记录填写表格线程
+ self.create_FPGA_record_trd = create_FPGA_record(self)
+ self.create_FPGA_record_trd.sin_out.connect(self.text_display)
+ self.pushButton_30.clicked.connect(self.create_FPGA_record_btn)
+
+ ## FPGA记录转为说明线程
+ self.create_FPGA_JtoS_trd = create_FPGA_JtoS(self)
+ self.create_FPGA_JtoS_trd.sin_out.connect(self.text_display)
+ self.pushButton_32.clicked.connect(self.create_FPGA_JtoS_btn)
+
+ # 自定义信号连接
+ # 获取状态栏对象
+ self.user_statusbar = self.statusBar()
+ # 右下角窗口尺寸调整符号
+ self.user_statusbar.setSizeGripEnabled(True)
+ self.user_statusbar.setStyleSheet("QStatusBar.item{border:10px}")
+
+ #~~~~~~~~~~~~~~~按钮连接函数~~~~~~~~~~~~~~~~
+ ##选择文件按钮连接
+ self.pushButton.clicked.connect(self.choose_docx_func)
+ self.pushButton_4.clicked.connect(self.choose_docx_func)
+ self.pushButton_7.clicked.connect(self.choose_docx_func)
+ self.pushButton_11.clicked.connect(self.choose_docx_func)
+ self.pushButton_16.clicked.connect(self.choose_docx_func)
+ self.pushButton_17.clicked.connect(self.choose_docx_func)
+ self.pushButton_27.clicked.connect(self.choose_docx_func)
+ self.pushButton_29.clicked.connect(self.choose_docx_func)
+ self.pushButton_31.clicked.connect(self.choose_docx_func)
+ #清空显示区
+ self.pushButton_9.clicked.connect(self.clear_textEdit_content)
+ #显示帮助
+ self.pushButton_10.clicked.connect(self.display_help)
+
+ #~~~~~~~~~~~~~~~导航栏按钮连接函数~~~~~~~~~~~~~~~~
+ #显示关于本软件的菜单
+ self.actionAbout.triggered.connect(self.display_about)
+ #打开文件夹
+ self.actionopen.triggered.connect(self.choose_docx_func)
+ #打开IEEE754转换工具
+ self.actionIEEE754.triggered.connect(self.open_zhuan_tool)
+
+ if debug:
+ logging.debug("界面加载完成...")
+
+#~~~~~~~~~~~~~~~~~~~~初始化直接运行的函数(也就是起始运行一次)~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+#~~~~~~~~~~~~~~~~~~~~间接按钮函数,用户点击后操作~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#清空显示区函数
+
+ def clear_textEdit_content(self):
+ self.textBrowser.clear()
+ return
+
+ #显示帮助函数
+ def display_help(self):
+ txt_path = Path.cwd() / 'need' / 'others' / 'readme.txt'
+ with open(txt_path, 'r', encoding='utf-8') as f:
+ data = f.read()
+ self.textBrowser.append(data)
+ return
+
+ #显示关于函数
+ def display_about(self):
+ dlg = QDialog()
+ about_dlg = about.Ui_Dialog()
+ about_dlg.setupUi(dlg)
+ dlg.show()
+ dlg.exec_()
+ print("显示关于界面")
+ return
+
+ #显示IEEE754转换工具
+ def open_zhuan_tool(self):
+ dlg_zhuan = zhuan_dlg() #实例化界面
+ dlg_zhuan.show()
+ dlg_zhuan.exec_()
+ return
+
+#~~~~~~~~~~~~~~~~~~~~线程区域函数,用于启动线程~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#生成测试说明启动函数
+
+ def create_shuoming_btn(self):
+ self.create_shuoming_trd.start()
+ self.tabWidget.setEnabled(False)
+ return
+
+# 大纲追溯线程启动函数
+
+ def creat_dagang_zhuisu_btn(self):
+ self.create_dagang_zhuisu_trd.start()
+ self.tabWidget.setEnabled(False)
+
+# 说明追溯线程启动函数
+
+ def creat_shuoming_zhuisu_btn(self):
+ self.create_shuoming_zhuisu_trd.start()
+ self.tabWidget.setEnabled(False)
+
+# 提取单元格标题右侧内容线程启动函数
+
+ def create_baogao_zhuisu_btn(self):
+ self.create_baogao_zhuisu_trd.start()
+ self.tabWidget.setEnabled(False)
+
+# 记录反向生成说明线程
+
+ def creat_shuomingfanxiang_btn(self):
+ self.create_shuomingfanxiang_trd.start()
+ self.tabWidget.setEnabled(False)
+
+# 单元测试报告转换为我们的用例线程
+
+ def creat_danyuan_btn(self):
+ self.create_danyuan_trd.start()
+ self.tabWidget.setEnabled(False)
+
+# 单元测试报告转换为我们的用例线程
+
+ def creat_jilu_btn(self):
+ self.create_jilu_trd.start()
+ self.tabWidget.setEnabled(False)
+
+# 自动填充线程
+
+ def creat_zidong_btn(self):
+ self.create_zidong_trd.start()
+ self.tabWidget.setEnabled(False)
+
+# 清空表格单元格内容
+
+ def clear_cell_btn(self):
+ self.clear_cell_trd.start()
+ self.tabWidget.setEnabled(False)
+
+# 提取单元格标题右侧内容线程启动函数
+
+ def get_content_btn(self):
+ self.get_content_trd.start()
+ self.tabWidget.setEnabled(False)
+
+# 部件测试提取调用启动线程函数
+
+ def create_bujian_btn(self):
+ self.create_bujian_trd.start()
+ self.tabWidget.setEnabled(False)
+
+# FPGA记录填写
+
+ def create_FPGA_record_btn(self):
+ self.create_FPGA_record_trd.start()
+ self.tabWidget.setEnabled(False)
+
+# FPGA记录转说明
+
+ def create_FPGA_JtoS_btn(self):
+ self.create_FPGA_JtoS_trd.start()
+ self.tabWidget.setEnabled(False)
+
+#选择文档函数
+
+ def choose_docx_func(self):
+ self.open_file_name = QFileDialog.getOpenFileName(
+ self, '选择文件', '.', "Word files(*.docx)")
+ self.textBrowser.append('已选择文件路径:' + self.open_file_name[0])
+
+#关闭线程函数
+
+ def stop_shuoming_thread(self):
+ self.tabWidget.setEnabled(True)
+ QMessageBox.warning(self, '处理完毕', '文档处理完毕!')
+ print("停止线程成功!")
+
+#~~~~~~~~~~~~~~~~~~~~显示函数~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ def text_display(self, texttmp):
+ if texttmp[:9] == 'stoperror':
+ QMessageBox.warning(self, '处理完毕', '文档处理失败!')
+ self.tabWidget.setEnabled(True)
+ return
+
+ if texttmp[:11] == 'stopsuccess':
+ self.stop_shuoming_thread()
+ self.tabWidget.setEnabled(True)
+ return
+
+ if texttmp[:6] == 'total:':
+ cnt = int(texttmp[6:])
+ self.progressBar.setRange(0, cnt - 1)
+
+ if texttmp == 'function success':
+ QMessageBox.information(self, '操作成功', '请查看本程序当前文件夹下的相关文档!')
+ self.textBrowser.append('完成!!!')
+ self.tabWidget.setEnabled(True)
+ return
+ if texttmp == '保存文件错':
+ QMessageBox.warning(self, '出错了', '保存文件失败!')
+ self.tabWidget.setEnabled(True)
+ return
+ if texttmp == 'no folder':
+ QMessageBox.information(self, '没有选择文件夹', '还没有选择文件夹,点击"文件"菜单进行选择!')
+ self.tabWidget.setEnabled(True)
+ return
+ if texttmp.find('warning:') != -1:
+ QMessageBox.information(self, 'WARNING', texttmp[8:])
+ self.tabWidget.setEnabled(True)
+ return
+
+ if texttmp.find('open failed:') != -1:
+ QMessageBox.warning(
+ self, '打开文件失败',
+ '打开' + texttmp[12:] + '失败' + '请确认文档是否打开或者模板文件存在且后缀名为docx!')
+ self.tabWidget.setEnabled(True)
+ return
+ if texttmp == 'nofile':
+ QMessageBox.information(self, '错误',
+ '还没有选择文件(夹),点击"文件"菜单或者工具栏进行选择!')
+ self.tabWidget.setEnabled(True)
+ return
+ if texttmp.isdigit() == True:
+ self.progressBar.setValue(int(texttmp))
+ self.tabWidget.setEnabled(True)
+ else:
+ self.textBrowser.append(texttmp)
+ self.tabWidget.setEnabled(True)
+ # 如果前面是all_doned:则进度条填满
+ if texttmp.find('all_doned:') != -1:
+ self.progressBar.setRange(0, 100)
+ self.progressBar.setValue(100)
+
+ def closeEvent(self, event):
+ reply = QMessageBox.question(self, '提示', "是否要关闭所有窗口?",
+ QMessageBox.Yes | QMessageBox.No,
+ QMessageBox.No)
+ if reply == QMessageBox.Yes:
+ event.accept()
+ sys.exit(0) # 退出程序
+ else:
+ event.ignore()
+
+
+##################################################################################
+#大纲生成测试说明线程
+##################################################################################
+class create_shuoming(QtCore.QThread):
+ sin_out = pyqtSignal(str)
+
+ def __init__(self, parent):
+ super().__init__()
+ self.parent = parent
+
+ def run(self):
+ #用来储存测试项DC等转换
+ zhuan_dict = {'DC':'文档审查','SU':'功能测试','CR':'代码审查','SA':'静态分析','AC':'性能测试',\
+ 'IO':'接口测试','SE':'安全性测试','BT':'边界测试','RE':'恢复性测试','ST':'强度测试',\
+ 'AT':'余量测试','GUI':'人机交互界面测试','DP':'数据处理测试','JR':'兼容性测试',\
+ 'LG':'逻辑测试','AZ':'安装性测试','TT':'时序测试','PA':'功耗分析'}
+
+ self.sin_out.emit("进入军品大纲转说明......")
+ self.sin_out.emit("开始转换......")
+ #如果没有选择路径则退出
+ if not self.parent.open_file_name:
+ self.sin_out.emit('nofile')
+ self.parent.tabWidget.setEnabled(True)
+ return
+ #告诉windows单线程
+ pythoncom.CoInitialize()
+ #在用户选择的目录中查找大纲文档
+ self.sin_out.emit('打开测评大纲文档...')
+
+ #使用win32com打开-记得关闭
+ #打开word应用
+ self.w = DispatchEx('Word.Application')
+ #self.w.visible=True
+ self.w.DisplayAlerts = 0
+ try:
+ dagangfile = self.w.Documents.Open(self.parent.open_file_name[0])
+ except:
+ self.sin_out.emit('open failed:选择的文档')
+ self.w.Quit()
+ pythoncom.CoUninitialize()
+ self.parent.tabWidget.setEnabled(True)
+ return
+
+ self.sin_out.emit('复制测试说明文档模板到本程序所在目录...')
+ curpath = Path.cwd() / 'need'
+ shuoming_path_tmp = curpath / 'document_templates' / '测试说明模板.docx'
+ print(shuoming_path_tmp)
+ if shuoming_path_tmp.is_file():
+ self.sin_out.emit('已检测到有说明模板文件...')
+ else:
+ self.sin_out.emit('open failed:选择的文档')
+ return
+
+ #创建一个字典来储存单个用例
+
+ data_list = []
+
+ #获取表格数量
+ try:
+ csx_tb_count = dagangfile.Tables.Count
+ self.sin_out.emit('total:' + str(csx_tb_count))
+ except:
+ self.sin_out.emit('不存在表格!')
+ QMessageBox.warning(self.parent, '出错了', '测试说明文档格式错误或者没有正确表格')
+ try:
+ dagangfile.Close()
+ except:
+ pass
+ self.w.Quit()
+ pythoncom.CoUninitialize()
+ self.parent.tabWidget.setEnabled(True)
+ return
+
+ #循环表格
+ yongli_count = 0
+ #用来储存章节号中的DC、SU等标识,用于章节号判断
+ is_fire_su = ""
+ #用来储存基本_分割后个数
+ num_fenge = 3
+ for i in range(csx_tb_count):
+ self.sin_out.emit(str(i))
+ if dagangfile.Tables[i].Rows.Count > 2:
+ #注意win32com的Cell从1开始不是从0开始
+ if dagangfile.Tables[i].Cell(1,
+ 1).Range.Text.find('测试项名称') != -1:
+ #一个用例不变内容获取
+ dagangfile.Tables[i].Rows.First.Select()
+ zhangjiehao = self.w.Selection.Bookmarks("\headinglevel").\
+ Range.Paragraphs(1).Range.ListFormat.ListString
+ zhangjieming = self.w.Selection.Bookmarks("\headinglevel").\
+ Range.Paragraphs(1).Range.Text.rstrip('\r')
+ print("测试项所在章节号:", zhangjiehao)
+ #获取用例标识不加上序号_1
+ basic_biaoshi = dagangfile.Tables[i].Cell(
+ 1, 4).Range.Text.rstrip()[:-2]
+ print("测试项标识为:", basic_biaoshi)
+
+ #储存num_fenge的数值,初始化
+ if yongli_count == 0:
+ num_fenge = len(basic_biaoshi.split("_"))
+ #获取测试用例名称Cell(4,2)整行
+ info_ceshi_buzhou = dagangfile.Tables[i].Cell(4,
+ 2).Range.Text
+ info_ceshi_yuqi = dagangfile.Tables[i].Cell(9,
+ 2).Range.Text
+ #判断是否只有一行,如果只有一行处理表格
+ if dagangfile.Tables[i].Cell(
+ 4, 2).Range.Paragraphs.Count <= 1:
+
+ #缓存一个用例的data填入数据
+ data = {'zhangjie':'','mingcheng':'','biaoshi':'','is_first':'1', \
+ 'yueshu':'软件正常工作,环境连接正常', 'yongli_biaoshi':'','renyuan':'陈俊亦',\
+ 'chushi':'外接设备或软件运行正常','csx_mingcheng':'','is_begin':'0',\
+ 'zongsu':'',"zuhe":[],'csxbs':""}
+ zuhe_dict = {"buzhou": "", "yuqi": "", "xuhao": "1"}
+ try:
+ #填写一行情况下表格
+ data['mingcheng'] = dagangfile.Tables[i].Cell(
+ 1, 2).Range.Text.rstrip('\r\x07')
+ #注意word中后面都有2个字符
+ data['yongli_biaoshi'] = (basic_biaoshi +
+ "_1").replace(
+ 'XQ', 'YL')
+ data['zhangjie'] = zhangjiehao
+ data['csx_mingcheng'] = zhangjieming
+ data['biaoshi'] = basic_biaoshi
+ data['zongsu'] = dagangfile.Tables[i].Cell(
+ 3, 2).Range.Text[:-2]
+
+ zuhe_dict["buzhou"] = dagangfile.Tables[i].Cell(
+ 4, 2).Range.Text.rstrip('\r\x07')
+ zuhe_dict["yuqi"] = dagangfile.Tables[i].Cell(
+ 9, 2).Range.Text.rstrip('\r\x07')
+ zuhe_dict["xuhao"] = '1'
+ data["zuhe"].append(zuhe_dict)
+ #判断是否为第一个测试类型,如果是修改章节号标识,则将章节号展示,如果和储存相同
+ #则章节号不展示
+ #首先获取测试项标识,分割成列表
+ fenge = data['biaoshi'].split("_")
+ #获取当前测试项分割后的个数
+ if len(fenge) == 4:
+ if fenge[-2] != is_fire_su:
+ is_fire_su = fenge[-2]
+ data['is_begin'] = "1"
+ data['csxbs'] = zhuan_dict[fenge[-2]]
+ elif len(fenge) == 3:
+ if fenge[-1] == 'DC' or fenge[
+ -1] == 'CR' or fenge[-1] == 'SA':
+ if fenge[-1] != is_fire_su:
+ is_fire_su = fenge[-1]
+ data['is_begin'] = "1"
+ data['csxbs'] = zhuan_dict[fenge[-1]]
+ else:
+ if fenge[-2] != is_fire_su:
+ is_fire_su = fenge[-2]
+ data['is_begin'] = "1"
+ data['csxbs'] = zhuan_dict[fenge[-2]]
+ else:
+ if fenge[-1] != is_fire_su:
+ is_fire_su = fenge[-1]
+ data['is_begin'] = "1"
+ data['csxbs'] = zhuan_dict[fenge[-1]]
+
+ if self.parent.lineEdit.text():
+ data['renyuan'] = self.parent.lineEdit.text()
+ #将data加入data_list
+ data['is_first'] = "1"
+ data_list.append(data)
+ yongli_count += 1
+
+ self.sin_out.emit(
+ '###获取用例序号:{}'.format(yongli_count))
+ self.sin_out.emit('###该用例标识为:{}'.format(
+ data['yongli_biaoshi']))
+ except:
+ self.sin_out.emit(
+ f'$$$$$$$$$$$$第{str(i+1)}个表格处理失败$$$$$$$$$$$$')
+ pass
+
+ elif dagangfile.Tables[i].Cell(
+ 4, 2).Range.Paragraphs.Count > 1:
+
+ try:
+ #下面拆分每行,使用\r(回车)分割
+ info_buzhou_list = list(
+ filter(lambda x: x != "\x07" and x != "",
+ info_ceshi_buzhou.split('\r')))
+ info_yuqi_list = list(
+ filter(lambda x: x != "\x07" and x != "",
+ info_ceshi_yuqi.split('\r')))
+
+ #去掉括号和以下字符
+ rule = "[;;。]" #rule为去掉的符号(这个可以改TODO)
+
+ #初始化去掉rule的列表
+ buzhou_list = []
+ yuqi_list = []
+
+ for item in info_buzhou_list:
+ index = item.find("(")
+ if index != -1:
+ item = item[index + 1:]
+ index = item.find("(")
+ if index != -1:
+ item = item[index + 1:]
+ index = item.find(")")
+ if index != -1:
+ item = item[index + 1:]
+ index = item.find(")")
+ if index != -1:
+ item = item[index + 1:]
+ buzhou_list.append(
+ re.sub(rule, "",
+ item).lstrip(string.digits))
+ for item in info_yuqi_list:
+ index = item.find("(")
+ if index != -1:
+ item = item[index + 1:]
+ index = item.find("(")
+ if index != -1:
+ item = item[index + 1:]
+ index = item.find(")")
+ if index != -1:
+ item = item[index + 1:]
+ index = item.find(")")
+ if index != -1:
+ item = item[index + 1:]
+ yuqi_list.append(
+ re.sub(rule, "",
+ item).lstrip(string.digits))
+
+ #获取测试项综述-为该循环前不变内容
+ basic_zongshu = buzhou_list.pop(0).strip()
+ print('获取的测试用例综述是:', data["zongsu"])
+
+ #获取字典中的buzhou和yuqi,找冒号
+ j = -1 #自制列表索引
+ substrict_list = [] #差值列表
+ for item in buzhou_list:
+ #先找到冒号所在索引
+ j = j + 1
+ if item.find(":") != -1 or item.find(
+ ":") != -1:
+ #现在知道冒号所在行号,现在要确定每个用例几行
+ substrict_list.append(j)
+
+ #!!!注意差值计算步骤需要-1才是正确的步骤数量
+ # self.sin_out.emit("解析测试项序号"+ str(i) + "|检测到冒号所在行号为:" \
+ # + str(substrict_list))
+ # self.sin_out.emit("|检测到步骤总行数(序号):" \
+ # + str(len(buzhou_list)))
+
+ #循环用例个数
+ count_test = len(substrict_list)
+ temp_list = substrict_list
+ temp_list.append(len(buzhou_list))
+
+ for item in range(count_test):
+ #初始化data数据,包括步骤和预期、序号dict
+ data = {'zhangjie':'','mingcheng':'','biaoshi':'','is_first':'0', \
+ 'yueshu':'软件正常工作,环境连接正常', 'yongli_biaoshi':'','renyuan':'陈俊亦',\
+ 'chushi':'外接设备或软件运行正常','csx_mingcheng':'','is_begin':'0',\
+ 'zongsu':'',"zuhe":[],'csxbs':""}
+
+ #这里要求冒号最后一个
+ data['mingcheng'] = buzhou_list[
+ substrict_list[item]][:-1]
+ data['yongli_biaoshi'] = (
+ basic_biaoshi + f'_{item+1}').replace(
+ 'XQ', 'YL')
+ #常规填入
+ data['zhangjie'] = zhangjiehao
+ data['csx_mingcheng'] = zhangjieming
+ data['biaoshi'] = basic_biaoshi
+ data['zongsu'] = basic_zongshu
+ #步骤填入,首先根据substrict_list获取有几个步骤
+
+ #循环行数
+ for x in range(temp_list[item + 1] -
+ (temp_list[item] +
+ 1)): #循环一个用例步骤预期数
+ zuhe_dict = {
+ "buzhou": "",
+ "yuqi": "",
+ "xuhao": ""
+ }
+ #把每个步骤和预期都放进zuhe_dict中
+ zuhe_dict["buzhou"] = buzhou_list[
+ temp_list[item] + x + 1]
+ zuhe_dict["yuqi"] = yuqi_list[
+ temp_list[item] + x + 1]
+ zuhe_dict["xuhao"] = str(x + 1)
+ data["zuhe"].append(zuhe_dict)
+
+ if item == 0:
+ data['is_first'] = '1'
+ #判断是否为SU标题
+ fenge = data['biaoshi'].split("_")
+ #获取当前测试项分割后的个数
+ if len(fenge) == 4:
+ if fenge[-2] != is_fire_su:
+ is_fire_su = fenge[-2]
+ data['is_begin'] = "1"
+ data['csxbs'] = zhuan_dict[fenge[-2]]
+ elif len(fenge) == 3:
+ if fenge[-1] == 'DC' or fenge[
+ -1] == 'CR' or fenge[-1] == 'SA':
+ if fenge[-1] != is_fire_su:
+ is_fire_su = fenge[-1]
+ data['is_begin'] = "1"
+ data['csxbs'] = zhuan_dict[
+ fenge[-1]]
+ else:
+ if fenge[-2] != is_fire_su:
+ is_fire_su = fenge[-2]
+ data['is_begin'] = "1"
+ data['csxbs'] = zhuan_dict[
+ fenge[-2]]
+ else:
+ if fenge[-1] != is_fire_su:
+ is_fire_su = fenge[-1]
+ data['is_begin'] = "1"
+ data['csxbs'] = zhuan_dict[fenge[-1]]
+ if self.parent.lineEdit.text():
+ data[
+ 'renyuan'] = self.parent.lineEdit.text(
+ )
+ #加入data_list
+ data_list.append(data)
+ yongli_count += 1 #用例计数加一
+
+ self.sin_out.emit(
+ '###获取用例序号:{}'.format(yongli_count))
+ self.sin_out.emit('###该用例标识为:{}'.format(
+ data['yongli_biaoshi']))
+ except:
+ self.sin_out.emit(
+ f'$$$$$$$$$$$$第{str(i+1)}个表格处理失败$$$$$$$$$$$$')
+ pass
+
+ #关闭大纲文档(因为以及提取完毕)
+ try:
+ dagangfile.Close()
+ self.w.Quit()
+ pythoncom.CoUninitialize()
+ except:
+ self.sin_out.emit('function fail')
+ self.w.Quit()
+ pythoncom.CoUninitialize()
+ return
+
+ #打开模板文件进行渲染,然后就是用docxtpl生成用例
+ try:
+ tpl_path = Path.cwd(
+ ) / "need" / "document_templates" / "测试说明模板.docx"
+ self.sin_out.emit('导入模板文件路径为:' + str(tpl_path))
+ tpl = DocxTemplate(tpl_path) #模板导入成功
+
+ except:
+ QMessageBox.warning(self.parent, "出错了", "导入模板出错请检查模板文件是否存在或名字不正确")
+ return
+
+ #开始渲染模板文件-有2层循环
+ try:
+ context = {
+ "tables": data_list,
+ }
+ tpl.render(context)
+ tpl.save("生成的说明文档.docx")
+ self.sin_out.emit('stopsuccess')
+ except:
+ self.sin_out.emit('stoperror')
+ return
+
+
+##################################################################################
+#大纲生成追踪关系
+##################################################################################
+class create_dagang_zhuisu(QtCore.QThread):
+ sin_out = pyqtSignal(str)
+
+ def __init__(self, parent):
+ super().__init__()
+ self.parent = parent
+
+ def run(self):
+ self.sin_out.emit("进入大纲追踪线程......")
+ self.sin_out.emit("开始填写追踪......")
+
+ #如果没有选择路径则退出
+ if not self.parent.open_file_name:
+ self.sin_out.emit('nofile')
+ self.parent.tabWidget.setEnabled(True)
+ return
+ #告诉windows单线程
+ pythoncom.CoInitialize()
+ #在用户选择的目录中查找大纲文档
+ self.sin_out.emit('打开测评大纲文档...')
+
+ #使用win32com打开-记得关闭
+ #打开word应用
+ self.w = DispatchEx('Word.Application')
+ #self.w.visible=True
+ self.w.DisplayAlerts = 0
+ try:
+ dagangfile = self.w.Documents.Open(self.parent.open_file_name[0])
+ except:
+ self.sin_out.emit('open failed:选择的文档')
+ self.w.Quit()
+ pythoncom.CoUninitialize()
+ self.parent.tabWidget.setEnabled(True)
+ return
+
+ curpath = Path.cwd() / 'need'
+ zhuisu_path_tmp = curpath / 'document_templates' / '大纲追踪模板.docx'
+ print(zhuisu_path_tmp)
+
+ if zhuisu_path_tmp.is_file():
+ self.sin_out.emit('已检测到有追溯模板文件...')
+ else:
+ self.sin_out.emit('open failed:选择的文档')
+ return
+
+ #创建个列表放数据
+ data_list = []
+ data2_list = []
+
+ try:
+ csx_tb_count = dagangfile.Tables.Count
+ self.sin_out.emit('total:' + str(csx_tb_count))
+ except:
+ self.sin_out.emit('不存在表格!')
+ QMessageBox.warning(self.parent, '出错了', '测试说明文档格式错误或者没有正确表格')
+ try:
+ dagangfile.Close()
+ except:
+ pass
+ self.w.Quit()
+ pythoncom.CoUninitialize()
+ self.parent.tabWidget.setEnabled(True)
+ return
+
+ for i in range(csx_tb_count):
+ self.sin_out.emit(str(i))
+ self.sin_out.emit("正在处理第{}个表格...".format(str(i)))
+ print("正在处理第{}个表格...".format(str(i)))
+ #准备填入的data
+ data = {
+ 'xuqiu': [],
+ 'dg_zhangjie': '',
+ 'mingcheng': '',
+ 'biaoshi': ''
+ }
+ data2 = {
+ 'xuqiu': [],
+ 'dg_zhangjie': '',
+ 'mingcheng': '',
+ 'biaoshi': ''
+ }
+ if dagangfile.Tables[i].Rows.Count > 2:
+ #注意win32com的Cell从1开始不是从0开始
+ if dagangfile.Tables[i].Cell(1,
+ 1).Range.Text.find('测试项名称') != -1:
+ #一个用例不变内容获取
+ dagangfile.Tables[i].Rows.First.Select() #获取测试项章节号
+ zhangjiehao = self.w.Selection.Bookmarks("\headinglevel").\
+ Range.Paragraphs(1).Range.ListFormat.ListString #获取测试项章节名
+ zhangjieming = self.w.Selection.Bookmarks("\headinglevel").\
+ Range.Paragraphs(1).Range.Text.rstrip('\r')
+ biaoshi = dagangfile.Tables[i].Cell(
+ 1, 4).Range.Text.rstrip()[:-2]
+
+ #获取需规的章节号和描述
+ if dagangfile.Tables[i].Cell(
+ 2, 1).Range.Text.find("追踪关系") != -1:
+ zhuizong_tmp = dagangfile.Tables[i].Cell(
+ 2, 2).Range.Text[:-2]
+ #由于有/的存在,先判断/和隐含需求
+ zhuizong_list = zhuizong_tmp.split("\r")
+ print(zhuizong_list)
+ if zhuizong_tmp == "/" or zhuizong_tmp == "隐含需求":
+ xuqiu_dict = {
+ 'xq_zhangjie': '/',
+ 'xq_miaoshu': '/'
+ }
+ data['xuqiu'].append(xuqiu_dict)
+ data2['xuqiu'].append(xuqiu_dict)
+ else:
+ if len(zhuizong_list) >= 1:
+ for item in zhuizong_list:
+ xuqiu_dict = {}
+ if item.find("需求") != -1:
+ try:
+ match_string = re.search(
+ "\d(.\d+)+", item).group()
+ match_ming = item.split(
+ match_string)[-1]
+ xuqiu_dict[
+ 'xq_zhangjie'] = match_string
+ xuqiu_dict[
+ 'xq_miaoshu'] = match_ming.lstrip(
+ " ")
+ data['xuqiu'].append(xuqiu_dict)
+ except:
+ self.sin_out.emit(
+ f'$$$$$$$$$$$$第{str(i+1)}个表格无章节号$$$$$$$$$$$$'
+ )
+ self.sin_out.emit(
+ "转换终止!请检查表格中追踪关系有无章节号")
+ pass
+ else:
+ try:
+ match_string = re.search(
+ "\d(.\d+)+", item).group()
+ match_ming = item.split(
+ match_string)[-1]
+ xuqiu_dict[
+ 'xq_zhangjie'] = match_string
+ xuqiu_dict[
+ 'xq_miaoshu'] = match_ming.lstrip(
+ " ")
+ data2['xuqiu'].append(xuqiu_dict)
+ except:
+ self.sin_out.emit(
+ f'$$$$$$$$$$$$第{str(i+1)}个表格无章节号$$$$$$$$$$$$'
+ )
+ self.sin_out.emit(
+ "转换终止!请检查表格中追踪关系有无章节号")
+ pass
+
+ #如果追踪关系行数小于1行的情况
+ else:
+ xuqiu_dict = {
+ 'xq_zhangjie': '/',
+ 'xq_miaoshu': '/'
+ }
+ data['xuqiu'].append(xuqiu_dict)
+ data2['xuqiu'].append(xuqiu_dict)
+
+ try:
+ data['dg_zhangjie'] = zhangjiehao
+ data['mingcheng'] = zhangjieming
+ data['biaoshi'] = biaoshi
+ data_list.append(data)
+ data2['dg_zhangjie'] = zhangjiehao
+ data2['mingcheng'] = zhangjieming
+ data2['biaoshi'] = biaoshi
+ data2_list.append(data2)
+ except:
+ print("获取追踪出错啦!")
+ self.sin_out.emit(
+ f'$$$$$$$$$$$$第{str(i+1)}个表格追踪处理失败$$$$$$$$$$$$'
+ )
+ pass
+
+ #最后关闭文档
+ try:
+ self.w.Quit()
+ pythoncom.CoUninitialize()
+ self.parent.tabWidget.setEnabled(True)
+ except:
+ QMessageBox.warning(self.parent, "关闭文档失败", "关闭文档失败!")
+ return
+
+ try:
+ tpl_path = Path.cwd(
+ ) / "need" / "document_templates" / "大纲追踪模板.docx"
+ self.sin_out.emit('导入模板文件路径为:' + str(tpl_path))
+ tpl = DocxTemplate(tpl_path) #模板导入成功
+
+ except:
+ QMessageBox.warning(self.parent, "出错了", "导入模板出错请检查模板文件是否存在或名字不正确")
+ return
+
+ #开始渲染模板文件
+ try:
+ context = {
+ "tables": data_list,
+ "tables2": data2_list,
+ }
+ tpl.render(context)
+ tpl.save("生成的大纲追踪文档.docx")
+ self.sin_out.emit('stopsuccess')
+ except:
+ QMessageBox.warning(self.parent, "生成文档出错",
+ "生成文档错误,请确认模板文档是否已打开或格式错误")
+ self.sin_out.emit('stoperror')
+ return
+
+
+##################################################################################
+#单元测试UAS转换
+##################################################################################
+class create_danyuan(QtCore.QThread):
+ sin_out = pyqtSignal(str)
+
+ def __init__(self, parent):
+ super().__init__()
+ self.parent = parent
+
+ def run(self):
+ self.sin_out.emit("进入单元测试SunwiseAUnit转换线程......")
+ self.sin_out.emit("开始填写文档......")
+
+ #如果没有选择路径则退出
+ if not self.parent.open_file_name:
+ self.sin_out.emit('nofile')
+ self.parent.tabWidget.setEnabled(True)
+ return
+
+ #告诉windows单线程
+ pythoncom.CoInitialize()
+ #在用户选择的目录中查找UAS单位测试报告文档
+ self.sin_out.emit('打开单元测试原文件...')
+
+ #使用win32com打开-记得关闭
+ #打开word应用
+ self.w = DispatchEx('Word.Application')
+ #self.w.visible=True
+ self.w.DisplayAlerts = 0
+ try:
+ danyuanfile = self.w.Documents.Open(self.parent.open_file_name[0])
+ except:
+ self.sin_out.emit('open failed:选择的文档')
+ self.w.Quit()
+ pythoncom.CoUninitialize()
+ self.parent.tabWidget.setEnabled(True)
+ return
+
+ curpath = Path.cwd() / 'need'
+ danyuan_file_tmp = curpath / 'document_templates' / 'SunwiseAUnit单元测试转换模板.docx'
+ print(danyuan_file_tmp)
+
+ if danyuan_file_tmp.is_file():
+ self.sin_out.emit('已检测到有追溯模板文件...')
+ else:
+ self.sin_out.emit('open failed:选择的文档')
+ return
+
+ #创建个列表放数据-important
+ data_list = []
+
+ #try统计表格数量
+ try:
+ csx_tb_count = danyuanfile.Tables.Count
+ self.sin_out.emit('total:' + str(csx_tb_count))
+ self.sin_out.emit("正在调用word文档操作接口,可能会有点慢...")
+ except:
+ self.sin_out.emit('不存在表格!')
+ QMessageBox.warning(self.parent, '出错了', '测试说明文档格式错误或者没有正确表格')
+ try:
+ danyuanfile.Close()
+ except:
+ pass
+ self.w.Quit()
+ pythoncom.CoUninitialize()
+ self.parent.tabWidget.setEnabled(True)
+ return
+
+ #开始处理表格-important
+ #我先统计有多少个生成的表格-即用例有多少个呗
+ yongli_count = 0
+ for i in range(csx_tb_count):
+ if danyuanfile.Tables[i].Rows.Count > 2:
+ #注意win32com的Cell从1开始不是从0开始
+ if danyuanfile.Tables[i].Cell(1,
+ 1).Range.Text.find('用例名称') != -1:
+ yongli_count += 1
+
+ #yongli_num指向当前处理的用例
+ yongli_num = 0
+ hanshuming = ''
+ hanshuming_duibi = ''
+ wenjian = ''
+ wenjian_duibi = ''
+ for i in range(csx_tb_count):
+ self.sin_out.emit('正在处理的表格序号:' + str(yongli_num + 1))
+ self.sin_out.emit(str(i))
+ #准备填入的data
+ data = {'ruanjian_ming':'','ruanjian_biaoshi':'yongli_biaoshi','wenjian_ming':'',\
+ 'hanshu_ming':'','bianlian_and_canshu':'','zhuang':[],\
+ 'yuqi_jieguo':'','ceshi_jieguo':'','is_begin':'0','is_wenjian':'0'}
+
+ #填入用户输入的软件名
+ try:
+ data['ruanjian_ming'] = self.parent.lineEdit_2.text()
+ data['ruanjian_biaoshi'] = self.parent.lineEdit_3.text()
+
+ except:
+ QMessageBox.critical(self.parent, "未填入数据", "请先填入软件名和软件标识或.C名称")
+ self.w.Quit()
+ pythoncom.CoUninitialize()
+ self.parent.tabWidget.setEnabled(True)
+ pass
+
+ #找到函数名,这里容易出问题
+ if danyuanfile.Tables[i].Rows.Count > 2:
+ if danyuanfile.Tables[i].Cell(1,
+ 1).Range.Text.find('功能描述') != -1:
+ danyuanfile.Tables[i].Cell(1, 1).Range.Select()
+ self.w.Selection.MoveUp()
+ self.w.Selection.MoveUp()
+ self.w.Selection.MoveUp()
+ s = self.w.Selection.Paragraphs(1).Range.Text[:-1]
+ s1 = s.split(". ")[-1]
+ #放入函数名比对
+ if s1 != hanshuming_duibi:
+ hanshuming_duibi = s1
+
+ #再向上看1行
+ self.w.Selection.MoveUp()
+ temp2 = self.w.Selection.Paragraphs(1).Range.Text[:-1]
+ s2 = temp2.split("\\")[-1]
+ if '.' in temp2 and '\\' in temp2:
+ print('@@@@@@:', s2)
+ if s2 != wenjian_duibi: #这里有改动
+ wenjian_duibi = s2
+
+ #找章节号
+ if danyuanfile.Tables[i].Rows.Count > 2:
+ #注意win32com的Cell从1开始不是从0开始
+ if danyuanfile.Tables[i].Cell(1,
+ 1).Range.Text.find('用例名称') != -1:
+ #TODO:如何找到测试模块?
+ biaoshi_temp = danyuanfile.Tables[i].Cell(
+ 1, 4).Range.Text[:-2]
+ data['yongli_biaoshi'] = biaoshi_temp
+
+ #获取表格中参数组合()
+ quanju = danyuanfile.Tables[i].Cell(5, 3).Range.Text[:-2]
+ hcan = danyuanfile.Tables[i].Cell(6, 3).Range.Text[:-2]
+ qitashu = danyuanfile.Tables[i].Cell(7, 3).Range.Text[:-2]
+
+ if quanju.find('无') != -1:
+ quanju = ""
+ if hcan.find('无') != -1:
+ hcan = ""
+ if qitashu.find('无') != -1:
+ qitashu = ""
+
+ data['bianlian_and_canshu'] = quanju + hcan + qitashu
+ #将预期结果和测试结果填入
+ data['yuqi_jieguo'] = danyuanfile.Tables[i].Cell(
+ 8, 2).Range.Text[:-2]
+ data['ceshi_jieguo'] = danyuanfile.Tables[i].Cell(
+ 13, 2).Range.Text[:-2]
+ #函数名获取
+ if hanshuming_duibi != hanshuming:
+ hanshuming = hanshuming_duibi
+ data['is_begin'] = '1'
+ data['hanshu_ming'] = hanshuming_duibi
+ #文件名获取
+ if wenjian_duibi != wenjian:
+ wenjian = wenjian_duibi
+ data['is_wenjian'] = '1'
+ data['wenjian_ming'] = wenjian_duibi
+
+ data_list.append(data)
+ yongli_num += 1 #用例创建加一
+
+ elif danyuanfile.Tables[i].Cell(1,
+ 2).Range.Text.find('定义') != -1:
+ #定义个桩函数dict
+ zhuang_dict = {'zhuang_name':'','zhuang_dingyi':'','zhuang_fanhui':'',\
+ 'zhuang_fuzuoyong':''}
+
+ zhuang_dict['zhuang_name'] = danyuanfile.Tables[i].Cell(
+ 1, 1).Range.Text[:-2]
+ zhuang_dict['zhuang_dingyi'] = danyuanfile.Tables[i].Cell(
+ 1, 3).Range.Text[:-2]
+ zhuang_dict['zhuang_fanhui'] = danyuanfile.Tables[i].Cell(2, 3).Range.Paragraphs(1).\
+ Range.Text[:-1]
+
+ #副作用可能有多行
+ fuzuoyong_temp = ''
+ for count_fuzuo in range(
+ len(danyuanfile.Tables[i].Cell(
+ 2, 3).Range.Paragraphs) - 2):
+ fuzuoyong_temp = fuzuoyong_temp + ';' + danyuanfile.Tables[i].Cell(2, 3).\
+ Range.Paragraphs(count_fuzuo + 3).Range.Text[:-2].replace(" ", "")
+ zhuang_dict['zhuang_fuzuoyong'] = fuzuoyong_temp
+
+ data_list[yongli_num - 1]['zhuang'].append(zhuang_dict)
+
+ #最后关闭文档
+ try:
+ self.w.Quit()
+ pythoncom.CoUninitialize()
+ self.parent.tabWidget.setEnabled(True)
+ except:
+ QMessageBox.warning(self.parent, "关闭文档失败", "关闭文档失败!")
+ return
+
+ try:
+ tpl_path = Path.cwd(
+ ) / "need" / "document_templates" / "SunwiseAUnit单元测试转换模板.docx"
+ self.sin_out.emit('导入模板文件路径为:' + str(tpl_path))
+ tpl = DocxTemplate(tpl_path) #模板导入成功
+ except:
+ QMessageBox.warning(self.parent, "出错了", "导入模板出错请检查模板文件是否存在或名字不正确")
+ return
+
+ #开始渲染模板文件
+ try:
+ context = {
+ "tables": data_list,
+ }
+ tpl.render(context)
+ tpl.save("软件单元测试用例记录表.docx")
+ self.sin_out.emit('stopsuccess')
+ except:
+ self.sin_out.emit('stoperror')
+ return
+
+
+##################################################################################
+#测试说明追踪以及用例表
+##################################################################################
+class create_shuoming_zhuisu(QtCore.QThread):
+ sin_out = pyqtSignal(str)
+
+ def __init__(self, parent):
+ super().__init__()
+ self.parent = parent
+
+ def run(self):
+ self.sin_out.emit("进入说明追踪线程......")
+ self.sin_out.emit("开始填写说明追踪以及用例表格......")
+
+ # 如果没有选择文件
+ if not self.parent.open_file_name:
+ self.sin_out.emit('nofile')
+ self.parent.tabWidget.setEnabled(True)
+ return
+ # 告诉windows单线程
+ pythoncom.CoInitialize()
+ # 在用户选择的目录中查找大纲文档
+ self.sin_out.emit('打开测试说明文档...')
+
+ # 使用win32com打开-记得关闭
+ # 打开word应用
+ self.w = DispatchEx('Word.Application')
+ # self.w.visible=True
+ self.w.DisplayAlerts = 0
+ try:
+ shuomingfile = self.w.Documents.Open(self.parent.open_file_name[0])
+ except:
+ self.sin_out.emit('open failed:选择的文档')
+ self.w.Quit()
+ pythoncom.CoUninitialize()
+ self.parent.tabWidget.setEnabled(True)
+ return
+
+ self.sin_out.emit('已正确打开说明文档...')
+ curpath = Path.cwd() / 'need'
+ zhuisu_path_tmp = curpath / 'document_templates' / '说明追踪模板.docx'
+ print("打开追踪模板文件", zhuisu_path_tmp)
+
+ if zhuisu_path_tmp.is_file():
+ self.sin_out.emit('已检测到有说明追溯模板文件...')
+ else:
+ self.sin_out.emit('open failed:选择的文档')
+ return
+
+ # 创建个列表放数据
+ data_list = []
+ data2_list = []
+
+ #统计整个表格数量用于processbar显示进度
+ try:
+ tb_count = shuomingfile.Tables.Count
+ self.sin_out.emit('total:' + str(tb_count))
+ except:
+ self.sin_out.emit('不存在表格!')
+ QMessageBox.warning(self.parent, '出错了', '测试说明文档格式错误或者没有正确表格')
+ try:
+ shuomingfile.Close()
+ except:
+ QMessageBox.warning(self.parent, '错误', "未正确关闭Word文档!")
+ return
+ self.w.Quit()
+ pythoncom.CoUninitialize()
+ self.parent.tabWidget.setEnabled(True)
+ return
+
+ #遍历循环表格,这里面就要初始化数据dict了
+ #不能像大纲追踪一样data在循环表格里面
+ #创建一个大纲测试项索引
+ csx_name = ''
+ data = {
+ 'dg_zhangjie': '',
+ 'mingcheng': '',
+ 'biaoshi': '',
+ 'yongli': [],
+ 'index': 0
+ }
+ for i in range(tb_count):
+ self.sin_out.emit(str(i))
+ #self.sin_out.emit("正在处理第{}个表格...".format(str(i+1)))
+ print("正在处理第{}个表格...".format(str(i + 1)))
+ # 准备填入的data
+ data2 = {
+ 'yongli_ming': '',
+ 'yongli_biaoshi': '',
+ 'yongli_zongsu': ''
+ }
+ yongli_dict = {'yongli_ming': '', 'yongli_biaoshi': ''}
+ yongliming = ''
+ biaoshi = ''
+ zongsu = ''
+ zhui_temp = ''
+
+ if shuomingfile.Tables[i].Rows.Count > 2:
+ try:
+ # 注意win32com的Cell从1开始不是从0开始
+ if shuomingfile.Tables[i].Cell(1, 1).Range.Text.find('测试用例名称') != -1 or \
+ shuomingfile.Tables[i].Cell(2, 1).Range.Text.find('测试用例名称') != -1:
+ #取出cell(1,,1)的数据
+ table_heard = shuomingfile.Tables[i].Cell(1,
+ 1).Range.Text
+ if table_heard.find("测试用例名称") != -1:
+ yongliming = shuomingfile.Tables[i].Cell(
+ 1, 2).Range.Text.rstrip()[:-2]
+ biaoshi = shuomingfile.Tables[i].Cell(
+ 1, 4).Range.Text.rstrip()[:-2]
+ zongsu = shuomingfile.Tables[i].Cell(
+ 3, 2).Range.Text.rstrip()[:-2]
+ zhui_temp = shuomingfile.Tables[i].Cell(
+ 2, 2).Range.Text.rstrip()[:-2]
+ elif table_heard.find('用例') != -1:
+ yongliming = shuomingfile.Tables[i].Cell(
+ 2, 2).Range.Text.rstrip()[:-2]
+ biaoshi = shuomingfile.Tables[i].Cell(
+ 2, 4).Range.Text.rstrip()[:-2]
+ zongsu = shuomingfile.Tables[i].Cell(
+ 4, 2).Range.Text.rstrip()[:-2]
+ zhui_temp = shuomingfile.Tables[i].Cell(
+ 3, 2).Range.Text.rstrip()[:-2]
+ else:
+ self.sin_out.emit("未找到合适的填写数据,退出处理")
+ print("未找到合适的填写数据")
+ self.w.Quit()
+ pythoncom.CoUninitialize()
+ self.parent.tabWidget.setEnabled(True)
+ return
+ shuomingfile.Tables[i].Rows.First.Select() # 获取测试项章节号
+ #############################目前模板不用获取用例章节号暂时省去
+ # zhangjiehao = self.w.Selection.Bookmarks("\headinglevel"). \
+ # Range.Paragraphs(1).Range.ListFormat.ListString # 获取测试项章节名
+ ##############################################################
+ zhangjieming = self.w.Selection.Bookmarks("\headinglevel"). \
+ Range.Paragraphs(1).Range.Text.rstrip('\r')
+
+ yongli_dict['yongli_ming'] = yongliming
+ yongli_dict['yongli_biaoshi'] = biaoshi
+ data2['yongli_ming'] = yongliming
+ data2['yongli_biaoshi'] = biaoshi
+ data2['yongli_zongsu'] = zongsu
+ data2_list.append(data2)
+ print("当前yongli_dict为:", yongli_dict)
+ # 获取大纲的章节号和用例名,而且data按自己的来
+ ## 按python行进行分割为列表
+ zhui_list = zhui_temp.split("\r")
+ if len(zhui_list) == 3:
+ if zhui_list[1].find("需求") != -1:
+ #使用re模块正则表达式
+ match_string = re.search(
+ "\d(.\d+)+", zhui_list[1]).group()
+ match_ming = zhui_list[1].split(
+ match_string)[-1]
+ #使用re.sub模块替换为空
+ rules = "[)()(] "
+ match_ming = re.sub(rules, '', match_ming)
+ if zhui_list[2]:
+ rules = ":"
+ dg_biaoshi_temp = re.sub(
+ rules, ':', zhui_list[2])
+ dg_biaoshi = dg_biaoshi_temp.split(":")[-1]
+ #判断是否是新的测试项,如果是新的索引index加1,创建新dict进入
+ if zhangjieming != csx_name:
+ data_list.append(data)
+ data_index = data['index'] + 1
+ data = {
+ 'dg_zhangjie': '',
+ 'mingcheng': '',
+ 'biaoshi': '',
+ 'yongli': [],
+ 'index': data_index
+ }
+ data['dg_zhangjie'] = match_string
+ data['mingcheng'] = match_ming
+ data['biaoshi'] = dg_biaoshi
+ data['yongli'].append(yongli_dict)
+ csx_name = zhangjieming
+ self.sin_out.emit("已处理第{}个测试项...".format(
+ data['index']))
+ else:
+ data['yongli'].append(yongli_dict)
+ except:
+ self.sin_out.emit(
+ f'$$$$$$$$$$$$第{str(i+1)}个表格,获取单元格内容不存在$$$$$$$$$$$$')
+ pass
+
+ # 最后关闭文档
+ try:
+ self.w.Quit()
+ pythoncom.CoUninitialize()
+ self.parent.tabWidget.setEnabled(True)
+ except:
+ QMessageBox.warning(self.parent, "关闭文档失败", "关闭文档失败!")
+ return
+
+ try:
+ tpl_path = Path.cwd(
+ ) / "need" / "document_templates" / "说明追踪模板.docx"
+ self.sin_out.emit('导入模板文件路径为:' + str(tpl_path))
+ tpl = DocxTemplate(tpl_path) # 模板导入成功
+
+ except:
+ QMessageBox.warning(self.parent, "出错了", "导入模板出错请检查模板文件是否存在或名字不正确")
+ return
+
+ # 开始渲染模板文件
+ try:
+ context = {
+ "tables": data_list,
+ "tables2": data2_list,
+ }
+ tpl.render(context)
+ tpl.save("说明追踪文档.docx")
+ self.sin_out.emit('stopsuccess')
+ except:
+ self.sin_out.emit('stoperror')
+ return
+
+
+##################################################################################
+#根据说明生成测试记录线程
+##################################################################################
+class create_jilu(QtCore.QThread):
+ sin_out = pyqtSignal(str)
+
+ def __init__(self, parent):
+ super().__init__()
+ self.parent = parent
+
+ def run(self):
+ #用来储存章节号转换
+ zhuan_dict = {'DC':'文档审查','SU':'功能测试','CR':'代码审查','SA':'静态分析','AC':'性能测试',\
+ 'IO':'接口测试','SE':'安全性测试','BT':'边界测试','RE':'恢复性测试','ST':'强度测试',\
+ 'AT':'余量测试','GUI':'人机交互界面测试','DP':'数据处理测试','JR':'兼容性测试',\
+ 'LG':'逻辑测试','AZ':'安装性测试','TT':'时序测试','PA':'功耗分析'}
+
+ self.sin_out.emit("进入根据说明转换记录线程......")
+ self.sin_out.emit("开始转换......")
+ #如果没有选择文件则退出
+ if not self.parent.open_file_name:
+ self.sin_out.emit('nofile')
+ self.parent.tabWidget.setEnabled(True)
+ return
+ pythoncom.CoInitialize()
+ self.sin_out.emit('打开说明文档...')
+ self.w = DispatchEx('Word.Application')
+ self.w.DisplayAlerts = 0
+ try:
+ shuomingfile = self.w.Documents.Open(self.parent.open_file_name[0])
+ except:
+ self.sin_out.emit('open failed:选择的文档')
+ self.w.Quit()
+ pythoncom.CoUninitialize()
+ self.parent.tabWidget.setEnabled(True)
+ return
+ self.sin_out.emit('复制测试记录文档模板到本程序所在目录...')
+ curpath = Path.cwd() / 'need'
+ shuoming_path_tmp = curpath / 'document_templates' / '说明生成记录模板.docx'
+ if shuoming_path_tmp.is_file():
+ self.sin_out.emit('已检测到有记录模板文件...')
+ else:
+ self.sin_out.emit('open failed:选择的文档')
+ return
+ #创建一个字典来储存单个用例
+ data_list = []
+ #获取表格数量
+ try:
+ csx_tb_count = shuomingfile.Tables.Count
+ self.sin_out.emit('total:' + str(csx_tb_count))
+ except:
+ self.sin_out.emit('不存在表格,请检查文档!')
+ QMessageBox.warning(self.parent, '出错了', '测试说明文档格式错误或者没有正确表格')
+ try:
+ shuomingfile.Close()
+ except:
+ pass
+ self.w.Quit()
+ pythoncom.CoUninitialize()
+ self.parent.tabWidget.setEnabled(True)
+ return
+
+ #用来储存章节号中的DC、SU等标识,用于章节号判断
+ is_type_su = ""
+ #储存章节号标志
+ is_fire_su = ""
+ for i in range(csx_tb_count):
+ self.sin_out.emit(str(i))
+ self.sin_out.emit("正在处理第{}个表格".format(i + 1))
+ try:
+ if shuomingfile.Tables[i].Rows.Count > 2:
+ if shuomingfile.Tables[i].Cell(
+ 2, 1).Range.Text.find('测试用例名称') != -1:
+ #一个用例不变内容获取
+ try:
+ shuomingfile.Tables[i].Rows.First.Select()
+ #获取章节名,用于判断
+ zhangjieming = self.w.Selection.Bookmarks("\headinglevel").\
+ Range.Paragraphs(1).Range.Text.rstrip('\r')
+ #获取表格基本信息
+ mingcheng = shuomingfile.Tables[i].Cell(
+ 2, 2).Range.Text[:-2]
+ biaoshi = shuomingfile.Tables[i].Cell(
+ 2, 4).Range.Text[:-2]
+ self.sin_out.emit(f"正在处理{biaoshi}用例{mingcheng}")
+ zhuizong = shuomingfile.Tables[i].Cell(
+ 3, 2).Range.Text[:-2]
+ zongsu = shuomingfile.Tables[i].Cell(
+ 4, 2).Range.Text[:-2]
+ chushihua = shuomingfile.Tables[i].Cell(
+ 5, 2).Range.Text[:-2]
+ qianti = shuomingfile.Tables[i].Cell(
+ 6, 2).Range.Text[:-2]
+
+ #缓存一个data数据
+ data = {'mingcheng':'','biaoshi':'','zhuizong':'','is_first':'0',\
+ 'zongsu':'','chushihua':'','qianti':'','zuhe':[],'is_begin':'0',\
+ 'csx_type':'','csx_name':''}
+ #获取步骤和预期
+ step_count = shuomingfile.Tables[i].Rows.Count - 11
+ for j in range(step_count):
+ buzhou_dict = {
+ 'buzhou': "",
+ 'yuqi': "",
+ 'xuhao': ''
+ }
+ buzhou_dict['buzhou'] = shuomingfile.Tables[
+ i].Cell(j + 9, 2).Range.Text[:-2]
+ buzhou_dict['yuqi'] = shuomingfile.Tables[
+ i].Cell(j + 9, 3).Range.Text[:-2]
+ buzhou_dict['xuhao'] = str(j + 1)
+ data['zuhe'].append(buzhou_dict)
+
+ #开始判断当前是否为测试项的第一个,如果是第一个则is_first改为1
+ if is_fire_su != zhangjieming:
+ is_fire_su = zhangjieming
+ data['is_first'] = '1'
+
+ #判断测试类型,这里从标识里面获取
+ biaoshi_list = biaoshi.split("_")
+ print('当前取的类型列表分割:', biaoshi_list)
+ if len(biaoshi_list) >= 4:
+ biaoshi_tmp = biaoshi_list[-3]
+ else:
+ biaoshi_tmp = biaoshi_list[1]
+ if biaoshi_tmp != is_type_su:
+ is_type_su = biaoshi_tmp
+ data['is_begin'] = '1'
+ if zhuan_dict[biaoshi_tmp] == '文档审查' or zhuan_dict[biaoshi_tmp] == '代码审查' or \
+ zhuan_dict[biaoshi_tmp] == '静态分析':
+ data['is_first'] = '0'
+
+ #data补全
+ data['mingcheng'] = mingcheng
+ data['biaoshi'] = biaoshi
+ data['zhuizong'] = zhuizong.replace('\r', '\n')
+ data['zongsu'] = zongsu
+ data['chushihua'] = chushihua
+ data['qianti'] = qianti
+ data['csx_type'] = zhuan_dict[biaoshi_tmp]
+ data['csx_name'] = zhangjieming
+ data_list.append(data)
+ self.sin_out.emit("处理完毕{}用例".format(biaoshi))
+ except:
+ self.sin_out.emit(f'错误!第{i+1}个表格处理失败!')
+ except:
+ self.sin_out.emit(f'错误!第{i+1}个表格处理失败!')
+
+ #关闭大纲文档(因为以及提取完毕)
+ try:
+ shuomingfile.Close()
+ self.w.Quit()
+ pythoncom.CoUninitialize()
+ except:
+ self.sin_out.emit('function fail')
+ self.w.Quit()
+ pythoncom.CoUninitialize()
+ return
+
+ #打开模板文件进行渲染,然后就是用docxtpl生成用例
+ try:
+ tpl_path = Path.cwd(
+ ) / "need" / "document_templates" / "说明生成记录模板.docx"
+ self.sin_out.emit('导入模板文件路径为:' + str(tpl_path))
+ tpl = DocxTemplate(tpl_path) #模板导入成功
+
+ except:
+ QMessageBox.warning(self.parent, "出错了", "导入模板出错请检查模板文件是否存在或名字不正确")
+ return
+
+ #开始渲染模板文件-有2层循环
+ try:
+ context = {
+ "tables": data_list,
+ "cs_renyuan": self.parent.lineEdit_4.text(),
+ "jc_renyuan": self.parent.lineEdit_5.text(),
+ "shijian": self.parent.lineEdit_6.text(),
+ }
+ tpl.render(context)
+ tpl.save("生成的测试记录文档.docx")
+ self.sin_out.emit('stopsuccess')
+ except:
+ self.sin_out.emit('stoperror')
+ return
+
+
+##################################################################################
+# 根据测试记录反向生成说明
+##################################################################################
+class create_shuomingfanxiang(QtCore.QThread):
+ sin_out = pyqtSignal(str)
+
+ def __init__(self, parent):
+ super().__init__()
+ self.parent = parent
+
+ def run(self):
+ # 用来储存测试项DC等转换
+ zhuan_dict = {'DC':'文档审查','SU':'功能测试','CR':'代码审查','SA':'静态分析','AC':'性能测试',\
+ 'IO':'接口测试','SE':'安全性测试','BT':'边界测试','RE':'恢复性测试','ST':'强度测试',\
+ 'AT':'余量测试','GUI':'人机交互界面测试','DP':'数据处理测试','JR':'兼容性测试',\
+ 'LG':'逻辑测试','AZ':'安装性测试','TT':'时序测试','PA':'功耗分析'}
+
+ self.sin_out.emit("进入测试记录转说明......")
+ self.sin_out.emit("开始转换......")
+ # 如果没有选择文件路径则退出
+ if not self.parent.open_file_name:
+ self.sin_out.emit('nofile')
+ self.parent.tabWidget.setEnabled(True)
+ return
+ pythoncom.CoInitialize()
+ self.sin_out.emit('打开测试记录文件...')
+ self.w = DispatchEx('Word.Application')
+ #self.w.visible=True
+ self.w.DisplayAlerts = 0
+ try:
+ jilufile = self.w.Documents.Open(self.parent.open_file_name[0])
+ except:
+ self.sin_out.emit('open failed:选择的文档')
+ self.w.Quit()
+ pythoncom.CoUninitialize()
+ self.parent.tabWidget.setEnabled(True)
+ return
+
+ self.sin_out.emit('复制测试说明文档模板到本程序所在目录...')
+ curpath = Path.cwd() / 'need'
+ shuoming_path_tmp = curpath / 'document_templates' / '反向测试说明模板.docx'
+ print(shuoming_path_tmp)
+ if shuoming_path_tmp.is_file():
+ self.sin_out.emit('已检测到有说明模板文件...')
+ else:
+ self.sin_out.emit('open failed:选择的文档')
+ return
+ #创建一个字典来储存单个用例
+ data_list = []
+ #获取表格数量
+ try:
+ csx_tb_count = jilufile.Tables.Count
+ self.sin_out.emit('total:' + str(csx_tb_count))
+ except:
+ self.sin_out.emit('不存在表格!')
+ QMessageBox.warning(self.parent, '出错了', '测试说明文档格式错误或者没有正确表格')
+ try:
+ jilufile.Close()
+ except:
+ pass
+ self.w.Quit()
+ pythoncom.CoUninitialize()
+ self.parent.tabWidget.setEnabled(True)
+ return
+
+ #初始化表格外全局变量
+ is_fire_su = ''
+ is_type_su = ''
+ for i in range(csx_tb_count):
+ self.sin_out.emit(str(i))
+ self.sin_out.emit(f"正在处理第{str(i+1)}个表格")
+ if jilufile.Tables[i].Rows.Count > 2:
+ if jilufile.Tables[i].Cell(2,
+ 1).Range.Text.find('测试用例名称') != -1:
+ #将表格中信息全部先拿出来
+ try:
+ jilufile.Tables[i].Rows.First.Select()
+ zhangjieming = self.w.Selection.Bookmarks("\headinglevel").\
+ Range.Paragraphs(1).Range.Text.rstrip('\r')
+ zhangjiehao = self.w.Selection.Bookmarks("\headinglevel").\
+ Range.Paragraphs(1).Range.ListFormat.ListString
+ mingcheng = jilufile.Tables[i].Cell(2,
+ 2).Range.Text[:-2]
+ biaoshi = jilufile.Tables[i].Cell(2, 4).Range.Text[:-2]
+ self.sin_out.emit(f"正在处理{biaoshi}-用例{mingcheng}")
+ zhuizong = jilufile.Tables[i].Cell(3,
+ 2).Range.Text[:-2]
+ zongsu = jilufile.Tables[i].Cell(4, 2).Range.Text[:-2]
+ chushi = jilufile.Tables[i].Cell(5, 2).Range.Text[:-2]
+ qianti = jilufile.Tables[i].Cell(6, 2).Range.Text[:-2]
+
+ #缓存一个data数据
+ data = {'mingcheng':'','biaoshi':'','zhuizong':'','is_first':'0',\
+ 'zongsu':'','chushi':'','qianti':'','zuhe':[],'is_begin':'0',\
+ 'csx_type':'','csx_mingcheng':'','renyuan':''}
+ #获取步骤和预期
+ step_count = jilufile.Tables[i].Rows.Count - 12
+ #获取人员信息
+ data['renyuan'] = jilufile.Tables[i].Cell(
+ 10 + step_count, 2).Range.Text[:-2]
+ for j in range(step_count):
+ buzhou_dict = {
+ 'buzhou': "",
+ 'yuqi': "",
+ 'xuhao': ''
+ }
+ buzhou_dict['buzhou'] = jilufile.Tables[i].Cell(
+ j + 9, 2).Range.Text[:-2]
+ buzhou_dict['yuqi'] = jilufile.Tables[i].Cell(
+ j + 9, 3).Range.Text[:-2]
+ buzhou_dict['xuhao'] = str(j + 1)
+ data['zuhe'].append(buzhou_dict)
+
+ # 开始判断当前是否为测试项的第一个,如果是第一个则is_first改为1
+ if is_fire_su != zhangjieming:
+ is_fire_su = zhangjieming
+ data['is_first'] = '1'
+ # 判断测试类型,这里从标识里面获取
+ biaoshi_list = biaoshi.split("_")
+ print('当前取的类型列表分割:', biaoshi_list)
+ if len(biaoshi_list) >= 4:
+ biaoshi_tmp = biaoshi_list[-4]
+ else:
+ biaoshi_tmp = biaoshi_list[1]
+ if biaoshi_tmp != is_type_su:
+ is_type_su = biaoshi_tmp
+ data['is_begin'] = '1'
+ if zhuan_dict[biaoshi_tmp] == '文档审查' or zhuan_dict[biaoshi_tmp] == '代码审查' or \
+ zhuan_dict[biaoshi_tmp] == '静态分析':
+ data['is_first'] = '0'
+
+ #data补全
+ data['mingcheng'] = mingcheng
+ data['biaoshi'] = biaoshi
+ data['zhuizong'] = zhuizong.replace('\r', '\n')
+ data['zongsu'] = zongsu
+ data['chushi'] = chushi
+ data['qianti'] = qianti
+ data['csx_type'] = zhuan_dict[biaoshi_tmp]
+ data['csx_mingcheng'] = zhangjieming
+ data_list.append(data)
+ self.sin_out.emit("处理完毕{}用例".format(biaoshi))
+ except:
+ self.sin_out.emit("第{}个表格处理失败,请检查".format(str(i + 1)))
+ pass
+
+ else:
+ self.sin_out.emit(
+ "该表格生成错误,请检查是否存在用例序号,每个用例必须有序号且必须包含【记录】两个字...")
+ else:
+ self.sin_out.emit("该表格生成错误,请检查表格是否存在并大于2行...")
+
+ #关闭大纲文档(因为以及提取完毕)
+ try:
+ jilufile.Close()
+ self.w.Quit()
+ pythoncom.CoUninitialize()
+ except:
+ self.sin_out.emit('function fail')
+ self.w.Quit()
+ pythoncom.CoUninitialize()
+ return
+
+ #打开模板文件进行渲染,然后就是用docxtpl生成用例
+ try:
+ tpl_path = Path.cwd(
+ ) / "need" / "document_templates" / "反向测试说明模板.docx"
+ self.sin_out.emit('导入模板文件路径为:' + str(tpl_path))
+ tpl = DocxTemplate(tpl_path) #模板导入成功
+
+ except:
+ QMessageBox.warning(self.parent, "出错了", "导入模板出错请检查模板文件是否存在或名字不正确")
+ return
+
+ #开始渲染模板文件-有2层循环
+ try:
+ context = {
+ "tables": data_list,
+ }
+ tpl.render(context)
+ tpl.save("反向生成的说明文档.docx")
+ self.sin_out.emit('stopsuccess')
+ except:
+ self.sin_out.emit('stoperror')
+ return
+
+
+##################################################################################
+#自动填充单元格线程
+##################################################################################
+class create_zidong(QtCore.QThread):
+ sin_out = pyqtSignal(str)
+
+ def __init__(self, parent):
+ super().__init__()
+ self.parent = parent
+
+ def run(self):
+ self.sin_out.emit('开始...')
+ if self.parent.open_file_name == '':
+ self.sin_out.emit('请点击“选择文档”按钮选择要填充的文档')
+ self.parent.tabWidget.setEnabled(True)
+ QMessageBox.warning(self.parent, '出错了!', '请选择要填充的文档!')
+ return
+ try:
+ t_s_file = docx.Document(self.parent.open_file_name[0])
+ except:
+ self.sin_out.emit('open failed:选择的文档')
+ self.parent.tabWidget.setEnabled(True)
+ QMessageBox.warning(self.parent, '出错了!',
+ '打开选择的文档失败,请确认文档类型为docx,且未被打开!')
+ return
+ if self.parent.lineEdit_9.text() == '':
+ self.sin_out.emit('单元格左侧不能为空!!!!')
+ self.parent.tabWidget.setEnabled(True)
+ QMessageBox.warning(self.parent, '出错了!', '单元格标题不能为空!')
+ return
+ if self.parent.lineEdit_10.text() == '':
+ self.sin_out.emit('确定填充内容为空吗?填充内容为空相当于清空操作。可直接点击清空按钮!!')
+ self.parent.tabWidget.setEnabled(True)
+ QMessageBox.warning(self.parent, '警告!',
+ '确定填充内容为空吗?填充内容为空相当于清空操作。可点击清空按钮!!')
+ return
+ tmp_fill = self.parent.lineEdit_11.text()
+ if tmp_fill == '':
+ tmp_fill = str(len(t_s_file.tables))
+
+ if (tmp_fill.strip().isdigit()) and (int(tmp_fill.strip()) < len(
+ t_s_file.tables)):
+ tmp_ran = int(tmp_fill)
+ else:
+ tmp_ran = len(t_s_file.tables)
+
+ tmp_fillnum = 0
+ k = 0
+
+ self.sin_out.emit('total:' + str(tmp_ran))
+
+ self.parent.progressBar.setRange(0, tmp_ran - 1)
+ for ft1 in t_s_file.tables:
+ k += 1
+ self.sin_out.emit(str(k))
+ self.parent.progressBar.setValue(k)
+ tmp_row = 0
+ for r in ft1.rows:
+ tmpflag = 0
+ tmp_column = 0
+ for cell in r.cells:
+ if cell.text.strip() == self.parent.lineEdit_9.text():
+ while ft1.cell(tmp_row, tmp_column).text.strip(
+ ) == self.parent.lineEdit_9.text():
+ tmp_column += 1
+ #这里如果需要替换还是不替换
+ if ft1.cell(tmp_row, tmp_column).text == '':
+ ft1.cell(tmp_row, tmp_column
+ ).text = self.parent.lineEdit_10.text()
+ tmp_fillnum += 1
+ else:
+ pass
+ tmpflag = 1
+ break
+ else:
+ tmp_column += 1
+ if tmpflag == 1:
+ break
+ tmp_row += 1
+ if tmp_fillnum >= int(tmp_fill):
+ break
+
+ try:
+ t_s_file.save(self.parent.open_file_name[0])
+ self.sin_out.emit('function success')
+ self.parent.tabWidget.setEnabled(True)
+ return
+ except:
+ self.parent.tabWidget.setEnabled(True)
+ self.sin_out.emit('function fail')
+ QMessageBox.information(self.parent, '', '填充完成!')
+ return
+
+
+##################################################################################
+#清空单元格线程
+##################################################################################
+class clear_cell(QtCore.QThread):
+ sin_out = pyqtSignal(str)
+
+ def __init__(self, parent):
+ super().__init__()
+ self.parent = parent
+
+ def run(self):
+ self.sin_out.emit('开始...')
+ if self.parent.open_file_name == '':
+ self.sin_out.emit('请点击“选择文档”按钮选择要填充的文档')
+ self.parent.tabWidget.setEnabled(True)
+ QMessageBox.warning(self.parent, '出错了!', '请选择要填充的文档!')
+ return
+ try:
+ t_s_file = docx.Document(self.parent.open_file_name[0])
+ except:
+ self.sin_out.emit('open failed:要填充的文档')
+ QMessageBox.warning(self.parent, '出错了!',
+ '打开选择的文档失败,请确认文档类型为docx,且未被打开!')
+ self.parent.tabWidget.setEnabled(True)
+ return
+ if self.parent.lineEdit_9.text() == '':
+ self.parent.tabWidget.setEnabled(True)
+ self.sin_out.emit('单元格标题不能为空!')
+ QMessageBox.warning(self.parent, '出错了!', '单元格标题不能为空!')
+ return
+ tmp_tblcnt = len(t_s_file.tables)
+ k = 0
+ self.sin_out.emit('total:' + str(tmp_tblcnt))
+ for ft1 in t_s_file.tables:
+ k += 1
+ self.sin_out.emit(str(k))
+ tmp_row = 0
+ for r in ft1.rows:
+ tmpflag = 0
+ tmp_column = 0
+ for cell in r.cells:
+
+ if cell.text.strip() == self.parent.lineEdit_9.text():
+ while ft1.cell(tmp_row, tmp_column).text.strip(
+ ) == self.parent.lineEdit_9.text():
+ tmp_column += 1
+
+ ft1.cell(tmp_row, tmp_column).text = ''
+ tmpflag = 1
+ break
+ else:
+ tmp_column += 1
+ if tmpflag == 1:
+ break
+ tmp_row += 1
+ try:
+ t_s_file.save(self.parent.open_file_name[0])
+ self.sin_out.emit('function success')
+ self.parent.tabWidget.setEnabled(True)
+ return
+ except:
+ self.parent.tabWidget.setEnabled(True)
+ self.sin_out.emit('function fail')
+ QMessageBox.information(self.parent, '', '清空单元格成功!')
+ return
+
+
+##################################################################################
+#提取表格内容线程
+##################################################################################
+class get_content(QtCore.QThread):
+ sin_out = pyqtSignal(str)
+
+ def __init__(self, parent):
+ super().__init__()
+ self.parent = parent
+
+ #获取文档中表格内容函数
+ def run(self):
+ curpath = Path.cwd()
+ content_tmp = curpath / 'need' / 'document_templates' / 'get_content.docx'
+ shutil.copy(content_tmp, curpath)
+ content_tmp_path = curpath / 'get_content.docx'
+ print(content_tmp_path)
+ try:
+ #c_file = self.w.Documents.Add()
+ c_file = docx.Document(content_tmp_path)
+ except:
+ self.sin_out.emit('open failed:文档模板')
+ self.parent.tabWidget.setEnabled(True)
+ return
+
+ try:
+ s_file = docx.Document(self.parent.open_file_name[0])
+ s_tbls = s_file.tables
+ except:
+ self.sin_out.emit('open failed:选择的文档')
+ c_file.save(content_tmp_path)
+ self.parent.tabWidget.setEnabled(True)
+ return
+ #原来是5,6,7
+ if self.parent.lineEdit_12.text(
+ ) == '' and self.parent.lineEdit_13.text(
+ ) == '' and self.parent.lineEdit_14.text() == '':
+
+ self.sin_out.emit(
+ 'warning:请至少填写一个要提取的内容的标题,\n标题为要提取的单元格的前一单元格中的内容!')
+ c_file.save(content_tmp_path)
+ s_file.save(self.parent.open_file_name[0])
+ self.parent.tabWidget.setEnabled(True)
+ return
+
+ line_list = [
+ self.parent.lineEdit_12.text(),
+ self.parent.lineEdit_13.text(),
+ self.parent.lineEdit_14.text()
+ ]
+ self.sin_out.emit('开始提取...')
+ rownum = 0
+ self.sin_out.emit('total:' + str(len(s_tbls)))
+ for stb in s_tbls:
+ c_file.tables[0].add_row()
+ rownum += 1
+ self.sin_out.emit(str(rownum))
+
+ row = 0
+ for r1 in stb.rows:
+ col = 0
+ for ce in r1.cells:
+ if line_list[0] != '' and ce.text == line_list[0]:
+ while stb.cell(row, col).text == line_list[0]:
+ col += 1
+ c_file.tables[0].cell(rownum,
+ 0).text = stb.cell(row, col).text
+ break
+ col += 1
+ col = 0
+ for ce in r1.cells:
+ if line_list[1] != '' and ce.text == line_list[1]:
+ while stb.cell(row, col).text == line_list[1]:
+ col += 1
+ c_file.tables[0].cell(rownum,
+ 1).text = stb.cell(row, col).text
+ break
+ col += 1
+ col = 0
+ for ce in r1.cells:
+ if line_list[2] != '' and ce.text == line_list[2]:
+ while stb.cell(row, col).text == line_list[2]:
+ col += 1
+ c_file.tables[0].cell(rownum,
+ 2).text = stb.cell(row, col).text
+ break
+ col += 1
+ row += 1
+ try:
+ c_file.save(content_tmp_path)
+ s_file.save(self.parent.open_file_name[0])
+ self.sin_out.emit('function success')
+ self.sin_out.emit('生成文件名为(get_content.docx),在根目录下查看')
+ self.parent.tabWidget.setEnabled(True)
+ return
+ except:
+ self.sin_out.emit('function fail')
+ self.parent.tabWidget.setEnabled(True)
+ return
+
+
+##################################################################################
+#测评报告追溯表
+##################################################################################
+class create_baogao_zhuisu(QtCore.QThread):
+ sin_out = pyqtSignal(str)
+
+ def __init__(self, parent):
+ super().__init__()
+ self.parent = parent
+
+ def run(self):
+ self.sin_out.emit("进入报告追溯线程......")
+ self.sin_out.emit("开始填写报告追溯表......")
+
+ # 如果没有选择文件
+ if not self.parent.open_file_name:
+ self.sin_out.emit('nofile')
+ self.parent.tabWidget.setEnabled(True)
+ return
+ self.sin_out.emit('打开测试记录文档...')
+ # 打开word应用
+ try:
+ doc_path = self.parent.open_file_name[0]
+ doc = Document(doc_path)
+ except:
+ self.sin_out.emit('open failed:选择的文档')
+ self.parent.tabWidget.setEnabled(True)
+ return
+
+ self.sin_out.emit('已正确打开说明文档...')
+ curpath = Path.cwd() / 'need'
+ zhuisu_path_tmp = curpath / 'document_templates' / '报告追踪模板.docx'
+ if zhuisu_path_tmp.is_file():
+ self.sin_out.emit('已检测到有报告追溯模板文件...')
+ else:
+ self.sin_out.emit('open failed:选择的文档')
+ return
+
+ # 创建个列表放数据
+ data_list = []
+ # 由于docx的是列表,所以直接len函数统计count
+ count = len(doc.tables)
+ self.sin_out.emit('total:' + str(count))
+ k = 0
+ for tb in doc.tables:
+ k += 1
+ self.sin_out.emit('total:' + str(k))
+ #注意docx处理方式不一样从0开始,并且要算总行数
+ try:
+ if tb.cell(1, 1).text.find('测试用例名称') != -1:
+ data = {
+ 'yongli_ming': '',
+ 'yongli_biaoshi': '',
+ 'yongli_qingkuang': '',
+ 'beizhu': ''
+ }
+ data['yongli_ming'] = tb.cell(1, 4).text
+ data['yongli_biaoshi'] = tb.cell(1, 8).text
+ wenti = tb.rows[-2].cells[2]
+ print('提取出来的信息:', wenti.text)
+ if wenti.text == '/' or wenti.text == '':
+ data['yongli_qingkuang'] = '通过'
+ data['beizhu'] = '/'
+ else:
+ data['yongli_qingkuang'] = '不通过'
+ data['beizhu'] = wenti.text
+ self.sin_out.emit(f'处理完毕({tb.cell(1,8).text})用例..')
+ data_list.append(data)
+ else:
+ self.sin_out.emit(f'当前表格({tb.cell(1,8).text})用例无法识别请检查')
+ except:
+ self.sin_out.emit(f'处理第{k}个表格失败,请检查该表格...')
+ pass
+
+ try:
+ tpl_path = Path.cwd(
+ ) / "need" / "document_templates" / '报告追踪模板.docx'
+ self.sin_out.emit('导入模板文件路径为:' + str(tpl_path))
+ tpl = DocxTemplate(tpl_path) # 模板导入成功
+
+ except:
+ QMessageBox.warning(self.parent, "出错了", "导入模板出错请检查模板文件是否存在或名字不正确")
+ return
+
+ # 开始渲染模板文件
+ print(data_list)
+ try:
+ context = {
+ "tables": data_list,
+ }
+ tpl.render(context)
+ tpl.save("说明追踪文档.docx")
+ self.sin_out.emit('stopsuccess')
+ except:
+ self.sin_out.emit('stoperror')
+ return
+
+
+##################################################################################
+##
+##################################################################################
diff --git a/need/new_JtoS.py b/need/new_JtoS.py
new file mode 100644
index 0000000..984a6ba
--- /dev/null
+++ b/need/new_JtoS.py
@@ -0,0 +1,170 @@
+from PyQt5 import QtCore
+from PyQt5.QtCore import pyqtSignal
+from pathlib import * # noqa: F403
+from PyQt5.QtWidgets import QMessageBox
+from docxtpl import DocxTemplate, InlineImage # type:ignore
+from docx import Document
+from docx.table import Table
+from docx.text.paragraph import Paragraph
+import io
+
+
+class create_new_JtoS(QtCore.QThread):
+ sin_out = pyqtSignal(str)
+ PREFIX = r'{http://schemas.openxmlformats.org/wordprocessingml/2006/main}'
+
+ def __init__(self, parent):
+ super().__init__()
+ self.parent = parent
+
+ def run(self):
+ self.sin_out.emit("进入CPU测试记录转说明线程......")
+ self.sin_out.emit("开始转换......")
+ # 如果没有选择文件路径则退出
+ if not self.parent.open_file_name:
+ self.sin_out.emit('nofile')
+ self.parent.tabWidget.setEnabled(True)
+ return
+
+ # 打开模板文件进行渲染,然后就是用docxtpl生成用例
+ try:
+ tpl_path = Path.cwd( # noqa: F405
+ ) / "need" / "document_templates" / "cpu新记录to说明模版.docx"
+ self.sin_out.emit('导入模板文件路径为:' + str(tpl_path))
+ tpl = DocxTemplate(tpl_path) # 模板导入成功
+
+ except: # noqa: E722
+ QMessageBox.warning(self.parent, "出错了", "导入模板出错请检查模板文件是否存在或名字不正确")
+ return
+
+ try:
+ doc = Document(self.parent.open_file_name[0])
+ self.sin_out.emit('已识别到CPU测试记录文件...')
+ except: # noqa: E722
+ self.sin_out.emit('open failed:选择的文档')
+ self.parent.tabWidget.setEnabled(True)
+ return
+
+ self.sin_out.emit('复制测试说明文档模板到本程序所在目录...')
+ curpath = Path.cwd() / 'need' # noqa: F405
+ shuoming_path_tmp = curpath / 'document_templates' / 'cpu新记录to说明模版.docx'
+ print(shuoming_path_tmp)
+ if shuoming_path_tmp.is_file():
+ self.sin_out.emit('已检测到有说明模板文件...')
+ else:
+ self.sin_out.emit('open failed:选择的文档')
+ return
+
+ # 获取表格数量
+ tables = doc.tables
+ tb_count = len(tables)
+ self.sin_out.emit('total:' + str(tb_count))
+ # 创建一个字典来储存单个用例
+ data_list = []
+ table_index = 1
+ # 获取表格数量
+ for ele in doc._element.body.iter():
+ data = {'type': ''}
+ if ele.tag.endswith('}p'):
+ for child in ele.iter():
+ if child.tag.endswith('pStyle'):
+ rank = child.get(f"{self.PREFIX}val")
+ t_ele = ele.findall(
+ f".//{self.PREFIX}t") # type:ignore
+ title = ''
+ for i in range(len(t_ele)):
+ if not t_ele[i].text.isdigit():
+ title = title + t_ele[i].text
+ data['type'] = rank
+ data['title'] = title
+ data_list.append(data)
+
+ elif ele.tag.endswith('}tbl'):
+ data = {
+ 'name': '',
+ 'biaoshi': '',
+ 'zhuizong': [],
+ 'zongsu': '',
+ 'init': '',
+ 'qianti': '',
+ 'step': []
+ }
+ data['type'] = 'table'
+ table = Table(ele, doc)
+ if table.cell(1, 0).text == '测试用例名称':
+ self.sin_out.emit(str(table_index))
+
+ try:
+ self.sin_out.emit(str(table_index))
+ self.sin_out.emit(f'正在处理第{table_index}个表格')
+ # 1、获取测试用例名称
+ data['name'] = table.cell(1, 3).text
+ # 2、获取用例标识
+ data['biaoshi'] = table.cell(1, 9).text
+ # 3、获取追踪关系 注意word中换行为\r\x07
+ temp = table.cell(2, 3)
+ for tem in temp.paragraphs:
+ data['zhuizong'].append(tem.text)
+ # 4、获取综述
+ data['zongsu'] = table.cell(3, 3).text.replace(
+ '\n', '\a')
+ # 5、初始化
+ data['init'] = table.cell(4,
+ 3).text.replace('\n', '\a')
+ # 6、获取前提与约束
+ data['qianti'] = table.cell(5, 3).text.replace(
+ '\n', '\a')
+ # 7、获取步骤信息-总行数减去12为步骤行数
+ row_count = len(table.rows)
+ step_count = row_count - 12
+ for j in range(step_count):
+ buzhou = {
+ 'shuru': '',
+ 'yuqi': '',
+ 'num': '',
+ 'image': '',
+ 'is_image': '0'
+ }
+ buzhou['num'] = table.rows[8 + j].cells[0].text
+ if buzhou['num'] == '':
+ buzhou['num'] = j + 1
+ buzhou['shuru'] = table.rows[
+ 8 + j].cells[2].text.replace('\n', '\a')
+ cel = table.rows[8 + j].cells[2]
+ if len(
+ cel._element.findall(
+ './/{http://schemas.openxmlformats.org/wordprocessingml/2006/main}drawing'
+ )) > 0:
+ img_ele = cel._element.xpath('.//pic:pic')[0]
+ embed = img_ele.xpath('.//a:blip/@r:embed')[0]
+ related_part = doc.part.related_parts[embed]
+ image = related_part.image
+ # blob属性就是二进制图片属性
+ image_bytes = image.blob
+ buzhou['image'] = InlineImage(
+ tpl, io.BytesIO(image_bytes))
+ buzhou['is_image'] = '1'
+ buzhou['yuqi'] = table.rows[
+ 8 + j].cells[4].text.replace('\n', '\a')
+ data['step'].append(buzhou)
+ # 8、最后加入data_list
+ data_list.append(data)
+ table_index += 1
+ except: # noqa: E722
+ self.sin_out.emit(f'第{table_index}个表格处理错误!')
+ table_index += 1
+ pass
+ # 开始渲染模板文件
+ try:
+ self.sin_out.emit('注意:如果生成文档没有标题,请检查您文档章节号格式是否正确!!!')
+ self.sin_out.emit('all_doned:')
+ context = {
+ "tables": data_list,
+ "renyuan": self.parent.lineEdit_17.text(),
+ }
+ tpl.render(context)
+ tpl.save("CPU新版反向生成说明.docx")
+ self.sin_out.emit('stopsuccess')
+ except: # noqa: E722
+ self.sin_out.emit('stoperror')
+ return
diff --git a/need/others/readme.txt b/need/others/readme.txt
new file mode 100644
index 0000000..d55b822
--- /dev/null
+++ b/need/others/readme.txt
@@ -0,0 +1,14 @@
+注意事项:
+1.本工具只能处理docx格式word文档,如果是doc的,需打开后另存为docx,不能直接改名称;
+2.目前不支持文档路径中带特殊字符,如空格等;
+3.document_templates为文档模板文档,其中非代码部分可以调整格式,调整后按新模板生成;
+
+功能说明:
+1、大纲转说明,使用的是成都鉴定测评模板,注意测试项格式的“;”以及“\r”(换行)
+2、追踪关系填写,可以根据大纲、说明和记录进行填写,说明和记录生成无需求规格说明的章节号和内容(需要根据大纲生成联合人工处理)
+3、根据大纲生成说明、根据说明生成测试记录,如果有3级标题,则需要人工添加二级标题
+4、文档小工具-UAS单元测试转换:是对UAS工具生成文档转换成本单位测评中心的用例
+5、自动填充以及选择文档功能和TDP工具一样,无变化;
+6、FPGA记录生产以及FPGA的记录转说明功能。
+
+
diff --git a/need/static/zxlogo.gif b/need/static/zxlogo.gif
new file mode 100644
index 0000000..6d13071
Binary files /dev/null and b/need/static/zxlogo.gif differ
diff --git a/need/threads.py b/need/threads.py
new file mode 100644
index 0000000..e665ea1
--- /dev/null
+++ b/need/threads.py
@@ -0,0 +1,154 @@
+import pythoncom
+from PyQt5 import QtCore
+from PyQt5.QtCore import pyqtSignal
+from win32com.client import DispatchEx
+from pathlib import *
+from PyQt5.QtWidgets import QMessageBox
+from docxtpl import DocxTemplate
+
+class create_bujian(QtCore.QThread):
+ sin_out = pyqtSignal(str)
+
+ def __init__(self,parent):
+ super().__init__()
+ self.parent = parent
+
+ def run(self):
+ self.sin_out.emit("进入部件测试获取调用函数线程......")
+ self.sin_out.emit("开始填写文档......")
+
+ #如果没有选择路径则退出
+ if not self.parent.open_file_name:
+ self.sin_out.emit('nofile')
+ self.parent.tabWidget.setEnabled(True)
+ return
+
+ #告诉windows单线程
+ pythoncom.CoInitialize()
+ #在用户选择的目录中查找UAS单位测试报告文档
+ self.sin_out.emit('打开单元测试原文件...')
+
+ #使用win32com打开-记得关闭
+ #打开word应用
+ self.w = DispatchEx('Word.Application')
+ #self.w.visible=True
+ self.w.DisplayAlerts = 0
+ try:
+ bujianfile = self.w.Documents.Open(self.parent.open_file_name[0])
+ except:
+ self.sin_out.emit('open failed:选择的文档')
+ self.w.Quit()
+ pythoncom.CoUninitialize()
+ self.parent.tabWidget.setEnabled(True)
+ return
+
+ curpath = Path.cwd() / 'need'
+ danyuan_file_tmp = curpath / 'document_templates' / '部件桩函数工具1.docx'
+ print(danyuan_file_tmp)
+
+ if danyuan_file_tmp.is_file():
+ self.sin_out.emit('已检测到有部件模板文件...')
+ else:
+ self.sin_out.emit('open failed:选择的文档')
+ return
+
+ #创建个列表放数据-important
+ data_list = []
+
+ #try统计表格数量
+ try:
+ csx_tb_count = bujianfile.Tables.Count
+ self.sin_out.emit('total:'+ str(csx_tb_count))
+ self.sin_out.emit("正在调用word文档操作接口,可能会有点慢...")
+ except:
+ self.sin_out.emit('不存在表格!')
+ QMessageBox.warning(self.parent,'出错了','测试说明文档格式错误或者没有正确表格')
+ try:
+ bujianfile.Close()
+ except:
+ pass
+ self.w.Quit()
+ pythoncom.CoUninitialize()
+ self.parent.tabWidget.setEnabled(True)
+ return
+
+ #开始处理表格-important
+ #我先统计有多少个生成的表格-即用例有多少个呗
+ yongli_count = 0
+ for i in range(csx_tb_count):
+ if bujianfile.Tables[i].Rows.Count > 2:
+ #注意win32com的Cell从1开始不是从0开始
+ if bujianfile.Tables[i].Cell(1, 1).Range.Text.find('用例名称') != -1:
+ yongli_count += 1
+
+
+ yongli_num = 0
+ hanshuming_duibi = ''
+ alowFunctionInject = True
+ for i in range(csx_tb_count):
+ self.sin_out.emit(str(i))
+ #准备填入的data
+ data = {'functionName':'','subitem':[]}
+
+ #找到函数名,这里容易出问题~~~~~~~~~~~~~~~~
+ if bujianfile.Tables[i].Rows.Count > 2:
+ if bujianfile.Tables[i].Cell(1, 1).Range.Text.find('功能描述') != -1:
+ bujianfile.Tables[i].Cell(1, 1).Range.Select()
+ self.w.Selection.MoveUp()
+ self.w.Selection.MoveUp()
+ self.w.Selection.MoveUp()
+ s = self.w.Selection.Paragraphs(1).Range.Text[:-1]
+ s1 = s.split(". ")[-1]
+ #放入函数名比对
+ data['functionName'] = s1
+ data_list.append(data)
+ yongli_num += 1 #用例创建加一
+
+ #找章节号~~~~~~~~~~~~~~~~~~~~~~~~
+ if bujianfile.Tables[i].Rows.Count > 2:
+ if bujianfile.Tables[i].Cell(1, 1).Range.Text.find('用例名称') != -1:
+ #函数名获取
+ if s1 != hanshuming_duibi:
+ hanshuming_duibi = s1
+ alowFunctionInject = True
+ else:
+ alowFunctionInject = False
+
+ elif bujianfile.Tables[i].Cell(1, 2).Range.Text.find('定义') != -1:
+ #定义个桩函数dict
+ if alowFunctionInject == True:
+ temp = bujianfile.Tables[i].Cell(1, 3).Range.Text[:-2]
+ temp1 = temp.split("(")[0]
+ temp2 = temp1.split(" ")[-1]
+ data_list[yongli_num - 1]['subitem'].append(temp2)
+
+
+ print('最后data_list',data_list)
+ #最后关闭文档
+ try:
+ self.w.Quit()
+ pythoncom.CoUninitialize()
+ self.parent.tabWidget.setEnabled(True)
+ except:
+ QMessageBox.warning(self.parent,"关闭文档失败","关闭文档失败!")
+ return
+
+ try:
+ tpl_path = Path.cwd() / "need" / "document_templates" / "部件桩函数工具1.docx"
+ self.sin_out.emit('导入模板文件路径为:' + str(tpl_path))
+ tpl = DocxTemplate(tpl_path) #模板导入成功
+ except:
+ QMessageBox.warning(self.parent,"出错了","导入模板出错请检查模板文件是否存在或名字不正确")
+ return
+
+ #开始渲染模板文件
+ try:
+ context = {
+ "tables":data_list,
+ }
+ tpl.render(context)
+ tpl.save("部件提起调用函数表格.docx")
+ self.sin_out.emit('stopsuccess')
+ except:
+ self.sin_out.emit('stoperror')
+ return
\ No newline at end of file
diff --git a/need/utils.py b/need/utils.py
new file mode 100644
index 0000000..6911959
--- /dev/null
+++ b/need/utils.py
@@ -0,0 +1,18 @@
+import datetime
+
+def get_current_time():
+ data = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')
+ data = "[" + data + " R] "
+ return data
+
+def get_current_name():
+ data = datetime.datetime.now().strftime('%Y-%m-%d-%H-%M-%S-%f')
+ return data
+
+def get_current_date():
+ data = datetime.datetime.now().strftime('%Y-%m-%d %H-%M-%S')
+ return data
+
+def get_current_hour():
+ data = datetime.datetime.now().strftime('%H.%M.%S')
+ return data
diff --git a/need/zhuan.py b/need/zhuan.py
new file mode 100644
index 0000000..ab9714b
--- /dev/null
+++ b/need/zhuan.py
@@ -0,0 +1,65 @@
+# -*- coding: utf-8 -*-
+
+# Form implementation generated from reading ui file 'zhuan.ui'
+#
+# Created by: PyQt5 UI code generator 5.15.4
+#
+# WARNING: Any manual changes made to this file will be lost when pyuic5 is
+# run again. Do not edit this file unless you know what you are doing.
+
+
+from PyQt5 import QtCore, QtGui, QtWidgets
+
+
+class Ui_Dialog(object):
+ def setupUi(self, Dialog):
+ Dialog.setObjectName("Dialog")
+ Dialog.resize(461, 70)
+ self.widget = QtWidgets.QWidget(Dialog)
+ self.widget.setGeometry(QtCore.QRect(10, 35, 446, 23))
+ self.widget.setObjectName("widget")
+ self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.widget)
+ self.horizontalLayout_3.setContentsMargins(0, 0, 0, 0)
+ self.horizontalLayout_3.setObjectName("horizontalLayout_3")
+ self.horizontalLayout = QtWidgets.QHBoxLayout()
+ self.horizontalLayout.setObjectName("horizontalLayout")
+ self.label = QtWidgets.QLabel(self.widget)
+ self.label.setObjectName("label")
+ self.horizontalLayout.addWidget(self.label)
+ self.lineEdit = QtWidgets.QLineEdit(self.widget)
+ self.lineEdit.setObjectName("lineEdit")
+ self.horizontalLayout.addWidget(self.lineEdit)
+ self.horizontalLayout_3.addLayout(self.horizontalLayout)
+ self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_2.setObjectName("horizontalLayout_2")
+ self.label_2 = QtWidgets.QLabel(self.widget)
+ self.label_2.setObjectName("label_2")
+ self.horizontalLayout_2.addWidget(self.label_2)
+ self.lineEdit_2 = QtWidgets.QLineEdit(self.widget)
+ self.lineEdit_2.setObjectName("lineEdit_2")
+ self.horizontalLayout_2.addWidget(self.lineEdit_2)
+ self.horizontalLayout_3.addLayout(self.horizontalLayout_2)
+ self.widget1 = QtWidgets.QWidget(Dialog)
+ self.widget1.setGeometry(QtCore.QRect(10, 10, 216, 18))
+ self.widget1.setObjectName("widget1")
+ self.horizontalLayout_4 = QtWidgets.QHBoxLayout(self.widget1)
+ self.horizontalLayout_4.setContentsMargins(0, 0, 0, 0)
+ self.horizontalLayout_4.setObjectName("horizontalLayout_4")
+ self.radioButton = QtWidgets.QRadioButton(self.widget1)
+ self.radioButton.setChecked(True)
+ self.radioButton.setObjectName("radioButton")
+ self.horizontalLayout_4.addWidget(self.radioButton)
+ self.radioButton_2 = QtWidgets.QRadioButton(self.widget1)
+ self.radioButton_2.setObjectName("radioButton_2")
+ self.horizontalLayout_4.addWidget(self.radioButton_2)
+
+ self.retranslateUi(Dialog)
+ QtCore.QMetaObject.connectSlotsByName(Dialog)
+
+ def retranslateUi(self, Dialog):
+ _translate = QtCore.QCoreApplication.translate
+ Dialog.setWindowTitle(_translate("Dialog", "IEEE754转换工具"))
+ self.label.setText(_translate("Dialog", "16进制表示"))
+ self.label_2.setText(_translate("Dialog", "float值"))
+ self.radioButton.setText(_translate("Dialog", "单精度(32位)"))
+ self.radioButton_2.setText(_translate("Dialog", "双精度(64位)"))
diff --git a/need/zhuan_tool.py b/need/zhuan_tool.py
new file mode 100644
index 0000000..3a59f7c
--- /dev/null
+++ b/need/zhuan_tool.py
@@ -0,0 +1,21 @@
+#python处理floatIEE754格式转换
+import struct
+
+def IEEE754_16_to_float(x,byte_type):
+ if byte_type == 32:
+ return struct.unpack('>f',struct.pack('>I',int(x,16)))[0]
+ if byte_type == 64:
+ return struct.unpack('>d',struct.pack('>Q',int(x,16)))[0]
+
+def IEEE754_float_to_16(x,byte_type):
+ if byte_type == 32:
+ return hex(struct.unpack('>I',struct.pack('>f',x))[0])[2:].upper()
+ if byte_type == 64:
+ return hex(struct.unpack('>Q',struct.pack('>d',x))[0])[2:].upper()
+
+if __name__ == '__main__':
+ ##测试程序##
+ x = 'BE051EB8'
+ y = -0.13
+ print(IEEE754_16_to_float(x,32))
+ print(IEEE754_float_to_16(y,32))
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..c3f2643
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,16 @@
+[project]
+name = "cttools"
+version = "1.9.1"
+description = "内网使用的东西"
+readme = "README.md"
+requires-python = ">=3.8.10"
+dependencies = [
+ "docxcompose>=1.4.0",
+ "docxtpl>=0.20.2",
+ "pyqt5==5.15.9",
+ "pyqt5-qt5==5.15.2",
+ "pyqt5-tools>=5.15.9.3.3",
+ "pywin32>=311",
+ "qtmodern>=0.2.0",
+ "six>=1.17.0",
+]
diff --git a/testDocumentGeneratorV0.01/document_template/测试大纲生成测试说明模版.docx b/testDocumentGeneratorV0.01/document_template/测试大纲生成测试说明模版.docx
new file mode 100644
index 0000000..f08e0f3
Binary files /dev/null and b/testDocumentGeneratorV0.01/document_template/测试大纲生成测试说明模版.docx differ
diff --git a/testDocumentGeneratorV0.01/main.py b/testDocumentGeneratorV0.01/main.py
new file mode 100644
index 0000000..887548d
--- /dev/null
+++ b/testDocumentGeneratorV0.01/main.py
@@ -0,0 +1,199 @@
+from pathlib import Path
+import re
+from docxtpl import DocxTemplate
+from docx import Document
+from docx.table import Table
+from docx.text.paragraph import Paragraph
+from nicegui import ui, app
+
+# 定义全局变量
+input_document_path = ''
+# 匹配测试方法里面的标题
+re_title = re.compile(r'(\w{2}_\w+_[a-zA-Z0-9]+_\w+\d+)')
+ui.html("
测试大纲生成测试说明demo
")
+
+# 进度全变量
+class DataModel:
+ content = 0.0
+
+db = DataModel()
+
+def generat_document():
+ global input_document_path
+ global db
+ # 定义当前四级标题的编号和名称
+ current_level4_title = ''
+ # 定义储存标题的东西
+ level1_title = []
+ level2_title = []
+ level3_title = []
+ level4_title = []
+ level5_title = []
+ level6_title = []
+ level7_title = []
+ if input_document_path:
+ tpl_path = Path.cwd() / 'document_template' / '测试大纲生成测试说明模版.docx'
+ tpl = DocxTemplate(tpl_path) # 模板导入成功
+ ui.notify('导入模版成功...')
+ try:
+ doc = Document(input_document_path)
+ except:
+ ui.notify('选择的文件格式不正确!!,请重新选择')
+ return
+ shuoming_path_tmp = Path.cwd() / 'generate_document' / '生成的测试说明.docx'
+ # 获取表格数量
+ tables = doc.tables
+ # 创建一个字典来储存单个用例
+ data_list = []
+ # 定义开关-当识别到测试定义的标题时候
+ open_title = False
+ ui.notify('开始生成测试说明...')
+ for ele in doc._element.body.iter():
+ if ele.tag.endswith('}p'):
+ elePstyle = ele.findall('.//{http://schemas.openxmlformats.org/wordprocessingml/2006/main}pStyle')
+ if len(elePstyle) >= 1:
+ parag = Paragraph(ele, doc)
+ if parag.style.name.startswith("Heading") or parag.style.name.startswith("标题"):
+ data = {}
+ rank = parag.style.name.split(" ")[-1] # 标题等级str类型
+ text = parag.text # 标题文字
+ # 先将标题储存在一个地方
+ if rank == '1' or rank == '10':
+ level1_title.append(1)
+ level2_title.clear()
+ level3_title.clear()
+ level4_title.clear()
+ level5_title.clear()
+ level6_title.clear()
+ level7_title.clear()
+ elif rank == '2' or rank == '20':
+ level2_title.append(1)
+ level3_title.clear()
+ level4_title.clear()
+ level5_title.clear()
+ level6_title.clear()
+ level7_title.clear()
+ elif rank == '3' or rank == '30':
+ level3_title.append(1)
+ level4_title.clear()
+ level5_title.clear()
+ level6_title.clear()
+ level7_title.clear()
+ elif rank == '4' or rank == '40':
+ level4_title.append(1)
+ level5_title.clear()
+ level6_title.clear()
+ level7_title.clear()
+ current_level4_title = f"({len(level1_title)}.{len(level2_title)}.{len(level3_title)}.{len(level4_title)}){text}"
+ elif rank == '5' or rank == '50':
+ level5_title.append(1)
+ level6_title.clear()
+ level7_title.clear()
+ elif rank == '6' or rank == '60':
+ level6_title.append(1)
+ level7_title.clear()
+ elif rank == '7' or rank == '70':
+ level7_title.append(1)
+ # 如果识别到标题为"测试定义"则打开获取标题开关
+ if text == '功能测试':
+ open_title = True
+ if text == '测试进度':
+ open_title = False
+ if open_title:
+ data['type'] = rank
+ data['text'] = text
+ data_list.append(data)
+ elif ele.tag.endswith('}tbl'):
+ table = Table(ele, doc)
+ # 1识别到大纲的一个表格
+ temp = table.cell(0, 0).text
+ if temp == '测试项名称' and table.cell(0, 1).text != '文档审查' \
+ and table.cell(0, 1).text != '静态分析' and \
+ table.cell(0, 1).text != '代码审查':
+ # 先提取表格其他信息
+ csx_name = table.cell(0, 1).text
+ csx_ident = table.cell(0, 3).text
+ res_text = ''
+ prefix = ''
+ count = 1
+ for para in table.cell(4, 2).paragraphs:
+ # 2.1 识别到测试方法的标题
+ re_res = re_title.findall(para.text)
+ if re_res:
+ data = {}
+ count = 1
+ data['type'] = '5'
+ data['text'] = re.sub(r'\d{1,2}[.]', '', para.text).strip()
+ prefix = re_res[0].replace('(', '').replace(")", "")
+ res_text = data['text'].split('(')[0]
+ data_list.append(data)
+ # print('生成五级标题为:', data['text'])
+ # 2.2 如果不是标题则需要生成表格了
+ else:
+ tb_data = {'type': 'table'}
+ tb_data['name'] = f"{res_text}_{count}"
+ tb_data['ident'] = f"{prefix}_{count}"
+ tb_data['destination'] = f"验证{csx_name.replace('测试','')}是否正确"
+ tb_data['xqfx'] = current_level4_title
+ tb_data['xqident'] = prefix
+ tb_data['step'] = []
+ # 步骤处理共4个字段
+ # 要求每句话必须有;中文分号
+ split_temp = para.text.split(';')
+ if len(split_temp) == 1:
+ split_temp.append("")
+ index = 1
+ for sss in split_temp:
+ if sss:
+ # 根据“查看分割”
+ ck_split = sss.split('查看')
+ if len(ck_split) == 1:
+ ck_split.insert(0, "")
+ step = {}
+ step['index'] = index
+ step['shuru'] = '巡天主控软件'
+ step['guocheng'] = ck_split[0]
+ # 去掉guocheng里面逗号
+ if step['guocheng']:
+ if step['guocheng'][-1] == ',':
+ step['guocheng'] = step['guocheng'][:-1]
+ else:
+ ui.notify('请检查,未有查看字样...', type = 'negative')
+ step['yuqi'] = ck_split[1]
+ tb_data['step'].append(step)
+ index += 1
+
+ count += 1
+ data_list.append(tb_data)
+ db.content = 1
+ try:
+ context = {
+ "tables": data_list,
+ }
+ tpl.render(context)
+ tpl.save(shuoming_path_tmp)
+ except:
+ ui.notify('在生成文档时报错', type = 'warning')
+ else:
+ ui.notify('请先选择需要转换的文件!')
+
+ ui.notify('生成完成!', type = 'positive')
+
+async def choose_file():
+ global input_document_path
+ files = await app.native.main_window.create_file_dialog(file_types = ("excel文件(*.docx)", ))
+ if files:
+ input_document_path = files[0]
+ # 设置界面label显示文件路径
+ label.text = input_document_path
+
+# 按钮
+with ui.row().classes('flex justify-center items-center'):
+ ui.button("上传文件", on_click = choose_file)
+ label = ui.label("")
+with ui.row().classes('flex justify-center items-center'):
+ ui.button('点击生成说明', on_click = generat_document)
+ # 定义进度条
+ knob = ui.knob(0.0, show_value = True).bind_value(db, 'content')
+
+ui.run(native = True)
diff --git a/testDocumentGeneratorV0.01/test.py b/testDocumentGeneratorV0.01/test.py
new file mode 100644
index 0000000..f92fc74
--- /dev/null
+++ b/testDocumentGeneratorV0.01/test.py
@@ -0,0 +1,19 @@
+from nicegui import ui
+
+class DataModel:
+ content1 = ''
+ content2 = ''
+ count = 0
+
+ @property
+ def result(self):
+ print('运行了该函数', self.count)
+ return self.content1 + self.content2
+
+dm = DataModel()
+
+label = ui.label('').bind_text_from(dm, 'result')
+input = ui.input('演示').bind_value_to(dm, 'content1')
+input = ui.input('演示').bind_value_to(dm, 'content2')
+
+ui.run()
diff --git a/testDocumentGeneratorV0.01/tkmain.py b/testDocumentGeneratorV0.01/tkmain.py
new file mode 100644
index 0000000..69d8c9b
--- /dev/null
+++ b/testDocumentGeneratorV0.01/tkmain.py
@@ -0,0 +1,192 @@
+import tkinter
+from tkinter import filedialog
+from pathlib import Path
+import re
+from docxtpl import DocxTemplate
+from docx import Document
+from docx.table import Table
+from docx.text.paragraph import Paragraph
+
+# 匹配测试方法里面的标题
+re_title = re.compile(r'(\w{2}_\w+_[a-zA-Z0-9]+_\w+\d+)')
+
+window = tkinter.Tk()
+window.title("大纲转换软件V0.01-tk-丑版")
+
+# 窗口大小
+window.geometry('600x300')
+
+# label
+label1 = tkinter.Label(window, text = '')
+label1.grid(row = 0, column = 2)
+
+def btn1click():
+ path = tkinter.filedialog.askopenfilename()
+ label1.config(text = path)
+
+# 选择文件按钮
+btn1 = tkinter.Button(window, text = "选择文件", command = btn1click)
+btn1.grid(column = 1, row = 0)
+
+# 生成文档函数
+def generate_document():
+ input_document_path = label1['text']
+ # 定义当前四级标题的编号和名称
+ current_level4_title = ''
+ # 定义储存标题的东西
+ level1_title = []
+ level2_title = []
+ level3_title = []
+ level4_title = []
+ level5_title = []
+ level6_title = []
+ level7_title = []
+ if input_document_path:
+ tpl_path = Path.cwd() / 'document_template' / '测试大纲生成测试说明模版.docx'
+ tpl = DocxTemplate(tpl_path) # 模板导入成功
+ try:
+ doc = Document(input_document_path)
+ except:
+ return
+ shuoming_path_tmp = Path.cwd() / 'generate_document' / '生成的测试说明.docx'
+ # 获取表格数量
+ tables = doc.tables
+ # 创建一个字典来储存单个用例
+ data_list = []
+ # 定义开关-当识别到测试定义的标题时候
+ open_title = False
+ for ele in doc._element.body.iter():
+ if ele.tag.endswith('}p'):
+ elePstyle = ele.findall('.//{http://schemas.openxmlformats.org/wordprocessingml/2006/main}pStyle')
+ if len(elePstyle) >= 1:
+ parag = Paragraph(ele, doc)
+ if parag.style.name.startswith("Heading") or parag.style.name.startswith("标题"):
+ data = {}
+ rank = parag.style.name.split(" ")[-1] # 标题等级str类型
+ text = parag.text # 标题文字
+ # 先将标题储存在一个地方
+ if rank == '1' or rank == '10':
+ level1_title.append(1)
+ level2_title.clear()
+ level3_title.clear()
+ level4_title.clear()
+ level5_title.clear()
+ level6_title.clear()
+ level7_title.clear()
+ elif rank == '2' or rank == '20':
+ level2_title.append(1)
+ level3_title.clear()
+ level4_title.clear()
+ level5_title.clear()
+ level6_title.clear()
+ level7_title.clear()
+ elif rank == '3' or rank == '30':
+ level3_title.append(1)
+ level4_title.clear()
+ level5_title.clear()
+ level6_title.clear()
+ level7_title.clear()
+ elif rank == '4' or rank == '40':
+ level4_title.append(1)
+ level5_title.clear()
+ level6_title.clear()
+ level7_title.clear()
+ current_level4_title = f"({len(level1_title)}.{len(level2_title)}.{len(level3_title)}.{len(level4_title)}){text}"
+ elif rank == '5' or rank == '50':
+ level5_title.append(1)
+ level6_title.clear()
+ level7_title.clear()
+ elif rank == '6' or rank == '60':
+ level6_title.append(1)
+ level7_title.clear()
+ elif rank == '7' or rank == '70':
+ level7_title.append(1)
+ # 如果识别到标题为"测试定义"则打开获取标题开关
+ if text == '功能测试':
+ open_title = True
+ if text == '测试进度':
+ open_title = False
+ if open_title:
+ data['type'] = rank
+ data['text'] = text
+ data_list.append(data)
+ elif ele.tag.endswith('}tbl'):
+ table = Table(ele, doc)
+ # 1识别到大纲的一个表格
+ temp = table.cell(0, 0).text
+ if temp == '测试项名称' and table.cell(0, 1).text != '文档审查' \
+ and table.cell(0, 1).text != '静态分析' and \
+ table.cell(0, 1).text != '代码审查':
+ # 先提取表格其他信息
+ csx_name = table.cell(0, 1).text
+ csx_ident = table.cell(0, 3).text
+ res_text = ''
+ prefix = ''
+ count = 1
+ for para in table.cell(4, 2).paragraphs:
+ # 2.1 识别到测试方法的标题
+ re_res = re_title.findall(para.text)
+ if re_res:
+ data = {}
+ count = 1
+ data['type'] = '5'
+ data['text'] = re.sub(r'\d{1,2}[.]', '', para.text).strip()
+ prefix = re_res[0].replace('(', '').replace(")", "")
+ res_text = data['text'].split('(')[0]
+ data_list.append(data)
+ # print('生成五级标题为:', data['text'])
+ # 2.2 如果不是标题则需要生成表格了
+ else:
+ tb_data = {'type': 'table'}
+ tb_data['name'] = f"{res_text}_{count}"
+ tb_data['ident'] = f"{prefix}_{count}"
+ tb_data['destination'] = f"验证{csx_name.replace('测试','')}是否正确"
+ tb_data['xqfx'] = current_level4_title
+ tb_data['xqident'] = prefix
+ tb_data['step'] = []
+ # 步骤处理共4个字段
+ # 要求每句话必须有;中文分号
+ split_temp = para.text.split(';')
+ if len(split_temp) == 1:
+ split_temp.append("")
+ index = 1
+ for sss in split_temp:
+ if sss:
+ # 根据“查看分割”
+ ck_split = sss.split('查看')
+ if len(ck_split) == 1:
+ ck_split.insert(0, "")
+ step = {}
+ step['index'] = index
+ step['shuru'] = '巡天主控软件'
+ step['guocheng'] = ck_split[0]
+ # 去掉guocheng里面逗号
+ if step['guocheng']:
+ if step['guocheng'][-1] == ',':
+ step['guocheng'] = step['guocheng'][:-1]
+ else:
+ print('请检查,未有查看字样...')
+ step['yuqi'] = ck_split[1]
+ tb_data['step'].append(step)
+ index += 1
+
+ count += 1
+ data_list.append(tb_data)
+ try:
+ context = {
+ "tables": data_list,
+ }
+ tpl.render(context)
+ tpl.save(shuoming_path_tmp)
+ except:
+ print('在生成文档时报错')
+ else:
+ print('请先选择需要转换的文件')
+ print('生成完成!')
+
+# 生成文档按钮
+btn2 = tkinter.Button(window, text = "生成文档", command = generate_document)
+btn2.grid(column = 1, row = 1)
+
+# 进入消息循环
+window.mainloop()
diff --git a/uv.lock b/uv.lock
new file mode 100644
index 0000000..e1a7610
--- /dev/null
+++ b/uv.lock
@@ -0,0 +1,820 @@
+version = 1
+revision = 3
+requires-python = ">=3.8.10"
+resolution-markers = [
+ "python_full_version >= '3.10'",
+ "python_full_version == '3.9.*'",
+ "python_full_version < '3.9'",
+]
+
+[[package]]
+name = "babel"
+version = "2.17.0"
+source = { registry = "https://mirrors.aliyun.com/pypi/simple" }
+dependencies = [
+ { name = "pytz", marker = "python_full_version < '3.9'" },
+]
+sdist = { url = "https://mirrors.aliyun.com/pypi/packages/7d/6b/d52e42361e1aa00709585ecc30b3f9684b3ab62530771402248b1b1d6240/babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d" }
+wheels = [
+ { url = "https://mirrors.aliyun.com/pypi/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2" },
+]
+
+[[package]]
+name = "click"
+version = "8.1.8"
+source = { registry = "https://mirrors.aliyun.com/pypi/simple" }
+resolution-markers = [
+ "python_full_version == '3.9.*'",
+ "python_full_version < '3.9'",
+]
+dependencies = [
+ { name = "colorama", marker = "python_full_version < '3.10' and sys_platform == 'win32'" },
+]
+sdist = { url = "https://mirrors.aliyun.com/pypi/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a" }
+wheels = [
+ { url = "https://mirrors.aliyun.com/pypi/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2" },
+]
+
+[[package]]
+name = "click"
+version = "8.3.1"
+source = { registry = "https://mirrors.aliyun.com/pypi/simple" }
+resolution-markers = [
+ "python_full_version >= '3.10'",
+]
+dependencies = [
+ { name = "colorama", marker = "python_full_version >= '3.10' and sys_platform == 'win32'" },
+]
+sdist = { url = "https://mirrors.aliyun.com/pypi/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a" }
+wheels = [
+ { url = "https://mirrors.aliyun.com/pypi/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6" },
+]
+
+[[package]]
+name = "colorama"
+version = "0.4.6"
+source = { registry = "https://mirrors.aliyun.com/pypi/simple" }
+sdist = { url = "https://mirrors.aliyun.com/pypi/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44" }
+wheels = [
+ { url = "https://mirrors.aliyun.com/pypi/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6" },
+]
+
+[[package]]
+name = "cttools"
+version = "1.9.1"
+source = { virtual = "." }
+dependencies = [
+ { name = "docxcompose" },
+ { name = "docxtpl" },
+ { name = "pyqt5" },
+ { name = "pyqt5-qt5" },
+ { name = "pyqt5-tools" },
+ { name = "pywin32" },
+ { name = "qtmodern" },
+ { name = "six" },
+]
+
+[package.metadata]
+requires-dist = [
+ { name = "docxcompose", specifier = ">=1.4.0" },
+ { name = "docxtpl", specifier = ">=0.20.2" },
+ { name = "pyqt5", specifier = "==5.15.9" },
+ { name = "pyqt5-qt5", specifier = "==5.15.2" },
+ { name = "pyqt5-tools", specifier = ">=5.15.9.3.3" },
+ { name = "pywin32", specifier = ">=311" },
+ { name = "qtmodern", specifier = ">=0.2.0" },
+ { name = "six", specifier = ">=1.17.0" },
+]
+
+[[package]]
+name = "docxcompose"
+version = "1.4.0"
+source = { registry = "https://mirrors.aliyun.com/pypi/simple" }
+dependencies = [
+ { name = "babel" },
+ { name = "lxml" },
+ { name = "python-docx", version = "1.1.2", source = { registry = "https://mirrors.aliyun.com/pypi/simple" }, marker = "python_full_version < '3.9'" },
+ { name = "python-docx", version = "1.2.0", source = { registry = "https://mirrors.aliyun.com/pypi/simple" }, marker = "python_full_version >= '3.9'" },
+ { name = "setuptools", version = "75.3.2", source = { registry = "https://mirrors.aliyun.com/pypi/simple" }, marker = "python_full_version < '3.9'" },
+ { name = "setuptools", version = "80.9.0", source = { registry = "https://mirrors.aliyun.com/pypi/simple" }, marker = "python_full_version >= '3.9'" },
+ { name = "six" },
+]
+sdist = { url = "https://mirrors.aliyun.com/pypi/packages/5d/25/07597a0fda04adf2f2fc375f48f704612a91c0c1da64f4c18e78a4a26630/docxcompose-1.4.0.tar.gz", hash = "sha256:bcf2799a0b63c29eb77a3d799a2f28443ae0f69f8691ff3d753f706be515c3e9" }
+
+[[package]]
+name = "docxtpl"
+version = "0.20.2"
+source = { registry = "https://mirrors.aliyun.com/pypi/simple" }
+dependencies = [
+ { name = "jinja2" },
+ { name = "lxml" },
+ { name = "python-docx", version = "1.1.2", source = { registry = "https://mirrors.aliyun.com/pypi/simple" }, marker = "python_full_version < '3.9'" },
+ { name = "python-docx", version = "1.2.0", source = { registry = "https://mirrors.aliyun.com/pypi/simple" }, marker = "python_full_version >= '3.9'" },
+]
+sdist = { url = "https://mirrors.aliyun.com/pypi/packages/b2/b4/4435f3fcb1357ec441079c4af1dda3ea926fad6dcead4aed2d93b369944e/docxtpl-0.20.2.tar.gz", hash = "sha256:eddf3350d70b4d123208e801d585bcb313d21044a377a14f75a66d0965841de1" }
+wheels = [
+ { url = "https://mirrors.aliyun.com/pypi/packages/a4/ad/e07939d8e020e513d3860400413ba1e0e06102c469639b440d921337efef/docxtpl-0.20.2-py3-none-any.whl", hash = "sha256:626d5c570a46a62b2ca73b4d08f1c240fa031a5bc45371e1466a4fe184923d10" },
+]
+
+[[package]]
+name = "jinja2"
+version = "3.1.6"
+source = { registry = "https://mirrors.aliyun.com/pypi/simple" }
+dependencies = [
+ { name = "markupsafe", version = "2.1.5", source = { registry = "https://mirrors.aliyun.com/pypi/simple" }, marker = "python_full_version < '3.9'" },
+ { name = "markupsafe", version = "3.0.3", source = { registry = "https://mirrors.aliyun.com/pypi/simple" }, marker = "python_full_version >= '3.9'" },
+]
+sdist = { url = "https://mirrors.aliyun.com/pypi/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d" }
+wheels = [
+ { url = "https://mirrors.aliyun.com/pypi/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67" },
+]
+
+[[package]]
+name = "lxml"
+version = "6.0.2"
+source = { registry = "https://mirrors.aliyun.com/pypi/simple" }
+sdist = { url = "https://mirrors.aliyun.com/pypi/packages/aa/88/262177de60548e5a2bfc46ad28232c9e9cbde697bd94132aeb80364675cb/lxml-6.0.2.tar.gz", hash = "sha256:cd79f3367bd74b317dda655dc8fcfa304d9eb6e4fb06b7168c5cf27f96e0cd62" }
+wheels = [
+ { url = "https://mirrors.aliyun.com/pypi/packages/db/8a/f8192a08237ef2fb1b19733f709db88a4c43bc8ab8357f01cb41a27e7f6a/lxml-6.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e77dd455b9a16bbd2a5036a63ddbd479c19572af81b624e79ef422f929eef388" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/12/64/27bcd07ae17ff5e5536e8d88f4c7d581b48963817a13de11f3ac3329bfa2/lxml-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5d444858b9f07cefff6455b983aea9a67f7462ba1f6cbe4a21e8bf6791bf2153" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/02/5a/a7d53b3291c324e0b6e48f3c797be63836cc52156ddf8f33cd72aac78866/lxml-6.0.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f952dacaa552f3bb8834908dddd500ba7d508e6ea6eb8c52eb2d28f48ca06a31" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/f5/55/d465e9b89df1761674d8672bb3e4ae2c47033b01ec243964b6e334c6743f/lxml-6.0.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:71695772df6acea9f3c0e59e44ba8ac50c4f125217e84aab21074a1a55e7e5c9" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/62/38/3073cd7e3e8dfc3ba3c3a139e33bee3a82de2bfb0925714351ad3d255c13/lxml-6.0.2-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:17f68764f35fd78d7c4cc4ef209a184c38b65440378013d24b8aecd327c3e0c8" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/4a/d3/1e001588c5e2205637b08985597827d3827dbaaece16348c8822bfe61c29/lxml-6.0.2-cp310-cp310-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:058027e261afed589eddcfe530fcc6f3402d7fd7e89bfd0532df82ebc1563dba" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/20/cf/cab09478699b003857ed6ebfe95e9fb9fa3d3c25f1353b905c9b73cfb624/lxml-6.0.2-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8ffaeec5dfea5881d4c9d8913a32d10cfe3923495386106e4a24d45300ef79c" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/a3/84/02a2d0c38ac9a8b9f9e5e1bbd3f24b3f426044ad618b552e9549ee91bd63/lxml-6.0.2-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:f2e3b1a6bb38de0bc713edd4d612969dd250ca8b724be8d460001a387507021c" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/56/87/e1ceadcc031ec4aa605fe95476892d0b0ba3b7f8c7dcdf88fdeff59a9c86/lxml-6.0.2-cp310-cp310-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d6690ec5ec1cce0385cb20896b16be35247ac8c2046e493d03232f1c2414d321" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/fe/13/5bb6cf42bb228353fd4ac5f162c6a84fd68a4d6f67c1031c8cf97e131fc6/lxml-6.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f2a50c3c1d11cad0ebebbac357a97b26aa79d2bcaf46f256551152aa85d3a4d1" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/e4/e2/ea0498552102e59834e297c5c6dff8d8ded3db72ed5e8aad77871476f073/lxml-6.0.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:3efe1b21c7801ffa29a1112fab3b0f643628c30472d507f39544fd48e9549e34" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/6a/9e/8de42b52a73abb8af86c66c969b3b4c2a96567b6ac74637c037d2e3baa60/lxml-6.0.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:59c45e125140b2c4b33920d21d83681940ca29f0b83f8629ea1a2196dc8cfe6a" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/28/a2/de776a573dfb15114509a37351937c367530865edb10a90189d0b4b9b70a/lxml-6.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:452b899faa64f1805943ec1c0c9ebeaece01a1af83e130b69cdefeda180bb42c" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/50/a0/3ae1b1f8964c271b5eec91db2043cf8c6c0bce101ebb2a633b51b044db6c/lxml-6.0.2-cp310-cp310-win32.whl", hash = "sha256:1e786a464c191ca43b133906c6903a7e4d56bef376b75d97ccbb8ec5cf1f0a4b" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/d1/70/bd42491f0634aad41bdfc1e46f5cff98825fb6185688dc82baa35d509f1a/lxml-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:dacf3c64ef3f7440e3167aa4b49aa9e0fb99e0aa4f9ff03795640bf94531bcb0" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/d2/d0/05c6a72299f54c2c561a6c6cbb2f512e047fca20ea97a05e57931f194ac4/lxml-6.0.2-cp310-cp310-win_arm64.whl", hash = "sha256:45f93e6f75123f88d7f0cfd90f2d05f441b808562bf0bc01070a00f53f5028b5" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/77/d5/becbe1e2569b474a23f0c672ead8a29ac50b2dc1d5b9de184831bda8d14c/lxml-6.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:13e35cbc684aadf05d8711a5d1b5857c92e5e580efa9a0d2be197199c8def607" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/28/66/1ced58f12e804644426b85d0bb8a4478ca77bc1761455da310505f1a3526/lxml-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3b1675e096e17c6fe9c0e8c81434f5736c0739ff9ac6123c87c2d452f48fc938" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/11/84/549098ffea39dfd167e3f174b4ce983d0eed61f9d8d25b7bf2a57c3247fc/lxml-6.0.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8ac6e5811ae2870953390452e3476694196f98d447573234592d30488147404d" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/ac/bd/f207f16abf9749d2037453d56b643a7471d8fde855a231a12d1e095c4f01/lxml-6.0.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5aa0fc67ae19d7a64c3fe725dc9a1bb11f80e01f78289d05c6f62545affec438" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/15/ae/bd813e87d8941d52ad5b65071b1affb48da01c4ed3c9c99e40abb266fbff/lxml-6.0.2-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:de496365750cc472b4e7902a485d3f152ecf57bd3ba03ddd5578ed8ceb4c5964" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/02/cd/9bfef16bd1d874fbe0cb51afb00329540f30a3283beb9f0780adbb7eec03/lxml-6.0.2-cp311-cp311-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:200069a593c5e40b8f6fc0d84d86d970ba43138c3e68619ffa234bc9bb806a4d" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/b8/89/ea8f91594bc5dbb879734d35a6f2b0ad50605d7fb419de2b63d4211765cc/lxml-6.0.2-cp311-cp311-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7d2de809c2ee3b888b59f995625385f74629707c9355e0ff856445cdcae682b7" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/b9/37/9c735274f5dbec726b2db99b98a43950395ba3d4a1043083dba2ad814170/lxml-6.0.2-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:b2c3da8d93cf5db60e8858c17684c47d01fee6405e554fb55018dd85fc23b178" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/20/28/7dfe1ba3475d8bfca3878365075abe002e05d40dfaaeb7ec01b4c587d533/lxml-6.0.2-cp311-cp311-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:442de7530296ef5e188373a1ea5789a46ce90c4847e597856570439621d9c553" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/e7/cf/5f14bc0de763498fc29510e3532bf2b4b3a1c1d5d0dff2e900c16ba021ef/lxml-6.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2593c77efde7bfea7f6389f1ab249b15ed4aa5bc5cb5131faa3b843c429fbedb" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/1c/b0/bb8275ab5472f32b28cfbbcc6db7c9d092482d3439ca279d8d6fa02f7025/lxml-6.0.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:3e3cb08855967a20f553ff32d147e14329b3ae70ced6edc2f282b94afbc74b2a" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/25/4c/7c222753bc72edca3b99dbadba1b064209bc8ed4ad448af990e60dcce462/lxml-6.0.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:2ed6c667fcbb8c19c6791bbf40b7268ef8ddf5a96940ba9404b9f9a304832f6c" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/6c/8c/478a0dc6b6ed661451379447cdbec77c05741a75736d97e5b2b729687828/lxml-6.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b8f18914faec94132e5b91e69d76a5c1d7b0c73e2489ea8929c4aaa10b76bbf7" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/2d/d9/5be3a6ab2784cdf9accb0703b65e1b64fcdd9311c9f007630c7db0cfcce1/lxml-6.0.2-cp311-cp311-win32.whl", hash = "sha256:6605c604e6daa9e0d7f0a2137bdc47a2e93b59c60a65466353e37f8272f47c46" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/e2/7d/ca6fb13349b473d5732fb0ee3eec8f6c80fc0688e76b7d79c1008481bf1f/lxml-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e5867f2651016a3afd8dd2c8238baa66f1e2802f44bc17e236f547ace6647078" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/ab/a2/51363b5ecd3eab46563645f3a2c3836a2fc67d01a1b87c5017040f39f567/lxml-6.0.2-cp311-cp311-win_arm64.whl", hash = "sha256:4197fb2534ee05fd3e7afaab5d8bfd6c2e186f65ea7f9cd6a82809c887bd1285" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/f3/c8/8ff2bc6b920c84355146cd1ab7d181bc543b89241cfb1ebee824a7c81457/lxml-6.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a59f5448ba2ceccd06995c95ea59a7674a10de0810f2ce90c9006f3cbc044456" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/37/6f/9aae1008083bb501ef63284220ce81638332f9ccbfa53765b2b7502203cf/lxml-6.0.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e8113639f3296706fbac34a30813929e29247718e88173ad849f57ca59754924" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/f1/ca/31fb37f99f37f1536c133476674c10b577e409c0a624384147653e38baf2/lxml-6.0.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a8bef9b9825fa8bc816a6e641bb67219489229ebc648be422af695f6e7a4fa7f" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/da/87/f6cb9442e4bada8aab5ae7e1046264f62fdbeaa6e3f6211b93f4c0dd97f1/lxml-6.0.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:65ea18d710fd14e0186c2f973dc60bb52039a275f82d3c44a0e42b43440ea534" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/c8/20/a7760713e65888db79bbae4f6146a6ae5c04e4a204a3c48896c408cd6ed2/lxml-6.0.2-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c371aa98126a0d4c739ca93ceffa0fd7a5d732e3ac66a46e74339acd4d334564" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/a2/b0/7e64e0460fcb36471899f75831509098f3fd7cd02a3833ac517433cb4f8f/lxml-6.0.2-cp312-cp312-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:700efd30c0fa1a3581d80a748157397559396090a51d306ea59a70020223d16f" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/b9/e1/e5df362e9ca4e2f48ed6411bd4b3a0ae737cc842e96877f5bf9428055ab4/lxml-6.0.2-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c33e66d44fe60e72397b487ee92e01da0d09ba2d66df8eae42d77b6d06e5eba0" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/c6/d1/232b3309a02d60f11e71857778bfcd4acbdb86c07db8260caf7d008b08f8/lxml-6.0.2-cp312-cp312-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:90a345bbeaf9d0587a3aaffb7006aa39ccb6ff0e96a57286c0cb2fd1520ea192" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/35/35/d955a070994725c4f7d80583a96cab9c107c57a125b20bb5f708fe941011/lxml-6.0.2-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:064fdadaf7a21af3ed1dcaa106b854077fbeada827c18f72aec9346847cd65d0" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/1e/be/667d17363b38a78c4bd63cfd4b4632029fd68d2c2dc81f25ce9eb5224dd5/lxml-6.0.2-cp312-cp312-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fbc74f42c3525ac4ffa4b89cbdd00057b6196bcefe8bce794abd42d33a018092" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/ea/47/62c70aa4a1c26569bc958c9ca86af2bb4e1f614e8c04fb2989833874f7ae/lxml-6.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6ddff43f702905a4e32bc24f3f2e2edfe0f8fde3277d481bffb709a4cced7a1f" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/bd/55/6ceddaca353ebd0f1908ef712c597f8570cc9c58130dbb89903198e441fd/lxml-6.0.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:6da5185951d72e6f5352166e3da7b0dc27aa70bd1090b0eb3f7f7212b53f1bb8" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/cf/e8/fd63e15da5e3fd4c2146f8bbb3c14e94ab850589beab88e547b2dbce22e1/lxml-6.0.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:57a86e1ebb4020a38d295c04fc79603c7899e0df71588043eb218722dabc087f" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/76/47/b3ec58dc5c374697f5ba37412cd2728f427d056315d124dd4b61da381877/lxml-6.0.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:2047d8234fe735ab77802ce5f2297e410ff40f5238aec569ad7c8e163d7b19a6" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/19/93/03ba725df4c3d72afd9596eef4a37a837ce8e4806010569bedfcd2cb68fd/lxml-6.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6f91fd2b2ea15a6800c8e24418c0775a1694eefc011392da73bc6cef2623b322" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/c6/80/c06de80bfce881d0ad738576f243911fccf992687ae09fd80b734712b39c/lxml-6.0.2-cp312-cp312-win32.whl", hash = "sha256:3ae2ce7d6fedfb3414a2b6c5e20b249c4c607f72cb8d2bb7cc9c6ec7c6f4e849" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/f7/d7/0cdfb6c3e30893463fb3d1e52bc5f5f99684a03c29a0b6b605cfae879cd5/lxml-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:72c87e5ee4e58a8354fb9c7c84cbf95a1c8236c127a5d1b7683f04bed8361e1f" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/ea/7b/93c73c67db235931527301ed3785f849c78991e2e34f3fd9a6663ffda4c5/lxml-6.0.2-cp312-cp312-win_arm64.whl", hash = "sha256:61cb10eeb95570153e0c0e554f58df92ecf5109f75eacad4a95baa709e26c3d6" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/53/fd/4e8f0540608977aea078bf6d79f128e0e2c2bba8af1acf775c30baa70460/lxml-6.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9b33d21594afab46f37ae58dfadd06636f154923c4e8a4d754b0127554eb2e77" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/5d/f4/2a94a3d3dfd6c6b433501b8d470a1960a20ecce93245cf2db1706adf6c19/lxml-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6c8963287d7a4c5c9a432ff487c52e9c5618667179c18a204bdedb27310f022f" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/25/2e/4efa677fa6b322013035d38016f6ae859d06cac67437ca7dc708a6af7028/lxml-6.0.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1941354d92699fb5ffe6ed7b32f9649e43c2feb4b97205f75866f7d21aa91452" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/ce/0f/526e78a6d38d109fdbaa5049c62e1d32fdd70c75fb61c4eadf3045d3d124/lxml-6.0.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bb2f6ca0ae2d983ded09357b84af659c954722bbf04dea98030064996d156048" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/81/76/99de58d81fa702cc0ea7edae4f4640416c2062813a00ff24bd70ac1d9c9b/lxml-6.0.2-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eb2a12d704f180a902d7fa778c6d71f36ceb7b0d317f34cdc76a5d05aa1dd1df" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/b5/35/9e57d25482bc9a9882cb0037fdb9cc18f4b79d85df94fa9d2a89562f1d25/lxml-6.0.2-cp313-cp313-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:6ec0e3f745021bfed19c456647f0298d60a24c9ff86d9d051f52b509663feeb1" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/a6/8e/cb99bd0b83ccc3e8f0f528e9aa1f7a9965dfec08c617070c5db8d63a87ce/lxml-6.0.2-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:846ae9a12d54e368933b9759052d6206a9e8b250291109c48e350c1f1f49d916" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/d0/34/9e591954939276bb679b73773836c6684c22e56d05980e31d52a9a8deb18/lxml-6.0.2-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ef9266d2aa545d7374938fb5c484531ef5a2ec7f2d573e62f8ce722c735685fd" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/8d/27/b29ff065f9aaca443ee377aff699714fcbffb371b4fce5ac4ca759e436d5/lxml-6.0.2-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:4077b7c79f31755df33b795dc12119cb557a0106bfdab0d2c2d97bd3cf3dffa6" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/2b/9f/f756f9c2cd27caa1a6ef8c32ae47aadea697f5c2c6d07b0dae133c244fbe/lxml-6.0.2-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a7c5d5e5f1081955358533be077166ee97ed2571d6a66bdba6ec2f609a715d1a" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/61/46/bb85ea42d2cb1bd8395484fd72f38e3389611aa496ac7772da9205bbda0e/lxml-6.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:8f8d0cbd0674ee89863a523e6994ac25fd5be9c8486acfc3e5ccea679bad2679" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/95/0c/443fc476dcc8e41577f0af70458c50fe299a97bb6b7505bb1ae09aa7f9ac/lxml-6.0.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2cbcbf6d6e924c28f04a43f3b6f6e272312a090f269eff68a2982e13e5d57659" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/48/78/6ef0b359d45bb9697bc5a626e1992fa5d27aa3f8004b137b2314793b50a0/lxml-6.0.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:dfb874cfa53340009af6bdd7e54ebc0d21012a60a4e65d927c2e477112e63484" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/ff/ea/e1d33808f386bc1339d08c0dcada6e4712d4ed8e93fcad5f057070b7988a/lxml-6.0.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:fb8dae0b6b8b7f9e96c26fdd8121522ce5de9bb5538010870bd538683d30e9a2" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/4f/47/eba75dfd8183673725255247a603b4ad606f4ae657b60c6c145b381697da/lxml-6.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:358d9adae670b63e95bc59747c72f4dc97c9ec58881d4627fe0120da0f90d314" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/76/04/5c5e2b8577bc936e219becb2e98cdb1aca14a4921a12995b9d0c523502ae/lxml-6.0.2-cp313-cp313-win32.whl", hash = "sha256:e8cd2415f372e7e5a789d743d133ae474290a90b9023197fd78f32e2dc6873e2" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/fe/0a/4643ccc6bb8b143e9f9640aa54e38255f9d3b45feb2cbe7ae2ca47e8782e/lxml-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:b30d46379644fbfc3ab81f8f82ae4de55179414651f110a1514f0b1f8f6cb2d7" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/31/ef/dcf1d29c3f530577f61e5fe2f1bd72929acf779953668a8a47a479ae6f26/lxml-6.0.2-cp313-cp313-win_arm64.whl", hash = "sha256:13dcecc9946dca97b11b7c40d29fba63b55ab4170d3c0cf8c0c164343b9bfdcf" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/03/15/d4a377b385ab693ce97b472fe0c77c2b16ec79590e688b3ccc71fba19884/lxml-6.0.2-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:b0c732aa23de8f8aec23f4b580d1e52905ef468afb4abeafd3fec77042abb6fe" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/c8/e8/c128e37589463668794d503afaeb003987373c5f94d667124ffd8078bbd9/lxml-6.0.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:4468e3b83e10e0317a89a33d28f7aeba1caa4d1a6fd457d115dd4ffe90c5931d" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/00/ce/74903904339decdf7da7847bb5741fc98a5451b42fc419a86c0c13d26fe2/lxml-6.0.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:abd44571493973bad4598a3be7e1d807ed45aa2adaf7ab92ab7c62609569b17d" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/1f/d3/131dec79ce61c5567fecf82515bd9bc36395df42501b50f7f7f3bd065df0/lxml-6.0.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:370cd78d5855cfbffd57c422851f7d3864e6ae72d0da615fca4dad8c45d375a5" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/3a/ea/a43ba9bb750d4ffdd885f2cd333572f5bb900cd2408b67fdda07e85978a0/lxml-6.0.2-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:901e3b4219fa04ef766885fb40fa516a71662a4c61b80c94d25336b4934b71c0" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/60/23/6885b451636ae286c34628f70a7ed1fcc759f8d9ad382d132e1c8d3d9bfd/lxml-6.0.2-cp314-cp314-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:a4bf42d2e4cf52c28cc1812d62426b9503cdb0c87a6de81442626aa7d69707ba" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/48/5b/fc2ddfc94ddbe3eebb8e9af6e3fd65e2feba4967f6a4e9683875c394c2d8/lxml-6.0.2-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b2c7fdaa4d7c3d886a42534adec7cfac73860b89b4e5298752f60aa5984641a0" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/29/9c/47293c58cc91769130fbf85531280e8cc7868f7fbb6d92f4670071b9cb3e/lxml-6.0.2-cp314-cp314-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:98a5e1660dc7de2200b00d53fa00bcd3c35a3608c305d45a7bbcaf29fa16e83d" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/9b/da/ba6eceb830c762b48e711ded880d7e3e89fc6c7323e587c36540b6b23c6b/lxml-6.0.2-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:dc051506c30b609238d79eda75ee9cab3e520570ec8219844a72a46020901e37" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/a5/24/7be3f82cb7990b89118d944b619e53c656c97dc89c28cfb143fdb7cd6f4d/lxml-6.0.2-cp314-cp314-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8799481bbdd212470d17513a54d568f44416db01250f49449647b5ab5b5dccb9" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/1b/bd/dcfb9ea1e16c665efd7538fc5d5c34071276ce9220e234217682e7d2c4a5/lxml-6.0.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9261bb77c2dab42f3ecd9103951aeca2c40277701eb7e912c545c1b16e0e4917" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/21/04/a60b0ff9314736316f28316b694bccbbabe100f8483ad83852d77fc7468e/lxml-6.0.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:65ac4a01aba353cfa6d5725b95d7aed6356ddc0a3cd734de00124d285b04b64f" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/d6/bd/7d54bd1846e5a310d9c715921c5faa71cf5c0853372adf78aee70c8d7aa2/lxml-6.0.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:b22a07cbb82fea98f8a2fd814f3d1811ff9ed76d0fc6abc84eb21527596e7cc8" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/fd/32/5643d6ab947bc371da21323acb2a6e603cedbe71cb4c99c8254289ab6f4e/lxml-6.0.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:d759cdd7f3e055d6bc8d9bec3ad905227b2e4c785dc16c372eb5b5e83123f48a" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/33/da/34c1ec4cff1eea7d0b4cd44af8411806ed943141804ac9c5d565302afb78/lxml-6.0.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:945da35a48d193d27c188037a05fec5492937f66fb1958c24fc761fb9d40d43c" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/82/57/4eca3e31e54dc89e2c3507e1cd411074a17565fa5ffc437c4ae0a00d439e/lxml-6.0.2-cp314-cp314-win32.whl", hash = "sha256:be3aaa60da67e6153eb15715cc2e19091af5dc75faef8b8a585aea372507384b" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/e3/e0/c96cf13eccd20c9421ba910304dae0f619724dcf1702864fd59dd386404d/lxml-6.0.2-cp314-cp314-win_amd64.whl", hash = "sha256:fa25afbadead523f7001caf0c2382afd272c315a033a7b06336da2637d92d6ed" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/d5/5d/b3f03e22b3d38d6f188ef044900a9b29b2fe0aebb94625ce9fe244011d34/lxml-6.0.2-cp314-cp314-win_arm64.whl", hash = "sha256:063eccf89df5b24e361b123e257e437f9e9878f425ee9aae3144c77faf6da6d8" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/5e/5c/42c2c4c03554580708fc738d13414801f340c04c3eff90d8d2d227145275/lxml-6.0.2-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:6162a86d86893d63084faaf4ff937b3daea233e3682fb4474db07395794fa80d" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/bf/4f/12df843e3e10d18d468a7557058f8d3733e8b6e12401f30b1ef29360740f/lxml-6.0.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:414aaa94e974e23a3e92e7ca5b97d10c0cf37b6481f50911032c69eeb3991bba" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/e4/0c/9dc31e6c2d0d418483cbcb469d1f5a582a1cd00a1f4081953d44051f3c50/lxml-6.0.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:48461bd21625458dd01e14e2c38dd0aea69addc3c4f960c30d9f59d7f93be601" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/e7/2b/9b870c6ca24c841bdd887504808f0417aa9d8d564114689266f19ddf29c8/lxml-6.0.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:25fcc59afc57d527cfc78a58f40ab4c9b8fd096a9a3f964d2781ffb6eb33f4ed" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/bf/0c/4f5f2a4dd319a178912751564471355d9019e220c20d7db3fb8307ed8582/lxml-6.0.2-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5179c60288204e6ddde3f774a93350177e08876eaf3ab78aa3a3649d43eb7d37" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/12/64/554eed290365267671fe001a20d72d14f468ae4e6acef1e179b039436967/lxml-6.0.2-cp314-cp314t-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:967aab75434de148ec80597b75062d8123cadf2943fb4281f385141e18b21338" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/7a/31/1d748aa275e71802ad9722df32a7a35034246b42c0ecdd8235412c3396ef/lxml-6.0.2-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d100fcc8930d697c6561156c6810ab4a508fb264c8b6779e6e61e2ed5e7558f9" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/8f/41/2c11916bcac09ed561adccacceaedd2bf0e0b25b297ea92aab99fd03d0fa/lxml-6.0.2-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2ca59e7e13e5981175b8b3e4ab84d7da57993eeff53c07764dcebda0d0e64ecd" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/99/05/4e5c2873d8f17aa018e6afde417c80cc5d0c33be4854cce3ef5670c49367/lxml-6.0.2-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:957448ac63a42e2e49531b9d6c0fa449a1970dbc32467aaad46f11545be9af1d" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/0f/c9/dcc2da1bebd6275cdc723b515f93edf548b82f36a5458cca3578bc899332/lxml-6.0.2-cp314-cp314t-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b7fc49c37f1786284b12af63152fe1d0990722497e2d5817acfe7a877522f9a9" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/9c/e2/5172e4e7468afca64a37b81dba152fc5d90e30f9c83c7c3213d6a02a5ce4/lxml-6.0.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e19e0643cc936a22e837f79d01a550678da8377d7d801a14487c10c34ee49c7e" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/a5/b3/15461fd3e5cd4ddcb7938b87fc20b14ab113b92312fc97afe65cd7c85de1/lxml-6.0.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:1db01e5cf14345628e0cbe71067204db658e2fb8e51e7f33631f5f4735fefd8d" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/05/33/f310b987c8bf9e61c4dd8e8035c416bd3230098f5e3cfa69fc4232de7059/lxml-6.0.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:875c6b5ab39ad5291588aed6925fac99d0097af0dd62f33c7b43736043d4a2ec" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/70/ff/51c80e75e0bc9382158133bdcf4e339b5886c6ee2418b5199b3f1a61ed6d/lxml-6.0.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:cdcbed9ad19da81c480dfd6dd161886db6096083c9938ead313d94b30aadf272" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/56/4d/4856e897df0d588789dd844dbed9d91782c4ef0b327f96ce53c807e13128/lxml-6.0.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:80dadc234ebc532e09be1975ff538d154a7fa61ea5031c03d25178855544728f" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/0f/85/86766dfebfa87bea0ab78e9ff7a4b4b45225df4b4d3b8cc3c03c5cd68464/lxml-6.0.2-cp314-cp314t-win32.whl", hash = "sha256:da08e7bb297b04e893d91087df19638dc7a6bb858a954b0cc2b9f5053c922312" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/fe/1a/b248b355834c8e32614650b8008c69ffeb0ceb149c793961dd8c0b991bb3/lxml-6.0.2-cp314-cp314t-win_amd64.whl", hash = "sha256:252a22982dca42f6155125ac76d3432e548a7625d56f5a273ee78a5057216eca" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/92/aa/df863bcc39c5e0946263454aba394de8a9084dbaff8ad143846b0d844739/lxml-6.0.2-cp314-cp314t-win_arm64.whl", hash = "sha256:bb4c1847b303835d89d785a18801a883436cdfd5dc3d62947f9c49e24f0f5a2c" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/5d/09/4d693ed4c8a407ceda14683bdbb6fcb6b72c7343382a06fe9d94ff18bdf1/lxml-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a656ca105115f6b766bba324f23a67914d9c728dafec57638e2b92a9dcd76c62" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/5e/f9/096e3a62d48438fbe2b70bb0e94d9652dfa5ac7b1ecf56c68a3c5143c2d5/lxml-6.0.2-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c54d83a2188a10ebdba573f16bd97135d06c9ef60c3dc495315c7a28c80a263f" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/54/0f/67d09bf12edcdbc308c0a66ad9d769aeb5c7742f35646ccede1771efafa3/lxml-6.0.2-cp38-cp38-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:1ea99340b3c729beea786f78c38f60f4795622f36e305d9c9be402201efdc3b7" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/4e/f0/49a595035c6b329840452fe9c163b3b7e0b330d542e687a318ea2a21f6e6/lxml-6.0.2-cp38-cp38-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:af85529ae8d2a453feee4c780d9406a5e3b17cee0dd75c18bd31adcd584debc3" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/c8/f1/3bfa59b1397206624d8debddb23882cf09099901de15562028f7676916d4/lxml-6.0.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:fe659f6b5d10fb5a17f00a50eb903eb277a71ee35df4615db573c069bcf967ac" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/62/b3/59a1126e6d94cd95c37745599f252a634455b7bfd78b344177d32c870eff/lxml-6.0.2-cp38-cp38-win32.whl", hash = "sha256:5921d924aa5468c939d95c9814fa9f9b5935a6ff4e679e26aaf2951f74043512" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/e3/b0/f9a25749c3c076b2dcf1df6f427adb0cdcf387fe307d2b153b6f13cbb033/lxml-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:0aa7070978f893954008ab73bb9e3c24a7c56c054e00566a21b553dc18105fca" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/38/66/dd13c74fad495957374c8a81c932f4874d3dca5aa0db9e4369f06a399718/lxml-6.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2c8458c2cdd29589a8367c09c8f030f1d202be673f0ca224ec18590b3b9fb694" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/5e/f4/edb9d47dce464b5dd044d35775ee794364935b93ab6226c95e199118890d/lxml-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3fee0851639d06276e6b387f1c190eb9d7f06f7f53514e966b26bae46481ec90" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/66/f2/d80c97b6ed83a99bc24b2b29919d5e618af5322df6d3aa61064093712309/lxml-6.0.2-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b2142a376b40b6736dfc214fd2902409e9e3857eff554fed2d3c60f097e62a62" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/d5/f1/18b750f79f8889b9109b24749f23ac137870b4f685edc4be54be0ff2c730/lxml-6.0.2-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a6b5b39cc7e2998f968f05309e666103b53e2edd01df8dc51b90d734c0825444" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/cf/88/2b6a415dbad411c3e9c092128eb7db06054d2d9460aa56676d17ee4f4fd5/lxml-6.0.2-cp39-cp39-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d4aec24d6b72ee457ec665344a29acb2d35937d5192faebe429ea02633151aad" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/7c/d0/5354afaa0f2e53625e5f96f6bd049a4875c3ab79d96d6c4871dd1f4a98c4/lxml-6.0.2-cp39-cp39-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:b42f4d86b451c2f9d06ffb4f8bbc776e04df3ba070b9fe2657804b1b40277c48" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/51/63/10dea35a01291dc529fa9d6ba204ea627a1c77b7fbb180d404f6cc4dd2fd/lxml-6.0.2-cp39-cp39-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6cdaefac66e8b8f30e37a9b4768a391e1f8a16a7526d5bc77a7928408ef68e93" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/37/58/51ef422d8bec58db600b3552e5f2d870ec01ffacf11d98689c42ffdcbf7f/lxml-6.0.2-cp39-cp39-manylinux_2_31_armv7l.whl", hash = "sha256:b738f7e648735714bbb82bdfd030203360cfeab7f6e8a34772b3c8c8b820568c" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/77/97/3f797820e82e3a58a19bc51068b40f3b9ab7d0934ba6e5ba6b147b618319/lxml-6.0.2-cp39-cp39-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:daf42de090d59db025af61ce6bdb2521f0f102ea0e6ea310f13c17610a97da4c" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/e2/14/a9306a8ab122e2f5dfbf4f71fb09beeadca26b0c275708432bbc33f40edc/lxml-6.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:66328dabea70b5ba7e53d94aa774b733cf66686535f3bc9250a7aab53a91caaf" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/ea/23/2118a1685277b9fa8726ec7ee903db55aa300dcea3d406a220cbe3710953/lxml-6.0.2-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:e237b807d68a61fc3b1e845407e27e5eb8ef69bc93fe8505337c1acb4ee300b6" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/4e/e8/d5be34da2059dc9a4ff8643fd6ad3f8234a27b2a44831b7fff58c4dbb3e3/lxml-6.0.2-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:ac02dc29fd397608f8eb15ac1610ae2f2f0154b03f631e6d724d9e2ad4ee2c84" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/61/84/5aebc8e150d5bf488815ea2d8798c7ff509cc37b5725caa3c1f11bdd3245/lxml-6.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:817ef43a0c0b4a77bd166dc9a09a555394105ff3374777ad41f453526e37f9cb" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/35/04/629ae603c1c17fb7adc9df2bc21aa5ac96afb84001700b13c1f038f3118c/lxml-6.0.2-cp39-cp39-win32.whl", hash = "sha256:bc532422ff26b304cfb62b328826bd995c96154ffd2bac4544f37dbb95ecaa8f" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/71/de/07b7b1249acbecbf48f7e42c3ce87a657af6ff38e30f12a1ad81f16010f2/lxml-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:995e783eb0374c120f528f807443ad5a83a656a8624c467ea73781fc5f8a8304" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/60/e3/02c4c55b281606f3c8e118300e16a9fcf5f3462cc46ce740ed0b82fc3f1b/lxml-6.0.2-cp39-cp39-win_arm64.whl", hash = "sha256:08b9d5e803c2e4725ae9e8559ee880e5328ed61aa0935244e0515d7d9dbec0aa" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/e7/9c/780c9a8fce3f04690b374f72f41306866b0400b9d0fdf3e17aaa37887eed/lxml-6.0.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:e748d4cf8fef2526bb2a589a417eba0c8674e29ffcb570ce2ceca44f1e567bf6" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/f5/5a/1ab260c00adf645d8bf7dec7f920f744b032f69130c681302821d5debea6/lxml-6.0.2-pp310-pypy310_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4ddb1049fa0579d0cbd00503ad8c58b9ab34d1254c77bc6a5576d96ec7853dba" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/f2/37/565f3b3d7ffede22874b6d86be1a1763d00f4ea9fc5b9b6ccb11e4ec8612/lxml-6.0.2-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cb233f9c95f83707dae461b12b720c1af9c28c2d19208e1be03387222151daf5" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/22/ec/f3a1b169b2fb9d03467e2e3c0c752ea30e993be440a068b125fc7dd248b0/lxml-6.0.2-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bc456d04db0515ce3320d714a1eac7a97774ff0849e7718b492d957da4631dd4" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/77/a2/585a28fe3e67daa1cf2f06f34490d556d121c25d500b10082a7db96e3bcd/lxml-6.0.2-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2613e67de13d619fd283d58bda40bff0ee07739f624ffee8b13b631abf33083d" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/7b/d9/a57dd8bcebd7c69386c20263830d4fa72d27e6b72a229ef7a48e88952d9a/lxml-6.0.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:24a8e756c982c001ca8d59e87c80c4d9dcd4d9b44a4cbeb8d9be4482c514d41d" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/0b/11/29d08bc103a62c0eba8016e7ed5aeebbf1e4312e83b0b1648dd203b0e87d/lxml-6.0.2-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:1c06035eafa8404b5cf475bb37a9f6088b0aca288d4ccc9d69389750d5543700" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/12/b3/52ab9a3b31e5ab8238da241baa19eec44d2ab426532441ee607165aebb52/lxml-6.0.2-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c7d13103045de1bdd6fe5d61802565f1a3537d70cd3abf596aa0af62761921ee" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/a0/33/1eaf780c1baad88224611df13b1c2a9dfa460b526cacfe769103ff50d845/lxml-6.0.2-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0a3c150a95fbe5ac91de323aa756219ef9cf7fde5a3f00e2281e30f33fa5fa4f" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/7a/c1/27428a2ff348e994ab4f8777d3a0ad510b6b92d37718e5887d2da99952a2/lxml-6.0.2-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:60fa43be34f78bebb27812ed90f1925ec99560b0fa1decdb7d12b84d857d31e9" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/f0/d0/3020fa12bcec4ab62f97aab026d57c2f0cfd480a558758d9ca233bb6a79d/lxml-6.0.2-pp311-pypy311_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:21c73b476d3cfe836be731225ec3421fa2f048d84f6df6a8e70433dff1376d5a" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/6c/77/d7f491cbc05303ac6801651aabeb262d43f319288c1ea96c66b1d2692ff3/lxml-6.0.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:27220da5be049e936c3aca06f174e8827ca6445a4353a1995584311487fc4e3e" },
+]
+
+[[package]]
+name = "markupsafe"
+version = "2.1.5"
+source = { registry = "https://mirrors.aliyun.com/pypi/simple" }
+resolution-markers = [
+ "python_full_version < '3.9'",
+]
+sdist = { url = "https://mirrors.aliyun.com/pypi/packages/87/5b/aae44c6655f3801e81aa3eef09dbbf012431987ba564d7231722f68df02d/MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b" }
+wheels = [
+ { url = "https://mirrors.aliyun.com/pypi/packages/e4/54/ad5eb37bf9d51800010a74e4665425831a9db4e7c4e0fde4352e391e808e/MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/6a/4a/a4d49415e600bacae038c67f9fecc1d5433b9d3c71a4de6f33537b89654c/MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/0a/7b/85681ae3c33c385b10ac0f8dd025c30af83c78cec1c37a6aa3b55e67f5ec/MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/7c/52/2b1b570f6b8b803cef5ac28fdf78c0da318916c7d2fe9402a84d591b394c/MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/29/fe/a36ba8c7ca55621620b2d7c585313efd10729e63ef81e4e61f52330da781/MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/60/ae/9c60231cdfda003434e8bd27282b1f4e197ad5a710c14bee8bea8a9ca4f0/MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/65/dc/1510be4d179869f5dafe071aecb3f1f41b45d37c02329dfba01ff59e5ac5/MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/30/39/8d845dd7d0b0613d86e0ef89549bfb5f61ed781f59af45fc96496e897f3a/MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/c7/5c/356a6f62e4f3c5fbf2602b4771376af22a3b16efa74eb8716fb4e328e01e/MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/69/48/acbf292615c65f0604a0c6fc402ce6d8c991276e16c80c46a8f758fbd30c/MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/11/e7/291e55127bb2ae67c64d66cef01432b5933859dfb7d6949daa721b89d0b3/MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/6b/cb/aed7a284c00dfa7c0682d14df85ad4955a350a21d2e3b06d8240497359bf/MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/1c/cf/35fe557e53709e93feb65575c93927942087e9b97213eabc3fe9d5b25a55/MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/97/18/c30da5e7a0e7f4603abfc6780574131221d9148f323752c2755d48abad30/MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/0c/40/2e73e7d532d030b1e41180807a80d564eda53babaf04d65e15c1cf897e40/MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/18/46/5dca760547e8c59c5311b332f70605d24c99d1303dd9a6e1fc3ed0d73561/MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/6d/c5/27febe918ac36397919cd4a67d5579cbbfa8da027fa1238af6285bb368ea/MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/f8/81/56e567126a2c2bc2684d6391332e357589a96a76cb9f8e5052d85cb0ead8/MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/00/0b/23f4b2470accb53285c613a3ab9ec19dc944eaf53592cb6d9e2af8aa24cc/MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/b7/a2/c78a06a9ec6d04b3445a949615c4c7ed86a0b2eb68e44e7541b9d57067cc/MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/53/bd/583bf3e4c8d6a321938c13f49d44024dbe5ed63e0a7ba127e454a66da974/MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/48/d6/e7cd795fc710292c3af3a06d80868ce4b02bfbbf370b7cee11d282815a2a/MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/51/b5/5d8ec796e2a08fc814a2c7d2584b55f889a55cf17dd1a90f2beb70744e5c/MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/0a/0d/2454f072fae3b5a137c119abf15465d1771319dfe9e4acbb31722a0fff91/MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/2d/75/fd6cb2e68780f72d47e6671840ca517bda5ef663d30ada7616b0462ad1e3/MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/b0/81/147c477391c2750e8fc7705829f7351cf1cd3be64406edcf900dc633feb2/MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/8b/ff/9a52b71839d7a256b563e85d11050e307121000dcebc97df120176b3ad93/MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/88/07/2dc76aa51b481eb96a4c3198894f38b480490e834479611a4053fbf08623/MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/96/0c/620c1fb3661858c0e37eb3cbffd8c6f732a67cd97296f725789679801b31/MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/3f/14/c3554d512d5f9100a95e737502f4a2323a1959f6d0d01e0d0997b35f7b10/MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/f8/ff/2c942a82c35a49df5de3a630ce0a8456ac2969691b230e530ac12314364c/MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/4f/14/6f294b9c4f969d0c801a4615e221c1e084722ea6114ab2114189c5b8cbe0/MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/81/d4/fd74714ed30a1dedd0b82427c02fa4deec64f173831ec716da11c51a50aa/MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/c7/bd/50319665ce81bb10e90d1cf76f9e1aa269ea6f7fa30ab4521f14d122a3df/MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/4c/6f/f2b0f675635b05f6afd5ea03c094557bdb8622fa8e673387444fe8d8e787/MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/51/e0/393467cf899b34a9d3678e78961c2c8cdf49fb902a959ba54ece01273fb1/MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/f6/02/5437e2ad33047290dafced9df741d9efc3e716b75583bbd73a9984f1b6f7/MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/0e/7d/968284145ffd9d726183ed6237c77938c021abacde4e073020f920e060b2/MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/bf/f3/ecb00fc8ab02b7beae8699f34db9357ae49d9f21d4d3de6f305f34fa949e/MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/92/21/357205f03514a49b293e214ac39de01fadd0970a6e05e4bf1ddd0ffd0881/MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/0f/31/780bb297db036ba7b7bbede5e1d7f1e14d704ad4beb3ce53fb495d22bc62/MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/6c/77/d77701bbef72892affe060cdacb7a2ed7fd68dae3b477a8642f15ad3b132/MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/d9/a7/1e558b4f78454c8a3a0199292d96159eb4d091f983bc35ef258314fe7269/MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/5f/5a/360da85076688755ea0cceb92472923086993e86b5613bbae9fbc14136b0/MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/6a/18/ae5a258e3401f9b8312f92b028c54d7026a97ec3ab20bfaddbdfa7d8cce8/MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/0b/cc/48206bd61c5b9d0129f4d75243b156929b04c94c09041321456fd06a876d/MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/d1/06/a41c112ab9ffdeeb5f77bc3e331fdadf97fa65e52e44ba31880f4e7f983c/MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/02/8c/ab9a463301a50dab04d5472e998acbd4080597abc048166ded5c7aa768c8/MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/bc/29/9bc18da763496b055d8e98ce476c8e718dcfd78157e17f555ce6dd7d0895/MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/f6/f8/4da07de16f10551ca1f640c92b5f316f9394088b183c6a57183df6de5ae4/MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5" },
+]
+
+[[package]]
+name = "markupsafe"
+version = "3.0.3"
+source = { registry = "https://mirrors.aliyun.com/pypi/simple" }
+resolution-markers = [
+ "python_full_version >= '3.10'",
+ "python_full_version == '3.9.*'",
+]
+sdist = { url = "https://mirrors.aliyun.com/pypi/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698" }
+wheels = [
+ { url = "https://mirrors.aliyun.com/pypi/packages/e8/4b/3541d44f3937ba468b75da9eebcae497dcf67adb65caa16760b0a6807ebb/markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/40/01/e560d658dc0bb8ab762670ece35281dec7b6c1b33f5fbc09ebb57a185519/markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/af/cd/ce6e848bbf2c32314c9b237839119c5a564a59725b53157c856e90937b7a/markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/c9/2a/b5c12c809f1c3045c4d580b035a743d12fcde53cf685dbc44660826308da/markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/cf/e3/9427a68c82728d0a88c50f890d0fc072a1484de2f3ac1ad0bfc1a7214fd5/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/bc/36/23578f29e9e582a4d0278e009b38081dbe363c5e7165113fad546918a232/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/56/21/dca11354e756ebd03e036bd8ad58d6d7168c80ce1fe5e75218e4945cbab7/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/87/99/faba9369a7ad6e4d10b6a5fbf71fa2a188fe4a593b15f0963b73859a1bbd/markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/d6/25/55dc3ab959917602c96985cb1253efaa4ff42f71194bddeb61eb7278b8be/markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/d0/9e/0a02226640c255d1da0b8d12e24ac2aa6734da68bff14c05dd53b94a0fc3/markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/08/db/fefacb2136439fc8dd20e797950e749aa1f4997ed584c62cfb8ef7c2be0e/markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/e1/2e/5898933336b61975ce9dc04decbc0a7f2fee78c30353c5efba7f2d6ff27a/markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/1d/09/adf2df3699d87d1d8184038df46a9c80d78c0148492323f4693df54e17bb/markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/30/ac/0273f6fcb5f42e314c6d8cd99effae6a5354604d461b8d392b5ec9530a54/markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/19/ae/31c1be199ef767124c042c6c3e904da327a2f7f0cd63a0337e1eca2967a8/markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/b2/76/7edcab99d5349a4532a459e1fe64f0b0467a3365056ae550d3bcf3f79e1e/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/a4/28/6e74cdd26d7514849143d69f0bf2399f929c37dc2b31e6829fd2045b2765/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/62/7e/a145f36a5c2945673e590850a6f8014318d5577ed7e5920a4b3448e0865d/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/0f/62/d9c46a7f5c9adbeeeda52f5b8d802e1094e9717705a645efc71b0913a0a8/markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/83/8a/4414c03d3f891739326e1783338e48fb49781cc915b2e0ee052aa490d586/markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/35/73/893072b42e6862f319b5207adc9ae06070f095b358655f077f69a35601f0/markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/33/8a/8e42d4838cd89b7dde187011e97fe6c3af66d8c044997d2183fbd6d31352/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/b5/64/7660f8a4a8e53c924d0fa05dc3a55c9cee10bbd82b11c5afb27d44b096ce/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/da/ef/e648bfd021127bef5fa12e1720ffed0c6cbb8310c8d9bea7266337ff06de/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/41/3c/a36c2450754618e62008bf7435ccb0f88053e07592e6028a34776213d877/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/bc/20/b7fdf89a8456b099837cd1dc21974632a02a999ec9bf7ca3e490aacd98e7/markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/9a/a7/591f592afdc734f47db08a75793a55d7fbcc6902a723ae4cfbab61010cc5/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/7d/33/45b24e4f44195b26521bc6f1a82197118f74df348556594bd2262bda1038/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/ff/0e/53dfaca23a69fbfbbf17a4b64072090e70717344c52eaaaa9c5ddff1e5f0/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/46/11/f333a06fc16236d5238bfe74daccbca41459dcd8d1fa952e8fbd5dccfb70/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/28/52/182836104b33b444e400b14f797212f720cbc9ed6ba34c800639d154e821/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/6f/18/acf23e91bd94fd7b3031558b1f013adfa21a8e407a3fdb32745538730382/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/3c/f0/57689aa4076e1b43b15fdfa646b04653969d50cf30c32a102762be2485da/markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/f0/00/be561dce4e6ca66b15276e184ce4b8aec61fe83662cce2f7d72bd3249d28/markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/22/44/a0681611106e0b2921b3033fc19bc53323e0b50bc70cffdd19f7d679bb66/markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/5f/57/1b0b3f100259dc9fffe780cfb60d4be71375510e435efec3d116b6436d43/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/26/6a/4bf6d0c97c4920f1597cc14dd720705eca0bf7c787aebc6bb4d1bead5388/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/14/c7/ca723101509b518797fedc2fdf79ba57f886b4aca8a7d31857ba3ee8281f/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/56/23/0d8c13a44bde9154821586520840643467aee574d8ce79a17da539ee7fed/markupsafe-3.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15d939a21d546304880945ca1ecb8a039db6b4dc49b2c5a400387cdae6a62e26" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/fd/23/07a2cb9a8045d5f3f0890a8c3bc0859d7a47bfd9a560b563899bec7b72ed/markupsafe-3.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f71a396b3bf33ecaa1626c255855702aca4d3d9fea5e051b41ac59a9c1c41edc" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/bc/e4/6be85eb81503f8e11b61c0b6369b6e077dcf0a74adbd9ebf6b349937b4e9/markupsafe-3.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f4b68347f8c5eab4a13419215bdfd7f8c9b19f2b25520968adfad23eb0ce60c" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/6f/bc/4dc914ead3fe6ddaef035341fee0fc956949bbd27335b611829292b89ee2/markupsafe-3.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e8fc20152abba6b83724d7ff268c249fa196d8259ff481f3b1476383f8f24e42" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/89/6e/5fe81fbcfba4aef4093d5f856e5c774ec2057946052d18d168219b7bd9f9/markupsafe-3.0.3-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:949b8d66bc381ee8b007cd945914c721d9aba8e27f71959d750a46f7c282b20b" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/f6/f6/e0e5a3d3ae9c4020f696cd055f940ef86b64fe88de26f3a0308b9d3d048c/markupsafe-3.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:3537e01efc9d4dccdf77221fb1cb3b8e1a38d5428920e0657ce299b20324d758" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/c8/25/651753ef4dea08ea790f4fbb65146a9a44a014986996ca40102e237aa49a/markupsafe-3.0.3-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:591ae9f2a647529ca990bc681daebdd52c8791ff06c2bfa05b65163e28102ef2" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/dc/0a/c3cf2b4fef5f0426e8a6d7fce3cb966a17817c568ce59d76b92a233fdbec/markupsafe-3.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a320721ab5a1aba0a233739394eb907f8c8da5c98c9181d1161e77a0c8e36f2d" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/cd/1b/a7782984844bd519ad4ffdbebbba2671ec5d0ebbeac34736c15fb86399e8/markupsafe-3.0.3-cp39-cp39-win32.whl", hash = "sha256:df2449253ef108a379b8b5d6b43f4b1a8e81a061d6537becd5582fba5f9196d7" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/18/1f/8d9c20e1c9440e215a44be5ab64359e207fcb4f675543f1cf9a2a7f648d0/markupsafe-3.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:7c3fb7d25180895632e5d3148dbdc29ea38ccb7fd210aa27acbd1201a1902c6e" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/4e/d3/fe08482b5cd995033556d45041a4f4e76e7f0521112a9c9991d40d39825f/markupsafe-3.0.3-cp39-cp39-win_arm64.whl", hash = "sha256:38664109c14ffc9e7437e86b4dceb442b0096dfe3541d7864d9cbe1da4cf36c8" },
+]
+
+[[package]]
+name = "packaging"
+version = "25.0"
+source = { registry = "https://mirrors.aliyun.com/pypi/simple" }
+sdist = { url = "https://mirrors.aliyun.com/pypi/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f" }
+wheels = [
+ { url = "https://mirrors.aliyun.com/pypi/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484" },
+]
+
+[[package]]
+name = "pyqt5"
+version = "5.15.9"
+source = { registry = "https://mirrors.aliyun.com/pypi/simple" }
+dependencies = [
+ { name = "pyqt5-qt5" },
+ { name = "pyqt5-sip", version = "12.15.0", source = { registry = "https://mirrors.aliyun.com/pypi/simple" }, marker = "python_full_version < '3.9'" },
+ { name = "pyqt5-sip", version = "12.17.1", source = { registry = "https://mirrors.aliyun.com/pypi/simple" }, marker = "python_full_version == '3.9.*'" },
+ { name = "pyqt5-sip", version = "12.17.2", source = { registry = "https://mirrors.aliyun.com/pypi/simple" }, marker = "python_full_version >= '3.10'" },
+]
+sdist = { url = "https://mirrors.aliyun.com/pypi/packages/5c/46/b4b6eae1e24d9432905ef1d4e7c28b6610e28252527cdc38f2a75997d8b5/PyQt5-5.15.9.tar.gz", hash = "sha256:dc41e8401a90dc3e2b692b411bd5492ab559ae27a27424eed4bd3915564ec4c0" }
+wheels = [
+ { url = "https://mirrors.aliyun.com/pypi/packages/77/c7/82f92662afdd85b69d126353d498f71e0fce03cbf1c01b700e0e495adf16/PyQt5-5.15.9-cp37-abi3-macosx_10_13_x86_64.whl", hash = "sha256:883ba5c8a348be78c8be6a3d3ba014c798e679503bce00d76c666c2dc6afe828" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/28/99/78db05e606dbb4a9425c159e7f1f64b69683c16ee3dcd0f97ed9ede6b205/PyQt5-5.15.9-cp37-abi3-manylinux_2_17_x86_64.whl", hash = "sha256:dd5ce10e79fbf1df29507d2daf99270f2057cdd25e4de6fbf2052b46c652e3a5" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/f3/b5/00a3c80a4c738e92e9d9e144c9bb5bd9d0842bac5517c63d42e7c9633826/PyQt5-5.15.9-cp37-abi3-win32.whl", hash = "sha256:e45c5cc15d4fd26ab5cb0e5cdba60691a3e9086411f8e3662db07a5a4222a696" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/55/5d/8df8a2aa0de6588965d048fca9306cf15a5801be3078f195e8f8f41fa863/PyQt5-5.15.9-cp37-abi3-win_amd64.whl", hash = "sha256:e030d795df4cbbfcf4f38b18e2e119bcc9e177ef658a5094b87bb16cac0ce4c5" },
+]
+
+[[package]]
+name = "pyqt5-plugins"
+version = "5.15.9.2.3"
+source = { registry = "https://mirrors.aliyun.com/pypi/simple" }
+dependencies = [
+ { name = "click", version = "8.1.8", source = { registry = "https://mirrors.aliyun.com/pypi/simple" }, marker = "python_full_version < '3.10'" },
+ { name = "click", version = "8.3.1", source = { registry = "https://mirrors.aliyun.com/pypi/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "pyqt5" },
+ { name = "pyqt5-qt5" },
+ { name = "qt5-tools" },
+]
+wheels = [
+ { url = "https://mirrors.aliyun.com/pypi/packages/66/01/bbadae4076b0d96174d26f93d45676f92dc6a3387c7228ed7e6dff333612/pyqt5_plugins-5.15.9.2.3-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:798b9f7d212972ac3940425d0cfe3a90669520b29b113da9d63a0996b7e121f4" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/67/b5/93e6e22d6829fe090436ad8d330ddb6c6911ae4c9de2e83238b7937e9092/pyqt5_plugins-5.15.9.2.3-cp310-cp310-manylinux2014_x86_64.whl", hash = "sha256:a818862de6a19965fca26174d462097829f523e177025e96c415e0389d212616" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/bd/95/e343e662e951f90b50ba2b2c3059405d06dff439403001cfe24568c92524/pyqt5_plugins-5.15.9.2.3-cp310-cp310-win32.whl", hash = "sha256:a1abd0aaaf4bb1c0d35ed33eba9707f2212a235f45bf9bd103e65d60147d8865" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/42/0b/1499fabac51e183350b05c81b9e059e77dfc63c5aa74eab8ce50f9836a3f/pyqt5_plugins-5.15.9.2.3-cp310-cp310-win_amd64.whl", hash = "sha256:b3f2c1598a171c36bcc78f68d58370e6876afacdda66e0c1e2c1ce861907a7c9" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/e7/be/b6cb8bd5b2e05e74178e9bb2b2ecdce76b2067bac41919aff80cb8b17ad0/pyqt5_plugins-5.15.9.2.3-cp311-cp311-macosx_10_13_universal2.whl", hash = "sha256:078b1564a54c1549e40a87c32deb9cf9e77d72f004cd0f5f42a2acfd4d6aea36" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/fe/2b/11790a554b49d590cb02b466ea496670b2291c3e828bb9576219d812d0f8/pyqt5_plugins-5.15.9.2.3-cp311-cp311-manylinux2014_x86_64.whl", hash = "sha256:c883469f6d17859c8991d44d72fff6b2b9e3fa18b371c86ff002afb5e790f9c6" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/b1/56/616d43b195330f0f322a36fee70a0bea55b641baf57afc58b383d870f471/pyqt5_plugins-5.15.9.2.3-cp311-cp311-win32.whl", hash = "sha256:f48754c09ed46a0b6305109c0c19ed7cd8b13925ba81ef2df2e8a870437b3aa7" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/cd/29/b9e0ad2d345b425a111f22eac83e45c68afe8d3475a0adabc2da5dbfa5b3/pyqt5_plugins-5.15.9.2.3-cp311-cp311-win_amd64.whl", hash = "sha256:1d9acf423062c6694a5e68782fb54ce90355481d33281c9193da45c43426853c" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/04/fa/a071c78d58a4b7d9344a725d55fdf47dd996d86d7f191cabe47b5d62e2b3/pyqt5_plugins-5.15.9.2.3-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:b862c340b13cf782f77778cc9c5e28ceeb7ecbf9da0c7410b5c55050a59efe59" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/bd/35/53cc6d0df6bb84f11d1527c9e3930ab3b61eae39cc41ac8494435a1c6f17/pyqt5_plugins-5.15.9.2.3-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:b4225d531773c3c69814a05877651b29d639f1887f25b8b19dcc0e160427582a" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/b7/70/4d3b240f55aa937a93b80f5394ac2a9527d581b64b03b2f657f7d6b0812f/pyqt5_plugins-5.15.9.2.3-cp38-cp38-win32.whl", hash = "sha256:e0715d4149701fac3ad3b6777a272edab7ca375524d4c3742b3a6c11d46b2d35" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/ca/35/a9bdf51500444ef9121e1b3c97746dc405c1033fbbe4293d4c84867220a6/pyqt5_plugins-5.15.9.2.3-cp38-cp38-win_amd64.whl", hash = "sha256:ad82f31bfd6c7039909980628fcbcc7e843013dbdfcf3674f1ffaf53f90b71cc" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/ce/11/5dc8c6f7588374e0659ce12827f58ad935ee32815b252fcb84dfa57ea779/pyqt5_plugins-5.15.9.2.3-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:3e7ba7995e71ba06d536c8a36168ae03199a3983a727d627000f170d6e3a29f4" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/3c/27/991247ea590ce8d95ef25d24a1b97d18db2192caf330401c6ac54983dd58/pyqt5_plugins-5.15.9.2.3-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:b3e747cd3be0885b12e8bde32234df0ee082dfc9607751ce81fb2aa694462048" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/59/af/9a2bf5d46db2cbdcf0ab205f6e8a959142fad952a0d057488c9958b19e0f/pyqt5_plugins-5.15.9.2.3-cp39-cp39-win32.whl", hash = "sha256:e4670917c36b039b6d195af177afa369f603aa00376890fd540c955ec56c9284" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/72/c0/24afe113ea502a1f18e754241c4e28f1c96be12cc3c18f9de3f08d807148/pyqt5_plugins-5.15.9.2.3-cp39-cp39-win_amd64.whl", hash = "sha256:bacaae333802856871e24045f121967f73e2b5f95a55b633f76b78c6a87e034c" },
+]
+
+[[package]]
+name = "pyqt5-qt5"
+version = "5.15.2"
+source = { registry = "https://mirrors.aliyun.com/pypi/simple" }
+wheels = [
+ { url = "https://mirrors.aliyun.com/pypi/packages/62/09/99a222b0360616250fb2e6003a54e43a2a06b0774f0f8d5daafb86a2c375/PyQt5_Qt5-5.15.2-py3-none-macosx_10_13_intel.whl", hash = "sha256:76980cd3d7ae87e3c7a33bfebfaee84448fd650bad6840471d6cae199b56e154" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/83/d4/241a6a518d0bcf0a9fcdcbad5edfed18d43e884317eab8d5230a2b27e206/PyQt5_Qt5-5.15.2-py3-none-manylinux2014_x86_64.whl", hash = "sha256:1988f364ec8caf87a6ee5d5a3a5210d57539988bf8e84714c7d60972692e2f4a" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/1c/7e/ce7c66a541a105fa98b41d6405fe84940564695e29fc7dccf6d9e8c5f898/PyQt5_Qt5-5.15.2-py3-none-win32.whl", hash = "sha256:9cc7a768b1921f4b982ebc00a318ccb38578e44e45316c7a4a850e953e1dd327" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/37/97/5d3b222b924fa2ed4c2488925155cd0b03fd5d09ee1cfcf7c553c11c9f66/PyQt5_Qt5-5.15.2-py3-none-win_amd64.whl", hash = "sha256:750b78e4dba6bdf1607febedc08738e318ea09e9b10aea9ff0d73073f11f6962" },
+]
+
+[[package]]
+name = "pyqt5-sip"
+version = "12.15.0"
+source = { registry = "https://mirrors.aliyun.com/pypi/simple" }
+resolution-markers = [
+ "python_full_version < '3.9'",
+]
+sdist = { url = "https://mirrors.aliyun.com/pypi/packages/1b/15/78318d50f10062c428e97e7ce387e772616a4673c356018b905f247a6a85/PyQt5_sip-12.15.0.tar.gz", hash = "sha256:d23fdfcf363b5cedd9d39f8a9c5710e7d52804f5b08a58e91c638b36eafcb702" }
+wheels = [
+ { url = "https://mirrors.aliyun.com/pypi/packages/f9/cb/5989258c3d70c78eabaebe3ac900c56c863caf6de7961e4b7b556a8c9e7a/PyQt5_sip-12.15.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:749f7a3ffd6e3d2d5db65ed92c95cbd14490631595c61f0c0672c9238bfb17de" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/c1/06/3fffcc82005d83ce5f923c52a13fc40661c081c0aa7a2588af09351d9075/PyQt5_sip-12.15.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:b4adc529fa4ec05728e14ea55194d907cc51f18d6f2ac5cc9f6eb52ac038aa0f" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/64/29/9508798f4009a7ffcfb92818fbe6dbfdc63fbc300b32c6c193f5c0879c16/PyQt5_sip-12.15.0-cp310-cp310-win32.whl", hash = "sha256:83d247cdc43ef224410b14c97413067ea26356dfa39e9ed0fe702a31e25710b0" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/18/c2/a53caa812b3886550eb82ba7af63a8293a6ffbceaef1f6f192fe34fdd580/PyQt5_sip-12.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:13f0c6a78e781255863e3e160304648efaf62276b7102741af637b63a6e96930" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/e9/7e/4b87c65adf9cb74895acc129043d04bb300436cab1e39469f4a9fc40b602/PyQt5_sip-12.15.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:855563d4d3b59ce7438bbf2dd32fed2707787defa40f3efe94f204a19ef92b25" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/ec/90/8bf505a096553a253e1a65078ca1aeb6de8a83f27afa3a43bb89ae29da31/PyQt5_sip-12.15.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0b718a362f4392430903bbb2a4b9bbff9841a16a52f0cfdd5b5bbd9d11457980" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/6b/80/ed1a360df9128e0e26e28c6341174a7e02efc57816799af5e3a3cb865fc8/PyQt5_sip-12.15.0-cp311-cp311-win32.whl", hash = "sha256:2575f428de584a12009fd29d00c89df16ed101a3b38beba818dfdcbc4a10709c" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/4e/d6/ea034ad64290c541042dc4c349d5aa854c8a0b54802a0759ec37671f0939/PyQt5_sip-12.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:c85be433fbafcb3d417581c0e1b67c8198d23858166e4f938e971c2262c13cdb" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/90/47/de48934a0d692c65b0833924a618786146c0869910c707a5e508351d5b91/PyQt5_sip-12.15.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:852b75cf208825602480e95ab63314108f872d0da251e9ad3deaaff5a183a6f5" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/d1/6c/9a2fe24f8970e092613f709283a2101403490a209a30de3de89a413d9915/PyQt5_sip-12.15.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0cd21c3215e3c47fdd5fa7a2dc3dd1e07a7230b0626e905a7217925068c788b9" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/90/53/0a4dc2d448619f2a51849e124d375ec7a8e95c938eccfaf8711bb77a62b6/PyQt5_sip-12.15.0-cp312-cp312-win32.whl", hash = "sha256:b58eeedc9b2a3037b136bf96915196c391a33be470ed1c0723d7163ef0b727a2" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/aa/c2/c07c531fe5a6124d91942c48a85ff4e14918766cd37819f7841cf2debabb/PyQt5_sip-12.15.0-cp312-cp312-win_amd64.whl", hash = "sha256:24a1d4937332bf0a38dd95bb2ce4d89723df449f6e912b52ef0e107e11fefac1" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/fe/c5/448f5757bfe8215ee570f490f4f600d4f92fdaf06690117eae369a5b3da0/PyQt5_sip-12.15.0-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:91b9538458a3a23e033c213bc879ce64f3d0a33d5a49cbd03e1e584efe307a35" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/13/ae/e48632f12f0186f9719b001e9fe0495233d8dfa807ecc9f4b54462cd76f5/PyQt5_sip-12.15.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0c1c727ede7fdc464a1fe2e46109ba836509b2d7187a46fdeae443148ce51d1c" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/64/34/507fd1aedb0919137d9a3fd806462543a7697e877999efbbdcb890f41379/PyQt5_sip-12.15.0-cp38-cp38-win32.whl", hash = "sha256:dd241de9c569c07bbba62bff1049996e5b52478164f61f430073a87bf6d26d33" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/4f/fc/7d44e8f83eded93fa1517d8354529b7a21cae5d93c26e1681fd7e4bcbb2b/PyQt5_sip-12.15.0-cp38-cp38-win_amd64.whl", hash = "sha256:f600ae6f03e4bff91153c0dc7ebe52f90bd2b6afda58fd580e6990b3b951adc0" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/bc/76/302ace0f93ff919be5fcbc763372c3b07fdb06005becd2e53b3d425204e4/PyQt5_sip-12.15.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c0c543d604116af26694a8a5ba90f510551ff9124d503ae5ee14bb73a61363a3" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/1a/b6/85f21bc6d0edde6a64e29fd5e6493ab184cc8bad502b3394416db6fbd7ea/PyQt5_sip-12.15.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:97f2d6e8d9b7b3d3e795d576d7f56e6257f524221f6383b33ded7287763e9f06" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/d8/9f/c4bfa0dce78b15352bc750c3faef8bd884aadf66603eacaabfa7ef99d5b7/PyQt5_sip-12.15.0-cp39-cp39-win32.whl", hash = "sha256:ed5221c6241981bd98d39504823efb9cbe36841bf8917288f8fe8fc1d5569a41" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/bc/ff/239f3304db74fac086e9c1152256374a98ddab980e60e54b6f0df0ce79f4/PyQt5_sip-12.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:7f88c85702dce80ac2e1a162054f688ed394811d6dd03a5574b3fa8111b0a6db" },
+]
+
+[[package]]
+name = "pyqt5-sip"
+version = "12.17.1"
+source = { registry = "https://mirrors.aliyun.com/pypi/simple" }
+resolution-markers = [
+ "python_full_version == '3.9.*'",
+]
+sdist = { url = "https://mirrors.aliyun.com/pypi/packages/ea/08/88a20c862f40b5c178c517cdc7e93767967dec5ac1b994e226d517991c9b/pyqt5_sip-12.17.1.tar.gz", hash = "sha256:0eab72bcb628f1926bf5b9ac51259d4fa18e8b2a81d199071135458f7d087ea8" }
+wheels = [
+ { url = "https://mirrors.aliyun.com/pypi/packages/8f/38/d03cef62cc03348249ce279c7e42159d1c902b1d550924403b1986a2b0f4/pyqt5_sip-12.17.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:bd4f73b1ebd5e0bd8d4539a8e55132318efc70a92f648ef0f9d93329ad50adeb" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/08/92/5aa38d8c17ee857fc3f7866dc84d4f4e7ab2180b5026e4f6ffd594ed2432/pyqt5_sip-12.17.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:b52e85520dbfe5c3d0c0c47aa2c10fc1853d892ae60ebebfe8154b052394da50" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/58/5c/0990f3a9a07346417a6728102cbe3d97b13786bce974b24a8d649a49db59/pyqt5_sip-12.17.1-cp310-cp310-win32.whl", hash = "sha256:71a67e2c9b77a74e943e220db0a341c702fd9bcf83c4a2e07342dfce691742ae" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/07/ad/f101338acf81cbd562362741aee9d0ee3c9242a6127c12ca698a15c851c6/pyqt5_sip-12.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:2710effb921bf6955b902779c763d890bb593da6325f0e128a0e3991cc855e9f" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/15/e4/451e465c75584a7cbd10e10404317b7443af83f56a64e02080b1f3cda5b5/pyqt5_sip-12.17.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5134d637efadd108a70306bab55b3d7feaa951bf6b8162161a67ae847bea9130" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/dc/b2/330f97434b21fbc99ab16f6ce71358ff5ea1bf1f09ed14dfe6b28b5ed8f5/pyqt5_sip-12.17.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:155cf755266c8bf64428916e2ff720d5efa1aec003d4ccc40c003b147dbdac03" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/3b/fd/53925099d0fc8aaf7adee613b6cebfb3fdfcd1238add64ff9edf6711e5f8/pyqt5_sip-12.17.1-cp311-cp311-win32.whl", hash = "sha256:9dfa7fe4ac93b60004430699c4bf56fef842a356d64dfea7cbc6d580d0427d6d" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/33/f8/f47a849c17676557c4220fbce9fcc24e15736af247c4dddcaf9ff0124b57/pyqt5_sip-12.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:2ddd214cf40119b86942a5da2da5a7345334955ab00026d8dcc56326b30e6d3c" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/a5/15/291f83f336558300626bebb0c403084ec171bbc8a70683e3376234422eb6/pyqt5_sip-12.17.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:c362606de782d2d46374a38523632786f145c517ee62de246a6069e5f2c5f336" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/45/85/ea1ae099260fd1859d71b31f51760b4226abfa778d5796b76d92c8fe6dcd/pyqt5_sip-12.17.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:140cc582151456103ebb149fefc678f3cae803e7720733db51212af5219cd45c" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/b4/b3/d5b50c721651a0f2ccbef6f8db3dabf3db296b9ec239ba007f5615f57dd7/pyqt5_sip-12.17.1-cp312-cp312-win32.whl", hash = "sha256:9dc1f1525d4d42c080f6cfdfc70d78239f8f67b0a48ea0745497251d8d848b1d" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/14/b6/474d8b17763683ab45fb364f3a44f25fdc25d97b47b29ad8819b95a15ac8/pyqt5_sip-12.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:d5e2e9e175559017cd161d661e0ee0b551684f824bb90800c5a8c8a3bea9355e" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/1d/58/9ecb688050e79ffe7bbd9fc917aa13f63856a5081ac46bbce87bb11ab971/pyqt5_sip-12.17.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9ebbd7769ccdaaa6295e9c872553b6cde17f38e171056f17300d8af9a14d1fc8" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/b1/9f/ae691360a9f18e3e06fd297e854d7ad175367e35ea184fd2fcf6c79b8c25/pyqt5_sip-12.17.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:b023da906a70af2cf5e6fc1932f441ede07530f3e164dd52c6c2bb5ab7c6f424" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/d7/31/491c45423174a359a4b8a8d84a7b541c453f48497ae928cbe4006bcd3e01/pyqt5_sip-12.17.1-cp313-cp313-win32.whl", hash = "sha256:36dbef482bd638786b909f3bda65b7b3d5cbd6cbf16797496de38bae542da307" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/64/61/e28681dd5200094f7b2e6671e85c02a4d6693da36d23ad7d39ffbc70b15c/pyqt5_sip-12.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:d04e5551bbc3bcec98acc63b3b0618ddcbf31ff107349225b516fe7e7c0a7c8b" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/71/f9/06c09dc94474ffe3f518f80e47fc69d34abf8e4a971ae7e7c667d6ff30a7/pyqt5_sip-12.17.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:c49918287e1ad77956d1589f1d3d432a0be7630c646ea02cf652413a48e14458" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/40/ae/be6e338ea427deac5cd81a93f51ae3fb6505d99d6d5e5d5341bcc099327e/pyqt5_sip-12.17.1-cp314-cp314-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:944a4bf1e1ee18ad03a54964c1c6433fb6de582313a1f0b17673e7203e22fc83" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/fc/a3/8b758518bd0dd5d1581f7a6d522c9b4d9b58d05087b1d0b4dfaad5376434/pyqt5_sip-12.17.1-cp314-cp314-win32.whl", hash = "sha256:99a2935fd662a67748625b1e6ffa0a2d1f2da068b9df6db04fa59a4a5d4ee613" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/40/8c/e96f9877548810b1e537f46fc21ba74552dd4e8c498658114a8353bdf659/pyqt5_sip-12.17.1-cp314-cp314-win_amd64.whl", hash = "sha256:aaa33232cc80793d14fdb3b149b27eec0855612ed66aad480add5ac49b9cee63" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/1d/fd/097af91c0446c4877b2614f3e7e40729c7d0a276c401cef3ff95850cd236/pyqt5_sip-12.17.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6fdc457bd528e5909a5893db0a7dee0066d5f22e08234c9152db0ae6df9a367f" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/2c/cf/58143e15d0bfa1d1450071ad9a2d71adca82ebefbd7729d0c543463d4d31/pyqt5_sip-12.17.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:06ea59741c1bffb198d99b00d26594791f45fb11b10f774c8105aea5962e3835" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/e6/9b/8e8f1af1b500f0d4fcd48c9f7ee474731db8b046d3629151e382634eaf59/pyqt5_sip-12.17.1-cp39-cp39-win32.whl", hash = "sha256:b9ef23869d35c6740a95fcb1f387f4aea8d8fac80e19096fbaf1a64e18409c4b" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/64/1e/08bd86000c8294772c6c4aaaf53babd69b9b37e80d1c87583c1fe8eeab5b/pyqt5_sip-12.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:90eed15f19557dfab22e68c7763e3690053cc8dd30d93ade2523d1b5a04a87be" },
+]
+
+[[package]]
+name = "pyqt5-sip"
+version = "12.17.2"
+source = { registry = "https://mirrors.aliyun.com/pypi/simple" }
+resolution-markers = [
+ "python_full_version >= '3.10'",
+]
+sdist = { url = "https://mirrors.aliyun.com/pypi/packages/1e/4a/195cf4d2a7e1ff480b4cabcd51aa5c0068c03a19a97282317536e4a82e1e/pyqt5_sip-12.17.2.tar.gz", hash = "sha256:7f66565c2a13d34d8ad6aad08e953d355ea3fe466d991d51aa5a0966a5289f05" }
+wheels = [
+ { url = "https://mirrors.aliyun.com/pypi/packages/44/16/96faed1e31658d27979f36f9a56642c6a348ff44a9a35ccbb267c9b66ab3/pyqt5_sip-12.17.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:43c2bc7e7d19eb67998374c49adbaa8072d4261a286bdf64d08382bacae84fb7" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/11/81/4237700a1154e908c9c5d3be332bf8c58e6a31ed773bccd42ce4248ee297/pyqt5_sip-12.17.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:dda1e7e6840935f17fbeb445ec5da63b9b8e7f673317019397611230faeb81a6" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/be/e3/2bce195fb0229d7d2d6b009c44638ec02f06b7a14e912d053f3d80aa658a/pyqt5_sip-12.17.2-cp310-cp310-win32.whl", hash = "sha256:2dca03cd1d6c2c843e5de4d0a7b33a7812ed37d576ea65249f1a97c17d9f988b" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/80/20/d3baa26aebe4c33f314f7ae4565b4cf922d1d68f98f4919a0e0ad50653e7/pyqt5_sip-12.17.2-cp310-cp310-win_amd64.whl", hash = "sha256:0005227f10a6221d68f764e24181fe15b770da364fd3a67529ac13f589523991" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/47/57/acd812ddfdde9991f4cfe2a738e3646ab66ad2561c3dc0ba8e7541883aff/pyqt5_sip-12.17.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a6ce4b763f17ac89ef44716dbfa77ed93677ac502aa402989989508715185e74" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/c2/2e/2ff71739ee601347f7b6f6bd3265a259f39d145dfa474c44372d369b06ec/pyqt5_sip-12.17.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:cf8e8a88a3c031dd35bb19c4d7d9a3d65cca84719bed1bc5dd7e2aaf0cf517d2" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/9f/bf/8bef9051e49178e18a0c345de95a982c7a4f3779208ab793381d613ea435/pyqt5_sip-12.17.2-cp311-cp311-win32.whl", hash = "sha256:291d0e2aeddd18081533804150cc59e183b3ab6b4da2b2cf701fdf3ea41ffdda" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/54/d1/377bdc729877f12bdf3841716a4e620aa51b50a0cddcfa8aeecc3a152c9b/pyqt5_sip-12.17.2-cp311-cp311-win_amd64.whl", hash = "sha256:d53bea28b881cd9a4536c27c0658ae182bfb514dc1ff9235d16d10288010fc59" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/4b/3e/f5c7bc43668147ddc00a1a579f22639dffdbfb9470ce3a5bc1cf27e0d541/pyqt5_sip-12.17.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0bd1a8e59124a90a05f078bceeb9d4d93c3986c349030487c202fffde6612969" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/b9/41/63f81a53704425092558f1ec17adbed11787f4322e60a849e0539516b3aa/pyqt5_sip-12.17.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:55ff374feb4bad783241649c7b946e05d7e83d60b0755526ed8fb25bf54e3408" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/b5/cd/2b749a174e61394085d61cafb7dc3c11ddf40307edfb2d71cb9b71b7f320/pyqt5_sip-12.17.2-cp312-cp312-win32.whl", hash = "sha256:45dc6e2121d175fdab1431c448fd3e88c97caf873a33cb65efa2e9ad0056337b" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/73/ac/7f6d6a6a4505b251f1174092f09d5611c2ed66602c40d3411d93a1d2a95f/pyqt5_sip-12.17.2-cp312-cp312-win_amd64.whl", hash = "sha256:e3bb16e43afd68dd013228075876cf8f8b1a7d86ba67767dd2c6a97be677c18d" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/38/b1/78432c271b2a5477f5fe1ad9eb69cdc482430230b8d552cf5cee393d7862/pyqt5_sip-12.17.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:cfeee3c27f28c091d6a46f8befe9afcfafc76846846bedf1112d403a7299e864" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/e8/d9/6451973300f7dffe70476cad7fc4a59ffe08417ee4add6afb3288c91bd85/pyqt5_sip-12.17.2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:b5df33e198d5d7cccc8e081f80eb97b8d70100f887362074a029a6c19cb92c8b" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/c6/1e/241d9ddef5cb1bb3e3b5839b6f8c05ae727e196be82b4646ea4ef9475ef7/pyqt5_sip-12.17.2-cp313-cp313-win32.whl", hash = "sha256:2c0a278b8fc289d34d4e62bbb9ef6da96b45cc9ab3f6886397b1490d2b4a5604" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/fd/33/a393163b6299a7e0743fad86fbcb06cf219878fbdd629ee6cb46d2a4d9f7/pyqt5_sip-12.17.2-cp313-cp313-win_amd64.whl", hash = "sha256:7e0d663b583a4d3ac63c9fbade2228de6ee628b44a025f5fd964b97dbbcbebc9" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/58/29/b4943def737d3f8876bfd4f9af1909892ae1998099695b3e81870c39aaa7/pyqt5_sip-12.17.2-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:6f03c25a18294f2d66befc4f2adf3f35fceba877b937dc8a94783fa7da8b7345" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/18/62/e7ac79bb080d4e5a7d7fea50ca7d9231a7ded07e01f24d4e123f089e1630/pyqt5_sip-12.17.2-cp314-cp314-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a6d716801d512643b7b1f50dfbdcd16408fe9a6df907d8627b4ad82190604bec" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/92/11/b63ee88ffc2e04af90ced17dbe0d774f5f4e51122c13f8118e565707954e/pyqt5_sip-12.17.2-cp314-cp314-win32.whl", hash = "sha256:c617c29524fdcf826e619d77ffd0d6142622f8422adc2608ecc89edd3e605339" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/d0/70/efe47083dea494613fc41da55f25c07b4e73bb90c98dee8fe87afbfbc303/pyqt5_sip-12.17.2-cp314-cp314-win_amd64.whl", hash = "sha256:b008755d2222a064ec90c525fce5df3fe9d410371e47c43a21c049e07683b7fb" },
+]
+
+[[package]]
+name = "pyqt5-tools"
+version = "5.15.9.3.3"
+source = { registry = "https://mirrors.aliyun.com/pypi/simple" }
+dependencies = [
+ { name = "click", version = "8.1.8", source = { registry = "https://mirrors.aliyun.com/pypi/simple" }, marker = "python_full_version < '3.10'" },
+ { name = "click", version = "8.3.1", source = { registry = "https://mirrors.aliyun.com/pypi/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "pyqt5" },
+ { name = "pyqt5-plugins" },
+ { name = "python-dotenv", version = "1.0.1", source = { registry = "https://mirrors.aliyun.com/pypi/simple" }, marker = "python_full_version < '3.9'" },
+ { name = "python-dotenv", version = "1.2.1", source = { registry = "https://mirrors.aliyun.com/pypi/simple" }, marker = "python_full_version >= '3.9'" },
+]
+wheels = [
+ { url = "https://mirrors.aliyun.com/pypi/packages/11/7e/3a5bce0e31650e091a16826d7a588be8bd56c2ac30871286b6c90d68ceeb/pyqt5_tools-5.15.9.3.3-py3-none-any.whl", hash = "sha256:4b45b26111c583a34fa364b98d7120f5aeca4f96ac72e251f1b37a9cca809f86" },
+]
+
+[[package]]
+name = "python-docx"
+version = "1.1.2"
+source = { registry = "https://mirrors.aliyun.com/pypi/simple" }
+resolution-markers = [
+ "python_full_version < '3.9'",
+]
+dependencies = [
+ { name = "lxml", marker = "python_full_version < '3.9'" },
+ { name = "typing-extensions", version = "4.13.2", source = { registry = "https://mirrors.aliyun.com/pypi/simple" }, marker = "python_full_version < '3.9'" },
+]
+sdist = { url = "https://mirrors.aliyun.com/pypi/packages/35/e4/386c514c53684772885009c12b67a7edd526c15157778ac1b138bc75063e/python_docx-1.1.2.tar.gz", hash = "sha256:0cf1f22e95b9002addca7948e16f2cd7acdfd498047f1941ca5d293db7762efd" }
+wheels = [
+ { url = "https://mirrors.aliyun.com/pypi/packages/3e/3d/330d9efbdb816d3f60bf2ad92f05e1708e4a1b9abe80461ac3444c83f749/python_docx-1.1.2-py3-none-any.whl", hash = "sha256:08c20d6058916fb19853fcf080f7f42b6270d89eac9fa5f8c15f691c0017fabe" },
+]
+
+[[package]]
+name = "python-docx"
+version = "1.2.0"
+source = { registry = "https://mirrors.aliyun.com/pypi/simple" }
+resolution-markers = [
+ "python_full_version >= '3.10'",
+ "python_full_version == '3.9.*'",
+]
+dependencies = [
+ { name = "lxml", marker = "python_full_version >= '3.9'" },
+ { name = "typing-extensions", version = "4.15.0", source = { registry = "https://mirrors.aliyun.com/pypi/simple" }, marker = "python_full_version >= '3.9'" },
+]
+sdist = { url = "https://mirrors.aliyun.com/pypi/packages/a9/f7/eddfe33871520adab45aaa1a71f0402a2252050c14c7e3009446c8f4701c/python_docx-1.2.0.tar.gz", hash = "sha256:7bc9d7b7d8a69c9c02ca09216118c86552704edc23bac179283f2e38f86220ce" }
+wheels = [
+ { url = "https://mirrors.aliyun.com/pypi/packages/d0/00/1e03a4989fa5795da308cd774f05b704ace555a70f9bf9d3be057b680bcf/python_docx-1.2.0-py3-none-any.whl", hash = "sha256:3fd478f3250fbbbfd3b94fe1e985955737c145627498896a8a6bf81f4baf66c7" },
+]
+
+[[package]]
+name = "python-dotenv"
+version = "1.0.1"
+source = { registry = "https://mirrors.aliyun.com/pypi/simple" }
+resolution-markers = [
+ "python_full_version < '3.9'",
+]
+sdist = { url = "https://mirrors.aliyun.com/pypi/packages/bc/57/e84d88dfe0aec03b7a2d4327012c1627ab5f03652216c63d49846d7a6c58/python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca" }
+wheels = [
+ { url = "https://mirrors.aliyun.com/pypi/packages/6a/3e/b68c118422ec867fa7ab88444e1274aa40681c606d59ac27de5a5588f082/python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a" },
+]
+
+[[package]]
+name = "python-dotenv"
+version = "1.2.1"
+source = { registry = "https://mirrors.aliyun.com/pypi/simple" }
+resolution-markers = [
+ "python_full_version >= '3.10'",
+ "python_full_version == '3.9.*'",
+]
+sdist = { url = "https://mirrors.aliyun.com/pypi/packages/f0/26/19cadc79a718c5edbec86fd4919a6b6d3f681039a2f6d66d14be94e75fb9/python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6" }
+wheels = [
+ { url = "https://mirrors.aliyun.com/pypi/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61" },
+]
+
+[[package]]
+name = "pytz"
+version = "2025.2"
+source = { registry = "https://mirrors.aliyun.com/pypi/simple" }
+sdist = { url = "https://mirrors.aliyun.com/pypi/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3" }
+wheels = [
+ { url = "https://mirrors.aliyun.com/pypi/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00" },
+]
+
+[[package]]
+name = "pywin32"
+version = "311"
+source = { registry = "https://mirrors.aliyun.com/pypi/simple" }
+wheels = [
+ { url = "https://mirrors.aliyun.com/pypi/packages/7b/40/44efbb0dfbd33aca6a6483191dae0716070ed99e2ecb0c53683f400a0b4f/pywin32-311-cp310-cp310-win32.whl", hash = "sha256:d03ff496d2a0cd4a5893504789d4a15399133fe82517455e78bad62efbb7f0a3" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/5e/bf/360243b1e953bd254a82f12653974be395ba880e7ec23e3731d9f73921cc/pywin32-311-cp310-cp310-win_amd64.whl", hash = "sha256:797c2772017851984b97180b0bebe4b620bb86328e8a884bb626156295a63b3b" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/57/38/d290720e6f138086fb3d5ffe0b6caa019a791dd57866940c82e4eeaf2012/pywin32-311-cp310-cp310-win_arm64.whl", hash = "sha256:0502d1facf1fed4839a9a51ccbcc63d952cf318f78ffc00a7e78528ac27d7a2b" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/7c/af/449a6a91e5d6db51420875c54f6aff7c97a86a3b13a0b4f1a5c13b988de3/pywin32-311-cp311-cp311-win32.whl", hash = "sha256:184eb5e436dea364dcd3d2316d577d625c0351bf237c4e9a5fabbcfa5a58b151" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/51/8f/9bb81dd5bb77d22243d33c8397f09377056d5c687aa6d4042bea7fbf8364/pywin32-311-cp311-cp311-win_amd64.whl", hash = "sha256:3ce80b34b22b17ccbd937a6e78e7225d80c52f5ab9940fe0506a1a16f3dab503" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/44/7b/9c2ab54f74a138c491aba1b1cd0795ba61f144c711daea84a88b63dc0f6c/pywin32-311-cp311-cp311-win_arm64.whl", hash = "sha256:a733f1388e1a842abb67ffa8e7aad0e70ac519e09b0f6a784e65a136ec7cefd2" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/e7/ab/01ea1943d4eba0f850c3c61e78e8dd59757ff815ff3ccd0a84de5f541f42/pywin32-311-cp312-cp312-win32.whl", hash = "sha256:750ec6e621af2b948540032557b10a2d43b0cee2ae9758c54154d711cc852d31" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/d1/a8/a0e8d07d4d051ec7502cd58b291ec98dcc0c3fff027caad0470b72cfcc2f/pywin32-311-cp312-cp312-win_amd64.whl", hash = "sha256:b8c095edad5c211ff31c05223658e71bf7116daa0ecf3ad85f3201ea3190d067" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/ba/3a/2ae996277b4b50f17d61f0603efd8253cb2d79cc7ae159468007b586396d/pywin32-311-cp312-cp312-win_arm64.whl", hash = "sha256:e286f46a9a39c4a18b319c28f59b61de793654af2f395c102b4f819e584b5852" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/a5/be/3fd5de0979fcb3994bfee0d65ed8ca9506a8a1260651b86174f6a86f52b3/pywin32-311-cp313-cp313-win32.whl", hash = "sha256:f95ba5a847cba10dd8c4d8fefa9f2a6cf283b8b88ed6178fa8a6c1ab16054d0d" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/e3/28/e0a1909523c6890208295a29e05c2adb2126364e289826c0a8bc7297bd5c/pywin32-311-cp313-cp313-win_amd64.whl", hash = "sha256:718a38f7e5b058e76aee1c56ddd06908116d35147e133427e59a3983f703a20d" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/04/bf/90339ac0f55726dce7d794e6d79a18a91265bdf3aa70b6b9ca52f35e022a/pywin32-311-cp313-cp313-win_arm64.whl", hash = "sha256:7b4075d959648406202d92a2310cb990fea19b535c7f4a78d3f5e10b926eeb8a" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/c9/31/097f2e132c4f16d99a22bfb777e0fd88bd8e1c634304e102f313af69ace5/pywin32-311-cp314-cp314-win32.whl", hash = "sha256:b7a2c10b93f8986666d0c803ee19b5990885872a7de910fc460f9b0c2fbf92ee" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/90/4b/07c77d8ba0e01349358082713400435347df8426208171ce297da32c313d/pywin32-311-cp314-cp314-win_amd64.whl", hash = "sha256:3aca44c046bd2ed8c90de9cb8427f581c479e594e99b5c0bb19b29c10fd6cb87" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/c0/d2/21af5c535501a7233e734b8af901574572da66fcc254cb35d0609c9080dd/pywin32-311-cp314-cp314-win_arm64.whl", hash = "sha256:a508e2d9025764a8270f93111a970e1d0fbfc33f4153b388bb649b7eec4f9b42" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/75/20/6cd04d636a4c83458ecbb7c8220c13786a1a80d3f5fb568df39310e73e98/pywin32-311-cp38-cp38-win32.whl", hash = "sha256:6c6f2969607b5023b0d9ce2541f8d2cbb01c4f46bc87456017cf63b73f1e2d8c" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/ff/6c/94c10268bae5d0d0c6509bdfb5aa08882d11a9ccdf89ff1cde59a6161afb/pywin32-311-cp38-cp38-win_amd64.whl", hash = "sha256:c8015b09fb9a5e188f83b7b04de91ddca4658cee2ae6f3bc483f0b21a77ef6cd" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/59/42/b86689aac0cdaee7ae1c58d464b0ff04ca909c19bb6502d4973cdd9f9544/pywin32-311-cp39-cp39-win32.whl", hash = "sha256:aba8f82d551a942cb20d4a83413ccbac30790b50efb89a75e4f586ac0bb8056b" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/9f/8a/1403d0353f8c5a2f0829d2b1c4becbf9da2f0a4d040886404fc4a5431e4d/pywin32-311-cp39-cp39-win_amd64.whl", hash = "sha256:e0c4cfb0621281fe40387df582097fd796e80430597cb9944f0ae70447bacd91" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/60/22/e0e8d802f124772cec9c75430b01a212f86f9de7546bda715e54140d5aeb/pywin32-311-cp39-cp39-win_arm64.whl", hash = "sha256:62ea666235135fee79bb154e695f3ff67370afefd71bd7fea7512fc70ef31e3d" },
+]
+
+[[package]]
+name = "qt5-applications"
+version = "5.15.2.2.3"
+source = { registry = "https://mirrors.aliyun.com/pypi/simple" }
+wheels = [
+ { url = "https://mirrors.aliyun.com/pypi/packages/14/32/a2fcd818fe62dfcd24600782c7b71bc7c476406bbb4c5680a992fcb7b9d9/qt5_applications-5.15.2.2.3-py3-none-macosx_10_14_x86_64.whl", hash = "sha256:45395074b742ca6765990d3645d5e24a59415c1d968c40c6a3443da22c621ba8" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/35/e3/f5ab9980d601e62a75bb4d5d01d2324cb0d2a414f36474e26a83de409548/qt5_applications-5.15.2.2.3-py3-none-manylinux_2_17_x86_64.whl", hash = "sha256:9ac537caf18fc339149391f58e6716c472296df4431d68e76670e75a14238de0" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/96/32/5f6b843992c28efde2c3dadbe67296064d09c506c2fc9f9ebe76090eb00a/qt5_applications-5.15.2.2.3-py3-none-win32.whl", hash = "sha256:8d4ebdd955653f693edac4697f80e016270efcf861ebb1b8b7e238fd6faba5f5" },
+ { url = "https://mirrors.aliyun.com/pypi/packages/ae/a9/cd64cda6f58321c4a0021ced80117b225562efc42f1318ff2cea69c23eb7/qt5_applications-5.15.2.2.3-py3-none-win_amd64.whl", hash = "sha256:5156cc710ed3942f736ec2c46889f73d829fcd4093bed8dbddf2fd83929fdf0b" },
+]
+
+[[package]]
+name = "qt5-tools"
+version = "5.15.2.1.3"
+source = { registry = "https://mirrors.aliyun.com/pypi/simple" }
+dependencies = [
+ { name = "click", version = "8.1.8", source = { registry = "https://mirrors.aliyun.com/pypi/simple" }, marker = "python_full_version < '3.10'" },
+ { name = "click", version = "8.3.1", source = { registry = "https://mirrors.aliyun.com/pypi/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "qt5-applications" },
+]
+wheels = [
+ { url = "https://mirrors.aliyun.com/pypi/packages/e2/45/3062d0df2bbc88ee4ea04b1073072b337b9e287c0b4ac12109729b413e2e/qt5_tools-5.15.2.1.3-py3-none-any.whl", hash = "sha256:3e73b7aa3cd03abba6e703aa1d21a5934eff42a068292500a1f02c9bc6da95cb" },
+]
+
+[[package]]
+name = "qtmodern"
+version = "0.2.0"
+source = { registry = "https://mirrors.aliyun.com/pypi/simple" }
+dependencies = [
+ { name = "qtpy" },
+]
+sdist = { url = "https://mirrors.aliyun.com/pypi/packages/e3/17/bc8a3882571e852e96d79b8c5a6989f72e2b7eda22998cd6018bfc5644fb/qtmodern-0.2.0.tar.gz", hash = "sha256:d433a54fbb400d49790aff65d35f203de2a8cc67795ac5bb04c5e766433fafae" }
+wheels = [
+ { url = "https://mirrors.aliyun.com/pypi/packages/0a/24/499704896d57752a1d4b724f011f56a33bc163e96a77e572b81f2e5b0189/qtmodern-0.2.0-py3-none-any.whl", hash = "sha256:57e62617656494a9d8a27ac3bd51ae3ae61a265f43b92d6f6ea59dc8bed2179d" },
+]
+
+[[package]]
+name = "qtpy"
+version = "2.4.3"
+source = { registry = "https://mirrors.aliyun.com/pypi/simple" }
+dependencies = [
+ { name = "packaging" },
+]
+sdist = { url = "https://mirrors.aliyun.com/pypi/packages/70/01/392eba83c8e47b946b929d7c46e0f04b35e9671f8bb6fc36b6f7945b4de8/qtpy-2.4.3.tar.gz", hash = "sha256:db744f7832e6d3da90568ba6ccbca3ee2b3b4a890c3d6fbbc63142f6e4cdf5bb" }
+wheels = [
+ { url = "https://mirrors.aliyun.com/pypi/packages/69/76/37c0ccd5ab968a6a438f9c623aeecc84c202ab2fabc6a8fd927580c15b5a/QtPy-2.4.3-py3-none-any.whl", hash = "sha256:72095afe13673e017946cc258b8d5da43314197b741ed2890e563cf384b51aa1" },
+]
+
+[[package]]
+name = "setuptools"
+version = "75.3.2"
+source = { registry = "https://mirrors.aliyun.com/pypi/simple" }
+resolution-markers = [
+ "python_full_version < '3.9'",
+]
+sdist = { url = "https://mirrors.aliyun.com/pypi/packages/5c/01/771ea46cce201dd42cff043a5eea929d1c030fb3d1c2ee2729d02ca7814c/setuptools-75.3.2.tar.gz", hash = "sha256:3c1383e1038b68556a382c1e8ded8887cd20141b0eb5708a6c8d277de49364f5" }
+wheels = [
+ { url = "https://mirrors.aliyun.com/pypi/packages/15/65/3f0dba35760d902849d39d38c0a72767794b1963227b69a587f8a336d08c/setuptools-75.3.2-py3-none-any.whl", hash = "sha256:90ab613b6583fc02d5369cbca13ea26ea0e182d1df2d943ee9cbe81d4c61add9" },
+]
+
+[[package]]
+name = "setuptools"
+version = "80.9.0"
+source = { registry = "https://mirrors.aliyun.com/pypi/simple" }
+resolution-markers = [
+ "python_full_version >= '3.10'",
+ "python_full_version == '3.9.*'",
+]
+sdist = { url = "https://mirrors.aliyun.com/pypi/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c" }
+wheels = [
+ { url = "https://mirrors.aliyun.com/pypi/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922" },
+]
+
+[[package]]
+name = "six"
+version = "1.17.0"
+source = { registry = "https://mirrors.aliyun.com/pypi/simple" }
+sdist = { url = "https://mirrors.aliyun.com/pypi/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81" }
+wheels = [
+ { url = "https://mirrors.aliyun.com/pypi/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274" },
+]
+
+[[package]]
+name = "typing-extensions"
+version = "4.13.2"
+source = { registry = "https://mirrors.aliyun.com/pypi/simple" }
+resolution-markers = [
+ "python_full_version < '3.9'",
+]
+sdist = { url = "https://mirrors.aliyun.com/pypi/packages/f6/37/23083fcd6e35492953e8d2aaaa68b860eb422b34627b13f2ce3eb6106061/typing_extensions-4.13.2.tar.gz", hash = "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef" }
+wheels = [
+ { url = "https://mirrors.aliyun.com/pypi/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl", hash = "sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c" },
+]
+
+[[package]]
+name = "typing-extensions"
+version = "4.15.0"
+source = { registry = "https://mirrors.aliyun.com/pypi/simple" }
+resolution-markers = [
+ "python_full_version >= '3.10'",
+ "python_full_version == '3.9.*'",
+]
+sdist = { url = "https://mirrors.aliyun.com/pypi/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466" }
+wheels = [
+ { url = "https://mirrors.aliyun.com/pypi/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548" },
+]
diff --git a/zhuan.py b/zhuan.py
new file mode 100644
index 0000000..ab9714b
--- /dev/null
+++ b/zhuan.py
@@ -0,0 +1,65 @@
+# -*- coding: utf-8 -*-
+
+# Form implementation generated from reading ui file 'zhuan.ui'
+#
+# Created by: PyQt5 UI code generator 5.15.4
+#
+# WARNING: Any manual changes made to this file will be lost when pyuic5 is
+# run again. Do not edit this file unless you know what you are doing.
+
+
+from PyQt5 import QtCore, QtGui, QtWidgets
+
+
+class Ui_Dialog(object):
+ def setupUi(self, Dialog):
+ Dialog.setObjectName("Dialog")
+ Dialog.resize(461, 70)
+ self.widget = QtWidgets.QWidget(Dialog)
+ self.widget.setGeometry(QtCore.QRect(10, 35, 446, 23))
+ self.widget.setObjectName("widget")
+ self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.widget)
+ self.horizontalLayout_3.setContentsMargins(0, 0, 0, 0)
+ self.horizontalLayout_3.setObjectName("horizontalLayout_3")
+ self.horizontalLayout = QtWidgets.QHBoxLayout()
+ self.horizontalLayout.setObjectName("horizontalLayout")
+ self.label = QtWidgets.QLabel(self.widget)
+ self.label.setObjectName("label")
+ self.horizontalLayout.addWidget(self.label)
+ self.lineEdit = QtWidgets.QLineEdit(self.widget)
+ self.lineEdit.setObjectName("lineEdit")
+ self.horizontalLayout.addWidget(self.lineEdit)
+ self.horizontalLayout_3.addLayout(self.horizontalLayout)
+ self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_2.setObjectName("horizontalLayout_2")
+ self.label_2 = QtWidgets.QLabel(self.widget)
+ self.label_2.setObjectName("label_2")
+ self.horizontalLayout_2.addWidget(self.label_2)
+ self.lineEdit_2 = QtWidgets.QLineEdit(self.widget)
+ self.lineEdit_2.setObjectName("lineEdit_2")
+ self.horizontalLayout_2.addWidget(self.lineEdit_2)
+ self.horizontalLayout_3.addLayout(self.horizontalLayout_2)
+ self.widget1 = QtWidgets.QWidget(Dialog)
+ self.widget1.setGeometry(QtCore.QRect(10, 10, 216, 18))
+ self.widget1.setObjectName("widget1")
+ self.horizontalLayout_4 = QtWidgets.QHBoxLayout(self.widget1)
+ self.horizontalLayout_4.setContentsMargins(0, 0, 0, 0)
+ self.horizontalLayout_4.setObjectName("horizontalLayout_4")
+ self.radioButton = QtWidgets.QRadioButton(self.widget1)
+ self.radioButton.setChecked(True)
+ self.radioButton.setObjectName("radioButton")
+ self.horizontalLayout_4.addWidget(self.radioButton)
+ self.radioButton_2 = QtWidgets.QRadioButton(self.widget1)
+ self.radioButton_2.setObjectName("radioButton_2")
+ self.horizontalLayout_4.addWidget(self.radioButton_2)
+
+ self.retranslateUi(Dialog)
+ QtCore.QMetaObject.connectSlotsByName(Dialog)
+
+ def retranslateUi(self, Dialog):
+ _translate = QtCore.QCoreApplication.translate
+ Dialog.setWindowTitle(_translate("Dialog", "IEEE754转换工具"))
+ self.label.setText(_translate("Dialog", "16进制表示"))
+ self.label_2.setText(_translate("Dialog", "float值"))
+ self.radioButton.setText(_translate("Dialog", "单精度(32位)"))
+ self.radioButton_2.setText(_translate("Dialog", "双精度(64位)"))
diff --git a/zhuan.ui b/zhuan.ui
new file mode 100644
index 0000000..230039e
--- /dev/null
+++ b/zhuan.ui
@@ -0,0 +1,88 @@
+
+
+ Dialog
+
+
+
+ 0
+ 0
+ 461
+ 84
+
+
+
+ IEEE754转换工具
+
+
+
+
+ 10
+ 35
+ 446
+ 23
+
+
+
+ -
+
+
-
+
+
+ 16进制表示
+
+
+
+ -
+
+
+
+
+ -
+
+
-
+
+
+ float值
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+ 10
+ 10
+ 216
+ 18
+
+
+
+ -
+
+
+ 单精度(32位)
+
+
+ true
+
+
+
+ -
+
+
+ 双精度(64位)
+
+
+
+
+
+
+
+
+
diff --git a/提交github的shell.py b/提交github的shell.py
new file mode 100644
index 0000000..97534aa
--- /dev/null
+++ b/提交github的shell.py
@@ -0,0 +1,7 @@
+#os.system(command)
+import os,time
+comment = input('请输入提交的标记名称:')
+os.system("git add .")
+os.system(f"git commit -m {comment}")
+os.system("git push origin main --force")
+os.system("pause")
\ No newline at end of file
diff --git a/版本记录.md b/版本记录.md
new file mode 100644
index 0000000..b2fce45
--- /dev/null
+++ b/版本记录.md
@@ -0,0 +1,11 @@
+Ŀǰ汾V0.12
+Ŀǰ汾V0.13 -UIļĵֲԪתתIEEE754
+Ŀǰ汾V0.14 -ļʶ
+Ŀǰ汾V0.14 - 3 -汾һҪ
+Ŀǰ汾V0.15
+Ŀǰ汾V0.16
+Ŀǰ汾V0.17-fpgaĵ
+Ŀǰ汾V0.18-fpga¼ת˵⣡
+Ŀǰ汾V0.19 - ķɼ¼ƥʶ/ϰ汾CPU¼->˵Ϊ°汾
+Ŀǰ汾V0.19.1 - ŻCPU¼TO˵
+
diff --git a/生成的说明文档.docx b/生成的说明文档.docx
new file mode 100644
index 0000000..25f77b3
Binary files /dev/null and b/生成的说明文档.docx differ