Skip to content

BUG: Always define PdfWriter._reader - #3960

Merged
stefan6419846 merged 2 commits into
py-pdf:mainfrom
RavSinghChandan:fix-writer-protocol-reader
Aug 13, 2026
Merged

stefan6419846 merged 2 commits into
py-pdf:mainfrom
RavSinghChandan:fix-writer-protocol-reader

Conversation

@RavSinghChandan

Copy link
Copy Markdown
Contributor

Pulled on another one of the typeguard failures from #3689 and this one
turned out to be a real defect rather than test noise.

PdfWriterProtocol declares _reader, but PdfWriter only assigns it in the
incremental branch of init. So a writer built the normal way doesn't
actually satisfy the protocol it gets passed as — isinstance(writer,
PdfWriterProtocol) is False, and anything doing a runtime protocol check
rejects it. Under make testtype it's 62 of the failures, all on that one
missing attribute.

Declared it Optional[PdfReader] defaulting to None, next to the other
attribute docstrings in init. The three places that read it
(write(), _write_increment() twice) are all already inside
if self.incremental, so nothing changes at runtime — they just needed an
assert to narrow the Optional, which is the same assert ..., "mypy" style
already used elsewhere in this file.

Added a test that fails on main with AttributeError. mypy on pypdf/ reports
the same 22 pre-existing errors before and after, none in these files; the
offline suite goes 1007 → 1008 passed with the only failure being
test_appearance_stream_rtl, which fails the same way on a clean checkout here.

PdfWriterProtocol declares `_reader`, but PdfWriter only assigned it in
the incremental branch of __init__. A writer created the normal way has
no such attribute, so it does not satisfy the protocol it gets passed
as -- `isinstance(writer, PdfWriterProtocol)` is False, and typeguard
fails 62 checks across the test suite on that one attribute.

Declare it as Optional[PdfReader] defaulting to None. The three reads
are all inside `if self.incremental`, so behaviour is unchanged; they
get an assert to narrow the type, matching the existing style in this
file.
@codecov

codecov Bot commented Aug 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.93%. Comparing base (1d92adf) to head (12d7589).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #3960   +/-   ##
=======================================
  Coverage   97.93%   97.93%           
=======================================
  Files          57       57           
  Lines       10936    10940    +4     
  Branches     2048     2048           
=======================================
+ Hits        10710    10714    +4     
  Misses        125      125           
  Partials      101      101           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment thread pypdf/_protocols.py Resolved
Comment thread pypdf/_protocols.py Resolved
@RavSinghChandan

Copy link
Copy Markdown
Contributor Author

Both trimmed — dropped the backticks since these are plain comments rather
than rendered docstrings, and cut the second line. Left the one on
_write_increment, since "only reached from write() inside if self.incremental"
is the reason the assert is safe and isn't obvious from the call site.

@stefan6419846
stefan6419846 merged commit c8e1c72 into py-pdf:main Aug 13, 2026
23 of 31 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants