8000 para: add Paragraph.contains_page_break · python-openxml/python-docx@b85b24f · GitHub
[go: up one dir, main page]

Skip to content

Commit b85b24f

Browse files
committed
para: add Paragraph.contains_page_break
1 parent 1afedd0 commit b85b24f

File tree

6 files changed

+55
-11
lines changed

6 files changed

+55
-11
lines changed

features/par-access-inner-content.feature

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

66

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

src/docx/oxml/text/paragraph.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
if TYPE_CHECKING:
1111
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
12+
from docx.oxml.text.pagebreak import CT_LastRenderedPageBreak
1213
from docx.oxml.text.parfmt import CT_PPr
1314
from docx.oxml.text.run import CT_R
1415

@@ -46,6 +47,17 @@ def clear_content(self):
4647
for child in self.xpath("./*[not(self::w:pPr)]"):
4748
self.remove(child)
4849

50+
@property
51+
def lastRenderedPageBreaks(self) -> List[CT_LastRenderedPageBreak]:
52+
"""All `w:lastRenderedPageBreak` descendants of this paragraph.
53+
54+
Rendered page-breaks commonly occur in a run but can also occur in a run inside
55+
a hyperlink. This returns both.
56+
"""
57+
return self.xpath(
58+
"./w:r/w:lastRenderedPageBreak | ./w:hyperlink/w:r/w:lastRenderedPageBreak"
59+
)
60+
4961
def set_sectPr(self, sectPr):
5062
"""Unconditionally replace or add `sectPr` as grandchild in correct sequence."""
5163
pPr = self.get_or_add_pPr()

src/docx/text/paragraph.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,11 @@ def clear(self):
6464
self._p.clear_content()
6565
return self
6666

67+
@property
68+
def contains_page_break(self) -> bool:
69+
"""`True` when one or more rendered page-breaks occur in this paragraph."""
70+
return bool(self._p.lastRenderedPageBreaks)
71+
6772
def insert_paragraph_before(
6873
self, text: str | None = None, style: str | ParagraphStyle | None = None
6974
) -> Self:

tests/conftest.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
"""pytest fixtures that are shared across test modules."""
2+
3+
import pytest
4+
5+
from docx import types as t
6+
from docx.parts.story import StoryPart
7+
8+
9+
@pytest.fixture
10+
def fake_parent() -> t.StoryChild:
11+
class StoryChild:
12+
@property
13+
def part(self) -> StoryPart:
14+
raise NotImplementedError
15+
16+
return StoryChild()

tests/text/test_paragraph.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
"""Unit test suite for the docx.text.paragraph module."""
22

3+
from typing import cast
4+
35
import pytest
46

7+
from docx import types as t
58
from docx.enum.style import WD_STYLE_TYPE
69
from docx.enum.text import WD_ALIGN_PARAGRAPH
710
from docx.oxml.text.paragraph import CT_P
@@ -16,6 +19,25 @@
1619

1720

1821
class DescribeParagraph(object):
22+
"""Unit-test suite for `docx.text.run.Paragraph`."""
23+
24+
@pytest.mark.parametrize(
25+
("p_cxml", "expected_value"),
26+
[
27+
("w:p/w:r", False),
28+
('w:p/w:r/w:t"foobar"', False),
29+
('w:p/w:hyperlink/w:r/(w:t"abc",w:lastRenderedPageBreak,w:t"def")', True),
30+
("w:p/w:r/(w:lastRenderedPageBreak, w:lastRenderedPageBreak)", True),
31+
],
32+
)
33+
def it_knows_whether_it_contains_a_page_break(
34+
self, p_cxml: str, expected_value: bool, fake_parent: t.StoryChild
35+
):
36+
p = cast(CT_P, element(p_cxml))
37+
paragraph = Paragraph(p, fake_parent)
38+
39+
assert paragraph.contains_page_break == expected_value
40+
1941
def it_knows_its_paragraph_style(self, style_get_fixture):
2042
paragraph, style_id_, style_ = style_get_fixture
2143
style = paragraph.style

tests/text/test_run.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
from docx.enum.text import WD_BREAK, WD_UNDERLINE
1212
from docx.oxml.text.run import CT_R
1313
from docx.parts.document import DocumentPart
14-
from docx.parts.story import StoryPart
1514
from docx.shape import InlineShape
1615
from docx.text.font import Font
1716
from docx.text.run import Run
@@ -278,15 +277,6 @@ def clear_fixture(self, request):
278277
expected_xml = xml(expected_cxml)
279278
return run, expected_xml
280279

281-
@pytest.fixture
282-
def fake_parent(self) -> t.StoryChild:
283-
class StoryChild:
284-
@property
285-
def part(self) -> StoryPart:
286-
raise NotImplementedError
287-
288-
return StoryChild()
289-
290280
@pytest.fixture
291281
def font_fixture(self, Font_, font_):
292282
run = Run(element("w:r"), None)

0 commit comments

Comments
 (0)
0