More work on data() return types

This commit is contained in:
Keith Edmunds 2025-03-09 16:40:19 +00:00
parent 582803dccc
commit 4e51b44b44
5 changed files with 90 additions and 87 deletions

View File

@ -91,18 +91,18 @@ class NoteColours(dbtables.NoteColoursTable):
cache_key = "note_colours_all" cache_key = "note_colours_all"
cached_result = cache_region.get(cache_key) cached_result = cache_region.get(cache_key)
if cached_result is NO_VALUE: if cached_result is not NO_VALUE:
# Query the database return cached_result
result = session.scalars(
select(cls) # Query the database
.where( result = session.scalars(
cls.enabled.is_(True), select(cls)
) .where(
.order_by(cls.order) cls.enabled.is_(True),
).all() )
cache_region.set(cache_key, result) .order_by(cls.order)
else: ).all()
result = cached_result cache_region.set(cache_key, result)
return result return result
@ -143,7 +143,8 @@ class NoteColours(dbtables.NoteColoursTable):
return rec.colour return rec.colour
return "" return ""
def invalidate_cache(self) -> None: @staticmethod
def invalidate_cache() -> None:
"""Invalidate dogpile cache""" """Invalidate dogpile cache"""
cache_region.delete("note_colours_all") cache_region.delete("note_colours_all")

View File

@ -57,7 +57,6 @@ from PyQt6.QtWidgets import (
) )
# Third party imports # Third party imports
import line_profiler
from pygame import mixer from pygame import mixer
from sqlalchemy.orm.session import Session from sqlalchemy.orm.session import Session
import stackprinter # type: ignore import stackprinter # type: ignore
@ -694,6 +693,7 @@ class PreviewManager:
mixer.init() mixer.init()
self.intro: Optional[int] = None self.intro: Optional[int] = None
self.path: str = "" self.path: str = ""
self.row_number: Optional[int] = None
self.start_time: Optional[dt.datetime] = None self.start_time: Optional[dt.datetime] = None
self.track_id: int = 0 self.track_id: int = 0
@ -2114,7 +2114,6 @@ class Window(QMainWindow):
webbrowser.get("browser").open_new_tab(url) webbrowser.get("browser").open_new_tab(url)
@line_profiler.profile
def paste_rows(self, dummy_for_profiling: int | None = None) -> None: def paste_rows(self, dummy_for_profiling: int | None = None) -> None:
""" """
Paste earlier cut rows. Paste earlier cut rows.
@ -2255,6 +2254,7 @@ class Window(QMainWindow):
return return
if not track_info: if not track_info:
return return
self.preview_manager.row_number = track_info.row_number
with db.Session() as session: with db.Session() as session:
track = session.get(Tracks, track_info.track_id) track = session.get(Tracks, track_info.track_id)
if not track: if not track:
@ -2278,7 +2278,9 @@ class Window(QMainWindow):
def preview_arm(self): def preview_arm(self):
"""Manager arm button for setting intro length""" """Manager arm button for setting intro length"""
self.footer_section.btnPreviewMark.setEnabled(self.btnPreviewArm.isChecked()) self.footer_section.btnPreviewMark.setEnabled(
self.footer_section.btnPreviewArm.isChecked()
)
def preview_back(self) -> None: def preview_back(self) -> None:
"""Wind back preview file""" """Wind back preview file"""

View File

@ -184,7 +184,7 @@ class PlaylistModel(QAbstractTableModel):
self.signals.resize_rows_signal.emit(self.playlist_id) self.signals.resize_rows_signal.emit(self.playlist_id)
def background_role(self, row: int, column: int, rat: RowAndTrack) -> QBrush: def _background_role(self, row: int, column: int, rat: RowAndTrack) -> QBrush:
"""Return background setting""" """Return background setting"""
# Handle entire row colouring # Handle entire row colouring
@ -333,7 +333,7 @@ class PlaylistModel(QAbstractTableModel):
def data( def data(
self, index: QModelIndex, role: int = Qt.ItemDataRole.DisplayRole self, index: QModelIndex, role: int = Qt.ItemDataRole.DisplayRole
) -> QVariant | QFont | QBrush | str: ) -> QVariant | QFont | QBrush | str | int:
"""Return data to view""" """Return data to view"""
if ( if (
@ -360,17 +360,17 @@ class PlaylistModel(QAbstractTableModel):
# These are ordered in approximately the frequency with which # These are ordered in approximately the frequency with which
# they are called # they are called
if role == Qt.ItemDataRole.BackgroundRole: if role == Qt.ItemDataRole.BackgroundRole:
return self.background_role(row, column, rat) return self._background_role(row, column, rat)
elif role == Qt.ItemDataRole.DisplayRole: elif role == Qt.ItemDataRole.DisplayRole:
return self.display_role(row, column, rat) return self._display_role(row, column, rat)
elif role == Qt.ItemDataRole.EditRole: elif role == Qt.ItemDataRole.EditRole:
return self.edit_role(row, column, rat) return self._edit_role(row, column, rat)
elif role == Qt.ItemDataRole.FontRole: elif role == Qt.ItemDataRole.FontRole:
return self.font_role(row, column, rat) return self._font_role(row, column, rat)
elif role == Qt.ItemDataRole.ForegroundRole: elif role == Qt.ItemDataRole.ForegroundRole:
return self.foreground_role(row, column, rat) return self._foreground_role(row, column, rat)
elif role == Qt.ItemDataRole.ToolTipRole: elif role == Qt.ItemDataRole.ToolTipRole:
return self.tooltip_role(row, column, rat) return self._tooltip_role(row, column, rat)
return QVariant() return QVariant()
@ -403,7 +403,7 @@ class PlaylistModel(QAbstractTableModel):
self.reset_track_sequence_row_numbers() self.reset_track_sequence_row_numbers()
self.update_track_times() self.update_track_times()
def display_role(self, row: int, column: int, rat: RowAndTrack) -> str: def _display_role(self, row: int, column: int, rat: RowAndTrack) -> str:
""" """
Return text for display Return text for display
""" """
@ -478,9 +478,9 @@ class PlaylistModel(QAbstractTableModel):
super().endResetModel() super().endResetModel()
self.reset_track_sequence_row_numbers() self.reset_track_sequence_row_numbers()
def edit_role(self, row: int, column: int, rat: RowAndTrack) -> str: def _edit_role(self, row: int, column: int, rat: RowAndTrack) -> str | int:
""" """
Return text for editing Return value for editing
""" """
# If this is a header row and we're being asked for the # If this is a header row and we're being asked for the
@ -489,7 +489,7 @@ class PlaylistModel(QAbstractTableModel):
return rat.note return rat.note
if column == Col.INTRO.value: if column == Col.INTRO.value:
return str(rat.intro or "") return rat.intro or 0
if column == Col.TITLE.value: if column == Col.TITLE.value:
return rat.title return rat.title
if column == Col.ARTIST.value: if column == Col.ARTIST.value:
@ -499,7 +499,7 @@ class PlaylistModel(QAbstractTableModel):
return "" return ""
def foreground_role(self, row: int, column: int, rat: RowAndTrack) -> QBrush: def _foreground_role(self, row: int, column: int, rat: RowAndTrack) -> QBrush:
"""Return header foreground colour or QBrush() if none""" """Return header foreground colour or QBrush() if none"""
if self.is_header_row(row): if self.is_header_row(row):
@ -536,7 +536,7 @@ class PlaylistModel(QAbstractTableModel):
return default return default
def font_role(self, row: int, column: int, rat: RowAndTrack) -> QFont: def _font_role(self, row: int, column: int, rat: RowAndTrack) -> QFont:
""" """
Return font Return font
""" """
@ -644,22 +644,22 @@ class PlaylistModel(QAbstractTableModel):
section: int, section: int,
orientation: Qt.Orientation, orientation: Qt.Orientation,
role: int = Qt.ItemDataRole.DisplayRole, role: int = Qt.ItemDataRole.DisplayRole,
) -> QVariant: ) -> str | int | QFont | QVariant:
""" """
Return text for headers Return text for headers
""" """
display_dispatch_table = { display_dispatch_table = {
Col.START_GAP.value: QVariant(Config.HEADER_START_GAP), Col.START_GAP.value: Config.HEADER_START_GAP,
Col.INTRO.value: QVariant(Config.HEADER_INTRO), Col.INTRO.value: Config.HEADER_INTRO,
Col.TITLE.value: QVariant(Config.HEADER_TITLE), Col.TITLE.value: Config.HEADER_TITLE,
Col.ARTIST.value: QVariant(Config.HEADER_ARTIST), Col.ARTIST.value: Config.HEADER_ARTIST,
Col.DURATION.value: QVariant(Config.HEADER_DURATION), Col.DURATION.value: Config.HEADER_DURATION,
Col.START_TIME.value: QVariant(Config.HEADER_START_TIME), Col.START_TIME.value: Config.HEADER_START_TIME,
Col.END_TIME.value: QVariant(Config.HEADER_END_TIME), Col.END_TIME.value: Config.HEADER_END_TIME,
Col.LAST_PLAYED.value: QVariant(Config.HEADER_LAST_PLAYED), Col.LAST_PLAYED.value: Config.HEADER_LAST_PLAYED,
Col.BITRATE.value: QVariant(Config.HEADER_BITRATE), Col.BITRATE.value: Config.HEADER_BITRATE,
Col.NOTE.value: QVariant(Config.HEADER_NOTE), Col.NOTE.value: Config.HEADER_NOTE,
} }
if role == Qt.ItemDataRole.DisplayRole: if role == Qt.ItemDataRole.DisplayRole:
@ -667,14 +667,14 @@ class PlaylistModel(QAbstractTableModel):
return display_dispatch_table[section] return display_dispatch_table[section]
else: else:
if Config.ROWS_FROM_ZERO: if Config.ROWS_FROM_ZERO:
return QVariant(str(section)) return section
else: else:
return QVariant(str(section + 1)) return section + 1
elif role == Qt.ItemDataRole.FontRole: elif role == Qt.ItemDataRole.FontRole:
boldfont = QFont() boldfont = QFont()
boldfont.setBold(True) boldfont.setBold(True)
return QVariant(boldfont) return boldfont
return QVariant() return QVariant()
@ -1616,7 +1616,7 @@ class PlaylistModel(QAbstractTableModel):
def supportedDropActions(self) -> Qt.DropAction: def supportedDropActions(self) -> Qt.DropAction:
return Qt.DropAction.MoveAction | Qt.DropAction.CopyAction return Qt.DropAction.MoveAction | Qt.DropAction.CopyAction
def tooltip_role(self, row: int, column: int, rat: RowAndTrack) -> str: def _tooltip_role(self, row: int, column: int, rat: RowAndTrack) -> str:
""" """
Return tooltip. Currently only used for last_played column. Return tooltip. Currently only used for last_played column.
""" """

View File

@ -31,7 +31,6 @@ from PyQt6.QtWidgets import (
) )
# Third party imports # Third party imports
import line_profiler
# App imports # App imports
from audacity_controller import AudacityController from audacity_controller import AudacityController
@ -184,11 +183,11 @@ class PlaylistDelegate(QStyledItemDelegate):
data_modified = False data_modified = False
if isinstance(editor, QTextEdit): if isinstance(editor, QTextEdit):
data_modified = ( data_modified = (
self.original_model_data.value() != editor.toPlainText() self.original_model_data != editor.toPlainText()
) )
elif isinstance(editor, QDoubleSpinBox): elif isinstance(editor, QDoubleSpinBox):
data_modified = ( data_modified = (
self.original_model_data.value() != int(editor.value()) * 1000 self.original_model_data != int(editor.value()) * 1000
) )
if not data_modified: if not data_modified:
self.closeEditor.emit(editor) self.closeEditor.emit(editor)
@ -247,10 +246,10 @@ class PlaylistDelegate(QStyledItemDelegate):
edit_index, Qt.ItemDataRole.EditRole edit_index, Qt.ItemDataRole.EditRole
) )
if index.column() == Col.INTRO.value: if index.column() == Col.INTRO.value:
if self.original_model_data.value(): if self.original_model_data:
editor.setValue(self.original_model_data.value() / 1000) editor.setValue(self.original_model_data / 1000)
else: else:
editor.setPlainText(self.original_model_data.value()) editor.setPlainText(self.original_model_data)
def setModelData(self, editor, model, index): def setModelData(self, editor, model, index):
proxy_model = index.model() proxy_model = index.model()
@ -358,7 +357,6 @@ class PlaylistTab(QTableView):
# Deselect edited line # Deselect edited line
self.clear_selection() self.clear_selection()
@line_profiler.profile
def dropEvent(self, event: Optional[QDropEvent], dummy: int | None = None) -> None: def dropEvent(self, event: Optional[QDropEvent], dummy: int | None = None) -> None:
""" """
Move dropped rows Move dropped rows

View File

@ -15,6 +15,7 @@ from PyQt6.QtCore import (
QVariant, QVariant,
) )
from PyQt6.QtGui import ( from PyQt6.QtGui import (
QBrush,
QColor, QColor,
QFont, QFont,
) )
@ -82,27 +83,27 @@ class QuerylistModel(QAbstractTableModel):
def __repr__(self) -> str: def __repr__(self) -> str:
return f"<QuerylistModel: filter={self.filter}, {self.rowCount()} rows>" return f"<QuerylistModel: filter={self.filter}, {self.rowCount()} rows>"
def background_role(self, row: int, column: int, qrow: QueryRow) -> QVariant: def _background_role(self, row: int, column: int, qrow: QueryRow) -> QBrush:
"""Return background setting""" """Return background setting"""
# Unreadable track file # Unreadable track file
if file_is_unreadable(qrow.path): if file_is_unreadable(qrow.path):
return QVariant(QColor(Config.COLOUR_UNREADABLE)) return QBrush(QColor(Config.COLOUR_UNREADABLE))
# Selected row # Selected row
if row in self._selected_rows: if row in self._selected_rows:
return QVariant(QColor(Config.COLOUR_QUERYLIST_SELECTED)) return QBrush(QColor(Config.COLOUR_QUERYLIST_SELECTED))
# Individual cell colouring # Individual cell colouring
if column == QueryCol.BITRATE.value: if column == QueryCol.BITRATE.value:
if not qrow.bitrate or qrow.bitrate < Config.BITRATE_LOW_THRESHOLD: if not qrow.bitrate or qrow.bitrate < Config.BITRATE_LOW_THRESHOLD:
return QVariant(QColor(Config.COLOUR_BITRATE_LOW)) return QBrush(QColor(Config.COLOUR_BITRATE_LOW))
elif qrow.bitrate < Config.BITRATE_OK_THRESHOLD: elif qrow.bitrate < Config.BITRATE_OK_THRESHOLD:
return QVariant(QColor(Config.COLOUR_BITRATE_MEDIUM)) return QBrush(QColor(Config.COLOUR_BITRATE_MEDIUM))
else: else:
return QVariant(QColor(Config.COLOUR_BITRATE_OK)) return QBrush(QColor(Config.COLOUR_BITRATE_OK))
return QVariant() return QBrush()
def columnCount(self, parent: QModelIndex = QModelIndex()) -> int: def columnCount(self, parent: QModelIndex = QModelIndex()) -> int:
"""Standard function for view""" """Standard function for view"""
@ -114,7 +115,23 @@ class QuerylistModel(QAbstractTableModel):
) -> QVariant: ) -> QVariant:
"""Return data to view""" """Return data to view"""
if not index.isValid() or not (0 <= index.row() < len(self.querylist_rows)): if (
not index.isValid()
or not (0 <= index.row() < len(self.querylist_rows))
or role
in [
Qt.ItemDataRole.CheckStateRole,
Qt.ItemDataRole.DecorationRole,
Qt.ItemDataRole.EditRole,
Qt.ItemDataRole.FontRole,
Qt.ItemDataRole.ForegroundRole,
Qt.ItemDataRole.InitialSortOrderRole,
Qt.ItemDataRole.SizeHintRole,
Qt.ItemDataRole.StatusTipRole,
Qt.ItemDataRole.TextAlignmentRole,
Qt.ItemDataRole.WhatsThisRole,
]
):
return QVariant() return QVariant()
row = index.row() row = index.row()
@ -124,48 +141,33 @@ class QuerylistModel(QAbstractTableModel):
# Dispatch to role-specific functions # Dispatch to role-specific functions
dispatch_table: dict[int, Callable] = { dispatch_table: dict[int, Callable] = {
int(Qt.ItemDataRole.BackgroundRole): self.background_role, int(Qt.ItemDataRole.BackgroundRole): self._background_role,
int(Qt.ItemDataRole.DisplayRole): self.display_role, int(Qt.ItemDataRole.DisplayRole): self._display_role,
int(Qt.ItemDataRole.ToolTipRole): self.tooltip_role, int(Qt.ItemDataRole.ToolTipRole): self._tooltip_role,
} }
if role in dispatch_table: if role in dispatch_table:
return QVariant(dispatch_table[role](row, column, qrow)) return QVariant(dispatch_table[role](row, column, qrow))
# Document other roles but don't use them
if role in [
Qt.ItemDataRole.DecorationRole,
Qt.ItemDataRole.EditRole,
Qt.ItemDataRole.FontRole,
Qt.ItemDataRole.ForegroundRole,
Qt.ItemDataRole.InitialSortOrderRole,
Qt.ItemDataRole.SizeHintRole,
Qt.ItemDataRole.StatusTipRole,
Qt.ItemDataRole.TextAlignmentRole,
Qt.ItemDataRole.ToolTipRole,
Qt.ItemDataRole.WhatsThisRole,
]:
return QVariant()
# Fall through to no-op # Fall through to no-op
return QVariant() return QVariant()
def display_role(self, row: int, column: int, qrow: QueryRow) -> QVariant: def _display_role(self, row: int, column: int, qrow: QueryRow) -> str:
""" """
Return text for display Return text for display
""" """
dispatch_table = { dispatch_table = {
QueryCol.ARTIST.value: QVariant(qrow.artist), QueryCol.ARTIST.value: qrow.artist,
QueryCol.BITRATE.value: QVariant(qrow.bitrate), QueryCol.BITRATE.value: str(qrow.bitrate),
QueryCol.DURATION.value: QVariant(ms_to_mmss(qrow.duration)), QueryCol.DURATION.value: ms_to_mmss(qrow.duration),
QueryCol.LAST_PLAYED.value: QVariant(get_relative_date(qrow.lastplayed)), QueryCol.LAST_PLAYED.value: get_relative_date(qrow.lastplayed),
QueryCol.TITLE.value: QVariant(qrow.title), QueryCol.TITLE.value: qrow.title,
} }
if column in dispatch_table: if column in dispatch_table:
return dispatch_table[column] return dispatch_table[column]
return QVariant() return ""
def flags(self, index: QModelIndex) -> Qt.ItemFlag: def flags(self, index: QModelIndex) -> Qt.ItemFlag:
""" """
@ -266,7 +268,7 @@ class QuerylistModel(QAbstractTableModel):
bottom_right = self.index(row, self.columnCount() - 1) bottom_right = self.index(row, self.columnCount() - 1)
self.dataChanged.emit(top_left, bottom_right, [Qt.ItemDataRole.BackgroundRole]) self.dataChanged.emit(top_left, bottom_right, [Qt.ItemDataRole.BackgroundRole])
def tooltip_role(self, row: int, column: int, rat: RowAndTrack) -> QVariant: def _tooltip_role(self, row: int, column: int, rat: RowAndTrack) -> str | QVariant:
""" """
Return tooltip. Currently only used for last_played column. Return tooltip. Currently only used for last_played column.
""" """
@ -278,7 +280,7 @@ class QuerylistModel(QAbstractTableModel):
if not track_id: if not track_id:
return QVariant() return QVariant()
playdates = Playdates.last_playdates(session, track_id) playdates = Playdates.last_playdates(session, track_id)
return QVariant( return (
"<br>".join( "<br>".join(
[ [
a.lastplayed.strftime(Config.LAST_PLAYED_TOOLTIP_DATE_FORMAT) a.lastplayed.strftime(Config.LAST_PLAYED_TOOLTIP_DATE_FORMAT)