上传初版
This commit is contained in:
@@ -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())
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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",
|
||||
@@ -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 初始化完成")
|
||||
|
||||
|
||||
@@ -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>
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user