diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 88034e6..005dcb8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,12 +18,16 @@ repos: - id: licenseheaders args: ["-t", ".copyright.tmpl", "-cy", "-f", "-d", "statapp"] pass_filenames: false -- repo: https://github.com/pylint-dev/pylint.git - rev: v2.17.5 +- repo: local hooks: - id: pylint + name: pylint + entry: pylint + language: system + types: [python] args: [ "-rn", # Only display messages "-sn", # Don't display the score + "--rcfile=.pylintrc", ] diff --git a/statapp/__main__.py b/statapp/__main__.py index 476045d..b106134 100644 --- a/statapp/__main__.py +++ b/statapp/__main__.py @@ -31,7 +31,7 @@ def main(): translator = QtCore.QTranslator(app) locale = QtCore.QLocale.system().name() path = QtCore.QLibraryInfo.location(QtCore.QLibraryInfo.TranslationsPath) - translator.load('qt_%s' % locale, path) + translator.load(f'qt_{locale}', path) app.installTranslator(translator) window = MainWindow() diff --git a/statapp/about_window.py b/statapp/about_window.py index bb95aad..1b5d14c 100644 --- a/statapp/about_window.py +++ b/statapp/about_window.py @@ -19,12 +19,11 @@ # import sys -from PySide2.QtCore import QSize -from PySide2.QtGui import QMovie, QIcon +from PySide2.QtGui import QMovie from PySide2.QtWidgets import QMainWindow from statapp.ui.ui_about_window import Ui_AboutWindow -from statapp.utils import resource_path +from statapp.utils import resourcePath, addIcon if sys.version_info < (3, 8): import importlib_metadata @@ -40,8 +39,8 @@ class AboutWindow(QMainWindow): self.ui = Ui_AboutWindow() self.ui.setupUi(self) - image_path = resource_path('ui/images/sticker.gif') - movie = QMovie(image_path) + gifPath = resourcePath('ui/images/sticker.gif') + movie = QMovie(gifPath) self.ui.labelgif.setMovie(movie) movie.start() self.movie = movie @@ -50,6 +49,4 @@ class AboutWindow(QMainWindow): version = importlib_metadata.version(__package__ or __name__) self.ui.versionLabel.setText(f"Версия: {version}") - icon = QIcon() - icon.addFile(resource_path("ui/images/logo.ico"), QSize(), QIcon.Normal, QIcon.Off) - self.setWindowIcon(icon) + addIcon(self) diff --git a/statapp/calculations.py b/statapp/calculations.py index 1ac339e..871fafb 100644 --- a/statapp/calculations.py +++ b/statapp/calculations.py @@ -24,16 +24,16 @@ DIRECT_LINK = 0 INDIRECT_LINK = 1 -def generate_x_values(mean, std, typeConnection, y): - yMean = np.mean(y) +def generateXValues(mean, std, typeConnection, yColumn): + yMean = np.mean(yColumn) values = [] - for cur_y in y: + for y in yColumn: raz = np.abs(mean - np.random.normal(mean, std)) if typeConnection == INDIRECT_LINK: raz *= -1 - if cur_y > yMean: + if y > yMean: x = mean + raz - elif cur_y < yMean: + elif y < yMean: x = mean - raz else: x = mean @@ -41,11 +41,11 @@ def generate_x_values(mean, std, typeConnection, y): return np.array(values) -def variance_analysis(data): +def varianceAnalysis(data): return np.array([ [np.mean(col), np.std(col), np.min(col), np.max(col)] for col in data.T ]) -def correlation_analysis(data): +def correlationAnalysis(data): return pd.DataFrame(data).corr().to_numpy() diff --git a/statapp/correlation_analysis.py b/statapp/correlation_analysis.py index 45ad7f0..8e80920 100644 --- a/statapp/correlation_analysis.py +++ b/statapp/correlation_analysis.py @@ -21,24 +21,24 @@ from PySide2.QtCore import QSize from PySide2.QtGui import QIcon from PySide2.QtWidgets import QDialog, QHeaderView -from statapp.calculations import correlation_analysis +from statapp.calculations import correlationAnalysis from statapp.models.correlation_analysis_model import CorrelationAnalysisModel from statapp.ui.ui_correlation_analysis_window import Ui_CorrelationAnalysisWindow -from statapp.utils import resource_path +from statapp.utils import resourcePath -class СorrelationAnalysisWindow(QDialog): +class CorrelationAnalysisWindow(QDialog): def __init__(self, data): super().__init__() self.ui = Ui_CorrelationAnalysisWindow() self.ui.setupUi(self) - res = correlation_analysis(data) + res = correlationAnalysis(data) self.model = CorrelationAnalysisModel(res.round(2)) self.ui.tableView.setModel(self.model) header = self.ui.tableView.horizontalHeader() header.setSectionResizeMode(QHeaderView.ResizeMode.Stretch) icon = QIcon() - icon.addFile(resource_path("ui/images/logo.ico"), QSize(), QIcon.Normal, QIcon.Off) + icon.addFile(resourcePath("ui/images/logo.ico"), QSize(), QIcon.Normal, QIcon.Off) self.setWindowIcon(icon) diff --git a/statapp/generate_factor_window.py b/statapp/generate_factor_window.py index bab3d8f..dbb488f 100644 --- a/statapp/generate_factor_window.py +++ b/statapp/generate_factor_window.py @@ -17,13 +17,12 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . # -from PySide2.QtCore import Slot, QSize -from PySide2.QtGui import QIcon +from PySide2.QtCore import Slot from PySide2.QtWidgets import QDialog from statapp.ui.ui_generate_factor_window import Ui_GenerateFactorWindow from statapp.models.combobox_model import ComboBoxModel -from statapp.utils import resource_path +from statapp.utils import addIcon DIRECT_LINK = 0 INDIRECT_LINK = 1 @@ -44,9 +43,7 @@ class GenerateFactorWindow(QDialog): self.ui.setupUi(self) self.ui.typeComboBox.setModel(self._typeComboBox) - icon = QIcon() - icon.addFile(resource_path("ui/images/logo.ico"), QSize(), QIcon.Normal, QIcon.Off) - self.setWindowIcon(icon) + addIcon(self) @Slot() def on_generatePushButton_clicked(self): diff --git a/statapp/generate_window.py b/statapp/generate_window.py index 0449bd6..b3c8cfd 100644 --- a/statapp/generate_window.py +++ b/statapp/generate_window.py @@ -17,12 +17,11 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . # -from PySide2.QtCore import Slot, QSize -from PySide2.QtGui import QIcon +from PySide2.QtCore import Slot from PySide2.QtWidgets import QDialog from statapp.ui.ui_generate_window import Ui_GenerateWindow -from statapp.utils import resource_path +from statapp.utils import addIcon class GenerateWindow(QDialog): @@ -34,9 +33,7 @@ class GenerateWindow(QDialog): self.ui = Ui_GenerateWindow() self.ui.setupUi(self) - icon = QIcon() - icon.addFile(resource_path("ui/images/logo.ico"), QSize(), QIcon.Normal, QIcon.Off) - self.setWindowIcon(icon) + addIcon(self) @Slot() diff --git a/statapp/main_window.py b/statapp/main_window.py index fddc529..eb6172d 100644 --- a/statapp/main_window.py +++ b/statapp/main_window.py @@ -18,20 +18,19 @@ # along with this program. If not, see . # import numpy as np -from PySide2.QtCore import Slot, QSize -from PySide2.QtGui import QIcon -from PySide2.QtWidgets import QMainWindow, QMessageBox, QAction +from PySide2.QtCore import Slot +from PySide2.QtWidgets import QMainWindow, QMessageBox -from statapp.calculations import generate_x_values +from statapp.calculations import generateXValues from statapp.generate_factor_window import GenerateFactorWindow from statapp.models.input_values_model import InputValuesModel from statapp.generate_window import GenerateWindow from statapp.about_window import AboutWindow from statapp.models.fileslc_model import FileSLCModel from statapp.ui.ui_main_window import Ui_MainWindow -from statapp.utils import resource_path, buildMessageBox +from statapp.utils import buildMessageBox, addIcon from statapp.variance_analysis import VarianceAnalysisWindow -from statapp.correlation_analysis import СorrelationAnalysisWindow +from statapp.correlation_analysis import CorrelationAnalysisWindow class MainWindow(QMainWindow): @@ -41,14 +40,14 @@ class MainWindow(QMainWindow): self.ui = Ui_MainWindow() self.ui.setupUi(self) - icon = QIcon() - icon.addFile(resource_path("ui/images/logo.ico"), QSize(), QIcon.Normal, QIcon.Off) - self.setWindowIcon(icon) + addIcon(self) self.ui.generateXaction.setEnabled(False) self.ui.varianceAnalysisAction.setEnabled(False) self.ui.correlationAnalisisAction.setEnabled(False) + self.aboutWindow = None + self.isDataChanged = False self.model = InputValuesModel() self.fileModel = FileSLCModel() @@ -56,12 +55,12 @@ class MainWindow(QMainWindow): @Slot() def on_openfileaction_triggered(self): - current_data = self.model.getData() + currentData = self.model.getData() data = np.array([]) - if current_data.size > 1: + if currentData.size > 1: file = '' - if self.fileModel.file_name: - file = '\nФайл сохранения: ' + self.fileModel.file_name + if self.fileModel.fileName: + file = '\nФайл сохранения: ' + self.fileModel.fileName msgBox = buildMessageBox \ ('Сохранение данных', @@ -125,10 +124,9 @@ class MainWindow(QMainWindow): if gfw.exec(): data = self.model.getData() y = self.model.getY() - x_arr = generate_x_values(gfw.mat, gfw.deviation, gfw.typeConnection, y) - x_arr = x_arr.reshape(len(x_arr), 1).round(2) - # dd = dd.reshape(len(dd), 1) - data = np.concatenate((data, x_arr), axis=1) + xValues = generateXValues(gfw.mat, gfw.deviation, gfw.typeConnection, y) + xValues = xValues.reshape(len(xValues), 1).round(2) + data = np.concatenate((data, xValues), axis=1) self.model.updateAllData(data) self.ui.varianceAnalysisAction.setEnabled(True) self.ui.correlationAnalisisAction.setEnabled(True) @@ -136,9 +134,8 @@ class MainWindow(QMainWindow): @Slot() def on_aboutmenuaction_triggered(self): - global about_window - about_window = AboutWindow() - about_window.show() + self.aboutWindow = AboutWindow() + self.aboutWindow.show() @Slot() def on_varianceAnalysisAction_triggered(self): @@ -147,14 +144,14 @@ class MainWindow(QMainWindow): @Slot() def on_correlationAnalisisAction_triggered(self): - dw = СorrelationAnalysisWindow(self.model.getData()) + dw = CorrelationAnalysisWindow(self.model.getData()) dw.exec() def closeEvent(self, event): if self.isDataChanged: file = '' - if self.fileModel.file_name: - file = '\nФайл сохранения: ' + self.fileModel.file_name + if self.fileModel.fileName: + file = '\nФайл сохранения: ' + self.fileModel.fileName msgBox = buildMessageBox \ ('Завершение работы', diff --git a/statapp/models/correlation_analysis_model.py b/statapp/models/correlation_analysis_model.py index 9b287ff..582789d 100644 --- a/statapp/models/correlation_analysis_model.py +++ b/statapp/models/correlation_analysis_model.py @@ -20,7 +20,7 @@ from PySide2.QtCore import QModelIndex, Qt from statapp.models.ro_table_model import ROTableModel -from statapp.models.utils import yx_header +from statapp.models.utils import yxHeader class CorrelationAnalysisModel(ROTableModel): @@ -28,15 +28,12 @@ class CorrelationAnalysisModel(ROTableModel): super().__init__(data) def getHorizontalHeader(self): - return yx_header(self.columnCount(QModelIndex())) + return yxHeader(self.columnCount(QModelIndex())) def getVerticalHeader(self): - return yx_header(self.rowCount(QModelIndex())) + return yxHeader(self.rowCount(QModelIndex())) def data(self, index, role): - if role == Qt.DisplayRole: - if (index.column() <= index.row()): - return float(self._data[index.row(), index.column()]) - else: - None + if role == Qt.DisplayRole and index.column() <= index.row(): + return super().data(index, role) return None diff --git a/statapp/models/editable_table_model.py b/statapp/models/editable_table_model.py index 115fbbc..335f3d3 100644 --- a/statapp/models/editable_table_model.py +++ b/statapp/models/editable_table_model.py @@ -43,7 +43,7 @@ class EditableTableModel(ROTableModel): return False def data(self, index, role): - if role == Qt.DisplayRole or role == Qt.EditRole: - return float(self._data[index.row(), index.column()]) + if role in (Qt.DisplayRole, Qt.EditRole): + return super().data(index, Qt.DisplayRole) return None diff --git a/statapp/models/fileslc_model.py b/statapp/models/fileslc_model.py index 33a3c18..23c7679 100644 --- a/statapp/models/fileslc_model.py +++ b/statapp/models/fileslc_model.py @@ -24,30 +24,35 @@ from PySide2.QtWidgets import QFileDialog, QMessageBox class FileSLCModel: def __init__(self): super().__init__() - self.file_name = None + self.fileName = None def saveFile(self, data): - if not self.file_name: - self.file_name, _ = QFileDialog.getSaveFileName(None, "Сохранить файл", "", "Text Files (*.txt);;CSV Files (*.csv)") - if self.file_name: - np.savetxt(self.file_name, data, delimiter=",") + if not self.fileName: + self.fileName, _ = QFileDialog.getSaveFileName( + None, "Сохранить файл", "", "Text Files (*.txt);;CSV Files (*.csv)" + ) + if self.fileName: + np.savetxt(self.fileName, data, delimiter=",") return True return False def loadFile(self): - self.file_name, _ = QFileDialog.getOpenFileName(None, "Загрузить файл", "", "Files (*.txt *.csv)") - if self.file_name: + self.fileName, _ = QFileDialog.getOpenFileName( + None, "Загрузить файл", "", "Files (*.txt *.csv)" + ) + if self.fileName: try: - content = np.genfromtxt(self.file_name, delimiter=',', invalid_raise=True, ndmin=2) - except ValueError as e: + content = np.genfromtxt(self.fileName, delimiter=',', invalid_raise=True, ndmin=2) + except ValueError: QMessageBox.warning \ (None, 'Ошибка', "Ошибка чтения файла!\nФайл нельзя открыть или файл неверного формата") - self.file_name = None + self.fileName = None return None return content + return None + def closeFile(self): - self.file_name = None - pass + self.fileName = None diff --git a/statapp/models/input_values_model.py b/statapp/models/input_values_model.py index c257852..0b0de4c 100644 --- a/statapp/models/input_values_model.py +++ b/statapp/models/input_values_model.py @@ -18,10 +18,10 @@ # along with this program. If not, see . # import numpy as np -from PySide2.QtCore import Qt, QModelIndex +from PySide2.QtCore import QModelIndex from statapp.models.editable_table_model import EditableTableModel -from statapp.models.utils import yx_header +from statapp.models.utils import yxHeader class InputValuesModel(EditableTableModel): @@ -29,7 +29,7 @@ class InputValuesModel(EditableTableModel): super().__init__(data) def getHorizontalHeader(self): - return yx_header(self.columnCount(QModelIndex())) + return yxHeader(self.columnCount(QModelIndex())) def getY(self): return self._data[:, 0] diff --git a/statapp/models/ro_table_model.py b/statapp/models/ro_table_model.py index 6386295..6e138b5 100644 --- a/statapp/models/ro_table_model.py +++ b/statapp/models/ro_table_model.py @@ -17,12 +17,11 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . # -import PySide2 import numpy as np from PySide2 import QtCore from PySide2.QtCore import Qt -from statapp.utils import safe_list_get +from statapp.utils import safeListGet class ROTableModel(QtCore.QAbstractTableModel): @@ -55,7 +54,7 @@ class ROTableModel(QtCore.QAbstractTableModel): def headerData(self, section: int, orientation: Qt.Orientation, role: int = ...): if role == Qt.DisplayRole: - return safe_list_get(self._headers[orientation](), section, None) + return safeListGet(self._headers[orientation](), section, None) return None diff --git a/statapp/models/utils.py b/statapp/models/utils.py index beb310b..7d8f9ec 100644 --- a/statapp/models/utils.py +++ b/statapp/models/utils.py @@ -17,5 +17,5 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . # -def yx_header(count): +def yxHeader(count): return ['Y'] + [f'X{i}' for i in range(1, count)] diff --git a/statapp/models/variance_analysis_model.py b/statapp/models/variance_analysis_model.py index baed769..08ba1df 100644 --- a/statapp/models/variance_analysis_model.py +++ b/statapp/models/variance_analysis_model.py @@ -20,7 +20,7 @@ from PySide2.QtCore import QModelIndex from statapp.models.ro_table_model import ROTableModel -from statapp.models.utils import yx_header +from statapp.models.utils import yxHeader class VarianceAnalysisModel(ROTableModel): @@ -31,4 +31,4 @@ class VarianceAnalysisModel(ROTableModel): return ['Мат. ожидание', 'Среднекв. отклонение', 'Минимум', 'Максимум'] def getVerticalHeader(self): - return yx_header(self.rowCount(QModelIndex())) + return yxHeader(self.rowCount(QModelIndex())) diff --git a/statapp/utils.py b/statapp/utils.py index 7a90aa5..c4f019f 100644 --- a/statapp/utils.py +++ b/statapp/utils.py @@ -20,21 +20,28 @@ import os import sys +from PySide2.QtCore import QSize +from PySide2.QtGui import QIcon from PySide2.QtWidgets import QMessageBox -def resource_path(relative): +def resourcePath(relative): if getattr(sys, 'frozen', False): - bundle_dir = sys._MEIPASS + # pylint: disable=protected-access + bundleDir = sys._MEIPASS else: # we are running in a normal Python environment - bundle_dir = os.path.dirname(os.path.abspath(__file__)) - return os.path.join(bundle_dir, relative) + bundleDir = os.path.dirname(os.path.abspath(__file__)) + return os.path.join(bundleDir, relative) +def addIcon(windowOrDialog): + icon = QIcon() + icon.addFile(resourcePath("ui/images/logo.ico"), QSize(), QIcon.Normal, QIcon.Off) + windowOrDialog.setWindowIcon(icon) -def safe_list_get(l, idx, default): +def safeListGet(lst, idx, default): try: - return l[idx] + return lst[idx] except IndexError: return default diff --git a/statapp/variance_analysis.py b/statapp/variance_analysis.py index 0cbab8b..0209049 100644 --- a/statapp/variance_analysis.py +++ b/statapp/variance_analysis.py @@ -17,14 +17,12 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . # -from PySide2.QtCore import QSize -from PySide2.QtGui import QIcon from PySide2.QtWidgets import QDialog, QHeaderView -from statapp.calculations import variance_analysis +from statapp.calculations import varianceAnalysis from statapp.models.variance_analysis_model import VarianceAnalysisModel from statapp.ui.ui_variance_analysis_window import Ui_VarianceAnalysisWindow -from statapp.utils import resource_path +from statapp.utils import addIcon class VarianceAnalysisWindow(QDialog): @@ -33,12 +31,10 @@ class VarianceAnalysisWindow(QDialog): self.ui = Ui_VarianceAnalysisWindow() self.ui.setupUi(self) - res = variance_analysis(data) + res = varianceAnalysis(data) self.model = VarianceAnalysisModel(res.round(2)) self.ui.tableView.setModel(self.model) header = self.ui.tableView.horizontalHeader() header.setSectionResizeMode(QHeaderView.ResizeMode.Stretch) - icon = QIcon() - icon.addFile(resource_path("ui/images/logo.ico"), QSize(), QIcon.Normal, QIcon.Off) - self.setWindowIcon(icon) + addIcon(self)