Skip to content

Commit 6be61e4

Browse files
author
Steve Canny
committed
text: add Run.bold setter
1 parent b08f691 commit 6be61e4

6 files changed

Lines changed: 80 additions & 8 deletions

File tree

docx/oxml/shared.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,15 @@ def val(self):
186186
return True
187187
raise ValidationError("expected xsd:boolean, got '%s'" % val)
188188

189+
@val.setter
190+
def val(self, value):
191+
val = qn('w:val')
192+
if bool(value) is True:
193+
if val in self.attrib:
194+
del self.attrib[val]
195+
else:
196+
self.set(val, '0')
197+
189198

190199
class CT_String(OxmlBaseElement):
191200
"""

docx/oxml/text.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,15 @@ def add_t(self, text):
209209
self.append(t)
210210
return t
211211

212+
def get_or_add_rPr(self):
213+
"""
214+
Return the rPr child element, newly added if not present.
215+
"""
216+
rPr = self.rPr
217+
if rPr is None:
218+
rPr = self._add_rPr()
219+
return rPr
220+
212221
@classmethod
213222
def new(cls):
214223
"""
@@ -230,18 +239,46 @@ def t_lst(self):
230239
"""
231240
return self.findall(qn('w:t'))
232241

242+
def _add_rPr(self):
243+
"""
244+
Return a newly added rPr child element. Assumes one is not present.
245+
"""
246+
rPr = CT_RPr.new()
247+
self.insert(0, rPr)
248+
return rPr
249+
233250

234251
class CT_RPr(OxmlBaseElement):
235252
"""
236253
``<w:rPr>`` element, containing the properties for a run.
237254
"""
255+
def add_b(self):
256+
"""
257+
Return a newly added <w:b/> child element.
258+
"""
259+
b = OxmlElement('w:b')
260+
self.insert(0, b)
261+
return b
262+
238263
@property
239264
def b(self):
240265
"""
241266
First ``<w:b>`` child element or None if none are present.
242267
"""
243268
return self.find(qn('w:b'))
244269

270+
@classmethod
271+
def new(cls):
272+
"""
273+
Return a new ``<w:rPr>`` element.
274+
"""
275+
return OxmlElement('w:rPr')
276+
277+
def remove_b(self):
278+
b_lst = self.findall(qn('w:b'))
279+
for b in b_lst:
280+
self.remove(b)
281+
245282

246283
class CT_Text(OxmlBaseElement):
247284
"""

docx/text.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,15 @@ def bold(self):
106106
return None
107107
return b.val
108108

109+
@bold.setter
110+
def bold(self, value):
111+
rPr = self._r.get_or_add_rPr()
112+
rPr.remove_b()
113+
if value is not None:
114+
b = rPr.add_b()
115+
if bool(value) is False:
116+
b.val = False
117+
109118
@property
110119
def text(self):
111120
"""

features/run-bold-italic.feature

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,16 @@ Feature: Apply bold or italic to run
33
As a python-docx developer
44
I need a way to query and set bold and italic on a run
55

6-
@wip
76
Scenario: Apply bold to a run
87
Given a run
98
When I assign True to its bold property
109
Then the run appears in bold typeface
1110

12-
@wip
1311
Scenario: Remove bold from a run
1412
Given a run having bold set on
1513
When I assign None to its bold property
1614
Then the run appears with its inherited bold setting
1715

18-
@wip
1916
Scenario: Set bold off unconditionally
2017
Given a run
2118
When I assign False to its bold property

tests/test_api.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,6 @@ def it_can_add_a_table(self, add_table_fixture):
9999
add_table_fixture
100100
)
101101
table = document.add_table(rows, cols, style)
102-
print(table)
103102
document_part_.add_table.assert_called_once_with(rows, cols)
104103
assert table.style == expected_style
105104
assert table == table_

tests/test_text.py

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,15 @@ def text_prop_fixture(self):
9090

9191
class DescribeRun(object):
9292

93-
def it_knows_if_its_bold(self, bold_fixture):
94-
run, is_bold = bold_fixture
95-
print('\n%s' % run._r.xml)
93+
def it_knows_if_its_bold(self, bold_get_fixture):
94+
run, is_bold = bold_get_fixture
9695
assert run.bold == is_bold
9796

97+
def it_can_change_its_bold_setting(self, bold_set_fixture):
98+
run, bold_value, expected_xml = bold_set_fixture
99+
run.bold = bold_value
100+
assert run._r.xml == expected_xml
101+
98102
def it_can_add_text(self, add_text_fixture):
99103
run, text_str, expected_xml, Text_ = add_text_fixture
100104
_text = run.add_text(text_str)
@@ -143,7 +147,7 @@ def add_text_fixture(self, run, Text_):
143147
return run, text_str, expected_xml, Text_
144148

145149
@pytest.fixture(params=[True, False, None])
146-
def bold_fixture(self, request):
150+
def bold_get_fixture(self, request):
147151
is_bold = request.param
148152
r_bldr = an_r().with_nsdecls()
149153
if is_bold is not None:
@@ -156,6 +160,23 @@ def bold_fixture(self, request):
156160
run = Run(r)
157161
return run, is_bold
158162

163+
@pytest.fixture(params=[True, False, None])
164+
def bold_set_fixture(self, request):
165+
# run --------------------------
166+
r = an_r().with_nsdecls().element
167+
run = Run(r)
168+
# bold_value -------------------
169+
bold_value = request.param
170+
# expected_xml -----------------
171+
rPr_bldr = an_rPr()
172+
if bold_value is not None:
173+
b_bldr = a_b()
174+
if bold_value is False:
175+
b_bldr.with_val(0)
176+
rPr_bldr.with_child(b_bldr)
177+
expected_xml = an_r().with_nsdecls().with_child(rPr_bldr).xml()
178+
return run, bold_value, expected_xml
179+
159180
@pytest.fixture
160181
def run(self):
161182
r = an_r().with_nsdecls().element

0 commit comments

Comments
 (0)