Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions PyPDF2/_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@
from .constants import PageAttributes as PG
from .constants import PagesAttributes as PA
from .constants import TrailerKeys as TK
from .errors import PdfReadError, PdfStreamError
from .errors import PdfReadError, PdfStreamError, WrongPasswordError, \
FileNotDecryptedError, EmptyFileError
from .generic import (
ArrayObject,
ContentStream,
Expand Down Expand Up @@ -290,7 +291,7 @@ def __init__(
and password is not None
):
# raise if password provided
raise PdfReadError("Wrong password")
raise WrongPasswordError("Wrong password")
self._override_encryption = False
else:
if password is not None:
Expand Down Expand Up @@ -1155,7 +1156,7 @@ def get_object(self, indirect_reference: IndirectObject) -> Optional[PdfObject]:
if not self._override_encryption and self._encryption is not None:
# if we don't have the encryption key:
if not self._encryption.is_decrypted():
raise PdfReadError("File has not been decrypted")
raise FileNotDecryptedError("File has not been decrypted")
# otherwise, decrypt here...
retval = cast(PdfObject, retval)
retval = self._encryption.decrypt_object(
Expand Down Expand Up @@ -1306,7 +1307,7 @@ def _basic_validation(self, stream: StreamType) -> None:
# start at the end:
stream.seek(0, os.SEEK_END)
if not stream.tell():
raise PdfReadError("Cannot read an empty file")
raise EmptyFileError("Cannot read an empty file")
if self.strict:
stream.seek(0, os.SEEK_SET)
header_byte = stream.read(5)
Expand Down
12 changes: 12 additions & 0 deletions PyPDF2/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,16 @@ class ParseError(Exception):
pass


class FileNotDecryptedError(PdfReadError):
pass


class WrongPasswordError(FileNotDecryptedError):
pass


class EmptyFileError(PdfReadError):
pass


STREAM_TRUNCATED_PREMATURELY = "Stream has ended unexpectedly"
17 changes: 12 additions & 5 deletions tests/test_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from PyPDF2.constants import ImageAttributes as IA
from PyPDF2.constants import PageAttributes as PG
from PyPDF2.constants import Ressources as RES
from PyPDF2.errors import PdfReadError, PdfReadWarning
from PyPDF2.errors import PdfReadError, PdfReadWarning, EmptyFileError, FileNotDecryptedError, WrongPasswordError
from PyPDF2.filters import _xobj_to_image
from PyPDF2.generic import Destination

Expand Down Expand Up @@ -414,9 +414,8 @@ def test_get_page_mode(src, expected):


def test_read_empty():
with pytest.raises(PdfReadError) as exc:
with pytest.raises(EmptyFileError):
PdfReader(io.BytesIO())
assert exc.value.args[0] == "Cannot read an empty file"


def test_read_malformed_header():
Expand Down Expand Up @@ -560,9 +559,8 @@ def test_read_unknown_zero_pages(caplog):
def test_read_encrypted_without_decryption():
src = RESOURCE_ROOT / "libreoffice-writer-password.pdf"
reader = PdfReader(src)
with pytest.raises(PdfReadError) as exc:
with pytest.raises(FileNotDecryptedError):
len(reader.pages)
assert exc.value.args[0] == "File has not been decrypted"


def test_get_destination_page_number():
Expand Down Expand Up @@ -1066,3 +1064,12 @@ def test_PdfReaderMultipleDefinitions(caplog):
assert normalize_warnings(caplog.text) == [
"Multiple definitions in dictionary at byte 0xb5 for key /Group"
]


def test_wrong_password_error():
encrypted_pdf_path = RESOURCE_ROOT / "encrypted-file.pdf"
with pytest.raises(WrongPasswordError):
PdfReader(
encrypted_pdf_path,
password="definitely_the_wrong_password!",
)