def excepthook(exc_type, exc_value, exc_tb): """Отправляем на почту баг-репорт """ error_text = "".join( traceback.format_exception(exc_type, exc_value, exc_tb)) logging.error(error_text) if main_window.parametres['bug_report'] == 'True': msg = MIMEMultipart() msg['From'] = '*****@*****.**' msg['To'] = '*****@*****.**' msg['Subject'] = 'Ошибка в программе u_sonic_pro' body = error_text show_message( 'Неизвестная ошибка', f'Информация отправлена разработчику.\nПодробности:\n {body}.', ) msg.attach(MIMEText(body, 'plain')) server = smtplib.SMTP('bti.secna.ru', 25) server.send_message(msg) server.quit() else: show_message( 'Ошибка', f'{error_text}', ) QtWidgets.QApplication.quit()
def execute_write_query(self, data, columns): """Вносим данные в БД PostgreSQL. Args: data (list): Список данных. columns (list): Список колонок таблицы, в которые необходимо внести данные. """ connection = self.__connection data_records = ", ".join(["%s"] * len(data)) insert_query = ( f"INSERT INTO base_table ({columns}) VALUES ({data_records})" ) connection.autocommit = True cursor = connection.cursor() try: cursor.execute(insert_query, data) except Exception as e: show_message( 'Ошибка загрузки данных', f'При попытке загрузки данных обнаружена ошибка: {e}', ) else: show_message( 'Данные загружены на сервер', 'Данные успешно загружены в базу данных сервера.' ) connection.close()
def menu_click_print_screen(self): """Печать главного окна программы по нажатию пункта главного меню. """ if self.db.check() is False: return show_message( 'Ошибка печати', 'Данные для печати отсутствуют.', ) image = self.tabWidget.grab() image_widget = QLabel(self) image_widget.setPixmap(image) image_widget.resize(image.width(), image.height()) printer = QtPrintSupport.QPrinter( QtPrintSupport.QPrinter.HighResolution) dialog = QtPrintSupport.QPrintDialog(printer, self) if dialog.exec_() != QDialog.Accepted: return try: painter = QtGui.QPainter(printer) image_widget.render(painter) painter.end() show_message( 'Печать...', 'Файл отправлен на печать.', ) except Exception as e: show_message( 'Ошибка печати', f'Не удалось напечатать файл: {e}.', )
def btn_click_cancel_com(self): """Обрабатываем нажатие кнопки отмены передачи данных от COM-порта. Закрываем дополнительнй вычислительный поток. Делаем соответствующие виджеты доступными. """ self.COM_port.set_thread_stop(True) show_message( 'Отмена передачи данных', 'Передача данных от COM-порта прервана.', )
def execute_update_query(self, date, column, data): connection = self.__connection data_record = ", ".join(["%s"] * len(data)) update_query = ( f"UPDATE base_table SET {column} = '{data}' WHERE date='{date}'" ) connection.autocommit = True cursor = connection.cursor() try: cursor.execute(update_query, data_record) except OperationalError as e: show_message( 'Ошибка загрузки данных', f'При попытке загрузки данных обнаружена ошибка: {e}', ) connection.close()
def execute_delete_query(self, query): """Метод для удаления записей из таблицы Args: query (string): Запрос. """ connection = self.__connection connection.autocommit = True cursor = connection.cursor() try: cursor.execute(query) except OperationalError as e: show_message( 'Ошибка удаления данных', f'При попытке удаления данных обнаружена ошибка: {e}', )
def btn_click_update_com(self): """Обновляем элементы графического интерфейса в зависимости от наличия доступных COM-портов по нажатию на кнопку 'Обновить'. """ list_com_ports = self.COM_port.ports if list_com_ports: self.comboBox_com.clear() self.comboBox_com.addItems(list_com_ports) self.comboBox_com.setCurrentIndex(len(list_com_ports) - 1) self.set_objects_enabled(True) else: self.set_objects_enabled(False) show_message( 'COM-порт не найден', 'Нет доступных для работы COM-портов.', )
def init_settings(self, settings_file): """Загружаем параметры из файла настроек и применяем их к программе. Args: settings_file (string): Имя файла настроек. """ self.parametres = {} # Словарь с настройками if os.path.exists(settings_file): config = ConfigObj(settings_file, encoding='utf8') self.parametres['Creal'] = config['Creal'] self.parametres['Show_RLC'] = config['Show_RLC'] self.parametres['Start_freq'] = config['Start_freq'] self.parametres['Interval_freq'] = config['Interval_freq'] self.parametres['Step_freq'] = config['Step_freq'] self.parametres['db_name'] = config['db_name'] self.parametres['db_user'] = config['db_user'] self.parametres['db_password'] = config['db_password'] self.parametres['db_host'] = config['db_host'] self.parametres['db_port'] = config['db_port'] self.parametres['bug_report'] = config['bug_report'] self.parametres['operator'] = config['operator'] device_number = config['device_number'] device_main_model = config['device_main_model'] device_submodel_1 = config['device_submodel_1'] device_freq = config['device_freq'] device_submodel_2 = config['device_submodel_2'] self.lineEdit_1.setText(device_number) self.comboBox_2.setCurrentText(device_main_model) self.comboBox_3.setCurrentText(device_submodel_1) self.comboBox_4.setCurrentText(device_freq) self.comboBox_5.setCurrentText(device_submodel_2) Start_freq = int(self.parametres['Start_freq']) Interval_freq = int(self.parametres['Interval_freq']) Step_freq = str(self.parametres['Step_freq']) self.spin_start_freq.setValue(Start_freq) self.spin_freq_interval.setValue(Interval_freq) self.comboBox_6.setCurrentText(Step_freq) else: show_message( 'Ошибка - файл конфигурации не найден', 'Проверьте наличие файла конфигурации ' '(settings.ini) в корневой папке программы.', )
def menu_click_save_as_image(self): """Сохраняем содержимое виджета в файл .png по нажатию пункта меню. """ if self.db.check(): index = self.tabWidget.currentIndex() record_name = self.tabWidget.tabText(index) caption = 'img_' + record_name + '.png' outpath = '.\\data\\' + caption fname = QtWidgets.QFileDialog.getSaveFileName( self, 'Назовите файл', outpath, '*.png')[0] if fname != '': grab = self.tabWidget.grab() grab.save(fname, 'png') else: show_message( 'Нет данных для сохранения', 'Данные для сохранения в .png файл отсутствуют.', )
def menu_click_compare_phase(self): """Метод, вызываемый при активации меню сравнения данных. Открывает новую вкладку TabWidget особого класса и помещает на нее графики из всех открытых ранее записей. """ if self.db.length > 1: tab = pt.PlotTabCompare( creal=self.parametres['Creal'], database=self.db, mode='phase', ) self.tabWidget.addTab(tab.widget, 'Сравнение данных') self.tabWidget.setCurrentIndex(self.tabWidget.count() - 1) else: show_message( 'Недостаточно данных для сравнения', 'В программе должно быть открыто минимум 2 записи ' 'для сравнения.', )
def __connection(self): """Создаем соединение с сервером БД PostgreSQL. Returns: psycopg2.connect: Соединение с сервером. """ connection = None try: connection = psycopg2.connect( database=self.__settings['db_name'], user=self.__settings['db_user'], password=self.__settings['db_password'], host=self.__settings['db_host'], port=self.__settings['db_port']) except OperationalError as e: show_message( 'Ошибка соединения с SQL сервером', f'При попытке соединения с сервером обнаружена ошибка: {e}', ) return connection
def execute_read_query(self, query): """Считываем данные из БД по SQL запросу. Args: query (string): SQL запрос. Returns: tuple: Кортеж из данных. """ connection = self.__connection if not connection: show_message( 'SQL сервер не отвечает', 'Сервер базы данных не подает признаков жизни.', ) return None cursor = connection.cursor() result = None try: cursor.execute(query) result = cursor.fetchall() return result except OperationalError as e: show_message( 'Ошибка чтения данных', f'При попытке чтения данных обнаружена ошибка: {e}', ) except psycopg2.errors.UndefinedTable: show_message( 'Некорретный формат БД', 'SQL сервер, к которому подключена программа ' 'имеет БД другого формата.', ) finally: connection.close()
def menu_click_load_csv_file(self): """Загрузка данных из файла формата ".csv" при нажатии на соответствующую кнопку меню. """ outpath = '.\\data' file_list = QtWidgets.QFileDialog.getOpenFileNames( self, 'Выберите файл', outpath, '*.csv')[0] for file_name in file_list: file_split = file_name.split('/')[-1] file_split = file_split.split('.')[-2] temp = file_split.split('_') try: year_part = temp[0] hour_part = temp[1] if len(year_part) > 8 or len(hour_part) > 6: raise ValueError temp = int(year_part) + int(hour_part) file_split = f'{year_part}_{hour_part}' if file_name != '' and not self.db.check(file_split): record = rc.Record(file_split) record.date = file_split with open(file_name, encoding='utf-8') as read_f: file_reader = csv.reader(read_f, delimiter=';') for row in file_reader: record.set_row_to_dict(row) self.db += record except ValueError: show_message( 'Ошибка - некорректное название файла', 'Файл должен быть назван в формате Ymd_HMS.', ) except IndexError: show_message( 'Ошибка - неверный формат файла', f'{file_split} имеет неверный формат.', )