diff --git a/dangerzone/document.py b/dangerzone/document.py index f825b78..b49b512 100644 --- a/dangerzone/document.py +++ b/dangerzone/document.py @@ -9,7 +9,7 @@ from typing import Optional import appdirs -from .errors import DocumentFilenameException +from . import errors SAFE_EXTENSION = "-safe.pdf" @@ -54,28 +54,24 @@ class Document: try: open(filename, "rb") except FileNotFoundError as e: - raise DocumentFilenameException( - "Input file not found: make sure you typed it correctly." - ) from e + raise errors.InputFileNotFoundException() from e except PermissionError as e: - raise DocumentFilenameException( - "You don't have permission to open the input file." - ) from e + raise errors.InputFileNotReadableException() from e @staticmethod def validate_output_filename(filename: str) -> None: if not filename.endswith(".pdf"): - raise DocumentFilenameException("Safe PDF filename must end in '.pdf'") + raise errors.NonPDFOutputFileException() try: with open(filename, "wb"): pass except PermissionError as e: - raise DocumentFilenameException("Safe PDF filename is not writable") from e + raise errors.UnwriteableOutputFileException() from e @property def input_filename(self) -> str: if self._input_filename is None: - raise DocumentFilenameException("Input filename has not been set yet.") + raise errors.NotSetInputFilenameException() else: return self._input_filename @@ -92,7 +88,7 @@ class Document: if self._input_filename is not None: return self.default_output_filename else: - raise DocumentFilenameException("Output filename has not been set yet.") + raise errors.NotSetOutputFilenameException() else: return self._output_filename diff --git a/dangerzone/errors.py b/dangerzone/errors.py index a26d213..00eb702 100644 --- a/dangerzone/errors.py +++ b/dangerzone/errors.py @@ -14,6 +14,49 @@ class DocumentFilenameException(Exception): """Exception for document-related filename errors.""" +class InputFileNotFoundException(DocumentFilenameException): + """Exception for when an input file does not exist.""" + + def __init__(self) -> None: + super().__init__("Input file not found: make sure you typed it correctly.") + + +class InputFileNotReadableException(DocumentFilenameException): + """Exception for when an input file exists but is not readable.""" + + def __init__(self) -> None: + super().__init__("You don't have permission to open the input file.") + + +class NonPDFOutputFileException(DocumentFilenameException): + """Exception for when the output file is not a PDF.""" + + def __init__(self) -> None: + super().__init__("Safe PDF filename must end in '.pdf'") + + +class UnwriteableOutputFileException(DocumentFilenameException): + """Exception for when the output file is not writeable.""" + + def __init__(self) -> None: + super().__init__("Safe PDF filename is not writable") + + +class NotSetInputFilenameException(DocumentFilenameException): + """Exception for when the output filename is set before having an + associated input file.""" + + def __init__(self) -> None: + super().__init__("Input filename has not been set yet.") + + +class NotSetOutputFilenameException(DocumentFilenameException): + """Exception for when the output filename is read before it has been set.""" + + def __init__(self) -> None: + super().__init__("Output filename has not been set yet.") + + def handle_document_errors(func: F) -> F: """Log document-related errors and exit gracefully.""" diff --git a/tests/test_document.py b/tests/test_document.py index 61621ad..9e9d23b 100644 --- a/tests/test_document.py +++ b/tests/test_document.py @@ -5,8 +5,8 @@ from pathlib import Path import pytest +from dangerzone import errors from dangerzone.document import Document -from dangerzone.errors import DocumentFilenameException from . import sample_doc, unreadable_pdf, unwriteable_pdf @@ -25,15 +25,13 @@ def test_input_file_none() -> None: Attempts to read a document's filename when no doc has been set """ d = Document() - with pytest.raises(DocumentFilenameException) as e: + with pytest.raises(errors.NotSetInputFilenameException) as e: d.input_filename - assert "Input filename has not been set yet" in str(e.value) def test_input_file_non_existing() -> None: - with pytest.raises(DocumentFilenameException) as e: + with pytest.raises(errors.InputFileNotFoundException) as e: Document("non-existing-file.pdf") - assert "Input file not found" in str(e.value) # XXX: This is not easy to test on Windows, as the file owner can always read it. @@ -41,14 +39,13 @@ def test_input_file_non_existing() -> None: # https://stackoverflow.com/questions/72528318/what-file-permissions-make-a-file-unreadable-by-owner-in-windows @pytest.mark.skipif(platform.system() == "Windows", reason="Unix-specific") def test_input_file_unreadable(unreadable_pdf: str) -> None: - with pytest.raises(DocumentFilenameException) as e: + with pytest.raises(errors.InputFileNotReadableException) as e: Document(unreadable_pdf) - assert "don't have permission to open the input file" in str(e.value) def test_output_file_unwriteable(unwriteable_pdf: str) -> None: d = Document() - with pytest.raises(DocumentFilenameException) as e: + with pytest.raises(errors.UnwriteableOutputFileException) as e: d.output_filename = unwriteable_pdf assert "Safe PDF filename is not writable" in str(e.value) @@ -64,18 +61,16 @@ def test_output_file_none() -> None: Attempts to read a document's filename when no doc has been set """ d = Document() - with pytest.raises(DocumentFilenameException) as e: + with pytest.raises(errors.NotSetOutputFilenameException) as e: d.output_filename - assert "Output filename has not been set yet" in str(e.value) def test_output_file_not_pdf(tmp_path: Path) -> None: docx_file = str(tmp_path.joinpath("document.docx")) d = Document() - with pytest.raises(DocumentFilenameException) as e: + with pytest.raises(errors.NonPDFOutputFileException) as e: d.output_filename = docx_file - assert "Safe PDF filename must end in '.pdf'" in str(e.value) assert not os.path.exists(docx_file)