Skip to content

Add public external hyperlink authoring - #1611

Draft
pseudosavant wants to merge 12 commits into
python-openxml:masterfrom
pseudosavant:codex/hyperlink-authoring
Draft

pseudosavant wants to merge 12 commits into
python-openxml:masterfrom
pseudosavant:codex/hyperlink-authoring

Conversation

@pseudosavant

Copy link
Copy Markdown

Callers can read hyperlinks today but must construct XML to create them. This draft adds Paragraph.add_hyperlink(), Hyperlink.add_run(), and a read/write Hyperlink.tooltip property. Together they create external links with formatted labels and optional hover text through public APIs.

paragraph = document.add_paragraph("Read ")
link = paragraph.add_hyperlink(
    address="https://example.com/docs?lang=en#intro",
    tooltip="Project documentation",
)
link.add_run("the ")
link.add_run("documentation").bold = True
paragraph.add_run(" for details.")

The implementation extends the current Hyperlink proxy. Relationships belong to the containing story part, including headers and footers. Returned runs use existing formatting, style, and picture APIs. Invalid inputs are checked before attaching a hyperlink or registering its relationship.

This implements the external hyperlink creation described in #74, using the API proposed below. The issue discussion also covers internal links and other operations. Internal links and bookmarks, address mutation, removal, arbitrary run insertion, and visited-state management are outside this draft.

The "External authoring proposal" section in docs/dev/analysis/features/text/hyperlink.rst explains the API choices and the relationship to #278 and #784. This draft builds on the current reader instead of importing either older implementation. Following the acceptance-test guidance, the branch starts with an API proposal, then introduces acceptance specifications tagged @wip, followed by small implementation commits with isolated unit tests. Each tag is removed when its scenarios pass. The sequence was rebuilt from a local prototype, with the failing and passing stages rerun.

API decisions for review:

  • Require keyword-only address and preserve the complete external destination, including escapes and URI fragments. Defer a separate fragment argument and URL encoding.
  • Use append-only add_run(text, style) to match Paragraph.add_run(). Defer the broader insert_run proposal.
  • Leave character styling to the caller. No Hyperlink style is created or applied automatically. The user guide supplies a public-API recipe for themed styling.
  • Treat tooltip None as absent and "" as explicitly empty. Permit both creation-time assignment and later edits.

These choices need maintainer agreement. In particular, feedback on the narrow append-only API and the styling default would help settle the draft.

I plan to follow this with internal links and bookmark authoring. I can bring internal hyperlink creation into this PR if you prefer to review external and internal destinations together. Bookmark creation could remain a separate contribution, or be included here after we agree on its API and scope.

Validation on Windows with Python 3.13:

  • 1,677 unit and saved-document tests pass, including 68 new cases.
  • 672 acceptance scenarios pass, including 22 new scenarios.
  • Ruff lint and formatting checks pass.
  • No new Pyright diagnostics. The diagnostic multiset matches the upstream baseline of 7,577 existing diagnostics.
  • A clean HTML documentation build succeeds using Sphinx 9.1 with the legacy intersphinx mapping disabled in memory. One existing unresolved container reference remains in the comments guide.
  • The unchanged public API was previously exercised in Word. The sample opened without repair and rendered formatted labels, a linked picture, and links in body, table, header, and footer content. Word displayed the custom tooltip and exact destination. External navigation has not been exercised.

@pseudosavant

Copy link
Copy Markdown
Author

@scanny I’ve prepared this draft with acceptance tests, unit tests, and documentation. Before marking it ready for review, I’d appreciate your feedback on the proposed API and scope. Would you prefer internal hyperlink support included here or handled in a follow-up PR?

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.

1 participant