From 99e1bd29eb807a077986359da81ff006dcfe6aa5 Mon Sep 17 00:00:00 2001 From: Julian Smith Date: Fri, 10 Apr 2026 17:24:48 +0100 Subject: [PATCH 1/2] tests/: added test_4944(), reproducer for #4944. --- tests/resources/test_4944.pdf | Bin 0 -> 10801 bytes tests/test_annots.py | 21 +++++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 tests/resources/test_4944.pdf diff --git a/tests/resources/test_4944.pdf b/tests/resources/test_4944.pdf new file mode 100644 index 0000000000000000000000000000000000000000..8e9d0266940eb1d00a2199d162e450294d805e1d GIT binary patch literal 10801 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 Zgj&<3(o|I Date: Fri, 10 Apr 2026 17:46:12 +0100 Subject: [PATCH 2/2] src/ tests/: avoid exception in Page.annots() to fix #4928. Looks like self.annot_xrefs() can return bogus xref values, which we now ignore. --- src/__init__.py | 6 ++++-- tests/test_general.py | 7 +++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/__init__.py b/src/__init__.py index 1256fc450..96d986202 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -10670,8 +10670,10 @@ def annots(self, types=None): annot_xrefs = [a[0] for a in self.annot_xrefs() if a[1] in types and a[1] not in skip_types] for xref in annot_xrefs: annot = self.load_annot(xref) - annot._yielded=True - yield annot + # In #4928, annot can be None, which we need to ignore. + if annot: + annot._yielded=True + yield annot def apply_redactions( page: 'Page', diff --git a/tests/test_general.py b/tests/test_general.py index fd063ffa2..c3ab644c3 100644 --- a/tests/test_general.py +++ b/tests/test_general.py @@ -2213,13 +2213,12 @@ def test_4907(): display_list = page.get_displaylist(annots=False) text_page = display_list.get_textpage() + def test_4928(): path = os.path.normpath(f'{__file__}/../../tests/resources/test_4928.pdf') with pymupdf.open(path) as document: - try: - document.scrub() - except Exception as e: - print(f'Ignoring expected exception: {e}') + document.scrub() + def test_4902(): print()