Skip to content

Commit a02c220

Browse files
committed
hlink: add Hyperlink.text
1 parent 01061a8 commit a02c220

File tree

4 files changed

+39
-2
lines changed

4 files changed

+39
-2
lines changed

features/hlk-props.feature

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ Feature: Access hyperlink properties
3030
| two | 2 |
3131

3232

33-
@wip
3433
Scenario: Hyperlink.text has the visible text of the hyperlink
3534
Given a hyperlink
3635
Then hyperlink.text is the visible text of the hyperlink

src/docx/oxml/text/hyperlink.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,11 @@ class CT_Hyperlink(BaseOxmlElement):
3131
def lastRenderedPageBreaks(self) -> List[CT_LastRenderedPageBreak]:
3232
"""All `w:lastRenderedPageBreak` descendants of this hyperlink."""
3333
return self.xpath("./w:r/w:lastRenderedPageBreak")
34+
35+
@property # pyright: ignore[reportIncompatibleVariableOverride]
36+
def text(self) -> str:
37+
"""The textual content of this hyperlink.
38+
39+
`CT_Hyperlink` stores the hyperlink-text as one or more `w:r` children.
40+
"""
41+
return "".join(r.text for r in self.xpath("w:r"))

src/docx/text/hyperlink.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,13 @@ def runs(self) -> List[Run]:
6060
was saved.
6161
"""
6262
return [Run(r, self) for r in self._hyperlink.r_lst]
63+
64+
@property
65+
def text(self) -> str:
66+
"""String formed by concatenating the text of each run in the hyperlink.
67+
68+
Tabs and line breaks in the XML are mapped to ``\\t`` and ``\\n`` characters
69+
respectively. Note that rendered page-breaks can occur within a hyperlink but
70+
they are not reflected in this text.
71+
"""
72+
return self._hyperlink.text

tests/text/test_hyperlink.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,27 @@ def it_provides_access_to_the_runs_it_contains(
6363

6464
actual = [type(item).__name__ for item in runs]
6565
expected = ["Run" for _ in range(count)]
66-
assert actual == expected, f"expected: {expected}, got: {actual}"
66+
assert actual == expected
67+
68+
@pytest.mark.parametrize(
69+
("hlink_cxml", "expected_text"),
70+
[
71+
("w:hyperlink", ""),
72+
("w:hyperlink/w:r", ""),
73+
('w:hyperlink/w:r/w:t"foobar"', "foobar"),
74+
('w:hyperlink/w:r/(w:t"foo",w:lastRenderedPageBreak,w:t"bar")', "foobar"),
75+
('w:hyperlink/w:r/(w:t"abc",w:tab,w:t"def",w:noBreakHyphen)', "abc\tdef-"),
76+
],
77+
)
78+
def it_knows_the_visible_text_of_the_link(
79+
self, hlink_cxml: str, expected_text: str, fake_parent: t.StoryChild
80+
):
81+
hlink = cast(CT_Hyperlink, element(hlink_cxml))
82+
hyperlink = Hyperlink(hlink, fake_parent)
83+
84+
text = hyperlink.text
85+
86+
assert text == expected_text
6787

6888
# -- fixtures --------------------------------------------------------------------
6989

0 commit comments

Comments
 (0)