Skip to content

Commit 57892dd

Browse files
author
Steve Canny
committed
oxml: add unit tests for BaseOxmlElement
1 parent ddd5c30 commit 57892dd

4 files changed

Lines changed: 85 additions & 1 deletion

File tree

docx/oxml/ns.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
'xml': ('http://www.w3.org/XML/1998/namespace')
2121
}
2222

23+
pfxmap = dict((value, key) for key, value in nsmap.items())
24+
2325

2426
class NamespacePrefixedTag(str):
2527
"""
@@ -37,6 +39,12 @@ def __init__(self, nstag):
3739
def clark_name(self):
3840
return '{%s}%s' % (self._ns_uri, self._local_part)
3941

42+
@classmethod
43+
def from_clark_name(cls, clark_name):
44+
nsuri, local_name = clark_name[1:].split('}')
45+
nstag = '%s:%s' % (pfxmap[nsuri], local_name)
46+
return cls(nstag)
47+
4048
@property
4149
def local_part(self):
4250
"""

docx/oxml/xmlchemy.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
import re
1313

14-
from .ns import qn
14+
from .ns import NamespacePrefixedTag, qn
1515
from ..compat import Unicode
1616

1717

@@ -95,6 +95,11 @@ class BaseOxmlElement(etree.ElementBase):
9595
Base class for all custom element classes, to add standardized behavior
9696
to all classes in one place.
9797
"""
98+
def __repr__(self):
99+
return "<%s '<%s>' at 0x%0x>" % (
100+
self.__class__.__name__, self._nsptag, id(self)
101+
)
102+
98103
def first_child_found_in(self, *tagnames):
99104
"""
100105
Return the first child found with tag in *tagnames*, or None if
@@ -122,3 +127,7 @@ def xml(self):
122127
top.
123128
"""
124129
return serialize_for_reading(self)
130+
131+
@property
132+
def _nsptag(self):
133+
return NamespacePrefixedTag.from_clark_name(self.tag)

tests/oxml/test_ns.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ def it_behaves_like_a_string_when_you_want_it_to(self, nsptag):
2020
def it_knows_its_clark_name(self, nsptag, clark_name):
2121
assert nsptag.clark_name == clark_name
2222

23+
def it_can_construct_from_a_clark_name(self, clark_name, nsptag):
24+
_nsptag = NamespacePrefixedTag.from_clark_name(clark_name)
25+
assert _nsptag == nsptag
26+
2327
def it_knows_its_local_part(self, nsptag, local_part):
2428
assert nsptag.local_part == local_part
2529

tests/oxml/test_xmlchemy.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,71 @@
1010

1111
from docx.compat import Unicode
1212
from docx.oxml import parse_xml
13+
from docx.oxml.ns import qn
1314
from docx.oxml.xmlchemy import serialize_for_reading, XmlString
1415

16+
from .unitdata.text import a_b, a_u, an_i, an_rPr
17+
18+
19+
class DescribeBaseOxmlElement(object):
20+
21+
def it_can_find_the_first_of_its_children_named_in_a_sequence(
22+
self, first_fixture):
23+
element, tagnames, matching_child = first_fixture
24+
assert element.first_child_found_in(*tagnames) is matching_child
25+
26+
def it_can_insert_an_element_before_named_successors(
27+
self, insert_fixture):
28+
element, child, tagnames, expected_xml = insert_fixture
29+
element.insert_element_before(child, *tagnames)
30+
assert element.xml == expected_xml
31+
32+
# fixtures ---------------------------------------------
33+
34+
@pytest.fixture(params=[
35+
('iu', 'b', 'iu', 'biu'),
36+
('u', 'b', 'iu', 'bu'),
37+
('', 'b', 'iu', 'b'),
38+
('bu', 'i', 'u', 'biu'),
39+
('bi', 'u', '', 'biu'),
40+
])
41+
def insert_fixture(self, request):
42+
present, new, successors, after = request.param
43+
element = self.rPr_bldr(present).element
44+
child = {
45+
'b': a_b(), 'i': an_i(), 'u': a_u()
46+
}[new].with_nsdecls().element
47+
tagnames = [('w:%s' % char) for char in successors]
48+
expected_xml = self.rPr_bldr(after).xml()
49+
return element, child, tagnames, expected_xml
50+
51+
@pytest.fixture(params=[
52+
('biu', 'iu', 'i'),
53+
('bu', 'iu', 'u'),
54+
('bi', 'u', None),
55+
('b', 'iu', None),
56+
('iu', 'biu', 'i'),
57+
('', 'biu', None),
58+
])
59+
def first_fixture(self, request):
60+
present, matching, match = request.param
61+
element = self.rPr_bldr(present).element
62+
tagnames = [('w:%s' % char) for char in matching]
63+
matching_child = element.find(qn('w:%s' % match)) if match else None
64+
return element, tagnames, matching_child
65+
66+
# fixture components ---------------------------------------------
67+
68+
def rPr_bldr(self, children):
69+
rPr_bldr = an_rPr().with_nsdecls()
70+
if 'b' in children:
71+
rPr_bldr.with_child(a_b())
72+
if 'i' in children:
73+
rPr_bldr.with_child(an_i())
74+
if 'u' in children:
75+
rPr_bldr.with_child(a_u())
76+
return rPr_bldr
77+
1578

1679
class DescribeSerializeForReading(object):
1780

0 commit comments

Comments
 (0)