X Tutup
Skip to content

Commit e464e22

Browse files
author
Steve Canny
committed
sect: add CT_Body.add_section_break()
Removed CT_Body.add_p() test made redundant by xmlchemy.
1 parent b0ddc5a commit e464e22

File tree

5 files changed

+60
-23
lines changed

5 files changed

+60
-23
lines changed

docx/oxml/parts/document.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,11 @@ def add_section_break(self):
4141
sectPr in this case since we're always working at the end of the
4242
block content.
4343
"""
44-
raise NotImplementedError
44+
sentinel_sectPr = self.get_or_add_sectPr()
45+
cloned_sectPr = sentinel_sectPr.clone()
46+
p = self.add_p()
47+
p.set_sectPr(cloned_sectPr)
48+
return sentinel_sectPr
4549

4650
def _insert_p(self, p):
4751
return self._append_blocklevelelt(p)

docx/oxml/section.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44
Section-related custom element classes.
55
"""
66

7+
from __future__ import absolute_import, print_function
8+
9+
from copy import deepcopy
10+
711
from ..enum.section import WD_ORIENTATION, WD_SECTION_START
812
from .simpletypes import ST_SignedTwipsMeasure, ST_TwipsMeasure
913
from .xmlchemy import BaseOxmlElement, OptionalAttribute, ZeroOrOne
@@ -71,6 +75,16 @@ def bottom_margin(self, value):
7175
pgMar = self.get_or_add_pgMar()
7276
pgMar.bottom = value
7377

78+
def clone(self):
79+
"""
80+
Return an exact duplicate of this ``<w:sectPr>`` element tree
81+
suitable for use in adding a section break. All rsid* attributes are
82+
removed from the root ``<w:sectPr>`` element.
83+
"""
84+
clone_sectPr = deepcopy(self)
85+
clone_sectPr.attrib.clear()
86+
return clone_sectPr
87+
7488
@property
7589
def footer(self):
7690
"""

docx/oxml/text.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,15 @@ def _insert_pPr(self, pPr):
3232
self.insert(0, pPr)
3333
return pPr
3434

35+
def set_sectPr(self, sectPr):
36+
"""
37+
Unconditionally replace or add *sectPr* as a grandchild in the
38+
correct sequence.
39+
"""
40+
pPr = self.get_or_add_pPr()
41+
pPr._remove_sectPr()
42+
pPr._insert_sectPr(sectPr)
43+
3544
@property
3645
def style(self):
3746
"""
@@ -70,6 +79,7 @@ class CT_PPr(BaseOxmlElement):
7079
)
7180
pStyle = ZeroOrOne('w:pStyle')
7281
numPr = ZeroOrOne('w:numPr', successors=__child_sequence__[7:])
82+
sectPr = ZeroOrOne('w:sectPr', successors=('w:pPrChange',))
7383

7484
def _insert_pStyle(self, pStyle):
7585
self.insert(0, pStyle)

features/doc-add-section.feature

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ Feature: Add a document section
44
I need a way to add a new section to a document
55

66

7-
@wip
87
Scenario: Add a landscape section to a portrait document
98
Given a single-section document having portrait layout
109
When I add an even-page section to the document

tests/oxml/parts/test_document.py

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,33 +4,17 @@
44
Test suite for the docx.oxml.parts module.
55
"""
66

7-
from docx.oxml.text import CT_P
7+
from __future__ import absolute_import, print_function, unicode_literals
8+
9+
import pytest
810

911
from .unitdata.document import a_body
10-
from ..unitdata.text import a_p, a_sectPr
12+
from ..unitdata.section import a_type
13+
from ..unitdata.text import a_p, a_pPr, a_sectPr
1114

1215

1316
class DescribeCT_Body(object):
1417

15-
def it_can_add_a_p_to_itself(self):
16-
"""
17-
Return a newly created |CT_P| element that has been added after any
18-
existing content.
19-
"""
20-
cases = (
21-
(a_body().with_nsdecls(),
22-
a_body().with_nsdecls().with_child(a_p())),
23-
(a_body().with_nsdecls().with_child(a_sectPr()),
24-
a_body().with_nsdecls().with_child(a_p()).with_child(a_sectPr())),
25-
)
26-
for before_body_bldr, after_body_bldr in cases:
27-
body = before_body_bldr.element
28-
# exercise -----------------
29-
p = body.add_p()
30-
# verify -------------------
31-
assert body.xml == after_body_bldr.xml()
32-
assert isinstance(p, CT_P)
33-
3418
def it_can_clear_all_the_content_it_holds(self):
3519
"""
3620
Remove all content child elements from this <w:body> element.
@@ -51,3 +35,29 @@ def it_can_clear_all_the_content_it_holds(self):
5135
body.clear_content()
5236
# verify -------------------
5337
assert body.xml == after_body_bldr.xml()
38+
39+
def it_can_add_a_section_break(self, section_break_fixture):
40+
body, expected_xml = section_break_fixture
41+
sectPr = body.add_section_break()
42+
assert body.xml == expected_xml
43+
assert sectPr is body.get_or_add_sectPr()
44+
45+
# fixtures -------------------------------------------------------
46+
47+
@pytest.fixture
48+
def section_break_fixture(self):
49+
body = (
50+
a_body().with_nsdecls().with_child(
51+
a_sectPr().with_child(
52+
a_type().with_val('foobar')))
53+
).element
54+
expected_xml = (
55+
a_body().with_nsdecls().with_child(
56+
a_p().with_child(
57+
a_pPr().with_child(
58+
a_sectPr().with_child(
59+
a_type().with_val('foobar'))))).with_child(
60+
a_sectPr().with_child(
61+
a_type().with_val('foobar')))
62+
).xml()
63+
return body, expected_xml

0 commit comments

Comments
 (0)
X Tutup