Skip to content

Commit 65a59c6

Browse files
author
Steve Canny
committed
sect: add Section margin setters
1 parent 56cc5f7 commit 65a59c6

4 files changed

Lines changed: 121 additions & 30 deletions

File tree

docx/oxml/section.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,11 @@ def bottom_margin(self):
6666
return None
6767
return pgMar.bottom
6868

69+
@bottom_margin.setter
70+
def bottom_margin(self, value):
71+
pgMar = self.get_or_add_pgMar()
72+
pgMar.bottom = value
73+
6974
@property
7075
def footer(self):
7176
"""
@@ -78,6 +83,11 @@ def footer(self):
7883
return None
7984
return pgMar.footer
8085

86+
@footer.setter
87+
def footer(self, value):
88+
pgMar = self.get_or_add_pgMar()
89+
pgMar.footer = value
90+
8191
@property
8292
def gutter(self):
8393
"""
@@ -90,6 +100,11 @@ def gutter(self):
90100
return None
91101
return pgMar.gutter
92102

103+
@gutter.setter
104+
def gutter(self, value):
105+
pgMar = self.get_or_add_pgMar()
106+
pgMar.gutter = value
107+
93108
@property
94109
def header(self):
95110
"""
@@ -102,6 +117,11 @@ def header(self):
102117
return None
103118
return pgMar.header
104119

120+
@header.setter
121+
def header(self, value):
122+
pgMar = self.get_or_add_pgMar()
123+
pgMar.header = value
124+
105125
@property
106126
def left_margin(self):
107127
"""
@@ -114,6 +134,11 @@ def left_margin(self):
114134
return None
115135
return pgMar.left
116136

137+
@left_margin.setter
138+
def left_margin(self, value):
139+
pgMar = self.get_or_add_pgMar()
140+
pgMar.left = value
141+
117142
@property
118143
def right_margin(self):
119144
"""
@@ -126,6 +151,11 @@ def right_margin(self):
126151
return None
127152
return pgMar.right
128153

154+
@right_margin.setter
155+
def right_margin(self, value):
156+
pgMar = self.get_or_add_pgMar()
157+
pgMar.right = value
158+
129159
@property
130160
def orientation(self):
131161
"""
@@ -207,6 +237,11 @@ def top_margin(self):
207237
return None
208238
return pgMar.top
209239

240+
@top_margin.setter
241+
def top_margin(self, value):
242+
pgMar = self.get_or_add_pgMar()
243+
pgMar.top = value
244+
210245

211246
class CT_SectType(BaseOxmlElement):
212247
"""

docx/section.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ def bottom_margin(self):
2323
"""
2424
return self._sectPr.bottom_margin
2525

26+
@bottom_margin.setter
27+
def bottom_margin(self, value):
28+
self._sectPr.bottom_margin = value
29+
2630
@property
2731
def footer_distance(self):
2832
"""
@@ -32,6 +36,10 @@ def footer_distance(self):
3236
"""
3337
return self._sectPr.footer
3438

39+
@footer_distance.setter
40+
def footer_distance(self, value):
41+
self._sectPr.footer = value
42+
3543
@property
3644
def gutter(self):
3745
"""
@@ -42,6 +50,10 @@ def gutter(self):
4250
"""
4351
return self._sectPr.gutter
4452

53+
@gutter.setter
54+
def gutter(self, value):
55+
self._sectPr.gutter = value
56+
4557
@property
4658
def header_distance(self):
4759
"""
@@ -51,6 +63,10 @@ def header_distance(self):
5163
"""
5264
return self._sectPr.header
5365

66+
@header_distance.setter
67+
def header_distance(self, value):
68+
self._sectPr.header = value
69+
5470
@property
5571
def left_margin(self):
5672
"""
@@ -59,6 +75,10 @@ def left_margin(self):
5975
"""
6076
return self._sectPr.left_margin
6177

78+
@left_margin.setter
79+
def left_margin(self, value):
80+
self._sectPr.left_margin = value
81+
6282
@property
6383
def orientation(self):
6484
"""
@@ -107,6 +127,10 @@ def right_margin(self):
107127
"""
108128
return self._sectPr.right_margin
109129

130+
@right_margin.setter
131+
def right_margin(self, value):
132+
self._sectPr.right_margin = value
133+
110134
@property
111135
def start_type(self):
112136
"""
@@ -127,3 +151,7 @@ def top_margin(self):
127151
section in English Metric Units.
128152
"""
129153
return self._sectPr.top_margin
154+
155+
@top_margin.setter
156+
def top_margin(self, value):
157+
self._sectPr.top_margin = value

features/sct-section-props.feature

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@ Feature: Access and change section properties
7676
And the reported footer margin is 0.75 inches
7777

7878

79-
@wip
8079
Scenario Outline: Set section page margins
8180
Given a section having known page margins
8281
When I set the <margin-type> margin to <length> inches

tests/test_section.py

Lines changed: 58 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,15 @@ def it_knows_its_page_margins(self, margins_get_fixture):
6464
assert section.header_distance == header
6565
assert section.footer_distance == footer
6666

67+
def it_can_change_its_page_margins(self, margins_set_fixture):
68+
section, margin_prop_name, new_value, expected_xml = (
69+
margins_set_fixture
70+
)
71+
print(section._sectPr.xml)
72+
setattr(section, margin_prop_name, new_value)
73+
print(section._sectPr.xml)
74+
assert section._sectPr.xml == expected_xml
75+
6776
# fixtures -------------------------------------------------------
6877

6978
@pytest.fixture(params=[
@@ -74,25 +83,50 @@ def it_knows_its_page_margins(self, margins_get_fixture):
7483
def margins_get_fixture(self, request):
7584
(has_pgMar_child, left, right, top, bottom, gutter, header,
7685
footer) = request.param
77-
pgMar_bldr = self.pgMar_bldr(
78-
has_pgMar_child, left=left, right=right, top=top, bottom=bottom,
79-
gutter=gutter, header=header, footer=footer
80-
)
86+
pgMar_bldr = self.pgMar_bldr(**{
87+
'has_pgMar': has_pgMar_child, 'left': left, 'right': right,
88+
'top': top, 'bottom': bottom, 'gutter': gutter, 'header': header,
89+
'footer': footer
90+
})
8191
sectPr = self.sectPr_bldr(pgMar_bldr).element
8292
section = Section(sectPr)
83-
expected_left = left * 635 if left else None
84-
expected_right = right * 635 if right else None
85-
expected_top = top * 635 if top else None
86-
expected_bottom = bottom * 635 if bottom else None
87-
expected_gutter = gutter * 635 if gutter else None
88-
expected_header = header * 635 if header else None
89-
expected_footer = footer * 635 if footer else None
93+
expected_left = self.twips_to_emu(left)
94+
expected_right = self.twips_to_emu(right)
95+
expected_top = self.twips_to_emu(top)
96+
expected_bottom = self.twips_to_emu(bottom)
97+
expected_gutter = self.twips_to_emu(gutter)
98+
expected_header = self.twips_to_emu(header)
99+
expected_footer = self.twips_to_emu(footer)
90100
return (
91101
section, expected_left, expected_right, expected_top,
92102
expected_bottom, expected_gutter, expected_header,
93103
expected_footer
94104
)
95105

106+
@pytest.fixture(params=[
107+
('left', 1440, 720), ('right', None, 1800), ('top', 2160, None),
108+
('bottom', 720, 2160), ('gutter', None, 360), ('header', 720, 630),
109+
('footer', None, 810)
110+
])
111+
def margins_set_fixture(self, request):
112+
margin_side, initial_margin, new_margin = request.param
113+
# section ----------------------
114+
pgMar_bldr = self.pgMar_bldr(**{margin_side: initial_margin})
115+
sectPr = self.sectPr_bldr(pgMar_bldr).element
116+
section = Section(sectPr)
117+
# property name ----------------
118+
property_name = {
119+
'left': 'left_margin', 'right': 'right_margin',
120+
'top': 'top_margin', 'bottom': 'bottom_margin',
121+
'gutter': 'gutter', 'header': 'header_distance',
122+
'footer': 'footer_distance'
123+
}[margin_side]
124+
# expected_xml -----------------
125+
pgMar_bldr = self.pgMar_bldr(**{margin_side: new_margin})
126+
expected_xml = self.sectPr_bldr(pgMar_bldr).xml()
127+
new_value = self.twips_to_emu(new_margin)
128+
return section, property_name, new_value, expected_xml
129+
96130
@pytest.fixture(params=[
97131
(True, 'landscape', WD_ORIENT.LANDSCAPE),
98132
(True, 'portrait', WD_ORIENT.PORTRAIT),
@@ -211,26 +245,21 @@ def start_type_set_fixture(self, request):
211245

212246
# fixture components ---------------------------------------------
213247

214-
def pgMar_bldr(
215-
self, has_pgMar=True, left=None, right=None, top=None,
216-
bottom=None, header=None, footer=None, gutter=None):
217-
if not has_pgMar:
248+
@staticmethod
249+
def twips_to_emu(twips):
250+
if twips is None:
251+
return None
252+
return twips * 635
253+
254+
def pgMar_bldr(self, **kwargs):
255+
if kwargs.pop('has_pgMar', True) is False:
218256
return None
219257
pgMar_bldr = a_pgMar()
220-
if left is not None:
221-
pgMar_bldr.with_left(left)
222-
if right is not None:
223-
pgMar_bldr.with_right(right)
224-
if top is not None:
225-
pgMar_bldr.with_top(top)
226-
if bottom is not None:
227-
pgMar_bldr.with_bottom(bottom)
228-
if header is not None:
229-
pgMar_bldr.with_header(header)
230-
if footer is not None:
231-
pgMar_bldr.with_footer(footer)
232-
if gutter is not None:
233-
pgMar_bldr.with_gutter(gutter)
258+
for key, value in kwargs.items():
259+
if value is None:
260+
continue
261+
set_attr_method = getattr(pgMar_bldr, 'with_%s' % key)
262+
set_attr_method(value)
234263
return pgMar_bldr
235264

236265
def pgSz_bldr(self, has_pgSz=True, w=None, h=None, orient=None):

0 commit comments

Comments
 (0)