From 48d97bc764b1ef5efc79103f9cead01d0bba7e81 Mon Sep 17 00:00:00 2001 From: Jan Feil <11638228+jfeil@users.noreply.github.com> Date: Fri, 4 Mar 2022 20:41:12 +0100 Subject: [PATCH] Clean code, solve warnings and sort everything --- src/basic_config.py | 11 +++++---- src/controller.py | 7 ++---- src/datatypes.py | 8 +++++-- src/document_builder.py | 1 + src/main_application.py | 13 ++++++----- src/question_table.py | 49 ++++++++++++++++++----------------------- src/regeltestcreator.py | 20 +++++++++++------ 7 files changed, 57 insertions(+), 52 deletions(-) diff --git a/src/basic_config.py b/src/basic_config.py index 479b95c..025ccee 100644 --- a/src/basic_config.py +++ b/src/basic_config.py @@ -35,11 +35,15 @@ database_name = "database.db" +class EagerDefault: + def __init__(self, value: Any): + self.value = value + + def check_for_update() -> Tuple[VERSION_INFO, VERSION_INFO]: # new_version, description, url, download_url def check(cur_version, release_info): if version.parse(release_info['tag_name']) <= cur_version: return None - download_url = None fileendings = {'Darwin': ['.app', '.zip'], 'Windows': ['.exe'], 'Linux': []} @@ -68,11 +72,6 @@ def check(cur_version, release_info): # Source: https://variable-scope.com/posts/setting-eager-defaults-for-sqlalchemy-orm-models -class EagerDefault: - def __init__(self, value: Any): - self.value = value - - def defaults_included_constructor(instance, **kwds): mapper = inspect(instance).mapper for column in mapper.columns: diff --git a/src/controller.py b/src/controller.py index 3363013..3fa20f8 100644 --- a/src/controller.py +++ b/src/controller.py @@ -27,10 +27,6 @@ def populate_tabwidget(mainwindow: MainWindow): mainwindow.create_ruletabs(db.get_rulegroups()) -def populate_questions(mainwindow: MainWindow): - mainwindow.initialize_questions() - - def update_question_set(question: Question, mchoice: List[MultipleChoice]) -> Signature: return db.update_question_set(question, mchoice) @@ -60,7 +56,8 @@ def get_rulegroup_config() -> List[Tuple[Rulegroup, int, int]]: rulegroups = db.get_rulegroups() return [(rulegroup, db.get_questions_by_foreignkey(rulegroup_id=rulegroup.id, mchoice=False).count(), - db.get_questions_by_foreignkey(rulegroup_id=rulegroup.id, mchoice=True).count()) for rulegroup in rulegroups] + db.get_questions_by_foreignkey(rulegroup_id=rulegroup.id, mchoice=True).count()) for rulegroup in + rulegroups] def fill_database(dataset): diff --git a/src/datatypes.py b/src/datatypes.py index 9c08d1e..3267af0 100644 --- a/src/datatypes.py +++ b/src/datatypes.py @@ -114,6 +114,7 @@ class Question(Base): 'signature': "Signatur" } + # noinspection PyTypeChecker def table_checkbox(self, dict_key): return defaultdict(lambda: None, { 'multiple_choice': 2 * (self.answer_index != -1) @@ -132,6 +133,7 @@ def table_value(self, dict_key): 'signature': self.signature }[dict_key] + # noinspection PyTypeChecker def table_tooltip(self, dict_key): return defaultdict(lambda: None, { 'question': self.question, @@ -145,8 +147,10 @@ def export(self) -> Tuple[str, str]: answer_text = self.answer_text return (f"\n\n{self.group_id:02d}{self.rule_id:03d}\n\n\n{self.question}\n" f"\n\n", - f"\n\n{answer_text}\n\n\n{self.created.strftime('%d.%m.%Y')}\n\n\n" - f"{self.last_edited.strftime('%d.%m.%Y')}\n\n\n{self.signature}\n\n\n") + f"\n\n{answer_text}\n\n\n{self.created.strftime('%d.%m.%Y')}\n" + f"\n\n " + f"{self.last_edited.strftime('%d.%m.%Y')}\n\n\n{self.signature}\n\n" + f"\n") def __repr__(self): return f"Question(text={self.question!r}, answer={self.answer_index!r}:{self.answer_text!r}" \ diff --git a/src/document_builder.py b/src/document_builder.py index b722304..a815be8 100644 --- a/src/document_builder.py +++ b/src/document_builder.py @@ -81,6 +81,7 @@ def answer_letter(index): if self.answer_index == -1: self.height_answer = [max(self.lines_answer, min_lines) * linespacing] else: + # noinspection PyTypeChecker self.height_answer = [ max(len(simpleSplit(a, fontName, fontSize, ratio_answer * self.width)) * linespacing, 1.1 * radio_size) for a in self.mchoice] diff --git a/src/main_application.py b/src/main_application.py index 6918233..1fa3b13 100644 --- a/src/main_application.py +++ b/src/main_application.py @@ -89,8 +89,8 @@ def __init__(self, parent=None): super().__init__(parent) self.ui = Ui_MainWindow() self.ui.setupUi(self) - self.setWindowTitle(QCoreApplication.translate("MainWindow", f"{display_name} - {app_version}" - , None)) + # noinspection PyTypeChecker + self.setWindowTitle(QCoreApplication.translate("MainWindow", f"{display_name} - {app_version}", None)) self.ui.actionRegeldatensatz_einladen.triggered.connect(self.load_dataset) self.ui.actionAuf_Updates_pr_fen.triggered.connect(lambda: display_update_dialog(self, check_for_update())) self.ui.action_ber.triggered.connect(about_dialog) @@ -171,6 +171,8 @@ def create_ruletabs(self, rulegroups: List[Rulegroup]): self.ruletabs[rulegroup.id] = (filter_model, model) self.ui.tabWidget.addTab(tab, "") self.ui.tabWidget.setTabText(self.ui.tabWidget.indexOf(tab), f"{rulegroup.id:02d} {rulegroup.name}") + # self.filter_column(3, 'FaD') + # self.filter_column(3, 'VW') def setup_regeltest(self): regeltest_setup = RegeltestSetup(self) @@ -195,8 +197,8 @@ def create_regeltest(self): output_path = settings.ui.output_edit.text() if result: QApplication.setOverrideCursor(Qt.WaitCursor) - document_builder.create_document(question_set, output_path, settings.ui.title_edit.text() - , icon_path=settings.ui.icon_path_edit.text()) + document_builder.create_document(question_set, output_path, settings.ui.title_edit.text(), + icon_path=settings.ui.icon_path_edit.text()) QApplication.restoreOverrideCursor() webbrowser.open_new(output_path) @@ -230,5 +232,6 @@ def display(self): else: download_link = 'Noch kein Download für die aktuelle Plattform verfügbar.
' \ 'Bitte versuche es später erneut.' + release_notes = markdown2.markdown(release[1]).replace("h3>", "h4>").replace("h2>", "h3>").replace("h1>", "h2>") self.ui.text.setText(f'

Update {release[0]} verfügbar!

' - f'{markdown2.markdown(release[1]).replace("h3>", "h4>").replace("h2>", "h3>").replace("h1>", "h2>")}{download_link}') + f'{release_notes}{download_link}') diff --git a/src/question_table.py b/src/question_table.py index 290d4ae..a441c41 100644 --- a/src/question_table.py +++ b/src/question_table.py @@ -3,34 +3,17 @@ import PySide6 from PySide6.QtCore import Qt, QPoint, QAbstractTableModel, QSortFilterProxyModel from PySide6.QtGui import QAction, QDrag, QShortcut, QKeySequence -from PySide6.QtWidgets import QTreeWidget, QVBoxLayout, QDialog, QMessageBox, QMenu, QListView, \ - QTableView, QStyledItemDelegate, QWidget +from PySide6.QtWidgets import QTreeWidget, QVBoxLayout, QDialog, QMessageBox, QMenu, QListView, QTableView, \ + QStyledItemDelegate, QWidget from src import controller from src.datatypes import Question from src.question_editor import QuestionEditor -class RuleDelegate(QStyledItemDelegate): - def createEditor(self, parent: PySide6.QtWidgets.QWidget, option: PySide6.QtWidgets.QStyleOptionViewItem, - index: Union[ - PySide6.QtCore.QModelIndex, PySide6.QtCore.QPersistentModelIndex]) -> PySide6.QtWidgets.QWidget: - editor = QWidget(parent) - question = index.model().data(index, role=Qt.UserRole) - dialog = QuestionEditor(question, parent=editor) - if dialog.exec() == QDialog.Accepted: - # was updated - index.model().setData(index, (dialog.question, dialog.mchoice), Qt.UserRole) - return editor - - -class RuleSortFilterProxyModel(QSortFilterProxyModel): - pass - - class RuleDataModel(QAbstractTableModel): # When subclassing QAbstractTableModel, you must implement rowCount(), columnCount(), and data(). Default - # implementations of the index() and parent() functions are provided by QAbstractTableModel. Well behaved models + # implementations of the index() and parent() functions are provided by QAbstractTableModel. Well-behaved models # will also implement headerData(). # Models that provide interfaces to resizable data structures can provide implementations of insertRows(), @@ -45,13 +28,7 @@ class RuleDataModel(QAbstractTableModel): # implementation must call beginRemoveColumns() before the columns are removed from the data structure, # and it must call endRemoveColumns() immediately afterwards. - headers = [ - 'rule_id', - 'question', - 'multiple_choice', - 'answer_text', - 'last_edited', - ] + headers = ['rule_id', 'question', 'multiple_choice', 'answer_text', 'last_edited', ] def __init__(self, rulegroup_id, parent): super(RuleDataModel, self).__init__(parent) @@ -77,6 +54,7 @@ def insertColumns(self, column: int, count: int, parent: Union[PySide6.QtCore.QModelIndex, PySide6.QtCore.QPersistentModelIndex] = ...) -> bool: self.beginInsertColumns(parent, column, self.columnCount()) self.endInsertColumns() + return False def insertColumn(self, column: int, parent: Union[PySide6.QtCore.QModelIndex, PySide6.QtCore.QPersistentModelIndex] = ...) -> bool: @@ -174,6 +152,19 @@ def supportedDragActions(self) -> PySide6.QtCore.Qt.DropActions: return Qt.CopyAction +class RuleDelegate(QStyledItemDelegate): + def createEditor(self, parent: PySide6.QtWidgets.QWidget, option: PySide6.QtWidgets.QStyleOptionViewItem, + index: Union[PySide6.QtCore.QModelIndex, PySide6.QtCore.QPersistentModelIndex]) \ + -> PySide6.QtWidgets.QWidget: + editor = QWidget(parent) + question = index.model().data(index, role=Qt.UserRole) + dialog = QuestionEditor(question, parent=editor) + if dialog.exec() == QDialog.Accepted: + # was updated + index.model().setData(index, (dialog.question, dialog.mchoice), Qt.UserRole) + return editor + + class RulegroupView(QTableView): def __init__(self, parent): super(RulegroupView, self).__init__(parent) @@ -272,3 +263,7 @@ def startDrag(self, supportedActions: Qt.DropActions) -> None: result = drag.exec_(supportedActions, Qt.CopyAction) if result == Qt.CopyAction: self.clearSelection() + + +class RuleSortFilterProxyModel(QSortFilterProxyModel): + pass diff --git a/src/regeltestcreator.py b/src/regeltestcreator.py index 01ed34e..340b392 100644 --- a/src/regeltestcreator.py +++ b/src/regeltestcreator.py @@ -32,10 +32,12 @@ def add_question(self, question: Question): self.questions.append(question.signature) def delete_selected_items(self): - rows = sorted([index.row() for index in self.selectedIndexes()], reverse=True) - if not rows: + selection_model = self.selectionModel() + if not selection_model.hasSelection(): return - for index in rows: + selected_rows = sorted([index.row() for index in selection_model.selectedRows()], reverse=True) + + for index in selected_rows: self.questions.pop(index) item = self.takeItem(index) del item @@ -117,13 +119,14 @@ def __init__(self, parent): parameters = controller.get_rulegroup_config() divisor = 5 for i in range(len(parameters) // divisor): - self.create_tab(f"{parameters[i*divisor + 1][0].id:02d} - {parameters[(i+1)*divisor-1][0].id:02d}", parameters[i*divisor:(i+1)*divisor]) + self.create_tab(f"{parameters[i * divisor + 1][0].id:02d} - {parameters[(i + 1) * divisor - 1][0].id:02d}", + parameters[i * divisor:(i + 1) * divisor]) if len(parameters) // divisor != len(parameters) / divisor: len_rest = len(parameters) % divisor if len_rest == 1: text = f"{parameters[-1][0].id:02d}" else: - text = f"{parameters[len(parameters)-len_rest][0].id:02d} - {parameters[-1][0].id:02d}" + text = f"{parameters[len(parameters) - len_rest][0].id:02d} - {parameters[-1][0].id:02d}" self.create_tab(text, parameters[len(parameters) - len_rest:]) self.updated() @@ -134,6 +137,7 @@ def updated(self): question_count += text + mchoice self.ui.statistics.setText(f"{question_count} Fragen aktuell ausgewählt ({question_count * 2} Punkte)") + # noinspection PyUnresolvedReferences def create_tab(self, title: str, parameters: List[Tuple[Rulegroup, int, int]]): tab_widget = QWidget() self.ui.tabWidget.addTab(tab_widget, title) @@ -152,9 +156,11 @@ def collect_questions(self): text_questions = [] mchoice_questions = [] if text: - text_questions = controller.get_questions_by_foreignkey(rulegroup.id, mchoice=False, randomize=True)[0:text] + text_questions = controller.get_questions_by_foreignkey(rulegroup.id, mchoice=False, randomize=True)[ + 0:text] if mchoice: - mchoice_questions = controller.get_questions_by_foreignkey(rulegroup.id, mchoice=True, randomize=True)[0:mchoice] + mchoice_questions = controller.get_questions_by_foreignkey(rulegroup.id, mchoice=True, randomize=True)[ + 0:mchoice] text_questions += mchoice_questions if self.ui.checkbox_textmchoice.isChecked(): random.shuffle(text_questions)