Consolidate some code related to opening documents using the Documents feature. More code coverage
All checks were successful
Lint / test (push) Successful in 34s
Trivy / test (push) Successful in 22s
CI / test (push) Successful in 6m4s

This commit is contained in:
Miguel Jacq 2025-12-02 11:01:27 +11:00
parent 25f0c28582
commit 0b76f0b490
Signed by: mig5
GPG key ID: 59B3F0C24135C6A9
9 changed files with 2101 additions and 108 deletions

64
bouquin/document_utils.py Normal file
View file

@ -0,0 +1,64 @@
"""
Utility functions for document operations.
This module provides shared functionality for document handling across
different widgets (TodaysDocumentsWidget, DocumentsDialog, SearchResultsDialog,
and TagBrowserDialog).
"""
from __future__ import annotations
from pathlib import Path
import tempfile
from typing import TYPE_CHECKING, Optional
from PySide6.QtCore import QUrl
from PySide6.QtGui import QDesktopServices
from PySide6.QtWidgets import QMessageBox, QWidget
from . import strings
if TYPE_CHECKING:
from .db import DBManager
def open_document_from_db(
db: DBManager, doc_id: int, file_name: str, parent_widget: Optional[QWidget] = None
) -> bool:
"""
Open a document by fetching it from the database and opening with system default app.
"""
# Fetch document data from database
try:
data = db.document_data(doc_id)
except Exception as e:
# Show error dialog if parent widget is provided
if parent_widget:
QMessageBox.warning(
parent_widget,
strings._("project_documents_title"),
strings._("documents_open_failed").format(error=str(e)),
)
return False
# Extract file extension
suffix = Path(file_name).suffix or ""
# Create temporary file with same extension
tmp = tempfile.NamedTemporaryFile(
prefix="bouquin_doc_",
suffix=suffix,
delete=False,
)
# Write data to temp file
try:
tmp.write(data)
tmp.flush()
finally:
tmp.close()
# Open with system default application
success = QDesktopServices.openUrl(QUrl.fromLocalFile(tmp.name))
return success

View file

@ -1,11 +1,9 @@
from __future__ import annotations
from pathlib import Path
import tempfile
from typing import Optional
from PySide6.QtCore import Qt, QUrl
from PySide6.QtGui import QDesktopServices, QColor
from PySide6.QtCore import Qt
from PySide6.QtGui import QColor
from PySide6.QtWidgets import (
QDialog,
QVBoxLayout,
@ -147,29 +145,9 @@ class TodaysDocumentsWidget(QFrame):
def _open_document(self, doc_id: int, file_name: str) -> None:
"""Open a document from the list."""
try:
data = self._db.document_data(doc_id)
except Exception as e:
QMessageBox.warning(
self,
strings._("project_documents_title"),
strings._("documents_open_failed").format(error=str(e)),
)
return
from .document_utils import open_document_from_db
suffix = Path(file_name).suffix or ""
tmp = tempfile.NamedTemporaryFile(
prefix="bouquin_doc_",
suffix=suffix,
delete=False,
)
try:
tmp.write(data)
tmp.flush()
finally:
tmp.close()
QDesktopServices.openUrl(QUrl.fromLocalFile(tmp.name))
open_document_from_db(self._db, doc_id, file_name, parent_widget=self)
def _open_documents_dialog(self) -> None:
"""Open the full DocumentsDialog."""
@ -553,29 +531,9 @@ class DocumentsDialog(QDialog):
"""
Fetch BLOB from DB, write to a temporary file, and open with default app.
"""
try:
data = self._db.document_data(doc_id)
except Exception as e:
QMessageBox.warning(
self,
strings._("project_documents_title"),
strings._("documents_open_failed").format(error=str(e)),
)
return
from .document_utils import open_document_from_db
suffix = Path(file_name).suffix or ""
tmp = tempfile.NamedTemporaryFile(
prefix="bouquin_doc_",
suffix=suffix,
delete=False,
)
try:
tmp.write(data)
tmp.flush()
finally:
tmp.close()
QDesktopServices.openUrl(QUrl.fromLocalFile(tmp.name))
open_document_from_db(self._db, doc_id, file_name, parent_widget=self)
@staticmethod
def _format_size(size_bytes: int) -> str:

View file

@ -69,38 +69,10 @@ class Search(QWidget):
self._open_document(int(doc_id), file_name)
def _open_document(self, doc_id: int, file_name: str) -> None:
"""
Open a document search result via a temp file.
"""
from pathlib import Path
import tempfile
from PySide6.QtCore import QUrl
from PySide6.QtGui import QDesktopServices
from PySide6.QtWidgets import QMessageBox
"""Open the selected document in the user's default app."""
from bouquin.document_utils import open_document_from_db
try:
data = self._db.document_data(doc_id)
except Exception as e:
QMessageBox.warning(
self,
strings._("project_documents_title"),
strings._("documents_open_failed").format(error=str(e)),
)
return
suffix = Path(file_name).suffix or ""
tmp = tempfile.NamedTemporaryFile(
prefix="bouquin_doc_",
suffix=suffix,
delete=False,
)
try:
tmp.write(data)
tmp.flush()
finally:
tmp.close()
QDesktopServices.openUrl(QUrl.fromLocalFile(tmp.name))
open_document_from_db(self._db, doc_id, file_name, parent_widget=self)
def _search(self, text: str):
"""

View file

@ -1,5 +1,5 @@
from PySide6.QtCore import Qt, Signal, QUrl
from PySide6.QtGui import QColor, QDesktopServices
from PySide6.QtCore import Qt, Signal
from PySide6.QtGui import QColor
from PySide6.QtWidgets import (
QDialog,
QVBoxLayout,
@ -13,9 +13,6 @@ from PySide6.QtWidgets import (
QInputDialog,
)
from pathlib import Path
import tempfile
from .db import DBManager
from .settings import load_db_config
from . import strings
@ -197,30 +194,10 @@ class TagBrowserDialog(QDialog):
self._open_document(int(doc_id), str(data.get("file_name")))
def _open_document(self, doc_id: int, file_name: str) -> None:
"""Open a tagged document via the default external application."""
try:
data = self._db.document_data(doc_id)
except Exception as e:
QMessageBox.warning(
self,
strings._("project_documents_title"),
strings._("documents_open_failed").format(error=str(e)),
)
return
"""Open a tagged document from the list."""
from bouquin.document_utils import open_document_from_db
suffix = Path(file_name).suffix or ""
tmp = tempfile.NamedTemporaryFile(
prefix="bouquin_doc_",
suffix=suffix,
delete=False,
)
try:
tmp.write(data)
tmp.flush()
finally:
tmp.close()
QDesktopServices.openUrl(QUrl.fromLocalFile(tmp.name))
open_document_from_db(self._db, doc_id, file_name, parent_widget=self)
def _add_a_tag(self):
"""Add a new tag"""