1# encoding: utf-8 2 3""" 4Test suite for docx.oxml.xmlchemy 5""" 6 7from __future__ import absolute_import, print_function, unicode_literals 8 9import pytest 10 11from docx.compat import Unicode 12from docx.oxml import parse_xml, register_element_cls 13from docx.oxml.exceptions import InvalidXmlError 14from docx.oxml.ns import qn 15from docx.oxml.simpletypes import BaseIntType 16from docx.oxml.xmlchemy import ( 17 BaseOxmlElement, Choice, serialize_for_reading, OneOrMore, OneAndOnlyOne, 18 OptionalAttribute, RequiredAttribute, ZeroOrMore, ZeroOrOne, 19 ZeroOrOneChoice, XmlString 20) 21 22from ..unitdata import BaseBuilder 23from .unitdata.text import a_b, a_u, an_i, an_rPr 24 25 26class DescribeBaseOxmlElement(object): 27 28 def it_can_find_the_first_of_its_children_named_in_a_sequence( 29 self, first_fixture): 30 element, tagnames, matching_child = first_fixture 31 assert element.first_child_found_in(*tagnames) is matching_child 32 33 def it_can_insert_an_element_before_named_successors( 34 self, insert_fixture): 35 element, child, tagnames, expected_xml = insert_fixture 36 element.insert_element_before(child, *tagnames) 37 assert element.xml == expected_xml 38 39 def it_can_remove_all_children_with_name_in_sequence( 40 self, remove_fixture): 41 element, tagnames, expected_xml = remove_fixture 42 element.remove_all(*tagnames) 43 assert element.xml == expected_xml 44 45 # fixtures --------------------------------------------- 46 47 @pytest.fixture(params=[ 48 ('biu', 'iu', 'i'), 49 ('bu', 'iu', 'u'), 50 ('bi', 'u', None), 51 ('b', 'iu', None), 52 ('iu', 'biu', 'i'), 53 ('', 'biu', None), 54 ]) 55 def first_fixture(self, request): 56 present, matching, match = request.param 57 element = self.rPr_bldr(present).element 58 tagnames = self.nsptags(matching) 59 matching_child = element.find(qn('w:%s' % match)) if match else None 60 return element, tagnames, matching_child 61 62 @pytest.fixture(params=[ 63 ('iu', 'b', 'iu', 'biu'), 64 ('u', 'b', 'iu', 'bu'), 65 ('', 'b', 'iu', 'b'), 66 ('bu', 'i', 'u', 'biu'), 67 ('bi', 'u', '', 'biu'), 68 ]) 69 def insert_fixture(self, request): 70 present, new, successors, after = request.param 71 element = self.rPr_bldr(present).element 72 child = { 73 'b': a_b(), 'i': an_i(), 'u': a_u() 74 }[new].with_nsdecls().element 75 tagnames = [('w:%s' % char) for char in successors] 76 expected_xml = self.rPr_bldr(after).xml() 77 return element, child, tagnames, expected_xml 78 79 @pytest.fixture(params=[ 80 ('biu', 'b', 'iu'), ('biu', 'bi', 'u'), ('bbiiuu', 'i', 'bbuu'), 81 ('biu', 'i', 'bu'), ('biu', 'bu', 'i'), ('bbiiuu', '', 'bbiiuu'), 82 ('biu', 'u', 'bi'), ('biu', 'ui', 'b'), ('bbiiuu', 'bi', 'uu'), 83 ('bu', 'i', 'bu'), ('', 'ui', ''), 84 ]) 85 def remove_fixture(self, request): 86 present, remove, after = request.param 87 element = self.rPr_bldr(present).element 88 tagnames = self.nsptags(remove) 89 expected_xml = self.rPr_bldr(after).xml() 90 return element, tagnames, expected_xml 91 92 # fixture components --------------------------------------------- 93 94 def nsptags(self, letters): 95 return [('w:%s' % letter) for letter in letters] 96 97 def rPr_bldr(self, children): 98 rPr_bldr = an_rPr().with_nsdecls() 99 for char in children: 100 if char == 'b': 101 rPr_bldr.with_child(a_b()) 102 elif char == 'i': 103 rPr_bldr.with_child(an_i()) 104 elif char == 'u': 105 rPr_bldr.with_child(a_u()) 106 else: 107 raise NotImplementedError("got '%s'" % char) 108 return rPr_bldr 109 110 111class DescribeSerializeForReading(object): 112 113 def it_pretty_prints_an_lxml_element(self, pretty_fixture): 114 element, expected_xml_text = pretty_fixture 115 xml_text = serialize_for_reading(element) 116 assert xml_text == expected_xml_text 117 118 def it_returns_unicode_text(self, type_fixture): 119 element = type_fixture 120 xml_text = serialize_for_reading(element) 121 assert isinstance(xml_text, Unicode) 122 123 # fixtures --------------------------------------------- 124 125 @pytest.fixture 126 def pretty_fixture(self, element): 127 expected_xml_text = ( 128 '<foø>\n' 129 ' <bår>text</bår>\n' 130 '</foø>\n' 131 ) 132 return element, expected_xml_text 133 134 @pytest.fixture 135 def type_fixture(self, element): 136 return element 137 138 # fixture components ----------------------------------- 139 140 @pytest.fixture 141 def element(self): 142 return parse_xml('<foø><bår>text</bår></foø>') 143 144 145class DescribeXmlString(object): 146 147 def it_parses_a_line_to_help_compare(self, parse_fixture): 148 """ 149 This internal function is important to test separately because if it 150 doesn't parse a line properly, false equality can result. 151 """ 152 line, expected_front, expected_attrs = parse_fixture[:3] 153 expected_close, expected_text = parse_fixture[3:] 154 front, attrs, close, text = XmlString._parse_line(line) 155 # print("'%s' '%s' '%s' %s" % ( 156 # front, attrs, close, ('%s' % text) if text else text)) 157 assert front == expected_front 158 assert attrs == expected_attrs 159 assert close == expected_close 160 assert text == expected_text 161 162 def it_knows_if_two_xml_lines_are_equivalent(self, xml_line_case): 163 line, other, differs = xml_line_case 164 xml = XmlString(line) 165 assert xml == other 166 assert xml != differs 167 168 # fixtures --------------------------------------------- 169 170 @pytest.fixture(params=[ 171 ('<a>text</a>', '<a', '', '>', 'text</a>'), 172 ('<a:f/>', '<a:f', '', '/>', None), 173 ('<a:f b="c"/>', '<a:f', ' b="c"', '/>', None), 174 ('<a:f>t</a:f>', '<a:f', '', '>', 't</a:f>'), 175 ('<dcterms:created xsi:type="dcterms:W3CDTF">2013-12-23T23:15:00Z</d' 176 'cterms:created>', '<dcterms:created', ' xsi:type="dcterms:W3CDTF"', 177 '>', '2013-12-23T23:15:00Z</dcterms:created>'), 178 ]) 179 def parse_fixture(self, request): 180 line, front, attrs, close, text = request.param 181 return line, front, attrs, close, text 182 183 @pytest.fixture(params=[ 184 'simple_elm', 'nsp_tagname', 'indent', 'attrs', 'nsdecl_order', 185 'closing_elm', 186 ]) 187 def xml_line_case(self, request): 188 cases = { 189 'simple_elm': ( 190 '<name/>', 191 '<name/>', 192 '<name>', 193 ), 194 'nsp_tagname': ( 195 '<xyz:name/>', 196 '<xyz:name/>', 197 '<abc:name/>', 198 ), 199 'indent': ( 200 ' <xyz:name/>', 201 ' <xyz:name/>', 202 '<xyz:name/>', 203 ), 204 'attrs': ( 205 ' <abc:Name foo="bar" bar="foo">', 206 ' <abc:Name bar="foo" foo="bar">', 207 ' <abc:Name far="boo" foo="bar">', 208 ), 209 'nsdecl_order': ( 210 ' <name xmlns:a="http://ns/1" xmlns:b="http://ns/2"/>', 211 ' <name xmlns:b="http://ns/2" xmlns:a="http://ns/1"/>', 212 ' <name xmlns:b="http://ns/2" xmlns:a="http://ns/1">', 213 ), 214 'closing_elm': ( 215 '</xyz:name>', 216 '</xyz:name>', 217 '<xyz:name>', 218 ), 219 } 220 line, other, differs = cases[request.param] 221 return line, other, differs 222 223 224class DescribeChoice(object): 225 226 def it_adds_a_getter_property_for_the_choice_element( 227 self, getter_fixture): 228 parent, expected_choice = getter_fixture 229 assert parent.choice is expected_choice 230 231 def it_adds_a_creator_method_for_the_child_element(self, new_fixture): 232 parent, expected_xml = new_fixture 233 choice = parent._new_choice() 234 assert choice.xml == expected_xml 235 236 def it_adds_an_insert_method_for_the_child_element(self, insert_fixture): 237 parent, choice, expected_xml = insert_fixture 238 parent._insert_choice(choice) 239 assert parent.xml == expected_xml 240 assert parent._insert_choice.__doc__.startswith( 241 'Return the passed ``<w:choice>`` ' 242 ) 243 244 def it_adds_an_add_method_for_the_child_element(self, add_fixture): 245 parent, expected_xml = add_fixture 246 choice = parent._add_choice() 247 assert parent.xml == expected_xml 248 assert isinstance(choice, CT_Choice) 249 assert parent._add_choice.__doc__.startswith( 250 'Add a new ``<w:choice>`` child element ' 251 ) 252 253 def it_adds_a_get_or_change_to_method_for_the_child_element( 254 self, get_or_change_to_fixture): 255 parent, expected_xml = get_or_change_to_fixture 256 choice = parent.get_or_change_to_choice() 257 assert isinstance(choice, CT_Choice) 258 assert parent.xml == expected_xml 259 260 # fixtures ------------------------------------------------------- 261 262 @pytest.fixture 263 def add_fixture(self): 264 parent = self.parent_bldr().element 265 expected_xml = self.parent_bldr('choice').xml() 266 return parent, expected_xml 267 268 @pytest.fixture(params=[ 269 ('choice2', 'choice'), 270 (None, 'choice'), 271 ('choice', 'choice'), 272 ]) 273 def get_or_change_to_fixture(self, request): 274 before_member_tag, after_member_tag = request.param 275 parent = self.parent_bldr(before_member_tag).element 276 expected_xml = self.parent_bldr(after_member_tag).xml() 277 return parent, expected_xml 278 279 @pytest.fixture(params=['choice', None]) 280 def getter_fixture(self, request): 281 choice_tag = request.param 282 parent = self.parent_bldr(choice_tag).element 283 expected_choice = parent.find(qn('w:choice')) # None if not found 284 return parent, expected_choice 285 286 @pytest.fixture 287 def insert_fixture(self): 288 parent = ( 289 a_parent().with_nsdecls().with_child( 290 an_oomChild()).with_child( 291 an_oooChild()) 292 ).element 293 choice = a_choice().with_nsdecls().element 294 expected_xml = ( 295 a_parent().with_nsdecls().with_child( 296 a_choice()).with_child( 297 an_oomChild()).with_child( 298 an_oooChild()) 299 ).xml() 300 return parent, choice, expected_xml 301 302 @pytest.fixture 303 def new_fixture(self): 304 parent = self.parent_bldr().element 305 expected_xml = a_choice().with_nsdecls().xml() 306 return parent, expected_xml 307 308 # fixture components --------------------------------------------- 309 310 def parent_bldr(self, choice_tag=None): 311 parent_bldr = a_parent().with_nsdecls() 312 if choice_tag == 'choice': 313 parent_bldr.with_child(a_choice()) 314 if choice_tag == 'choice2': 315 parent_bldr.with_child(a_choice2()) 316 return parent_bldr 317 318 319class DescribeOneAndOnlyOne(object): 320 321 def it_adds_a_getter_property_for_the_child_element(self, getter_fixture): 322 parent, oooChild = getter_fixture 323 assert parent.oooChild is oooChild 324 325 # fixtures ------------------------------------------------------- 326 327 @pytest.fixture 328 def getter_fixture(self): 329 parent = a_parent().with_nsdecls().with_child(an_oooChild()).element 330 oooChild = parent.find(qn('w:oooChild')) 331 return parent, oooChild 332 333 334class DescribeOneOrMore(object): 335 336 def it_adds_a_getter_property_for_the_child_element_list( 337 self, getter_fixture): 338 parent, oomChild = getter_fixture 339 assert parent.oomChild_lst[0] is oomChild 340 341 def it_adds_a_creator_method_for_the_child_element(self, new_fixture): 342 parent, expected_xml = new_fixture 343 oomChild = parent._new_oomChild() 344 assert oomChild.xml == expected_xml 345 346 def it_adds_an_insert_method_for_the_child_element(self, insert_fixture): 347 parent, oomChild, expected_xml = insert_fixture 348 parent._insert_oomChild(oomChild) 349 assert parent.xml == expected_xml 350 assert parent._insert_oomChild.__doc__.startswith( 351 'Return the passed ``<w:oomChild>`` ' 352 ) 353 354 def it_adds_a_private_add_method_for_the_child_element(self, add_fixture): 355 parent, expected_xml = add_fixture 356 oomChild = parent._add_oomChild() 357 assert parent.xml == expected_xml 358 assert isinstance(oomChild, CT_OomChild) 359 assert parent._add_oomChild.__doc__.startswith( 360 'Add a new ``<w:oomChild>`` child element ' 361 ) 362 363 def it_adds_a_public_add_method_for_the_child_element(self, add_fixture): 364 parent, expected_xml = add_fixture 365 oomChild = parent.add_oomChild() 366 assert parent.xml == expected_xml 367 assert isinstance(oomChild, CT_OomChild) 368 assert parent._add_oomChild.__doc__.startswith( 369 'Add a new ``<w:oomChild>`` child element ' 370 ) 371 372 # fixtures ------------------------------------------------------- 373 374 @pytest.fixture 375 def add_fixture(self): 376 parent = self.parent_bldr(False).element 377 expected_xml = self.parent_bldr(True).xml() 378 return parent, expected_xml 379 380 @pytest.fixture 381 def getter_fixture(self): 382 parent = self.parent_bldr(True).element 383 oomChild = parent.find(qn('w:oomChild')) 384 return parent, oomChild 385 386 @pytest.fixture 387 def insert_fixture(self): 388 parent = ( 389 a_parent().with_nsdecls().with_child( 390 an_oooChild()).with_child( 391 a_zomChild()).with_child( 392 a_zooChild()) 393 ).element 394 oomChild = an_oomChild().with_nsdecls().element 395 expected_xml = ( 396 a_parent().with_nsdecls().with_child( 397 an_oomChild()).with_child( 398 an_oooChild()).with_child( 399 a_zomChild()).with_child( 400 a_zooChild()) 401 ).xml() 402 return parent, oomChild, expected_xml 403 404 @pytest.fixture 405 def new_fixture(self): 406 parent = self.parent_bldr(False).element 407 expected_xml = an_oomChild().with_nsdecls().xml() 408 return parent, expected_xml 409 410 # fixture components --------------------------------------------- 411 412 def parent_bldr(self, oomChild_is_present): 413 parent_bldr = a_parent().with_nsdecls() 414 if oomChild_is_present: 415 parent_bldr.with_child(an_oomChild()) 416 return parent_bldr 417 418 419class DescribeOptionalAttribute(object): 420 421 def it_adds_a_getter_property_for_the_attr_value(self, getter_fixture): 422 parent, optAttr_python_value = getter_fixture 423 assert parent.optAttr == optAttr_python_value 424 425 def it_adds_a_setter_property_for_the_attr(self, setter_fixture): 426 parent, value, expected_xml = setter_fixture 427 parent.optAttr = value 428 assert parent.xml == expected_xml 429 430 def it_adds_a_docstring_for_the_property(self): 431 assert CT_Parent.optAttr.__doc__.startswith( 432 "ST_IntegerType type-converted value of " 433 ) 434 435 # fixtures ------------------------------------------------------- 436 437 @pytest.fixture 438 def getter_fixture(self): 439 parent = a_parent().with_nsdecls().with_optAttr('24').element 440 return parent, 24 441 442 @pytest.fixture(params=[36, None]) 443 def setter_fixture(self, request): 444 value = request.param 445 parent = a_parent().with_nsdecls().with_optAttr('42').element 446 if value is None: 447 expected_xml = a_parent().with_nsdecls().xml() 448 else: 449 expected_xml = a_parent().with_nsdecls().with_optAttr(value).xml() 450 return parent, value, expected_xml 451 452 453class DescribeRequiredAttribute(object): 454 455 def it_adds_a_getter_property_for_the_attr_value(self, getter_fixture): 456 parent, reqAttr_python_value = getter_fixture 457 assert parent.reqAttr == reqAttr_python_value 458 459 def it_adds_a_setter_property_for_the_attr(self, setter_fixture): 460 parent, value, expected_xml = setter_fixture 461 parent.reqAttr = value 462 assert parent.xml == expected_xml 463 464 def it_adds_a_docstring_for_the_property(self): 465 assert CT_Parent.reqAttr.__doc__.startswith( 466 "ST_IntegerType type-converted value of " 467 ) 468 469 def it_raises_on_get_when_attribute_not_present(self): 470 parent = a_parent().with_nsdecls().element 471 with pytest.raises(InvalidXmlError): 472 parent.reqAttr 473 474 def it_raises_on_assign_invalid_value(self, invalid_assign_fixture): 475 parent, value, expected_exception = invalid_assign_fixture 476 with pytest.raises(expected_exception): 477 parent.reqAttr = value 478 479 # fixtures ------------------------------------------------------- 480 481 @pytest.fixture 482 def getter_fixture(self): 483 parent = a_parent().with_nsdecls().with_reqAttr('42').element 484 return parent, 42 485 486 @pytest.fixture(params=[ 487 (None, TypeError), 488 (-4, ValueError), 489 ('2', TypeError), 490 ]) 491 def invalid_assign_fixture(self, request): 492 invalid_value, expected_exception = request.param 493 parent = a_parent().with_nsdecls().with_reqAttr(1).element 494 return parent, invalid_value, expected_exception 495 496 @pytest.fixture 497 def setter_fixture(self): 498 parent = a_parent().with_nsdecls().with_reqAttr('42').element 499 value = 24 500 expected_xml = a_parent().with_nsdecls().with_reqAttr(value).xml() 501 return parent, value, expected_xml 502 503 504class DescribeZeroOrMore(object): 505 506 def it_adds_a_getter_property_for_the_child_element_list( 507 self, getter_fixture): 508 parent, zomChild = getter_fixture 509 assert parent.zomChild_lst[0] is zomChild 510 511 def it_adds_a_creator_method_for_the_child_element(self, new_fixture): 512 parent, expected_xml = new_fixture 513 zomChild = parent._new_zomChild() 514 assert zomChild.xml == expected_xml 515 516 def it_adds_an_insert_method_for_the_child_element(self, insert_fixture): 517 parent, zomChild, expected_xml = insert_fixture 518 parent._insert_zomChild(zomChild) 519 assert parent.xml == expected_xml 520 assert parent._insert_zomChild.__doc__.startswith( 521 'Return the passed ``<w:zomChild>`` ' 522 ) 523 524 def it_adds_an_add_method_for_the_child_element(self, add_fixture): 525 parent, expected_xml = add_fixture 526 zomChild = parent._add_zomChild() 527 assert parent.xml == expected_xml 528 assert isinstance(zomChild, CT_ZomChild) 529 assert parent._add_zomChild.__doc__.startswith( 530 'Add a new ``<w:zomChild>`` child element ' 531 ) 532 533 def it_adds_a_public_add_method_for_the_child_element(self, add_fixture): 534 parent, expected_xml = add_fixture 535 zomChild = parent.add_zomChild() 536 assert parent.xml == expected_xml 537 assert isinstance(zomChild, CT_ZomChild) 538 assert parent._add_zomChild.__doc__.startswith( 539 'Add a new ``<w:zomChild>`` child element ' 540 ) 541 542 def it_removes_the_property_root_name_used_for_declaration(self): 543 assert not hasattr(CT_Parent, 'zomChild') 544 545 # fixtures ------------------------------------------------------- 546 547 @pytest.fixture 548 def add_fixture(self): 549 parent = self.parent_bldr(False).element 550 expected_xml = self.parent_bldr(True).xml() 551 return parent, expected_xml 552 553 @pytest.fixture 554 def getter_fixture(self): 555 parent = self.parent_bldr(True).element 556 zomChild = parent.find(qn('w:zomChild')) 557 return parent, zomChild 558 559 @pytest.fixture 560 def insert_fixture(self): 561 parent = ( 562 a_parent().with_nsdecls().with_child( 563 an_oomChild()).with_child( 564 an_oooChild()).with_child( 565 a_zooChild()) 566 ).element 567 zomChild = a_zomChild().with_nsdecls().element 568 expected_xml = ( 569 a_parent().with_nsdecls().with_child( 570 an_oomChild()).with_child( 571 an_oooChild()).with_child( 572 a_zomChild()).with_child( 573 a_zooChild()) 574 ).xml() 575 return parent, zomChild, expected_xml 576 577 @pytest.fixture 578 def new_fixture(self): 579 parent = self.parent_bldr(False).element 580 expected_xml = a_zomChild().with_nsdecls().xml() 581 return parent, expected_xml 582 583 def parent_bldr(self, zomChild_is_present): 584 parent_bldr = a_parent().with_nsdecls() 585 if zomChild_is_present: 586 parent_bldr.with_child(a_zomChild()) 587 return parent_bldr 588 589 590class DescribeZeroOrOne(object): 591 592 def it_adds_a_getter_property_for_the_child_element(self, getter_fixture): 593 parent, zooChild = getter_fixture 594 assert parent.zooChild is zooChild 595 596 def it_adds_an_add_method_for_the_child_element(self, add_fixture): 597 parent, expected_xml = add_fixture 598 zooChild = parent._add_zooChild() 599 assert parent.xml == expected_xml 600 assert isinstance(zooChild, CT_ZooChild) 601 assert parent._add_zooChild.__doc__.startswith( 602 'Add a new ``<w:zooChild>`` child element ' 603 ) 604 605 def it_adds_an_insert_method_for_the_child_element(self, insert_fixture): 606 parent, zooChild, expected_xml = insert_fixture 607 parent._insert_zooChild(zooChild) 608 assert parent.xml == expected_xml 609 assert parent._insert_zooChild.__doc__.startswith( 610 'Return the passed ``<w:zooChild>`` ' 611 ) 612 613 def it_adds_a_get_or_add_method_for_the_child_element( 614 self, get_or_add_fixture): 615 parent, expected_xml = get_or_add_fixture 616 zooChild = parent.get_or_add_zooChild() 617 assert isinstance(zooChild, CT_ZooChild) 618 assert parent.xml == expected_xml 619 620 def it_adds_a_remover_method_for_the_child_element(self, remove_fixture): 621 parent, expected_xml = remove_fixture 622 parent._remove_zooChild() 623 assert parent.xml == expected_xml 624 625 # fixtures ------------------------------------------------------- 626 627 @pytest.fixture 628 def add_fixture(self): 629 parent = self.parent_bldr(False).element 630 expected_xml = self.parent_bldr(True).xml() 631 return parent, expected_xml 632 633 @pytest.fixture(params=[True, False]) 634 def getter_fixture(self, request): 635 zooChild_is_present = request.param 636 parent = self.parent_bldr(zooChild_is_present).element 637 zooChild = parent.find(qn('w:zooChild')) # None if not found 638 return parent, zooChild 639 640 @pytest.fixture(params=[True, False]) 641 def get_or_add_fixture(self, request): 642 zooChild_is_present = request.param 643 parent = self.parent_bldr(zooChild_is_present).element 644 expected_xml = self.parent_bldr(True).xml() 645 return parent, expected_xml 646 647 @pytest.fixture 648 def insert_fixture(self): 649 parent = ( 650 a_parent().with_nsdecls().with_child( 651 an_oomChild()).with_child( 652 an_oooChild()).with_child( 653 a_zomChild()) 654 ).element 655 zooChild = a_zooChild().with_nsdecls().element 656 expected_xml = ( 657 a_parent().with_nsdecls().with_child( 658 an_oomChild()).with_child( 659 an_oooChild()).with_child( 660 a_zomChild()).with_child( 661 a_zooChild()) 662 ).xml() 663 return parent, zooChild, expected_xml 664 665 @pytest.fixture(params=[True, False]) 666 def remove_fixture(self, request): 667 zooChild_is_present = request.param 668 parent = self.parent_bldr(zooChild_is_present).element 669 expected_xml = self.parent_bldr(False).xml() 670 return parent, expected_xml 671 672 # fixture components --------------------------------------------- 673 674 def parent_bldr(self, zooChild_is_present): 675 parent_bldr = a_parent().with_nsdecls() 676 if zooChild_is_present: 677 parent_bldr.with_child(a_zooChild()) 678 return parent_bldr 679 680 681class DescribeZeroOrOneChoice(object): 682 683 def it_adds_a_getter_for_the_current_choice(self, getter_fixture): 684 parent, expected_choice = getter_fixture 685 assert parent.eg_zooChoice is expected_choice 686 687 # fixtures ------------------------------------------------------- 688 689 @pytest.fixture(params=[None, 'choice', 'choice2']) 690 def getter_fixture(self, request): 691 choice_tag = request.param 692 parent = self.parent_bldr(choice_tag).element 693 tagname = 'w:%s' % choice_tag 694 expected_choice = parent.find(qn(tagname)) # None if not found 695 return parent, expected_choice 696 697 # fixture components --------------------------------------------- 698 699 def parent_bldr(self, choice_tag=None): 700 parent_bldr = a_parent().with_nsdecls() 701 if choice_tag == 'choice': 702 parent_bldr.with_child(a_choice()) 703 if choice_tag == 'choice2': 704 parent_bldr.with_child(a_choice2()) 705 return parent_bldr 706 707 708# -------------------------------------------------------------------- 709# static shared fixture 710# -------------------------------------------------------------------- 711 712class ST_IntegerType(BaseIntType): 713 714 @classmethod 715 def validate(cls, value): 716 cls.validate_int(value) 717 if value < 1 or value > 42: 718 raise ValueError( 719 "value must be in range 1 to 42 inclusive" 720 ) 721 722 723class CT_Parent(BaseOxmlElement): 724 """ 725 ``<w:parent>`` element, an invented element for use in testing. 726 """ 727 eg_zooChoice = ZeroOrOneChoice( 728 (Choice('w:choice'), Choice('w:choice2')), 729 successors=('w:oomChild', 'w:oooChild') 730 ) 731 oomChild = OneOrMore('w:oomChild', successors=( 732 'w:oooChild', 'w:zomChild', 'w:zooChild' 733 )) 734 oooChild = OneAndOnlyOne('w:oooChild') 735 zomChild = ZeroOrMore('w:zomChild', successors=('w:zooChild',)) 736 zooChild = ZeroOrOne('w:zooChild', successors=()) 737 optAttr = OptionalAttribute('w:optAttr', ST_IntegerType) 738 reqAttr = RequiredAttribute('reqAttr', ST_IntegerType) 739 740 741class CT_Choice(BaseOxmlElement): 742 """ 743 ``<w:choice>`` element 744 """ 745 746 747class CT_OomChild(BaseOxmlElement): 748 """ 749 Oom standing for 'OneOrMore', ``<w:oomChild>`` element, representing a 750 child element that can appear multiple times in sequence, but must appear 751 at least once. 752 """ 753 754 755class CT_ZomChild(BaseOxmlElement): 756 """ 757 Zom standing for 'ZeroOrMore', ``<w:zomChild>`` element, representing an 758 optional child element that can appear multiple times in sequence. 759 """ 760 761 762class CT_ZooChild(BaseOxmlElement): 763 """ 764 Zoo standing for 'ZeroOrOne', ``<w:zooChild>`` element, an invented 765 element for use in testing. 766 """ 767 768 769register_element_cls('w:parent', CT_Parent) 770register_element_cls('w:choice', CT_Choice) 771register_element_cls('w:oomChild', CT_OomChild) 772register_element_cls('w:zomChild', CT_ZomChild) 773register_element_cls('w:zooChild', CT_ZooChild) 774 775 776class CT_ChoiceBuilder(BaseBuilder): 777 __tag__ = 'w:choice' 778 __nspfxs__ = ('w',) 779 __attrs__ = () 780 781 782class CT_Choice2Builder(BaseBuilder): 783 __tag__ = 'w:choice2' 784 __nspfxs__ = ('w',) 785 __attrs__ = () 786 787 788class CT_ParentBuilder(BaseBuilder): 789 __tag__ = 'w:parent' 790 __nspfxs__ = ('w',) 791 __attrs__ = ('w:optAttr', 'reqAttr') 792 793 794class CT_OomChildBuilder(BaseBuilder): 795 __tag__ = 'w:oomChild' 796 __nspfxs__ = ('w',) 797 __attrs__ = () 798 799 800class CT_OooChildBuilder(BaseBuilder): 801 __tag__ = 'w:oooChild' 802 __nspfxs__ = ('w',) 803 __attrs__ = () 804 805 806class CT_ZomChildBuilder(BaseBuilder): 807 __tag__ = 'w:zomChild' 808 __nspfxs__ = ('w',) 809 __attrs__ = () 810 811 812class CT_ZooChildBuilder(BaseBuilder): 813 __tag__ = 'w:zooChild' 814 __nspfxs__ = ('w',) 815 __attrs__ = () 816 817 818def a_choice(): 819 return CT_ChoiceBuilder() 820 821 822def a_choice2(): 823 return CT_Choice2Builder() 824 825 826def a_parent(): 827 return CT_ParentBuilder() 828 829 830def a_zomChild(): 831 return CT_ZomChildBuilder() 832 833 834def a_zooChild(): 835 return CT_ZooChildBuilder() 836 837 838def an_oomChild(): 839 return CT_OomChildBuilder() 840 841 842def an_oooChild(): 843 return CT_OooChildBuilder() 844