diff --git a/src/tagstudio/qt/modals/folders_to_tags.py b/src/tagstudio/qt/modals/folders_to_tags.py index f9d837c5..df643f75 100644 --- a/src/tagstudio/qt/modals/folders_to_tags.py +++ b/src/tagstudio/qt/modals/folders_to_tags.py @@ -90,9 +90,11 @@ def reverse_tag(library: Library, tag: Tag, items: list[Tag] | None) -> list[Tag items.reverse() return items - for subtag_id in tag.parent_ids: - subtag = library.get_tag(subtag_id) - return reverse_tag(library, subtag, items) + parent_tag = None # to avoid subtag unbound error + for parent_tag_id in tag.parent_ids: + parent_tag = library.get_tag(parent_tag_id) + assert parent_tag is not None + return reverse_tag(library, parent_tag, items) # =========== UI =========== @@ -132,7 +134,7 @@ def generate_preview_data(library: Library) -> BranchData: if branch: has_tag = False for tag in entry.tags: - if tag.name == branch.tag.name: + if branch.tag and tag.name == branch.tag.name: has_tag = True break if not has_tag: @@ -216,20 +218,19 @@ class FoldersToTagsModal(QWidget): self.apply_button.setMinimumWidth(100) self.apply_button.clicked.connect(self.on_apply) - self.showEvent = self.on_open # type: ignore - self.root_layout.addWidget(self.title_widget) self.root_layout.addWidget(self.desc_widget) self.root_layout.addWidget(self.open_close_button_w) self.root_layout.addWidget(self.scroll_area) self.root_layout.addWidget(self.apply_button, alignment=Qt.AlignmentFlag.AlignCenter) - def on_apply(self, event): + def on_apply(self): folders_to_tags(self.library) self.close() self.driver.main_window.preview_panel.update_widgets(update_preview=False) - def on_open(self, event): + @override + def showEvent(self, event: QtGui.QShowEvent): for i in reversed(range(self.scroll_layout.count())): self.scroll_layout.itemAt(i).widget().setParent(None) @@ -271,6 +272,7 @@ class TreeItem(QWidget): self.label = QLabel() self.tag_layout.addWidget(self.label) + assert data.tag is not None and parent_tag is not None self.tag_widget = ModifiedTagWidget(data.tag, parent_tag) self.tag_widget.bg_button.clicked.connect(lambda: self.hide_show()) self.tag_layout.addWidget(self.tag_widget) @@ -323,10 +325,7 @@ class ModifiedTagWidget(QWidget): self.bg_button = QPushButton(self) self.bg_button.setFlat(True) - if parent_tag is not None: - text = f"{tag.name} ({parent_tag.name})".replace("&", "&&") - else: - text = tag.name.replace("&", "&&") + text = f"{tag.name} ({parent_tag.name})".replace("&", "&&") self.bg_button.setText(text) self.bg_button.setContextMenuPolicy(Qt.ContextMenuPolicy.ActionsContextMenu) diff --git a/src/tagstudio/qt/widgets/collage_icon.py b/src/tagstudio/qt/widgets/collage_icon.py index b4911d9c..63c1ddbf 100644 --- a/src/tagstudio/qt/widgets/collage_icon.py +++ b/src/tagstudio/qt/widgets/collage_icon.py @@ -29,14 +29,16 @@ class CollageIconRenderer(QObject): def render( self, - entry_id, + entry_id: int, size: tuple[int, int], - data_tint_mode, - data_only_mode, - keep_aspect, + data_tint_mode: bool, + data_only_mode: bool, + keep_aspect: bool, ): entry = self.lib.get_entry(entry_id) - filepath = self.lib.library_dir / entry.path + lib_dir = self.lib.library_dir + assert lib_dir is not None and entry is not None + filepath = lib_dir / entry.path color: str = "" try: @@ -57,7 +59,7 @@ class CollageIconRenderer(QObject): ext: str = filepath.suffix.lower() if MediaCategories.is_ext_in_category(ext, MediaCategories.IMAGE_TYPES): try: - with Image.open(str(self.lib.library_dir / entry.path)) as pic: + with Image.open(filepath) as pic: if keep_aspect: pic.thumbnail(size) else: diff --git a/src/tagstudio/qt/widgets/item_thumb.py b/src/tagstudio/qt/widgets/item_thumb.py index f4d9fd68..acbfc0a9 100644 --- a/src/tagstudio/qt/widgets/item_thumb.py +++ b/src/tagstudio/qt/widgets/item_thumb.py @@ -8,13 +8,13 @@ import typing from enum import Enum from functools import wraps from pathlib import Path -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, override from warnings import catch_warnings import structlog from PIL import Image, ImageQt from PySide6.QtCore import QEvent, QMimeData, QSize, Qt, QUrl -from PySide6.QtGui import QAction, QDrag, QEnterEvent, QPixmap +from PySide6.QtGui import QAction, QDrag, QEnterEvent, QMouseEvent, QPixmap from PySide6.QtWidgets import ( QBoxLayout, QCheckBox, @@ -403,7 +403,7 @@ class ItemThumb(FlowWidget): self.ext_badge.setHidden(True) self.count_badge.setHidden(True) - def set_filename_text(self, filename: Path | None): + def set_filename_text(self, filename: Path): self.set_item_path(filename) self.file_label.setText(str(filename.name)) @@ -437,22 +437,21 @@ class ItemThumb(FlowWidget): size (QSize): The new thumbnail size to set. """ if timestamp > ItemThumb.update_cutoff: - self.thumb_size = size.toTuple() # type: ignore + self.thumb_size = size.width(), size.height() self.thumb_button.setIconSize(size) self.thumb_button.setMinimumSize(size) self.thumb_button.setMaximumSize(size) - def update_clickable(self, clickable: typing.Callable): + def update_clickable(self, clickable: typing.Callable[[], None]): """Updates attributes of a thumbnail element.""" - if clickable: - with catch_warnings(record=True): - self.thumb_button.clicked.disconnect() - self.thumb_button.clicked.connect(clickable) + with catch_warnings(record=True): + self.thumb_button.clicked.disconnect() + self.thumb_button.clicked.connect(clickable) def set_item_id(self, item_id: int): self.item_id = item_id - def set_item_path(self, path: Path | str | None): + def set_item_path(self, path: Path | str): """Set the absolute filepath for the item. Used for locating on disk.""" self.opener.set_filepath(path) @@ -474,11 +473,13 @@ class ItemThumb(FlowWidget): is_hidden = not (show or self.badge_active[badge_type]) badge.setHidden(is_hidden) - def enterEvent(self, event: QEnterEvent) -> None: # noqa: N802 + @override + def enterEvent(self, event: QEnterEvent) -> None: # type: ignore[misc] self.show_check_badges(show=True) return super().enterEvent(event) - def leaveEvent(self, event: QEvent) -> None: # noqa: N802 + @override + def leaveEvent(self, event: QEvent) -> None: # type: ignore[misc] self.show_check_badges(show=False) return super().leaveEvent(event) @@ -490,6 +491,9 @@ class ItemThumb(FlowWidget): toggle_value = self.badges[badge_type].isChecked() self.badge_active[badge_type] = toggle_value badge_values: dict[BadgeType, bool] = {badge_type: toggle_value} + # TODO: Ensure that self.item_id is always an integer. During tests, it is currently None. + # This issue should be addressed by either fixing the test setup or modifying the + # self.driver.update_badges() method. self.driver.update_badges(badge_values, self.item_id) def toggle_item_tag( @@ -506,7 +510,8 @@ class ItemThumb(FlowWidget): else: pass - def mouseMoveEvent(self, event): # noqa: N802 + @override + def mouseMoveEvent(self, event: QMouseEvent) -> None: # type: ignore[misc] if event.buttons() is not Qt.MouseButton.LeftButton: return @@ -521,6 +526,7 @@ class ItemThumb(FlowWidget): if not entry: continue + assert self.lib.library_dir is not None url = QUrl.fromLocalFile(Path(self.lib.library_dir) / entry.path) paths.append(url)