8000 run: add Run.contains_page_break · python-openxml/python-docx@2364e90 · GitHub
[go: up one dir, main page]

Skip to content

Commit 2364e90

Browse files
committed
run: add Run.contains_page_break
1 parent 2e13d5c commit 2364e90

File tree

6 files changed

+59
-2
lines changed

6 files changed

+59
-2
lines changed

features/run-access-inner-content.feature

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ Feature: Access run inner-content including rendered page-breaks
44
I need to access differentiated run content in document order
55

66

7-
@wip
87
Scenario Outline: Run.contains_page_break reports presence of page-break
98
Given a run having <zero-or-more> rendered page breaks
109
Then run.contains_page_break is <value>

src/docx/oxml/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from __future__ import annotations
77

88
from docx.oxml.parser import register_element_cls
9+
from docx.oxml.text.pagebreak import CT_LastRenderedPageBreak
910
from docx.oxml.text.run import (
1011
CT_R,
1112
CT_Br,
@@ -20,6 +21,7 @@
2021

2122
register_element_cls("w:br", CT_Br)
2223
register_element_cls("w:cr", CT_Cr)
24+
register_element_cls("w:lastRenderedPageBreak", CT_LastRenderedPageBreak)
2325
register_element_cls("w:noBreakHyphen", CT_NoBreakHyphen)
2426
register_element_cls("w:ptab", CT_PTab)
2527
register_element_cls("w:r", CT_R)

src/docx/oxml/text/pagebreak.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
"""Custom element class for rendered page-break (CT_LastRenderedPageBreak)."""
2+
3+
from __future__ import annotations
4+
5+
from docx.oxml.xmlchemy import BaseOxmlElement
6+
7+
8+
class CT_LastRenderedPageBreak(BaseOxmlElement):
9+
"""`<w:lastRenderedPageBreak>` element, indicating page break inserted by renderer.
10+
11+
A rendered page-break is one inserted by the renderer when it runs out of room on a
12+
page. It is an empty element (no attrs or children) and is a child of CT_R, peer to
13+
CT_Text.
14+
15+
NOTE: this complex-type name does not exist in the schema, where
16+
`w:lastRenderedPageBreak` maps to `CT_Empty`. This name was added to give it
17+
distinguished behavior. CT_Empty is used for many elements.
18+
"""

src/docx/oxml/text/run.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@
22

33
from __future__ import annotations
44

5-
from typing import Callable
5+
from typing import TYPE_CHECKING, Callable, List
66

77
from docx.oxml.ns import qn
88
from docx.oxml.simpletypes import ST_BrClear, ST_BrType
99
from docx.oxml.text.font import CT_RPr
1010
from docx.oxml.xmlchemy import BaseOxmlElement, OptionalAttribute, ZeroOrMore, ZeroOrOne
1111

12+
if TYPE_CHECKING:
13+
from docx.oxml.text.pagebreak import CT_LastRenderedPageBreak
14+
1215
# ------------------------------------------------------------------------------------
1316
# Run-level elements
1417

@@ -49,6 +52,11 @@ def clear_content(self):
4952
for child in content_child_elms:
5053
self.remove(child)
5154

55+
@property
56+
def lastRenderedPageBreaks(self) -> List[CT_LastRenderedPageBreak]:
57+
"""All `w:lastRenderedPageBreaks` descendants of this run."""
58+
return self.xpath("./w:lastRenderedPageBreak")
59+
5260
@property
5361
def style(self) -> str | None:
5462
"""String contained in `w:val` attribute of `w:rStyle` grandchild.

src/docx/text/run.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,19 @@ def clear(self):
104104
self._r.clear_content()
105105
return self
106106

107+
@property
108+
def contains_page_break(self) -> bool:
109+
"""`True` when one or more rendered page-breaks occur in this run.
110+
111+
Note that "hard" page-breaks inserted by the author are not included. A hard
112+
page-break gives rise to a rendered page-break in the right position so if those
113+
were included that page-break would be "double-counted".
114+
115+
It would be very rare for multiple rendered page-breaks to occur in a single
116+
run, but it is possible.
117+
"""
118+
return bool(self._r.lastRenderedPageBreaks)
119+
107120
@property
108121
def font(self):
109122
"""The |Font| object providing access to the character formatting properties for

tests/text/test_run.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,23 @@ def it_can_change_its_bool_prop_settings(self, bool_prop_set_fixture):
2828
setattr(run, prop_name, value)
2929
assert run._r.xml == expected_xml
3030

31+
@pytest.mark.parametrize(
32+
("r_cxml", "expected_value"),
33+
[
34+
("w:r", False),
35+
('w:r/w:t"foobar"', False),
36+
('w:r/(w:t"abc", w:lastRenderedPageBreak, w:t"def")', True),
37+
("w:r/(w:lastRenderedPageBreak, w:lastRenderedPageBreak)", True),
38+
],
39+
)
40+
def it_knows_whether_it_contains_a_page_break(
41+
self, r_cxml: str, expected_value: bool
42+
):
43+
r = cast(CT_R, element(r_cxml))
44+
run = Run(r, None) # pyright: ignore[reportGeneralTypeIssues]
45+
46+
assert run.contains_page_break == expected_value
47+
3148
def it_knows_its_character_style(self, style_get_fixture):
3249
run, style_id_, style_ = style_get_fixture
3350
style = run.style

0 commit comments

Comments
 (0)
0