From 6ec119a53793650fdb90ecf7b5e22e415402efc5 Mon Sep 17 00:00:00 2001 From: Charles Haley Date: Mon, 8 Sep 2025 16:48:19 +0100 Subject: [PATCH] Fix tooltips for non-string objects throwing exceptions when custom tooltip templates are used. This happens because idx.data(Qt.ItemDataRole.ToolTipRole) can return a bool, QDateTime, float, or int instead of the string representation for these objects. pep8 will "fix" the Qt imports list. --- src/calibre/gui2/library/models.py | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/calibre/gui2/library/models.py b/src/calibre/gui2/library/models.py index ab4df75713..79fec7bb2f 100644 --- a/src/calibre/gui2/library/models.py +++ b/src/calibre/gui2/library/models.py @@ -15,7 +15,10 @@ import traceback from collections import defaultdict, namedtuple from itertools import groupby -from qt.core import QAbstractTableModel, QApplication, QColor, QFont, QFontMetrics, QIcon, QImage, QModelIndex, QPainter, QPixmap, Qt, pyqtSignal +from qt.core import ( + QAbstractTableModel, QApplication, QColor, QDateTime, + QFont, QFontMetrics, QIcon, QImage, QLocale, QModelIndex, QPainter, + QPixmap, Qt, pyqtSignal) from calibre import fit_image, human_readable, isbytestring, prepare_string_for_xml, strftime from calibre.constants import DEBUG, config_dir, dark_link_color, filesystem_encoding @@ -1008,14 +1011,29 @@ class BooksModel(QAbstractTableModel): # {{{ def f(idx): try: template = self.db.new_api.pref('column_tooltip_templates', {}).get(key, '') + # Simulate what Qt does to get the text for non-string data + # types so that idx.data(Qt.ItemDataRole.ToolTipRole) + # always returns a string. + orig_obj = orig_tt_func(idx) + match orig_obj: + case None: + v = '' + case str(): + v = orig_obj + case bool(): + v = str(orig_obj) + case int() | float() | QDateTime(): + v = QLocale().toString(orig_obj) + case _: + v = f'unsupported type {type(orig_obj)}' if template: - global_vars = {'column_lookup_name': key, 'original_text': orig_tt_func(idx)} + global_vars = {'column_lookup_name': key, 'original_text': v} mi = self.db.new_api.get_proxy_metadata(self.db.data.index_to_id(idx)) return self.formatter.safe_format( template, {}, _('tooltip template error'), mi, global_vars=global_vars) + return v except Exception as e: return str(e) - return orig_tt_func(idx) return f for f, allow_half in iteritems(rating_fields):