From d93da3c90ce99da52b25670e8aea91820f0ae644 Mon Sep 17 00:00:00 2001 From: lwark Date: Thu, 9 Jan 2025 07:25:40 -0600 Subject: [PATCH] Pre code cleanup. --- src/submissions/backend/db/models/__init__.py | 8 +++- src/submissions/backend/db/models/kits.py | 10 ++++- .../backend/db/models/organizations.py | 8 ++++ src/submissions/frontend/widgets/app.py | 2 +- .../frontend/widgets/omni_add_edit.py | 14 ++++-- .../frontend/widgets/omni_manager.py | 43 ++++++++++++++----- src/submissions/tools/__init__.py | 10 ++++- 7 files changed, 76 insertions(+), 19 deletions(-) diff --git a/src/submissions/backend/db/models/__init__.py b/src/submissions/backend/db/models/__init__.py index 1da3742..6393f16 100644 --- a/src/submissions/backend/db/models/__init__.py +++ b/src/submissions/backend/db/models/__init__.py @@ -238,7 +238,9 @@ class BaseClass(Base): return report def to_dict(self): - return {k: v for k, v in self.__dict__.items() if k not in ["_sa_instance_state", "id"]} + dicto = {k: v for k, v in self.__dict__.items() if k not in ["_sa_instance_state"]} + dicto = {'id': dicto.pop('id'), **dicto} + return dicto @classmethod def get_pydantic_model(cls): @@ -249,6 +251,10 @@ class BaseClass(Base): return None return model + @classproperty + def add_edit_tooltips(self): + return dict() + class ConfigItem(BaseClass): """ diff --git a/src/submissions/backend/db/models/kits.py b/src/submissions/backend/db/models/kits.py index 79b97d8..8ff7a86 100644 --- a/src/submissions/backend/db/models/kits.py +++ b/src/submissions/backend/db/models/kits.py @@ -260,7 +260,8 @@ class KitType(BaseClass): return base_dict @classmethod - def import_from_yml(cls, submission_type:str|SubmissionType, filepath: Path | str | None = None, import_dict: dict | None = None) -> KitType: + def import_from_yml(cls, submission_type: str | SubmissionType, filepath: Path | str | None = None, + import_dict: dict | None = None) -> KitType: if isinstance(submission_type, str): submission_type = SubmissionType.query(name=submission_type) if filepath: @@ -557,7 +558,6 @@ class Reagent(BaseClass, LogMixin): logger.debug(f"Instance: {instance}") return instance, new - @classmethod @setup_lookup def query(cls, @@ -637,6 +637,12 @@ class Reagent(BaseClass, LogMixin): self.__setattr__(key, field_value) self.save() + @classproperty + def add_edit_tooltips(self): + return dict( + expiry="Use exact date on reagent.\nEOL will be calculated from kit automatically" + ) + class Discount(BaseClass): """ diff --git a/src/submissions/backend/db/models/organizations.py b/src/submissions/backend/db/models/organizations.py index 5424c11..6e97e60 100644 --- a/src/submissions/backend/db/models/organizations.py +++ b/src/submissions/backend/db/models/organizations.py @@ -140,6 +140,7 @@ class Contact(BaseClass): @classmethod @setup_lookup def query(cls, + id: int | None = None, name: str | None = None, email: str | None = None, phone: str | None = None, @@ -158,6 +159,12 @@ class Contact(BaseClass): Contact|List[Contact]: Contact(s) of interest. """ query: Query = cls.__database_session__.query(cls) + match id: + case int(): + query = query.filter(cls.id == id) + limit = 1 + case _: + pass match name: case str(): query = query.filter(cls.name == name.title()) @@ -177,3 +184,4 @@ class Contact(BaseClass): case _: pass return cls.execute_query(query=query, limit=limit) + diff --git a/src/submissions/frontend/widgets/app.py b/src/submissions/frontend/widgets/app.py index c9387c9..6066fbb 100644 --- a/src/submissions/frontend/widgets/app.py +++ b/src/submissions/frontend/widgets/app.py @@ -217,7 +217,7 @@ class App(QMainWindow): dlg = ManagerWindow(parent=self, object_type=Organization, extras=[]) if dlg.exec(): new_org = dlg.parse_form() - logger.debug(new_org.__dict__) + # logger.debug(new_org.__dict__) class AddSubForm(QWidget): diff --git a/src/submissions/frontend/widgets/omni_add_edit.py b/src/submissions/frontend/widgets/omni_add_edit.py index f08978d..80ee90e 100644 --- a/src/submissions/frontend/widgets/omni_add_edit.py +++ b/src/submissions/frontend/widgets/omni_add_edit.py @@ -79,10 +79,11 @@ class EditProperty(QWidget): def __init__(self, parent: AddEdit, key: str, column_type: Any, value): super().__init__(parent) + self.name = key self.label = QLabel(key.title().replace("_", " ")) self.layout = QGridLayout() self.layout.addWidget(self.label, 0, 0, 1, 1) - self.setObjectName(key) + self.setObjectName(f"{key}:") match column_type['class_attr'].property: case ColumnProperty(): self.column_property_set(column_type, value=value) @@ -100,9 +101,9 @@ class EditProperty(QWidget): self.is_list = relationship_property['class_attr'].property.uselist choices = [item.name for item in self.property_class.query()] try: - instance_value = getattr(self.parent().instance, self.objectName().strip(":")) + instance_value = getattr(self.parent().instance, self.name) except AttributeError: - logger.debug(f"Unable to get instance {self.parent().instance} attribute: {self.objectName()}") + logger.error(f"Unable to get instance {self.parent().instance} attribute: {self.name}") instance_value = None if isinstance(instance_value, list): instance_value = next((item.name for item in instance_value), None) @@ -126,6 +127,11 @@ class EditProperty(QWidget): case _: logger.error(f"{column_property} not a supported property.") self.widget = None + try: + tooltip_text = self.parent().object_type.add_edit_tooltips[self.name] + self.widget.setToolTip(tooltip_text) + except KeyError: + pass def parse_form(self): try: @@ -145,4 +151,4 @@ class EditProperty(QWidget): # value = self.property_class.query(name=prelim) case _: value = None - return self.objectName(), value + return self.name, value diff --git a/src/submissions/frontend/widgets/omni_manager.py b/src/submissions/frontend/widgets/omni_manager.py index 11b2c80..9d64b79 100644 --- a/src/submissions/frontend/widgets/omni_manager.py +++ b/src/submissions/frontend/widgets/omni_manager.py @@ -1,8 +1,10 @@ +from operator import itemgetter from typing import Any, List from PyQt6.QtCore import QSortFilterProxyModel, Qt +from PyQt6.QtGui import QAction, QCursor from PyQt6.QtWidgets import ( QLabel, QDialog, - QTableView, QWidget, QLineEdit, QGridLayout, QComboBox, QPushButton, QDialogButtonBox, QDateEdit + QTableView, QWidget, QLineEdit, QGridLayout, QComboBox, QPushButton, QDialogButtonBox, QDateEdit, QMenu ) from sqlalchemy import String, TIMESTAMP from sqlalchemy.orm import InstrumentedAttribute @@ -14,7 +16,6 @@ from backend import db import logging from .omni_add_edit import AddEdit from .omni_search import SearchBox - from frontend.widgets.submission_table import pandasModel logger = logging.getLogger(f"submissions.{__name__}") @@ -168,6 +169,9 @@ class EditRelationship(QWidget): self.layout.addWidget(self.existing_button, 0, 7, 1, 1, alignment=Qt.AlignmentFlag.AlignRight) self.setLayout(self.layout) self.set_data() + self.table.resizeColumnsToContents() + self.table.resizeRowsToContents() + self.table.setSortingEnabled(True) def parse_row(self, x): context = {item: x.sibling(x.row(), self.data.columns.get_loc(item)).data() for item in self.data.columns} @@ -175,7 +179,6 @@ class EditRelationship(QWidget): object = self.entity.query(**context) except KeyError: object = None - # logger.debug(object) self.table.doubleClicked.disconnect() self.add_edit(instance=object) @@ -185,12 +188,10 @@ class EditRelationship(QWidget): dlg = AddEdit(self, instance=instance, manager=self.parent().object_type.__name__.lower()) if dlg.exec(): new_instance = dlg.parse_form() - # logger.debug(new_instance.__dict__) addition = getattr(self.parent().instance, self.objectName()) if isinstance(addition, InstrumentedList): addition.append(new_instance) self.parent().instance.save() - self.parent().update_data() def add_existing(self): @@ -215,12 +216,34 @@ class EditRelationship(QWidget): self.columns_of_interest = [dict(name=item, column=self.data.columns.get_loc(item)) for item in self.extras] except (KeyError, AttributeError): self.columns_of_interest = [] - # try: - # self.data['id'] = self.data['id'].apply(str) - # self.data['id'] = self.data['id'].str.zfill(3) - # except (TypeError, KeyError) as e: - # logger.error(f"Couldn't format id string: {e}") + try: + self.data['id'] = self.data['id'].apply(str) + self.data['id'] = self.data['id'].str.zfill(4) + except KeyError as e: + logger.error(f"Could not alter id to string due to {e}") proxy_model = QSortFilterProxyModel() proxy_model.setSourceModel(pandasModel(self.data)) self.table.setModel(proxy_model) self.table.doubleClicked.connect(self.parse_row) + + def contextMenuEvent(self, event): + """ + Creates actions for right click menu events. + + Args: + event (_type_): the item of interest + """ + id = self.table.selectionModel().currentIndex() + id = int(id.sibling(id.row(), 0).data()) + object = self.entity.query(id=id) + self.menu = QMenu(self) + action = QAction(f"Remove {object.name}", self) + action.triggered.connect(lambda: self.remove_item(object=object)) + self.menu.addAction(action) + self.menu.popup(QCursor.pos()) + + def remove_item(self, object): + editor = getattr(self.parent().instance, self.objectName().lower()) + editor.remove(object) + self.parent().instance.save() + self.parent().update_data() diff --git a/src/submissions/tools/__init__.py b/src/submissions/tools/__init__.py index 628ca8c..656e19a 100644 --- a/src/submissions/tools/__init__.py +++ b/src/submissions/tools/__init__.py @@ -2,7 +2,7 @@ Contains miscellaenous functions used by both frontend and backend. ''' from __future__ import annotations - +import builtins import importlib import time from datetime import date, datetime, timedelta @@ -1104,4 +1104,12 @@ def create_holidays_for_year(year: int | None = None) -> List[date]: return sorted(holidays) +class classproperty(property): + def __get__(self, owner_self, owner_cls): + return self.fget(owner_cls) + + +builtins.classproperty = classproperty + + ctx = get_config(None)