上传初版

This commit is contained in:
2026-07-10 13:35:16 +08:00
parent 38610e97eb
commit 4c5fc718c1
21 changed files with 855 additions and 593 deletions
+14 -20
View File
@@ -1,25 +1,19 @@
"""main.py - MIL SDK 测试示例"""
from pathlib import Path
from src.core import (
setup_logging,
read_excel_data,
read_excel_case,
create_excel_case,
update_case_excel,
)
from main_ui import Ui_MainWindow
from PySide6.QtWidgets import QApplication, QMainWindow
import sys
from qt_material import apply_stylesheet
def main() -> None:
"""MIL SDK 示例程序主函数"""
setup_logging()
class MainWindow(QMainWindow,Ui_MainWindow):
def __init__(self):
super().__init__()
self.setupUi(self)
excel_path = Path(__file__).parent
data_dict = read_excel_data("new_data.xlsx", return_object=False)
old_data_dict = read_excel_data("old_data.xlsx", return_object=False)
update_case_excel("new_case.xlsx", old_data_dict, data_dict)
apply_stylesheet(self, style=None,theme='dark_teal.xml')
if __name__ == "__main__":
main()
if __name__ == '__main__':
app = QApplication(sys.argv)
main: MainWindow = MainWindow()
main.show()
sys.exit(app.exec())
+52
View File
@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="FrameMILTool" name="frame">
<property name="frameShape">
<enum>QFrame::Shape::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Shadow::Raised</enum>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>21</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<customwidgets>
<customwidget>
<class>FrameMILTool</class>
<extends>QFrame</extends>
<header>src.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
+56
View File
@@ -0,0 +1,56 @@
# -*- coding: utf-8 -*-
################################################################################
## Form generated from reading UI file 'main.ui'
##
## Created by: Qt User Interface Compiler version 6.11.1
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################
from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
QMetaObject, QObject, QPoint, QRect,
QSize, QTime, QUrl, Qt)
from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
QFont, QFontDatabase, QGradient, QIcon,
QImage, QKeySequence, QLinearGradient, QPainter,
QPalette, QPixmap, QRadialGradient, QTransform)
from PySide6.QtWidgets import (QApplication, QFrame, QGridLayout, QMainWindow,
QMenuBar, QSizePolicy, QStatusBar, QWidget)
from mil import FrameMILTool
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
if not MainWindow.objectName():
MainWindow.setObjectName(u"MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QWidget(MainWindow)
self.centralwidget.setObjectName(u"centralwidget")
self.gridLayout = QGridLayout(self.centralwidget)
self.gridLayout.setObjectName(u"gridLayout")
self.frame = FrameMILTool(self.centralwidget)
self.frame.setObjectName(u"frame")
self.frame.setFrameShape(QFrame.Shape.StyledPanel)
self.frame.setFrameShadow(QFrame.Shadow.Raised)
self.gridLayout.addWidget(self.frame, 0, 0, 1, 1)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QMenuBar(MainWindow)
self.menubar.setObjectName(u"menubar")
self.menubar.setGeometry(QRect(0, 0, 800, 21))
MainWindow.setMenuBar(self.menubar)
self.statusbar = QStatusBar(MainWindow)
self.statusbar.setObjectName(u"statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QMetaObject.connectSlotsByName(MainWindow)
# setupUi
def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"MainWindow", None))
# retranslateUi
+27
View File
@@ -0,0 +1,27 @@
# This file was generated by Nuitka
# Stubs included by default
from openpyxl import Workbook
from ui.mil_tool import FrameMILTool
def create_mil_tool(parent: typing.Any) -> typing.Any:
...
__name__ = ...
# Modules used internally, to allow implicit dependencies to be seen:
import os
import openpyxl
import logging
import dataclasses
import typing
import copy
import openpyxl.worksheet
import openpyxl.worksheet.worksheet
import _frozen_importlib_external
import PySide6
import PySide6.QtWidgets
import PySide6.QtCore
import PySide6.QtGui
+5
View File
@@ -0,0 +1,5 @@
from .ui.mil_tool import FrameMILTool
from openpyxl import Workbook
def create_mil_tool(parent=None):
return FrameMILTool(parent)
@@ -3,9 +3,8 @@
提供 MIL 仿真数据读取功能
使用示例:
from src.core import setup_logging, read_excel_data
from src.core import read_excel_data
setup_logging()
result = read_excel_data("simulation.xlsx")
"""
import logging
@@ -23,7 +22,6 @@ from .exceptions import (
CaseDataError,
ExcelWriteError,
)
from .logging_config import setup_logging, get_logger
__all__ = [
"DataLog",
+17
View File
@@ -0,0 +1,17 @@
import logging
from .mil_tool_ui import Ui_FrameMILTool
from PySide6.QtWidgets import QFrame
logger = logging.getLogger(__name__)
class FrameMILTool(QFrame,Ui_FrameMILTool):
def __init__(self,parent=None):
super().__init__(parent)
self.setupUi(self)
def init_ui(self):
pass
# logger.info("FrameMILTool 初始化完成")
+367
View File
@@ -0,0 +1,367 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>FrameMILTool</class>
<widget class="QFrame" name="FrameMILTool">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>706</width>
<height>308</height>
</rect>
</property>
<property name="windowTitle">
<string>Frame</string>
</property>
<layout class="QGridLayout" name="gridLayout_8">
<item row="0" column="0">
<widget class="QTabWidget" name="tabWidget">
<property name="tabPosition">
<enum>QTabWidget::TabPosition::South</enum>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="widget">
<attribute name="title">
<string>功能面板</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_12">
<item row="0" column="0">
<widget class="QFrame" name="frame_3">
<property name="frameShape">
<enum>QFrame::Shape::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Shadow::Raised</enum>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>项目</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="comboBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(255, 255, 255);</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="2">
<widget class="QLineEdit" name="FilePath">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(255, 255, 255);</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLineEdit" name="DataPath">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(255, 255, 255);</string>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QPushButton" name="FileButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QCheckBox" name="checkBox">
<property name="text">
<string>累计时间</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QRadioButton" name="radioButtonFile">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="QPushButton" name="pushButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>生成</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_3">
<property name="text">
<string>测试用例 </string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_2">
<property name="text">
<string>数据文件 </string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QPushButton" name="DataButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QRadioButton" name="radioButtonData">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item row="1" column="0">
<widget class="QFrame" name="frame">
<property name="frameShape">
<enum>QFrame::Shape::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Shadow::Raised</enum>
</property>
<layout class="QGridLayout" name="gridLayout_6">
<item row="0" column="0">
<layout class="QGridLayout" name="gridLayout_5">
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>名称</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="lineEdit"/>
</item>
<item row="0" column="2">
<widget class="QLabel" name="label_7">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>名称</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QLineEdit" name="lineEdit_4"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_5">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>类型</string>
</property>
</widget>
</item>
<item row="1" column="1" rowspan="2">
<widget class="QLineEdit" name="lineEdit_2"/>
</item>
<item row="1" column="2">
<widget class="QLabel" name="label_8">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>类型</string>
</property>
</widget>
</item>
<item row="1" column="3" rowspan="2">
<widget class="QLineEdit" name="lineEdit_5"/>
</item>
<item row="2" column="0" rowspan="2">
<widget class="QLabel" name="label_6">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>值定义</string>
</property>
</widget>
</item>
<item row="2" column="2" rowspan="2">
<widget class="QLabel" name="label_9">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>值定义</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="lineEdit_3"/>
</item>
<item row="3" column="3">
<widget class="QLineEdit" name="lineEdit_6"/>
</item>
</layout>
</item>
<item row="1" column="0">
<layout class="QGridLayout" name="gridLayout_10">
<item row="0" column="0">
<widget class="QPushButton" name="pushButton_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>加载测试用例</string>
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QPushButton" name="pushButton_4">
<property name="text">
<string>删除</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="pushButton_5">
<property name="text">
<string>查找</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QPushButton" name="pushButton_3">
<property name="text">
<string>替换</string>
</property>
</widget>
</item>
<item row="0" column="5">
<widget class="QPushButton" name="UpdateButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>更新</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item row="2" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_2">
<attribute name="title">
<string>项目列表</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_11">
<item row="0" column="0">
<widget class="QListWidget" name="listWidget"/>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
+316
View File
@@ -0,0 +1,316 @@
# -*- coding: utf-8 -*-
################################################################################
## Form generated from reading UI file 'mil_tool.ui'
##
## Created by: Qt User Interface Compiler version 6.11.1
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################
from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
QMetaObject, QObject, QPoint, QRect,
QSize, QTime, QUrl, Qt)
from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
QFont, QFontDatabase, QGradient, QIcon,
QImage, QKeySequence, QLinearGradient, QPainter,
QPalette, QPixmap, QRadialGradient, QTransform)
from PySide6.QtWidgets import (QApplication, QCheckBox, QComboBox, QFrame,
QGridLayout, QLabel, QLineEdit, QListWidget,
QListWidgetItem, QPushButton, QRadioButton, QSizePolicy,
QSpacerItem, QTabWidget, QWidget)
class Ui_FrameMILTool(object):
def setupUi(self, FrameMILTool):
if not FrameMILTool.objectName():
FrameMILTool.setObjectName(u"FrameMILTool")
FrameMILTool.resize(706, 308)
self.gridLayout_8 = QGridLayout(FrameMILTool)
self.gridLayout_8.setObjectName(u"gridLayout_8")
self.tabWidget = QTabWidget(FrameMILTool)
self.tabWidget.setObjectName(u"tabWidget")
self.tabWidget.setTabPosition(QTabWidget.TabPosition.South)
self.widget = QWidget()
self.widget.setObjectName(u"widget")
self.gridLayout_12 = QGridLayout(self.widget)
self.gridLayout_12.setObjectName(u"gridLayout_12")
self.frame_3 = QFrame(self.widget)
self.frame_3.setObjectName(u"frame_3")
self.frame_3.setFrameShape(QFrame.Shape.StyledPanel)
self.frame_3.setFrameShadow(QFrame.Shadow.Raised)
self.gridLayout_3 = QGridLayout(self.frame_3)
self.gridLayout_3.setObjectName(u"gridLayout_3")
self.gridLayout_2 = QGridLayout()
self.gridLayout_2.setObjectName(u"gridLayout_2")
self.label = QLabel(self.frame_3)
self.label.setObjectName(u"label")
self.gridLayout_2.addWidget(self.label, 0, 0, 1, 1)
self.comboBox = QComboBox(self.frame_3)
self.comboBox.setObjectName(u"comboBox")
sizePolicy = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.comboBox.sizePolicy().hasHeightForWidth())
self.comboBox.setSizePolicy(sizePolicy)
self.comboBox.setStyleSheet(u"color: rgb(255, 255, 255);")
self.gridLayout_2.addWidget(self.comboBox, 0, 1, 1, 1)
self.gridLayout_3.addLayout(self.gridLayout_2, 0, 0, 1, 1)
self.gridLayout = QGridLayout()
self.gridLayout.setObjectName(u"gridLayout")
self.FilePath = QLineEdit(self.frame_3)
self.FilePath.setObjectName(u"FilePath")
sizePolicy1 = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred)
sizePolicy1.setHorizontalStretch(0)
sizePolicy1.setVerticalStretch(0)
sizePolicy1.setHeightForWidth(self.FilePath.sizePolicy().hasHeightForWidth())
self.FilePath.setSizePolicy(sizePolicy1)
self.FilePath.setStyleSheet(u"color: rgb(255, 255, 255);")
self.gridLayout.addWidget(self.FilePath, 1, 2, 1, 1)
self.DataPath = QLineEdit(self.frame_3)
self.DataPath.setObjectName(u"DataPath")
sizePolicy1.setHeightForWidth(self.DataPath.sizePolicy().hasHeightForWidth())
self.DataPath.setSizePolicy(sizePolicy1)
self.DataPath.setStyleSheet(u"color: rgb(255, 255, 255);")
self.gridLayout.addWidget(self.DataPath, 0, 2, 1, 1)
self.FileButton = QPushButton(self.frame_3)
self.FileButton.setObjectName(u"FileButton")
sizePolicy2 = QSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Preferred)
sizePolicy2.setHorizontalStretch(0)
sizePolicy2.setVerticalStretch(0)
sizePolicy2.setHeightForWidth(self.FileButton.sizePolicy().hasHeightForWidth())
self.FileButton.setSizePolicy(sizePolicy2)
self.gridLayout.addWidget(self.FileButton, 1, 3, 1, 1)
self.checkBox = QCheckBox(self.frame_3)
self.checkBox.setObjectName(u"checkBox")
self.gridLayout.addWidget(self.checkBox, 0, 4, 1, 1)
self.radioButtonFile = QRadioButton(self.frame_3)
self.radioButtonFile.setObjectName(u"radioButtonFile")
self.gridLayout.addWidget(self.radioButtonFile, 1, 0, 1, 1)
self.pushButton = QPushButton(self.frame_3)
self.pushButton.setObjectName(u"pushButton")
sizePolicy2.setHeightForWidth(self.pushButton.sizePolicy().hasHeightForWidth())
self.pushButton.setSizePolicy(sizePolicy2)
self.gridLayout.addWidget(self.pushButton, 1, 4, 1, 1)
self.label_3 = QLabel(self.frame_3)
self.label_3.setObjectName(u"label_3")
self.gridLayout.addWidget(self.label_3, 1, 1, 1, 1)
self.label_2 = QLabel(self.frame_3)
self.label_2.setObjectName(u"label_2")
self.gridLayout.addWidget(self.label_2, 0, 1, 1, 1)
self.DataButton = QPushButton(self.frame_3)
self.DataButton.setObjectName(u"DataButton")
sizePolicy2.setHeightForWidth(self.DataButton.sizePolicy().hasHeightForWidth())
self.DataButton.setSizePolicy(sizePolicy2)
self.gridLayout.addWidget(self.DataButton, 0, 3, 1, 1)
self.radioButtonData = QRadioButton(self.frame_3)
self.radioButtonData.setObjectName(u"radioButtonData")
self.radioButtonData.setChecked(True)
self.gridLayout.addWidget(self.radioButtonData, 0, 0, 1, 1)
self.gridLayout_3.addLayout(self.gridLayout, 1, 0, 1, 1)
self.gridLayout_12.addWidget(self.frame_3, 0, 0, 1, 1)
self.frame = QFrame(self.widget)
self.frame.setObjectName(u"frame")
self.frame.setFrameShape(QFrame.Shape.StyledPanel)
self.frame.setFrameShadow(QFrame.Shadow.Raised)
self.gridLayout_6 = QGridLayout(self.frame)
self.gridLayout_6.setObjectName(u"gridLayout_6")
self.gridLayout_5 = QGridLayout()
self.gridLayout_5.setObjectName(u"gridLayout_5")
self.label_4 = QLabel(self.frame)
self.label_4.setObjectName(u"label_4")
sizePolicy3 = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Expanding)
sizePolicy3.setHorizontalStretch(0)
sizePolicy3.setVerticalStretch(0)
sizePolicy3.setHeightForWidth(self.label_4.sizePolicy().hasHeightForWidth())
self.label_4.setSizePolicy(sizePolicy3)
self.gridLayout_5.addWidget(self.label_4, 0, 0, 1, 1)
self.lineEdit = QLineEdit(self.frame)
self.lineEdit.setObjectName(u"lineEdit")
self.gridLayout_5.addWidget(self.lineEdit, 0, 1, 1, 1)
self.label_7 = QLabel(self.frame)
self.label_7.setObjectName(u"label_7")
sizePolicy3.setHeightForWidth(self.label_7.sizePolicy().hasHeightForWidth())
self.label_7.setSizePolicy(sizePolicy3)
self.gridLayout_5.addWidget(self.label_7, 0, 2, 1, 1)
self.lineEdit_4 = QLineEdit(self.frame)
self.lineEdit_4.setObjectName(u"lineEdit_4")
self.gridLayout_5.addWidget(self.lineEdit_4, 0, 3, 1, 1)
self.label_5 = QLabel(self.frame)
self.label_5.setObjectName(u"label_5")
sizePolicy3.setHeightForWidth(self.label_5.sizePolicy().hasHeightForWidth())
self.label_5.setSizePolicy(sizePolicy3)
self.gridLayout_5.addWidget(self.label_5, 1, 0, 1, 1)
self.lineEdit_2 = QLineEdit(self.frame)
self.lineEdit_2.setObjectName(u"lineEdit_2")
self.gridLayout_5.addWidget(self.lineEdit_2, 1, 1, 2, 1)
self.label_8 = QLabel(self.frame)
self.label_8.setObjectName(u"label_8")
sizePolicy3.setHeightForWidth(self.label_8.sizePolicy().hasHeightForWidth())
self.label_8.setSizePolicy(sizePolicy3)
self.gridLayout_5.addWidget(self.label_8, 1, 2, 1, 1)
self.lineEdit_5 = QLineEdit(self.frame)
self.lineEdit_5.setObjectName(u"lineEdit_5")
self.gridLayout_5.addWidget(self.lineEdit_5, 1, 3, 2, 1)
self.label_6 = QLabel(self.frame)
self.label_6.setObjectName(u"label_6")
sizePolicy3.setHeightForWidth(self.label_6.sizePolicy().hasHeightForWidth())
self.label_6.setSizePolicy(sizePolicy3)
self.gridLayout_5.addWidget(self.label_6, 2, 0, 2, 1)
self.label_9 = QLabel(self.frame)
self.label_9.setObjectName(u"label_9")
sizePolicy3.setHeightForWidth(self.label_9.sizePolicy().hasHeightForWidth())
self.label_9.setSizePolicy(sizePolicy3)
self.gridLayout_5.addWidget(self.label_9, 2, 2, 2, 1)
self.lineEdit_3 = QLineEdit(self.frame)
self.lineEdit_3.setObjectName(u"lineEdit_3")
self.gridLayout_5.addWidget(self.lineEdit_3, 3, 1, 1, 1)
self.lineEdit_6 = QLineEdit(self.frame)
self.lineEdit_6.setObjectName(u"lineEdit_6")
self.gridLayout_5.addWidget(self.lineEdit_6, 3, 3, 1, 1)
self.gridLayout_6.addLayout(self.gridLayout_5, 0, 0, 1, 1)
self.gridLayout_10 = QGridLayout()
self.gridLayout_10.setObjectName(u"gridLayout_10")
self.pushButton_2 = QPushButton(self.frame)
self.pushButton_2.setObjectName(u"pushButton_2")
sizePolicy.setHeightForWidth(self.pushButton_2.sizePolicy().hasHeightForWidth())
self.pushButton_2.setSizePolicy(sizePolicy)
self.gridLayout_10.addWidget(self.pushButton_2, 0, 0, 1, 1)
self.pushButton_4 = QPushButton(self.frame)
self.pushButton_4.setObjectName(u"pushButton_4")
self.gridLayout_10.addWidget(self.pushButton_4, 0, 4, 1, 1)
self.pushButton_5 = QPushButton(self.frame)
self.pushButton_5.setObjectName(u"pushButton_5")
self.gridLayout_10.addWidget(self.pushButton_5, 0, 2, 1, 1)
self.pushButton_3 = QPushButton(self.frame)
self.pushButton_3.setObjectName(u"pushButton_3")
self.gridLayout_10.addWidget(self.pushButton_3, 0, 3, 1, 1)
self.UpdateButton = QPushButton(self.frame)
self.UpdateButton.setObjectName(u"UpdateButton")
sizePolicy2.setHeightForWidth(self.UpdateButton.sizePolicy().hasHeightForWidth())
self.UpdateButton.setSizePolicy(sizePolicy2)
self.gridLayout_10.addWidget(self.UpdateButton, 0, 5, 1, 1)
self.gridLayout_6.addLayout(self.gridLayout_10, 1, 0, 1, 1)
self.gridLayout_12.addWidget(self.frame, 1, 0, 1, 1)
self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
self.gridLayout_12.addItem(self.verticalSpacer, 2, 0, 1, 1)
self.tabWidget.addTab(self.widget, "")
self.tab_2 = QWidget()
self.tab_2.setObjectName(u"tab_2")
self.gridLayout_11 = QGridLayout(self.tab_2)
self.gridLayout_11.setObjectName(u"gridLayout_11")
self.listWidget = QListWidget(self.tab_2)
self.listWidget.setObjectName(u"listWidget")
self.gridLayout_11.addWidget(self.listWidget, 0, 0, 1, 1)
self.tabWidget.addTab(self.tab_2, "")
self.gridLayout_8.addWidget(self.tabWidget, 0, 0, 1, 1)
self.retranslateUi(FrameMILTool)
self.tabWidget.setCurrentIndex(0)
QMetaObject.connectSlotsByName(FrameMILTool)
# setupUi
def retranslateUi(self, FrameMILTool):
FrameMILTool.setWindowTitle(QCoreApplication.translate("FrameMILTool", u"Frame", None))
self.label.setText(QCoreApplication.translate("FrameMILTool", u"\u9879\u76ee", None))
self.FileButton.setText(QCoreApplication.translate("FrameMILTool", u"...", None))
self.checkBox.setText(QCoreApplication.translate("FrameMILTool", u"\u7d2f\u8ba1\u65f6\u95f4", None))
self.radioButtonFile.setText("")
self.pushButton.setText(QCoreApplication.translate("FrameMILTool", u"\u751f\u6210", None))
self.label_3.setText(QCoreApplication.translate("FrameMILTool", u"\u6d4b\u8bd5\u7528\u4f8b ", None))
self.label_2.setText(QCoreApplication.translate("FrameMILTool", u"\u6570\u636e\u6587\u4ef6 ", None))
self.DataButton.setText(QCoreApplication.translate("FrameMILTool", u"...", None))
self.radioButtonData.setText("")
self.label_4.setText(QCoreApplication.translate("FrameMILTool", u"\u540d\u79f0", None))
self.label_7.setText(QCoreApplication.translate("FrameMILTool", u"\u540d\u79f0", None))
self.label_5.setText(QCoreApplication.translate("FrameMILTool", u"\u7c7b\u578b", None))
self.label_8.setText(QCoreApplication.translate("FrameMILTool", u"\u7c7b\u578b", None))
self.label_6.setText(QCoreApplication.translate("FrameMILTool", u"\u503c\u5b9a\u4e49", None))
self.label_9.setText(QCoreApplication.translate("FrameMILTool", u"\u503c\u5b9a\u4e49", None))
self.pushButton_2.setText(QCoreApplication.translate("FrameMILTool", u"\u52a0\u8f7d\u6d4b\u8bd5\u7528\u4f8b", None))
self.pushButton_4.setText(QCoreApplication.translate("FrameMILTool", u"\u5220\u9664", None))
self.pushButton_5.setText(QCoreApplication.translate("FrameMILTool", u"\u67e5\u627e", None))
self.pushButton_3.setText(QCoreApplication.translate("FrameMILTool", u"\u66ff\u6362", None))
self.UpdateButton.setText(QCoreApplication.translate("FrameMILTool", u"\u66f4\u65b0", None))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.widget), QCoreApplication.translate("FrameMILTool", u"\u529f\u80fd\u9762\u677f", None))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), QCoreApplication.translate("FrameMILTool", u"\u9879\u76ee\u5217\u8868", None))
# retranslateUi
-61
View File
@@ -1,61 +0,0 @@
"""日志配置模块"""
import logging
import sys
from pathlib import Path
from typing import Literal
def setup_logging(
level: Literal["DEBUG", "INFO", "WARNING", "ERROR"] = "INFO",
log_file: str | Path | None = "logs/mil_sdk.log",
console_output: bool = True,
) -> logging.Logger:
"""配置日志系统
Args:
level: 日志级别,默认 INFO
log_file: 日志文件路径,默认 logs/mil_sdk.log。设为 None 则不写入文件
console_output: 是否输出到控制台,默认 True
Returns:
根日志记录器
"""
logger = logging.getLogger()
logger.setLevel(level)
if logger.hasHandlers():
logger.handlers.clear()
formatter = logging.Formatter(
"%(asctime)s [%(levelname)s] %(message)s",
datefmt="%Y-%m-%d %H:%M:%S"
)
if log_file is not None:
log_path = Path(log_file)
log_path.parent.mkdir(parents=True, exist_ok=True)
file_handler = logging.FileHandler(log_path, encoding="utf-8")
file_handler.setLevel(logging.DEBUG)
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
if console_output:
console_handler = logging.StreamHandler(sys.stdout)
console_handler.setLevel(level)
console_handler.setFormatter(formatter)
logger.addHandler(console_handler)
return logger
def get_logger(name: str) -> logging.Logger:
"""获取指定名称的日志记录器
Args:
name: 日志记录器名称,通常使用 __name__
Returns:
日志记录器实例
"""
return logging.getLogger(name)
View File
-47
View File
@@ -1,47 +0,0 @@
import pytest
from pathlib import Path
from openpyxl import Workbook
@pytest.fixture
def sample_excel_path() -> Path:
"""返回根目录下的 sample.xlsx 路径"""
path = Path(__file__).parent.parent / "sample.xlsx"
if not path.exists():
pytest.skip(f"测试文件 {path} 不存在")
return path
@pytest.fixture
def invalid_excel_path(tmp_path: Path) -> Path:
"""创建缺少 Scenario1 表的无效 Excel 文件"""
wb = Workbook()
wb.save(tmp_path / "invalid.xlsx")
return tmp_path / "invalid.xlsx"
@pytest.fixture
def sample_data_dict() -> dict:
"""返回示例数据字典"""
return {
"Scenario1": {
"headers": ["Column1", "Column2", "Column3"],
"rows": [
["Value1", "Value2", "Value3"],
["Value4", "Value5", "Value6"]
]
}
}
@pytest.fixture
def sample_sheets_dict() -> dict:
"""返回示例工作表字典"""
return {
"Scenario1": {
"A1": "Header1",
"B1": "Header2",
"A2": "Data1",
"B2": "Data2"
}
}
-20
View File
@@ -1,20 +0,0 @@
import pytest
from src.core.base import DataLog
def test_datalog_defaults():
log = DataLog()
assert log.time == 0.0
assert log.value == ""
def test_datalog_with_values():
log = DataLog(time=1.5, value="test")
assert log.time == 1.5
assert log.value == "test"
def test_datalog_equality():
log1 = DataLog(time=1.0, value="a")
log2 = DataLog(time=1.0, value="a")
assert log1 == log2
-292
View File
@@ -1,292 +0,0 @@
import pytest
from pathlib import Path
from openpyxl import Workbook
from src.core.mil_read_case_excel import (
read_excel_case,
_get_template_version,
_analysis_action,
)
from src.core.mil_create_data_excel import (
create_excel_case,
_init_data_log,
_analysis_case,
_analysis_step,
)
from src.core.exceptions import ExcelReadError, ExcelFormatError, CaseDataError
from src.core.base import DataLog
@pytest.fixture
def sample_data_dict():
"""返回示例数据字典"""
return {
"signal1": {
"type": "Type1",
"column": 2,
"datalog": [DataLog(0.0, "initial"), DataLog(1.0, "value1")]
},
"signal2": {
"type": "Type2",
"column": 3,
"datalog": [DataLog(0.0, "init2"), DataLog(1.0, "value2")]
}
}
@pytest.fixture
def sample_sheets_dict():
"""返回示例工作表字典"""
return {
"TestSheet": {
"TestCase1": {
"enable": False,
"step": {
"step0": {
"name": "Step1",
"time": 1.0,
"action": {"signal1": "new_value1"}
},
"step1": {
"name": "Step2",
"time": 2.0,
"action": {"signal2": "new_value2"}
}
}
},
"TestCase2": {
"enable": True,
"step": {}
}
}
}
def test_get_template_version():
"""验证获取模板版本号"""
wb = Workbook()
sheet = wb.active
sheet.cell(2, 1, "v1.0.0")
sheet.cell(3, 1, None)
version = _get_template_version(sheet)
assert version == "v1.0.0"
def test_get_template_version_empty():
"""验证空工作表的版本号"""
wb = Workbook()
sheet = wb.active
version = _get_template_version(sheet)
assert version is None
def test_analysis_action_valid(sample_data_dict):
"""验证解析有效操作字符串"""
wb = Workbook()
sheet = wb.create_sheet("TestSheet")
sheet.cell(1, 1, "Test")
action = _analysis_action(sheet, 1, 3, "signal1=newvalue", sample_data_dict, "test.xlsx")
assert "signal1" in action
assert action["signal1"] == "newvalue"
def test_analysis_action_multiple(sample_data_dict):
"""验证解析多个操作"""
wb = Workbook()
sheet = wb.create_sheet("TestSheet")
sheet.cell(1, 1, "Test")
action = _analysis_action(sheet, 1, 3, "signal1=v1; signal2=v2", sample_data_dict, "test.xlsx")
assert "signal1" in action
assert "signal2" in action
assert action["signal1"] == "v1"
assert action["signal2"] == "v2"
def test_analysis_action_invalid_signal(sample_data_dict):
"""验证解析无效信号时抛出异常"""
wb = Workbook()
sheet = wb.create_sheet("TestSheet")
sheet.cell(1, 1, "Test")
with pytest.raises(CaseDataError, match="信号 .* 不存在"):
_analysis_action(sheet, 1, 3, "invalid_signal=value", sample_data_dict, "test.xlsx")
def test_init_data_log(sample_data_dict):
"""验证初始化数据日志"""
data_copy = {k: v.copy() for k, v in sample_data_dict.items()}
for name in data_copy:
data_copy[name]["datalog"] = data_copy[name]["datalog"].copy()
_init_data_log(data_copy)
for name in data_copy:
assert len(data_copy[name]["datalog"]) == 1
assert data_copy[name]["datalog"][0].time == 0.0
def test_analysis_step_with_action(sample_data_dict):
"""验证分析带操作的步骤"""
step_dict = {
"step0": {
"name": "TestStep",
"time": 1.5,
"action": {"signal1": "newvalue"}
}
}
data_copy = {k: v.copy() for k, v in sample_data_dict.items()}
for name in data_copy:
data_copy[name]["datalog"] = data_copy[name]["datalog"].copy()
_analysis_step(step_dict, data_copy)
assert len(data_copy["signal1"]["datalog"]) == 3
assert data_copy["signal1"]["datalog"][-1].time == 1.5
assert data_copy["signal1"]["datalog"][-1].value == "newvalue"
def test_analysis_step_without_action(sample_data_dict):
"""验证分析不带操作的步骤"""
step_dict = {
"step0": {
"name": "TestStep",
"time": 1.0
}
}
data_copy = {k: v.copy() for k, v in sample_data_dict.items()}
for name in data_copy:
data_copy[name]["datalog"] = data_copy[name]["datalog"].copy()
initial_length = len(data_copy["signal1"]["datalog"])
_analysis_step(step_dict, data_copy)
assert len(data_copy["signal1"]["datalog"]) == initial_length + 1
def test_analysis_case(sample_data_dict, sample_sheets_dict):
"""验证用例分析"""
result = _analysis_case(sample_data_dict, sample_sheets_dict)
assert "TestCase1" in result
assert "TestCase2" not in result
def test_analysis_case_skips_enabled_cases(sample_data_dict):
"""验证跳过早启用的用例"""
sheets_dict = {
"TestSheet": {
"EnabledCase": {
"enable": True,
"step": {}
}
}
}
result = _analysis_case(sample_data_dict, sheets_dict)
assert "EnabledCase" not in result
def test_read_excel_case_file_not_found():
"""验证文件不存在时抛出异常"""
with pytest.raises(ExcelReadError, match="不存在"):
read_excel_case("nonexistent.xlsx", {}, False)
def test_read_excel_case_missing_atech_sheet(tmp_path: Path):
"""验证缺少 Atech-Hefei 表时抛出异常"""
wb = Workbook()
wb.create_sheet("OtherSheet")
invalid_path = tmp_path / "invalid.xlsx"
wb.save(invalid_path)
with pytest.raises(ExcelFormatError, match="缺少 Atech-Hefei 表"):
read_excel_case(invalid_path, {}, False)
def test_read_excel_case_missing_version(tmp_path: Path, sample_data_dict):
"""验证缺少版本号时抛出异常"""
wb = Workbook()
wb.create_sheet("Atech-Hefei")
wb.create_sheet("TestSheet")
invalid_path = tmp_path / "no_version.xlsx"
wb.save(invalid_path)
with pytest.raises(ExcelFormatError, match="缺少模板版本号"):
read_excel_case(invalid_path, sample_data_dict, False)
def test_read_excel_case_success(tmp_path: Path, sample_data_dict):
"""验证成功读取用例模板"""
wb = Workbook()
wb.remove(wb.active)
version_sheet = wb.create_sheet("Atech-Hefei")
version_sheet.cell(2, 1, "v1.0.0")
test_sheet = wb.create_sheet("TestSheet")
test_sheet.cell(2, 1, "TestCase1")
test_sheet.cell(2, 2, "未完成")
test_sheet.cell(2, 3, None)
test_sheet.cell(2, 4, "Step1")
test_sheet.cell(2, 5, 1.0)
test_sheet.cell(2, 6, None)
test_sheet.cell(3, 1, "TestCase1")
test_sheet.cell(3, 2, "未完成")
test_sheet.cell(3, 3, None)
test_sheet.cell(3, 4, "Step2")
test_sheet.cell(3, 5, 2.0)
test_sheet.cell(3, 6, None)
valid_path = tmp_path / "valid.xlsx"
wb.save(valid_path)
result = read_excel_case(valid_path, sample_data_dict, False)
assert "TestSheet" in result
assert "TestCase1" in result["TestSheet"]
def test_read_excel_case_missing_title(tmp_path: Path, sample_data_dict):
"""验证缺少标题时抛出异常"""
wb = Workbook()
version_sheet = wb.create_sheet("Atech-Hefei")
version_sheet.cell(2, 1, "v1.0.0")
test_sheet = wb.create_sheet("TestSheet")
test_sheet.cell(2, 1, None)
invalid_path = tmp_path / "missing_title.xlsx"
wb.save(invalid_path)
with pytest.raises(CaseDataError, match="必须有标题名"):
read_excel_case(invalid_path, sample_data_dict, False)
def test_read_excel_case_invalid_time(tmp_path: Path, sample_data_dict):
"""验证时间格式错误时抛出异常"""
wb = Workbook()
wb.remove(wb.active)
version_sheet = wb.create_sheet("Atech-Hefei")
version_sheet.cell(2, 1, "v1.0.0")
test_sheet = wb.create_sheet("TestSheet")
test_sheet.cell(2, 1, "TestCase1")
test_sheet.cell(2, 2, "未完成")
test_sheet.cell(2, 4, "Step1")
test_sheet.cell(2, 5, "invalid_time")
test_sheet.cell(2, 6, None)
invalid_path = tmp_path / "invalid_time.xlsx"
wb.save(invalid_path)
with pytest.raises(CaseDataError, match="时间必须是数字"):
read_excel_case(invalid_path, sample_data_dict, False)
-150
View File
@@ -1,150 +0,0 @@
import pytest
from pathlib import Path
from openpyxl import Workbook
from src.core.mil_read_data_excel import read_excel_data, ExcelReaderConfig
from src.core.exceptions import ExcelReadError, ExcelFormatError
def test_read_excel_data_returns_required_keys(sample_excel_path: Path):
"""验证返回结果包含必需键"""
result = read_excel_data(sample_excel_path)
assert "wb" in result
assert "sheet" in result
assert "source_row" in result
def test_read_excel_data_contains_signals(sample_excel_path: Path):
"""验证能解析出信号数据"""
result = read_excel_data(sample_excel_path)
signal_keys = [k for k in result.keys() if k not in ("wb", "sheet", "source_row")]
assert len(signal_keys) > 0, "应至少包含一个信号"
for name in signal_keys:
assert "type" in result[name]
assert "column" in result[name]
assert "datalog" in result[name]
def test_read_excel_file_not_found():
"""文件不存在时抛出 ExcelReadError"""
with pytest.raises(ExcelReadError, match="不存在"):
read_excel_data("nonexistent.xlsx")
def test_read_excel_missing_sheet(tmp_path: Path):
"""缺少 Scenario1 表时抛出 ExcelFormatError"""
wb = Workbook()
wb.create_sheet("WrongSheet")
invalid_path = tmp_path / "invalid.xlsx"
wb.save(invalid_path)
with pytest.raises(ExcelFormatError, match="缺少"):
read_excel_data(invalid_path)
def test_read_excel_missing_source_header(tmp_path: Path):
"""缺少 Source: Input 标记时抛出 ExcelFormatError"""
wb = Workbook()
sheet = wb.active
sheet.title = ExcelReaderConfig().sheet_name
sheet.cell(1, 1, "time")
sheet.cell(1, 2, "signal1")
invalid_path = tmp_path / "missing_header.xlsx"
wb.save(invalid_path)
with pytest.raises(ExcelFormatError, match="缺少"):
read_excel_data(invalid_path)
def test_datalog_is_list(sample_excel_path: Path):
"""验证 datalog 是 DataLog 对象列表"""
result = read_excel_data(sample_excel_path)
signal_keys = [k for k in result.keys() if k not in ("wb", "sheet", "source_row")]
assert len(signal_keys) > 0
first_signal = result[signal_keys[0]]
assert len(first_signal["datalog"]) > 0
assert hasattr(first_signal["datalog"][0], "time")
assert hasattr(first_signal["datalog"][0], "value")
def test_read_excel_data_return_object(sample_excel_path: Path):
"""验证 return_object=True 时返回 ExcelDataResult 对象"""
from src.core.base import ExcelDataResult, SignalData
result = read_excel_data(sample_excel_path, return_object=True)
assert isinstance(result, ExcelDataResult)
assert result.sheet_name == "Scenario1"
assert result.source_row > 0
assert len(result.signals) > 0
def test_read_excel_data_signal_data_access(sample_excel_path: Path):
"""验证 ExcelDataResult 的信号访问方法"""
from src.core.base import SignalData
result = read_excel_data(sample_excel_path, return_object=True)
signal_names = result.get_signal_names()
assert len(signal_names) > 0
first_signal_name = signal_names[0]
signal = result.get_signal(first_signal_name)
assert isinstance(signal, SignalData)
assert signal.datalog is not None
def test_excel_reader_config_defaults():
"""验证 ExcelReaderConfig 默认值"""
config = ExcelReaderConfig()
assert config.sheet_name == "Scenario1"
assert config.source_header == "Source: Input"
assert config.time_column == 1
assert config.header_row == 1
assert config.type_row == 3
assert config.data_start_row_offset == 1
def test_excel_reader_config_custom():
"""验证 ExcelReaderConfig 自定义值"""
config = ExcelReaderConfig(
sheet_name="CustomSheet",
source_header="CustomHeader",
time_column=2,
header_row=2,
type_row=4,
data_start_row_offset=2
)
assert config.sheet_name == "CustomSheet"
assert config.source_header == "CustomHeader"
assert config.time_column == 2
assert config.header_row == 2
assert config.type_row == 4
assert config.data_start_row_offset == 2
def test_read_excel_with_custom_config(tmp_path: Path):
"""验证使用自定义配置读取 Excel"""
wb = Workbook()
sheet = wb.active
sheet.title = "CustomSheet"
sheet.cell(1, 1, "time")
sheet.cell(1, 2, "signal1")
sheet.cell(2, 1, "CustomHeader")
sheet.cell(2, 2, "CustomHeader")
sheet.cell(3, 1, "Type1")
sheet.cell(4, 1, 0.0)
sheet.cell(4, 2, "value1")
sheet.cell(5, 1, 1.0)
sheet.cell(5, 2, "value2")
custom_path = tmp_path / "custom.xlsx"
wb.save(custom_path)
config = ExcelReaderConfig(
sheet_name="CustomSheet",
source_header="CustomHeader"
)
result = read_excel_data(custom_path, return_object=True, config=config)
assert result.sheet_name == "CustomSheet"
assert "signal1" in result.signals