From 1be3771d1ae2db60552a1fb9975d1e94bc105685 Mon Sep 17 00:00:00 2001 From: Jann Stute Date: Mon, 8 Sep 2025 21:14:12 +0200 Subject: [PATCH 1/2] fix: type fixes --- src/tagstudio/qt/mixed/media_player.py | 6 +-- src/tagstudio/qt/mixed/migration_modal.py | 29 ++++++------ src/tagstudio/qt/mixed/pagination.py | 20 +++++--- src/tagstudio/qt/previews/renderer.py | 56 ++++++++++++----------- 4 files changed, 59 insertions(+), 52 deletions(-) diff --git a/src/tagstudio/qt/mixed/media_player.py b/src/tagstudio/qt/mixed/media_player.py index 44997c28a..c7402ec63 100644 --- a/src/tagstudio/qt/mixed/media_player.py +++ b/src/tagstudio/qt/mixed/media_player.py @@ -5,7 +5,7 @@ import typing from pathlib import Path from time import gmtime -from typing import override +from typing import cast, override import structlog from PIL import Image, ImageDraw @@ -411,11 +411,11 @@ def play(self, filepath: Path) -> None: self.player.play() def load_toggle_play_icon(self, playing: bool) -> None: - icon = self.driver.rm.pause_icon if playing else self.driver.rm.play_icon + icon = cast(bytes, self.driver.rm.pause_icon if playing else self.driver.rm.play_icon) self.play_pause.load(icon) def load_mute_unmute_icon(self, muted: bool) -> None: - icon = self.driver.rm.volume_mute_icon if muted else self.driver.rm.volume_icon + icon = cast(bytes, self.driver.rm.volume_mute_icon if muted else self.driver.rm.volume_icon) self.mute_unmute.load(icon) def slider_value_changed(self, value: int) -> None: diff --git a/src/tagstudio/qt/mixed/migration_modal.py b/src/tagstudio/qt/mixed/migration_modal.py index c98505d18..86ef37db5 100644 --- a/src/tagstudio/qt/mixed/migration_modal.py +++ b/src/tagstudio/qt/mixed/migration_modal.py @@ -5,6 +5,7 @@ import traceback from pathlib import Path +from typing import cast import structlog from PySide6.QtCore import QObject, Qt, QThreadPool, Signal @@ -60,8 +61,8 @@ def __init__(self, path: Path): self.path: Path = path self.stack: list[PagedPanelState] = [] - self.json_lib: JsonLibrary = None - self.sql_lib: SqliteLibrary = None + self.json_lib: JsonLibrary = None # pyright: ignore[reportAttributeAccessIssue] + self.sql_lib: SqliteLibrary = None # pyright: ignore[reportAttributeAccessIssue] self.is_migration_initialized: bool = False self.discrepancies: list[str] = [] @@ -71,7 +72,7 @@ def __init__(self, path: Path): self.old_entry_count: int = 0 self.old_tag_count: int = 0 self.old_ext_count: int = 0 - self.old_ext_type: bool = None + self.old_ext_type: bool = None # pyright: ignore[reportAttributeAccessIssue] self.field_parity: bool = False self.path_parity: bool = False @@ -366,7 +367,7 @@ def migration_progress(self, skip_ui: bool = False): minimum=0, maximum=0, ) - pb.setCancelButton(None) + pb.setCancelButton(None) # pyright: ignore[reportArgumentType] self.body_wrapper_01.layout().addWidget(pb) try: @@ -389,7 +390,7 @@ def migration_progress(self, skip_ui: bool = False): pb.setMinimum(1), # type: ignore pb.setValue(1), # type: ignore # Enable the finish button - self.stack[1].buttons[4].setDisabled(False), + cast(QPushButtonWrapper, self.stack[1].buttons[4]).setDisabled(False), ) ) QThreadPool.globalInstance().start(r) @@ -473,7 +474,7 @@ def update_sql_value_ui(self, show_msg_box: bool = True): ) self.update_sql_value( self.ext_type_row, - self.sql_lib.prefs(LibraryPrefs.IS_EXCLUDE_LIST), + self.sql_lib.prefs(LibraryPrefs.IS_EXCLUDE_LIST), # pyright: ignore[reportArgumentType] self.old_ext_type, ) logger.info("Parity check complete!") @@ -635,18 +636,15 @@ def check_path_parity(self) -> bool: def check_subtag_parity(self) -> bool: """Check if all JSON parent tags match the new SQL parent tags.""" - sql_parent_tags: set[int] = None - json_parent_tags: set[int] = None - with Session(self.sql_lib.engine) as session: for tag in self.sql_lib.tags: tag_id = tag.id # Tag IDs start at 0 - sql_parent_tags = set( + sql_parent_tags: set[int] = set( session.scalars(select(TagParent.parent_id).where(TagParent.child_id == tag.id)) ) # JSON tags allowed self-parenting; SQL tags no longer allow this. - json_parent_tags = set(self.json_lib.get_tag(tag_id).subtag_ids) + json_parent_tags: set[int] = set(self.json_lib.get_tag(tag_id).subtag_ids) json_parent_tags.discard(tag_id) logger.info( @@ -676,16 +674,15 @@ def check_ext_type(self) -> bool: def check_alias_parity(self) -> bool: """Check if all JSON aliases match the new SQL aliases.""" - sql_aliases: set[str] = None - json_aliases: set[str] = None - with Session(self.sql_lib.engine) as session: for tag in self.sql_lib.tags: tag_id = tag.id # Tag IDs start at 0 - sql_aliases = set( + sql_aliases: set[str] = set( session.scalars(select(TagAlias.name).where(TagAlias.tag_id == tag.id)) ) - json_aliases = set([x for x in self.json_lib.get_tag(tag_id).aliases if x]) + json_aliases: set[str] = set( + [x for x in self.json_lib.get_tag(tag_id).aliases if x] + ) logger.info( "[Alias Parity]", diff --git a/src/tagstudio/qt/mixed/pagination.py b/src/tagstudio/qt/mixed/pagination.py index 7a18e56c8..e39fc048b 100644 --- a/src/tagstudio/qt/mixed/pagination.py +++ b/src/tagstudio/qt/mixed/pagination.py @@ -5,10 +5,10 @@ """A pagination widget created for TagStudio.""" -from typing import override +from typing import cast, override from PIL import Image, ImageQt -from PySide6.QtCore import QObject, QSize, Signal +from PySide6.QtCore import QSize, Signal from PySide6.QtGui import QIntValidator, QPixmap from PySide6.QtWidgets import QHBoxLayout, QLabel, QLineEdit, QSizePolicy, QWidget @@ -17,7 +17,7 @@ from tagstudio.qt.views.qbutton_wrapper import QPushButtonWrapper -class Pagination(QWidget, QObject): +class Pagination(QWidget): """Widget containing controls for navigating between pages of items.""" index = Signal(int) @@ -160,8 +160,8 @@ def update_buttons(self, page_count: int, index: int, emit: bool = True): srt_scale = max(1, (7 - (end_page - index))) if page_count >= 8: - end_size = self.button_size.width() * end_scale + (3 * (end_scale - 1)) - srt_size = self.button_size.width() * srt_scale + (3 * (srt_scale - 1)) + end_size = self.button_size.width() * end_scale + (3 * (end_scale - 1)) # pyright: ignore[reportPossiblyUnboundVariable] + srt_size = self.button_size.width() * srt_scale + (3 * (srt_scale - 1)) # pyright: ignore[reportPossiblyUnboundVariable] self.end_ellipses.setMinimumWidth(end_size) self.end_ellipses.setMaximumWidth(end_size) self.start_ellipses.setMinimumWidth(srt_size) @@ -223,7 +223,10 @@ def update_buttons(self, page_count: int, index: int, emit: bool = True): str(i + 1) ) self._assign_click( - self.start_buffer_layout.itemAt(i - start_offset).widget(), + cast( + QPushButtonWrapper, + self.start_buffer_layout.itemAt(i - start_offset).widget(), + ), i, ) sbc += 1 @@ -239,7 +242,10 @@ def update_buttons(self, page_count: int, index: int, emit: bool = True): str(i + 1) ) self._assign_click( - self.end_buffer_layout.itemAt(i - end_offset).widget(), + cast( + QPushButtonWrapper, + self.end_buffer_layout.itemAt(i - end_offset).widget(), + ), i, ) else: diff --git a/src/tagstudio/qt/previews/renderer.py b/src/tagstudio/qt/previews/renderer.py index 069e735e4..b48c251c7 100644 --- a/src/tagstudio/qt/previews/renderer.py +++ b/src/tagstudio/qt/previews/renderer.py @@ -23,7 +23,8 @@ import srctools import structlog from cv2.typing import MatLike -from mutagen import MutagenError, flac, id3, mp4 +from mutagen import flac, id3, mp4 +from mutagen._util import MutagenError from PIL import ( Image, ImageChops, @@ -398,9 +399,9 @@ def _render_center_icon( ) # Get icon by name - icon: Image.Image | None = self.rm.get(name) + icon: Image.Image | None = self.rm.get(name) # pyright: ignore[reportAssignmentType] if not icon: - icon = self.rm.get("file_generic") + icon = self.rm.get("file_generic") # pyright: ignore[reportAssignmentType] if not icon: icon = Image.new(mode="RGBA", size=(32, 32), color="magenta") @@ -496,9 +497,9 @@ def _render_corner_icon( ) # Get icon by name - icon: Image.Image | None = self.rm.get(name) + icon: Image.Image | None = self.rm.get(name) # pyright: ignore[reportAssignmentType] if not icon: - icon = self.rm.get("file_generic") + icon = self.rm.get("file_generic") # pyright: ignore[reportAssignmentType] if not icon: icon = Image.new(mode="RGBA", size=(32, 32), color="magenta") @@ -634,7 +635,7 @@ def _audio_album_thumb(filepath: Path, ext: str) -> Image.Image | None: image = artwork except ( FileNotFoundError, - id3.ID3NoHeaderError, + id3.ID3NoHeaderError, # pyright: ignore[reportPrivateImportUsage] mp4.MP4MetadataError, mp4.MP4StreamInfoError, MutagenError, @@ -742,7 +743,7 @@ def _blender(filepath: Path) -> Image.Image: if QGuiApplication.styleHints().colorScheme() is Qt.ColorScheme.Dark else "#FFFFFF" ) - im: Image.Image | None = None + im: Image.Image try: blend_image = blend_thumb(str(filepath)) @@ -763,7 +764,7 @@ def _blender(filepath: Path) -> Image.Image: else: logger.error("Couldn't render thumbnail", filepath=filepath, error=type(e).__name__) - return im + return im # pyright: ignore[reportPossiblyUnboundVariable] @staticmethod def _vtf_thumb(filepath: Path) -> Image.Image | None: @@ -910,7 +911,7 @@ def __cover_from_comic_info( cover = comic_info.find(f"./*Page[@Type='{cover_type}']") if cover is not None: pages = [f for f in zip_file.namelist() if f != "ComicInfo.xml"] - page_name = pages[int(cover.get("Image"))] + page_name = pages[int(unwrap(cover.get("Image")))] if page_name.endswith((".png", ".jpg", ".jpeg", ".gif", ".bmp", ".svg")): image_data = zip_file.read(page_name) im = Image.open(BytesIO(image_data)) @@ -924,7 +925,7 @@ def _font_short_thumb(self, filepath: Path, size: int) -> Image.Image: filepath (Path): The path of the file. size (tuple[int,int]): The size of the thumbnail. """ - im: Image.Image = None + im: Image.Image try: bg = Image.new("RGB", (size, size), color="#000000") raw = Image.new("RGB", (size * 3, size * 3), color="#000000") @@ -975,7 +976,7 @@ def _font_short_thumb(self, filepath: Path, size: int) -> Image.Image: im = self._apply_overlay_color(bg, UiColor.BLUE) except OSError as e: logger.error("Couldn't render thumbnail", filepath=filepath, error=type(e).__name__) - return im + return im # pyright: ignore[reportPossiblyUnboundVariable] @staticmethod def _font_long_thumb(filepath: Path, size: int) -> Image.Image: @@ -987,7 +988,7 @@ def _font_long_thumb(filepath: Path, size: int) -> Image.Image: """ # Scale the sample font sizes to the preview image # resolution,assuming the sizes are tuned for 256px. - im: Image.Image = None + im: Image.Image try: scaled_sizes: list[int] = [math.floor(x * (size / 256)) for x in FONT_SAMPLE_SIZES] bg = Image.new("RGBA", (size, size), color="#00000000") @@ -998,7 +999,10 @@ def _font_long_thumb(filepath: Path, size: int) -> Image.Image: for font_size in scaled_sizes: font = ImageFont.truetype(filepath, size=font_size) text_wrapped: str = wrap_full_text( - FONT_SAMPLE_TEXT, font=font, width=size, draw=draw + FONT_SAMPLE_TEXT, + font=font, # pyright: ignore[reportArgumentType] + width=size, + draw=draw, ) draw.multiline_text((0, y_offset), text_wrapped, font=font) y_offset += (len(text_wrapped.split("\n")) + lines_of_padding) * draw.textbbox( @@ -1007,7 +1011,7 @@ def _font_long_thumb(filepath: Path, size: int) -> Image.Image: im = theme_fg_overlay(bg, use_alpha=False) except OSError as e: logger.error("Couldn't render thumbnail", filepath=filepath, error=type(e).__name__) - return im + return im # pyright: ignore[reportPossiblyUnboundVariable] @staticmethod def _image_raw_thumb(filepath: Path) -> Image.Image: @@ -1016,7 +1020,7 @@ def _image_raw_thumb(filepath: Path) -> Image.Image: Args: filepath (Path): The path of the file. """ - im: Image.Image = None + im: Image.Image try: with rawpy.imread(str(filepath)) as raw: rgb = raw.postprocess(use_camera_wb=True) @@ -1028,11 +1032,11 @@ def _image_raw_thumb(filepath: Path) -> Image.Image: ) except ( DecompressionBombError, - rawpy._rawpy.LibRawIOError, - rawpy._rawpy.LibRawFileUnsupportedError, + rawpy._rawpy.LibRawIOError, # pyright: ignore[reportAttributeAccessIssue] + rawpy._rawpy.LibRawFileUnsupportedError, # pyright: ignore[reportAttributeAccessIssue] ) as e: logger.error("Couldn't render thumbnail", filepath=filepath, error=type(e).__name__) - return im + return im # pyright: ignore[reportPossiblyUnboundVariable] @staticmethod def _image_exr_thumb(filepath: Path) -> Image.Image | None: @@ -1071,7 +1075,7 @@ def _image_thumb(filepath: Path) -> Image.Image: Args: filepath (Path): The path of the file. """ - im: Image.Image = None + im: Image.Image try: im = Image.open(filepath) if im.mode != "RGB" and im.mode != "RGBA": @@ -1088,7 +1092,7 @@ def _image_thumb(filepath: Path) -> Image.Image: NotImplementedError, ) as e: logger.error("Couldn't render thumbnail", filepath=filepath, error=type(e).__name__) - return im + return im # pyright: ignore[reportPossiblyUnboundVariable] @staticmethod def _image_vector_thumb(filepath: Path, size: int) -> Image.Image: @@ -1098,7 +1102,7 @@ def _image_vector_thumb(filepath: Path, size: int) -> Image.Image: filepath (Path): The path of the file. size (tuple[int,int]): The size of the thumbnail. """ - im: Image.Image = None + im: Image.Image # Create an image to draw the svg to and a painter to do the drawing q_image: QImage = QImage(size, size, QImage.Format.Format_ARGB32) q_image.fill("#1e1e1e") @@ -1136,7 +1140,7 @@ def _iwork_thumb(filepath: Path) -> Image.Image: """ preview_thumb_dir = "preview.jpg" quicklook_thumb_dir = "QuickLook/Thumbnail.jpg" - im: Image.Image | None = None + im: Image.Image def get_image(path: str) -> Image.Image | None: thumb_im: Image.Image | None = None @@ -1163,7 +1167,7 @@ def get_image(path: str) -> Image.Image | None: except zipfile.BadZipFile as e: logger.error("Couldn't render thumbnail", filepath=filepath, error=e) - return im + return im # pyright: ignore[reportPossiblyUnboundVariable] @staticmethod def _model_stl_thumb(filepath: Path, size: int) -> Image.Image: @@ -1177,7 +1181,7 @@ def _model_stl_thumb(filepath: Path, size: int) -> Image.Image: # The following commented code describes a method for rendering via # matplotlib. # This implementation did not play nice with multithreading. - im: Image.Image = None + im: Image.Image = None # pyright: ignore[reportAssignmentType] # # Create a new plot # matplotlib.use('agg') # figure = plt.figure() @@ -1205,7 +1209,7 @@ def _pdf_thumb(filepath: Path, size: int) -> Image.Image: filepath (Path): The path of the file. size (int): The size of the icon. """ - im: Image.Image = None + im: Image.Image file: QFile = QFile(filepath) success: bool = file.open( @@ -1213,7 +1217,7 @@ def _pdf_thumb(filepath: Path, size: int) -> Image.Image: ) if not success: logger.error("Couldn't render thumbnail", filepath=filepath) - return im + return None # pyright: ignore[reportReturnType] document: QPdfDocument = QPdfDocument() document.load(file) file.close() From aea76c4dfc39dc0850f3bc36cdde0121101e9d45 Mon Sep 17 00:00:00 2001 From: Jann Stute Date: Tue, 9 Sep 2025 22:54:31 +0200 Subject: [PATCH 2/2] fix: address review feedback --- src/tagstudio/qt/previews/renderer.py | 53 ++++++++++++++------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/src/tagstudio/qt/previews/renderer.py b/src/tagstudio/qt/previews/renderer.py index 1dc9f7ad5..7bac3bed2 100644 --- a/src/tagstudio/qt/previews/renderer.py +++ b/src/tagstudio/qt/previews/renderer.py @@ -21,6 +21,7 @@ import numpy as np import pillow_avif # noqa: F401 # pyright: ignore[reportUnusedImport] import py7zr +import py7zr.io import rarfile import rawpy import srctools @@ -120,7 +121,7 @@ def namelist(self) -> list[str]: return self.getnames() def read(self, name: str) -> bytes: - return self.extractfile(name).read() + return unwrap(self.extractfile(name)).read() type _Archive_T = ( @@ -665,7 +666,7 @@ def _audio_album_thumb(filepath: Path, ext: str) -> Image.Image | None: artwork = Image.open(BytesIO(flac_covers[0].data)) elif ext in [".mp4", ".m4a", ".aac"]: mp4_tags: mp4.MP4 = mp4.MP4(filepath) - mp4_covers: list = mp4_tags.get("covr") + mp4_covers: list = mp4_tags.get("covr") # pyright: ignore[reportAssignmentType] if mp4_covers: artwork = Image.open(BytesIO(mp4_covers[0])) if artwork: @@ -769,7 +770,7 @@ def _audio_waveform_thumb( return im @staticmethod - def _blender(filepath: Path) -> Image.Image: + def _blender(filepath: Path) -> Image.Image | None: """Get an emended thumbnail from a Blender file, if a thumbnail is present. Args: @@ -780,7 +781,7 @@ def _blender(filepath: Path) -> Image.Image: if QGuiApplication.styleHints().colorScheme() is Qt.ColorScheme.Dark else "#FFFFFF" ) - im: Image.Image + im: Image.Image | None = None try: blend_image = blend_thumb(str(filepath)) @@ -801,7 +802,7 @@ def _blender(filepath: Path) -> Image.Image: else: logger.error("Couldn't render thumbnail", filepath=filepath, error=type(e).__name__) - return im # pyright: ignore[reportPossiblyUnboundVariable] + return im @staticmethod def _vtf_thumb(filepath: Path) -> Image.Image | None: @@ -964,14 +965,14 @@ def __cover_from_comic_info( return im - def _font_short_thumb(self, filepath: Path, size: int) -> Image.Image: + def _font_short_thumb(self, filepath: Path, size: int) -> Image.Image | None: """Render a small font preview ("Aa") thumbnail from a font file. Args: filepath (Path): The path of the file. size (tuple[int,int]): The size of the thumbnail. """ - im: Image.Image + im: Image.Image | None = None try: bg = Image.new("RGB", (size, size), color="#000000") raw = Image.new("RGB", (size * 3, size * 3), color="#000000") @@ -1022,10 +1023,10 @@ def _font_short_thumb(self, filepath: Path, size: int) -> Image.Image: im = self._apply_overlay_color(bg, UiColor.BLUE) except OSError as e: logger.error("Couldn't render thumbnail", filepath=filepath, error=type(e).__name__) - return im # pyright: ignore[reportPossiblyUnboundVariable] + return im @staticmethod - def _font_long_thumb(filepath: Path, size: int) -> Image.Image: + def _font_long_thumb(filepath: Path, size: int) -> Image.Image | None: """Render a large font preview ("Alphabet") thumbnail from a font file. Args: @@ -1034,7 +1035,7 @@ def _font_long_thumb(filepath: Path, size: int) -> Image.Image: """ # Scale the sample font sizes to the preview image # resolution,assuming the sizes are tuned for 256px. - im: Image.Image + im: Image.Image | None = None try: scaled_sizes: list[int] = [math.floor(x * (size / 256)) for x in FONT_SAMPLE_SIZES] bg = Image.new("RGBA", (size, size), color="#00000000") @@ -1057,16 +1058,16 @@ def _font_long_thumb(filepath: Path, size: int) -> Image.Image: im = theme_fg_overlay(bg, use_alpha=False) except OSError as e: logger.error("Couldn't render thumbnail", filepath=filepath, error=type(e).__name__) - return im # pyright: ignore[reportPossiblyUnboundVariable] + return im @staticmethod - def _image_raw_thumb(filepath: Path) -> Image.Image: + def _image_raw_thumb(filepath: Path) -> Image.Image | None: """Render a thumbnail for a RAW image type. Args: filepath (Path): The path of the file. """ - im: Image.Image + im: Image.Image | None = None try: with rawpy.imread(str(filepath)) as raw: rgb = raw.postprocess(use_camera_wb=True) @@ -1082,7 +1083,7 @@ def _image_raw_thumb(filepath: Path) -> Image.Image: rawpy._rawpy.LibRawFileUnsupportedError, # pyright: ignore[reportAttributeAccessIssue] ) as e: logger.error("Couldn't render thumbnail", filepath=filepath, error=type(e).__name__) - return im # pyright: ignore[reportPossiblyUnboundVariable] + return im @staticmethod def _image_exr_thumb(filepath: Path) -> Image.Image | None: @@ -1115,13 +1116,13 @@ def _image_exr_thumb(filepath: Path) -> Image.Image | None: return im @staticmethod - def _image_thumb(filepath: Path) -> Image.Image: + def _image_thumb(filepath: Path) -> Image.Image | None: """Render a thumbnail for a standard image type. Args: filepath (Path): The path of the file. """ - im: Image.Image + im: Image.Image | None = None try: im = Image.open(filepath) if im.mode != "RGB" and im.mode != "RGBA": @@ -1138,7 +1139,7 @@ def _image_thumb(filepath: Path) -> Image.Image: NotImplementedError, ) as e: logger.error("Couldn't render thumbnail", filepath=filepath, error=type(e).__name__) - return im # pyright: ignore[reportPossiblyUnboundVariable] + return im @staticmethod def _image_vector_thumb(filepath: Path, size: int) -> Image.Image: @@ -1148,7 +1149,7 @@ def _image_vector_thumb(filepath: Path, size: int) -> Image.Image: filepath (Path): The path of the file. size (tuple[int,int]): The size of the thumbnail. """ - im: Image.Image + im: Image.Image | None = None # Create an image to draw the svg to and a painter to do the drawing q_image: QImage = QImage(size, size, QImage.Format.Format_ARGB32) q_image.fill("#1e1e1e") @@ -1178,7 +1179,7 @@ def _image_vector_thumb(filepath: Path, size: int) -> Image.Image: return im @staticmethod - def _iwork_thumb(filepath: Path) -> Image.Image: + def _iwork_thumb(filepath: Path) -> Image.Image | None: """Extract and render a thumbnail for an Apple iWork (Pages, Numbers, Keynote) file. Args: @@ -1186,7 +1187,7 @@ def _iwork_thumb(filepath: Path) -> Image.Image: """ preview_thumb_dir = "preview.jpg" quicklook_thumb_dir = "QuickLook/Thumbnail.jpg" - im: Image.Image + im: Image.Image | None = None def get_image(path: str) -> Image.Image | None: thumb_im: Image.Image | None = None @@ -1213,10 +1214,10 @@ def get_image(path: str) -> Image.Image | None: except zipfile.BadZipFile as e: logger.error("Couldn't render thumbnail", filepath=filepath, error=e) - return im # pyright: ignore[reportPossiblyUnboundVariable] + return im @staticmethod - def _model_stl_thumb(filepath: Path, size: int) -> Image.Image: + def _model_stl_thumb(filepath: Path, size: int) -> Image.Image | None: """Render a thumbnail for an STL file. Args: @@ -1227,7 +1228,7 @@ def _model_stl_thumb(filepath: Path, size: int) -> Image.Image: # The following commented code describes a method for rendering via # matplotlib. # This implementation did not play nice with multithreading. - im: Image.Image = None # pyright: ignore[reportAssignmentType] + im: Image.Image | None = None # # Create a new plot # matplotlib.use('agg') # figure = plt.figure() @@ -1249,13 +1250,13 @@ def _model_stl_thumb(filepath: Path, size: int) -> Image.Image: return im @staticmethod - def _pdf_thumb(filepath: Path, size: int) -> Image.Image: + def _pdf_thumb(filepath: Path, size: int) -> Image.Image | None: """Render a thumbnail for a PDF file. filepath (Path): The path of the file. size (int): The size of the icon. """ - im: Image.Image + im: Image.Image | None = None file: QFile = QFile(filepath) success: bool = file.open( @@ -1263,7 +1264,7 @@ def _pdf_thumb(filepath: Path, size: int) -> Image.Image: ) if not success: logger.error("Couldn't render thumbnail", filepath=filepath) - return None # pyright: ignore[reportReturnType] + return im document: QPdfDocument = QPdfDocument() document.load(file) file.close()