ENH: Add /IRT (in-reply-to) support for markup annotations#3631
ENH: Add /IRT (in-reply-to) support for markup annotations#3631stefan6419846 merged 12 commits intopy-pdf:mainfrom
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #3631 +/- ##
=======================================
Coverage 97.36% 97.36%
=======================================
Files 55 55
Lines 9925 9942 +17
Branches 1817 1823 +6
=======================================
+ Hits 9663 9680 +17
Misses 152 152
Partials 110 110 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
9f0ca7e to
b65774c
Compare
|
Thanks for the thorough review! I've addressed all 7 comments in the latest commit:
|
|
Could you please have a look at the coverage?
I am not aware of having requested such a change. We should write it in all cases, even if it is considered the default here. |
|
Good catch — reverted to always writing |
stefan6419846
left a comment
There was a problem hiding this comment.
Sorry for the delay. I have added some further remarks I stumbled upon.
|
Thanks for the thorough follow-up review! Addressed all points in the latest push:
Re the |
|
@stefan6419846 Thanks for the thorough second round of feedback! I've addressed all comments in 8b39b2e:
Ready for another look when you have time. |
Add first-class support for annotation replies (PDF 1.5) by extending MarkupAnnotation with three new parameters: - in_reply_to: reference to the parent annotation, sets /IRT - reply_type: "R" (reply, default) or "Group", sets /RT - annotation_name: sets /NM for annotation threading (auto-generated UUID when in_reply_to is set) Closes py-pdf#2065
Raise ValueError if reply_type is not 'R' or 'Group' (the only values allowed by PDF spec Table 170), rather than silently writing an invalid /RT entry.
- Use Literal["R", "Group"] for reply_type instead of runtime string check - Accept IndirectObject directly for in_reply_to (not just DictionaryObject) - Raise ValueError for unregistered in_reply_to instead of logging warning - Only write /RT when reply_type is "Group" (per PDF spec, /R is the default) - Simplify tests: use PdfWriter(clone_from=...) and BytesIO instead of disk I/O
Use isinstance(indirect_ref, IndirectObject) instead of direct attribute access to handle both the missing-attribute case and mypy type narrowing.
Per maintainer feedback, always write /RT explicitly even when reply_type is the default "R", rather than omitting it. Update test assertion and docstring accordingly.
- Simplify in_reply_to and annotation_name docstrings to remove implementation details (DictionaryObject, /NM, UUID) - Use Sphinx :meth: cross-reference for add_annotation() - Rename test functions to test_markup_annotation_* prefix - Assert exact /IRT and /NM values after write/read cycle - Remove unnecessary BytesIO write in group type test - Convert inline comments to proper docstrings
8b39b2e to
462f82a
Compare
Move /NM assignment inside the in_reply_to block and add ValueError guards for annotation_name and reply_type when provided without in_reply_to. This prevents silent parameter discard and keeps the reply-specific parameters properly scoped.
|
Hey @stefan6419846, sorry for the late reply, totally missed your last comment. You're right, I've moved /NM inside the in_reply_to block so it's properly scoped to the reply context. Also added ValueError guards for both annotation_name and reply_type when passed without in_reply_to, so they don't just silently get ignored. Ready for another look whenever you get a chance. |
|
It seems like you forgot to push your latest changes? |
|
Hey, sorry about that. Pushed the changes just now. The pypy3.11 failure is a runner timeout (shutdown signal mid-test), not related to our changes. All other jobs pass. Could you re-trigger that one when you get a chance? |
## What's new ### Security (SEC) - Limit allowed `/Length` value of stream (#3675) by @stefan6419846 ### New Features (ENH) - Add /IRT (in-reply-to) support for markup annotations (#3631) by @costajohnt ### Documentation (DOC) - Avoid using `PageObject.replace_contents` on PdfReader (#3669) by @stefan6419846 - Document how to disable jbig2dec calls by @stefan6419846 [Full Changelog](6.7.5...6.8.0)
Summary
Adds first-class support for PDF annotation replies (PDF spec 1.5, Table 170) to the
MarkupAnnotationbase class.New parameters on
MarkupAnnotationin_reply_to: Reference to a parent annotation (the object returned bywriter.add_annotation()). Sets the/IRTentry.reply_type: Either"R"(reply, default) or"Group"(grouped). Sets the/RTentry.annotation_name: Sets the/NMentry for annotation threading. Auto-generated as a UUID whenin_reply_tois set and no name is provided.Usage example
Design notes
Popup(parent=...)for referencing other annotations viaindirect_referencein_reply_toreceives an unregistered annotation object, matching the existingPopupbehaviorMarkupAnnotationsubclasses requirerect, so the workaround discovered in the issue thread (reply annotations need/Rectto be visible) is handled naturallyTests
5 new tests covering:
/IRT,/RT,/NMverification + round-trip readreply_type="Group"variantannotation_namewithoutin_reply_toannotation_namewithin_reply_toCloses #2065