1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
|
"""Step implementations for text-related features."""
import hashlib
from behave import given, then, when
from behave.runner import Context
from docx import Document
from docx.enum.text import WD_BREAK, WD_UNDERLINE
from docx.oxml.ns import nsdecls, qn
from docx.oxml.parser import parse_xml
from docx.text.font import Font
from docx.text.run import Run
from helpers import test_docx, test_file, test_text
# given ===================================================
@given("a run")
def given_a_run(context):
document = Document()
run = document.add_paragraph().add_run()
context.document = document
context.run = run
@given("a run having {bool_prop_name} set on")
def given_a_run_having_bool_prop_set_on(context, bool_prop_name):
run = Document().add_paragraph().add_run()
setattr(run, bool_prop_name, True)
context.run = run
@given("a run having known text and formatting")
def given_a_run_having_known_text_and_formatting(context):
run = Document().add_paragraph().add_run("foobar")
run.bold = True
run.italic = True
context.run = run
@given("a run having mixed text content")
def given_a_run_having_mixed_text_content(context):
"""
Mixed here meaning it contains ``<w:tab/>``, ``<w:cr/>``, etc. elements.
"""
r_xml = """\
<w:r %s>
<w:t>abc</w:t>
<w:br/>
<w:t>def</w:t>
<w:cr/>
<w:t>ghi</w:t>
<w:drawing/>
<w:t>jkl</w:t>
<w:tab/>
<w:t>mno</w:t>
<w:noBreakHyphen/>
<w:t>pqr</w:t>
<w:ptab/>
<w:t>stu</w:t>
</w:r>""" % nsdecls("w")
r = parse_xml(r_xml)
context.run = Run(r, None)
@given("a run having {underline_type} underline")
def given_a_run_having_underline_type(context, underline_type):
run_idx = {"inherited": 0, "no": 1, "single": 2, "double": 3}[underline_type]
document = Document(test_docx("run-enumerated-props"))
context.run = document.paragraphs[0].runs[run_idx]
@given("a run having {style} style")
def given_a_run_having_style(context, style):
run_idx = {
"no explicit": 0,
"Emphasis": 1,
"Strong": 2,
}[style]
context.document = document = Document(test_docx("run-char-style"))
context.run = document.paragraphs[0].runs[run_idx]
@given("a run having {zero_or_more} rendered page breaks")
def given_a_run_having_rendered_page_breaks(context: Context, zero_or_more: str):
paragraph_idx = {"no": 0, "one": 1, "two": 3}[zero_or_more]
document = Document(test_docx("par-rendered-page-breaks"))
paragraph = document.paragraphs[paragraph_idx]
context.run = paragraph.runs[0]
@given("a run inside a table cell retrieved from {cell_source}")
def given_a_run_inside_a_table_cell_from_source(context, cell_source):
document = Document()
table = document.add_table(rows=2, cols=2)
if cell_source == "Table.cell":
cell = table.cell(0, 0)
elif cell_source == "Table.row.cells":
cell = table.rows[0].cells[1]
elif cell_source == "Table.column.cells":
cell = table.columns[1].cells[0]
run = cell.paragraphs[0].add_run()
context.document = document
context.run = run
# when ====================================================
@when("I add a column break")
def when_add_column_break(context):
run = context.run
run.add_break(WD_BREAK.COLUMN)
@when("I add a line break")
def when_add_line_break(context):
run = context.run
run.add_break()
@when("I add a page break")
def when_add_page_break(context):
run = context.run
run.add_break(WD_BREAK.PAGE)
@when("I add a picture to the run")
def when_I_add_a_picture_to_the_run(context):
run = context.run
run.add_picture(test_file("monty-truth.png"))
@when("I add a run specifying its text")
def when_I_add_a_run_specifying_its_text(context):
context.run = context.paragraph.add_run(test_text)
@when("I add a run specifying the character style Emphasis")
def when_I_add_a_run_specifying_the_character_style_Emphasis(context):
context.run = context.paragraph.add_run(test_text, "Emphasis")
@when("I add a tab")
def when_I_add_a_tab(context):
context.run.add_tab()
@when("I add text to the run")
def when_I_add_text_to_the_run(context):
context.run.add_text(test_text)
@when("I assign mixed text to the text property")
def when_I_assign_mixed_text_to_the_text_property(context):
context.run.text = "abc\ndef\rghijkl\tmno-pqr\tstu"
@when("I assign {value_str} to its {bool_prop_name} property")
def when_assign_true_to_bool_run_prop(context, value_str, bool_prop_name):
value = {"True": True, "False": False, "None": None}[value_str]
run = context.run
setattr(run, bool_prop_name, value)
@when("I assign {value} to run.style")
def when_I_assign_value_to_run_style(context, value):
if value == "None":
new_value = None
elif value.startswith("styles["):
new_value = context.document.styles[value.split("'")[1]]
else:
new_value = context.document.styles[value]
context.run.style = new_value
@when("I clear the run")
def when_I_clear_the_run(context):
context.run.clear()
@when("I set the run underline to {underline_value}")
def when_I_set_the_run_underline_to_value(context, underline_value):
new_value = {
"True": True,
"False": False,
"None": None,
"WD_UNDERLINE.SINGLE": WD_UNDERLINE.SINGLE,
"WD_UNDERLINE.DOUBLE": WD_UNDERLINE.DOUBLE,
}[underline_value]
context.run.underline = new_value
# then =====================================================
@then("it is a column break")
def then_type_is_column_break(context):
attrib = context.last_child.attrib
assert attrib == {qn("w:type"): "column"}
@then("it is a line break")
def then_type_is_line_break(context):
attrib = context.last_child.attrib
assert attrib == {}
@then("it is a page break")
def then_type_is_page_break(context):
attrib = context.last_child.attrib
assert attrib == {qn("w:type"): "page"}
@then("run.contains_page_break is {value}")
def then_run_contains_page_break_is_value(context: Context, value: str):
actual = context.run.contains_page_break
expected = {"True": True, "False": False}[value]
assert actual == expected, f"expected: {expected}, got: {actual}"
@then("run.font is the Font object for the run")
def then_run_font_is_the_Font_object_for_the_run(context):
run, font = context.run, context.run.font
assert isinstance(font, Font)
assert font.element is run.element
@then("run.iter_inner_content() generates the run text and rendered page-breaks")
def then_run_iter_inner_content_generates_text_and_page_breaks(context: Context):
actual_value = [type(item).__name__ for item in context.run.iter_inner_content()]
expected_value = ["str", "RenderedPageBreak", "str", "RenderedPageBreak", "str"]
assert actual_value == expected_value, f"expected: {expected_value}, got: {actual_value}"
@then("run.style is styles['{style_name}']")
def then_run_style_is_style(context, style_name):
expected_value = context.document.styles[style_name]
run = context.run
assert run.style == expected_value, "got %s" % run.style
@then("run.text contains the text content of the run")
def then_run_text_contains_the_text_content_of_the_run(context):
actual = context.run.text
expected = "abc\ndef\nghijkl\tmno-pqr\tstu"
assert actual == expected, f"expected:\n'{expected}'\n\ngot:\n'{actual}'"
@then("the last item in the run is a break")
def then_last_item_in_run_is_a_break(context):
run = context.run
context.last_child = run._r[-1]
expected_tag = "{http://schemas.openxmlformats.org/wordprocessingml/2006/main}br"
assert context.last_child.tag == expected_tag
@then("the picture appears at the end of the run")
def then_the_picture_appears_at_the_end_of_the_run(context):
run = context.run
r = run._r
blip_rId = r.xpath(
"./w:drawing/wp:inline/a:graphic/a:graphicData/pic:pic/pic:blipFill/a:blip/@r:embed"
)[0]
image_part = run.part.related_parts[blip_rId]
image_sha1 = hashlib.sha1(image_part.blob).hexdigest()
expected_sha1 = "79769f1e202add2e963158b532e36c2c0f76a70c"
assert image_sha1 == expected_sha1, "image SHA1 doesn't match, expected %s, got %s" % (
expected_sha1,
image_sha1,
)
@then("the run appears in {boolean_prop_name} unconditionally")
def then_run_appears_in_boolean_prop_name(context, boolean_prop_name):
run = context.run
assert getattr(run, boolean_prop_name) is True
@then("the run appears with its inherited {boolean_prop_name} setting")
def then_run_inherits_bool_prop_value(context, boolean_prop_name):
run = context.run
assert getattr(run, boolean_prop_name) is None
@then("the run appears without {boolean_prop_name} unconditionally")
def then_run_appears_without_bool_prop(context, boolean_prop_name):
run = context.run
assert getattr(run, boolean_prop_name) is False
@then("the run contains no text")
def then_the_run_contains_no_text(context):
assert context.run.text == ""
@then("the run contains the text I specified")
def then_the_run_contains_the_text_I_specified(context):
assert context.run.text == test_text
@then("the run formatting is preserved")
def then_the_run_formatting_is_preserved(context):
assert context.run.bold is True
assert context.run.italic is True
@then("the run underline property value is {underline_value}")
def then_the_run_underline_property_value_is(context, underline_value):
expected_value = {
"None": None,
"False": False,
"True": True,
"WD_UNDERLINE.DOUBLE": WD_UNDERLINE.DOUBLE,
}[underline_value]
assert context.run.underline == expected_value
@then("the tab appears at the end of the run")
def then_the_tab_appears_at_the_end_of_the_run(context):
r = context.run._r
tab = r.find(qn("w:tab"))
assert tab is not None
|