Skip to content

Commit 7496935

Browse files
committed
refactor: use proper type instead of dict for file stats
1 parent 1a3df01 commit 7496935

File tree

4 files changed

+42
-39
lines changed

4 files changed

+42
-39
lines changed

src/tagstudio/qt/controller/widgets/preview/preview_thumb_controller.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from tagstudio.qt.helpers.file_opener import open_file
1515
from tagstudio.qt.helpers.file_tester import is_readable_video
1616
from tagstudio.qt.view.widgets.preview.preview_thumb_view import PreviewThumbView
17+
from tagstudio.qt.widgets.preview.file_attributes import FileAttributeData
1718

1819
if TYPE_CHECKING:
1920
from tagstudio.qt.ts_qt import QtDriver
@@ -27,18 +28,18 @@ class PreviewThumb(PreviewThumbView):
2728
def __init__(self, library: Library, driver: "QtDriver"):
2829
super().__init__(library, driver)
2930

30-
def __get_image_stats(self, filepath: Path) -> dict[str, int]:
31+
def __get_image_stats(self, filepath: Path) -> FileAttributeData:
3132
"""Get width and height of an image as dict."""
32-
stats: dict[str, int] = {}
33+
stats = FileAttributeData()
3334
ext = filepath.suffix.lower()
3435

3536
if MediaCategories.IMAGE_RAW_TYPES.contains(ext, mime_fallback=True):
3637
try:
3738
with rawpy.imread(str(filepath)) as raw:
3839
rgb = raw.postprocess()
3940
image = Image.new("L", (rgb.shape[1], rgb.shape[0]), color="black")
40-
stats["width"] = image.width
41-
stats["height"] = image.height
41+
stats.width = image.width
42+
stats.height = image.height
4243
except (
4344
rawpy._rawpy._rawpy.LibRawIOError, # pyright: ignore[reportAttributeAccessIssue]
4445
rawpy._rawpy.LibRawFileUnsupportedError, # pyright: ignore[reportAttributeAccessIssue]
@@ -48,8 +49,8 @@ def __get_image_stats(self, filepath: Path) -> dict[str, int]:
4849
elif MediaCategories.IMAGE_RASTER_TYPES.contains(ext, mime_fallback=True):
4950
try:
5051
image = Image.open(str(filepath))
51-
stats["width"] = image.width
52-
stats["height"] = image.height
52+
stats.width = image.width
53+
stats.height = image.height
5354
except (
5455
DecompressionBombError,
5556
FileNotFoundError,
@@ -62,7 +63,7 @@ def __get_image_stats(self, filepath: Path) -> dict[str, int]:
6263

6364
return stats
6465

65-
def display_file(self, filepath: Path) -> dict[str, int]:
66+
def display_file(self, filepath: Path) -> FileAttributeData:
6667
"""Render a single file preview."""
6768
self.__current_file = filepath
6869

src/tagstudio/qt/view/widgets/preview/preview_thumb_view.py

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from tagstudio.qt.platform_strings import open_file_str, trash_term
2020
from tagstudio.qt.translations import Translations
2121
from tagstudio.qt.widgets.media_player import MediaPlayer
22+
from tagstudio.qt.widgets.preview.file_attributes import FileAttributeData
2223
from tagstudio.qt.widgets.thumb_renderer import ThumbRenderer
2324

2425
if TYPE_CHECKING:
@@ -249,37 +250,37 @@ def __update_media_player(self, filepath: Path) -> int:
249250
self.__media_player.play(filepath)
250251
return self.__media_player.player.duration() * 1000
251252

252-
def _display_video(self, filepath: Path) -> dict[str, int]:
253+
def _display_video(self, filepath: Path) -> FileAttributeData:
253254
self.__switch_preview(MediaType.VIDEO)
254-
stats = {"duration": self.__update_media_player(filepath)}
255+
stats = FileAttributeData(duration=self.__update_media_player(filepath))
255256

256257
try:
257258
success, size = self.__get_video_res(str(filepath))
258259
if success:
259-
self.__image_ratio = size.width() / size.height()
260+
stats.width = size.width()
261+
stats.height = size.height()
262+
263+
self.__image_ratio = stats.width / stats.height
260264
self.resizeEvent(
261265
QResizeEvent(
262-
QSize(size.width(), size.height()),
263-
QSize(size.width(), size.height()),
266+
QSize(stats.width, stats.height),
267+
QSize(stats.width, stats.height),
264268
)
265269
)
266-
267-
stats["width"] = size.width()
268-
stats["height"] = size.height()
269270
except cv2.error as e:
270271
logger.error("[PreviewThumb] Could not play video", filepath=filepath, error=e)
271272

272273
return stats
273274

274-
def _display_audio(self, filepath: Path) -> dict[str, int]:
275+
def _display_audio(self, filepath: Path) -> FileAttributeData:
275276
self.__switch_preview(MediaType.AUDIO)
276277
self.__render_thumb(filepath)
277-
return {"duration": self.__update_media_player(filepath)}
278+
return FileAttributeData(duration=self.__update_media_player(filepath))
278279

279-
def _display_animated_image(self, filepath: Path) -> dict[str, int] | None:
280+
def _display_animated_image(self, filepath: Path) -> FileAttributeData | None:
280281
"""Update the animated image preview from a filepath."""
281282
ext = filepath.suffix.lower()
282-
stats: dict[str, int] = {}
283+
stats = FileAttributeData()
283284

284285
# Ensure that any movie and buffer from previous animations are cleared.
285286
if self.__preview_gif.movie():
@@ -288,8 +289,8 @@ def _display_animated_image(self, filepath: Path) -> dict[str, int] | None:
288289

289290
try:
290291
image: Image.Image = Image.open(filepath)
291-
stats["width"] = image.width
292-
stats["height"] = image.height
292+
stats.width = image.width
293+
stats.height = image.height
293294

294295
self.__image_ratio = image.width / image.height
295296
if ext == ".apng":
@@ -321,13 +322,13 @@ def _display_animated_image(self, filepath: Path) -> dict[str, int] | None:
321322
self.__switch_preview(MediaType.IMAGE_ANIMATED)
322323
self.resizeEvent(
323324
QResizeEvent(
324-
QSize(stats["width"], stats["height"]),
325-
QSize(stats["width"], stats["height"]),
325+
QSize(stats.width, stats.height),
326+
QSize(stats.width, stats.height),
326327
)
327328
)
328329
movie.start()
329330

330-
stats["duration"] = movie.frameCount() // 60
331+
stats.duration = movie.frameCount() // 60
331332
except (UnidentifiedImageError, FileNotFoundError) as e:
332333
logger.error("[PreviewThumb] Could not load animated image", filepath=filepath, error=e)
333334
return None

src/tagstudio/qt/view/widgets/preview_panel_view.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
from tagstudio.qt.controller.widgets.preview.preview_thumb_controller import PreviewThumb
2323
from tagstudio.qt.translations import Translations
2424
from tagstudio.qt.widgets.preview.field_containers import FieldContainers
25-
from tagstudio.qt.widgets.preview.file_attributes import FileAttributes
25+
from tagstudio.qt.widgets.preview.file_attributes import FileAttributeData, FileAttributes
2626

2727
if typing.TYPE_CHECKING:
2828
from tagstudio.qt.ts_qt import QtDriver
@@ -160,7 +160,7 @@ def set_selection(self, selected: list[int], update_preview: bool = True):
160160
filepath: Path = self.lib.library_dir / entry.path
161161

162162
if update_preview:
163-
stats: dict = self.__thumb.display_file(filepath)
163+
stats: FileAttributeData = self.__thumb.display_file(filepath)
164164
self.__file_attrs.update_stats(filepath, stats)
165165
self.__file_attrs.update_date_label(filepath)
166166
self._fields.update_from_entry(entry_id)

src/tagstudio/qt/widgets/preview/file_attributes.py

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import os
77
import platform
88
import typing
9+
from dataclasses import dataclass
910
from datetime import datetime as dt
1011
from datetime import timedelta
1112
from pathlib import Path
@@ -29,6 +30,13 @@
2930
logger = structlog.get_logger(__name__)
3031

3132

33+
@dataclass
34+
class FileAttributeData:
35+
width: int | None = None
36+
height: int | None = None
37+
duration: int | None = None
38+
39+
3240
class FileAttributes(QWidget):
3341
"""The Preview Panel Widget."""
3442

@@ -131,10 +139,10 @@ def update_date_label(self, filepath: Path | None = None) -> None:
131139
self.date_created_label.setHidden(True)
132140
self.date_modified_label.setHidden(True)
133141

134-
def update_stats(self, filepath: Path | None = None, stats: dict | None = None):
142+
def update_stats(self, filepath: Path | None = None, stats: FileAttributeData | None = None):
135143
"""Render the panel widgets with the newest data from the Library."""
136144
if not stats:
137-
stats = {}
145+
stats = FileAttributeData()
138146

139147
if not filepath:
140148
self.layout().setSpacing(0)
@@ -179,16 +187,9 @@ def update_stats(self, filepath: Path | None = None, stats: dict | None = None):
179187
stats_label_text = ""
180188
ext_display: str = ""
181189
file_size: str = ""
182-
width_px_text: str = ""
183-
height_px_text: str = ""
184-
duration_text: str = ""
185190
font_family: str = ""
186191

187192
# Attempt to populate the stat variables
188-
width_px_text = stats.get("width", "")
189-
height_px_text = stats.get("height", "")
190-
duration_text = stats.get("duration", "")
191-
font_family = stats.get("font_family", "")
192193
ext_display = ext.upper()[1:] or filepath.stem.upper()
193194
if filepath:
194195
try:
@@ -217,14 +218,14 @@ def add_newline(stats_label_text: str) -> str:
217218
elif file_size:
218219
stats_label_text += file_size
219220

220-
if width_px_text and height_px_text:
221+
if stats.width is not None and stats.height is not None:
221222
stats_label_text = add_newline(stats_label_text)
222-
stats_label_text += f"{width_px_text} x {height_px_text} px"
223+
stats_label_text += f"{stats.width} x {stats.height} px"
223224

224-
if duration_text:
225+
if stats.duration is not None:
225226
stats_label_text = add_newline(stats_label_text)
226227
try:
227-
dur_str = str(timedelta(seconds=float(duration_text)))[:-7]
228+
dur_str = str(timedelta(seconds=float(stats.duration)))[:-7]
228229
if dur_str.startswith("0:"):
229230
dur_str = dur_str[2:]
230231
if dur_str.startswith("0"):

0 commit comments

Comments
 (0)