Skip to content

Commit e622c14

Browse files
committed
Raise exception if positional arguments are used for Choice elements
See mvantellingen#439
1 parent f7ef428 commit e622c14

File tree

3 files changed

+96
-1
lines changed

3 files changed

+96
-1
lines changed

CHANGES

+5
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,13 @@
33
- Default values of optional elements are not set by default anymore (#423)
44
- The call signature for Client.create_message() was changed. It now requires
55
the service argument:
6+
67
``Client.create_message(service, operation_name, *args, **kwargs)``
78

9+
- Choice elements now only work with keyword arguments and raise an exception
10+
if positional arguments are passed (#439)
11+
12+
813
1.6.0 (2017-04-27)
914
------------------
1015
- Implement ValueObject.__json__ for json serialization (#258)

src/zeep/xsd/elements/indicators.py

+13-1
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,14 @@ def accept(self, values):
106106
return max(results)
107107

108108
def parse_args(self, args, index=0):
109+
110+
# If the sequence contains an choice element then we can't convert
111+
# the args to kwargs since Choice elements don't work with position
112+
# arguments
113+
for name, elm in self.elements_nested:
114+
if isinstance(elm, Choice):
115+
raise TypeError("Choice elements only work with keyword arguments")
116+
109117
result = {}
110118
for name, element in self.elements:
111119
if index >= len(args):
@@ -283,6 +291,10 @@ def parse_xmlelements(self, xmlelements, schema, name=None, context=None):
283291
class Choice(OrderIndicator):
284292
"""Permits one and only one of the elements contained in the group."""
285293

294+
def parse_args(self, args, index=0):
295+
if args:
296+
raise TypeError("Choice elements only work with keyword arguments")
297+
286298
@property
287299
def is_optional(self):
288300
return True
@@ -702,4 +714,4 @@ def signature(self, schema=None, standalone=True):
702714
return '%s(%s)' % (
703715
name, self.child.signature(schema, standalone=False))
704716
else:
705-
return self.child.signature(schema, standalone=False)
717+
return self.child.signature(schema, standalone=False)

tests/test_xsd_indicators_choice.py

+78
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,84 @@ def test_choice_element_second_elm():
9595
assert value.item_2 == 'foo'
9696
assert value.item_3 is None
9797

98+
def test_choice_element_second_elm_positional():
99+
node = etree.fromstring("""
100+
<?xml version="1.0"?>
101+
<xsd:schema
102+
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
103+
xmlns:tns="http://tests.python-zeep.org/"
104+
elementFormDefault="qualified"
105+
targetNamespace="http://tests.python-zeep.org/">
106+
<xsd:complexType name="type_1">
107+
<xsd:sequence>
108+
<xsd:element name="child_1" type="xsd:string"/>
109+
<xsd:element name="child_2" type="xsd:string"/>
110+
</xsd:sequence>
111+
</xsd:complexType>
112+
<xsd:complexType name="type_2">
113+
<xsd:sequence>
114+
<xsd:element name="child_1" type="xsd:string"/>
115+
<xsd:element name="child_2" type="xsd:string"/>
116+
</xsd:sequence>
117+
</xsd:complexType>
118+
<xsd:element name="container">
119+
<xsd:complexType>
120+
<xsd:choice>
121+
<xsd:element name="item_1" type="tns:type_1" />
122+
<xsd:element name="item_2" type="tns:type_2" />
123+
</xsd:choice>
124+
</xsd:complexType>
125+
</xsd:element>
126+
<xsd:element name="containerArray">
127+
<xsd:complexType>
128+
<xsd:sequence>
129+
<xsd:choice>
130+
<xsd:element name="item_1" type="tns:type_1" />
131+
<xsd:element name="item_2" type="tns:type_2" />
132+
</xsd:choice>
133+
</xsd:sequence>
134+
</xsd:complexType>
135+
</xsd:element>
136+
</xsd:schema>
137+
""".strip())
138+
schema = xsd.Schema(node)
139+
140+
child = schema.get_type('ns0:type_2')(child_1='ha', child_2='ho')
141+
142+
element = schema.get_element('ns0:container')
143+
with pytest.raises(TypeError):
144+
value = element(child)
145+
value = element(item_2=child)
146+
147+
element = schema.get_element('ns0:containerArray')
148+
with pytest.raises(TypeError):
149+
value = element(child)
150+
value = element(item_2=child)
151+
152+
element = schema.get_element('ns0:container')
153+
value = element(item_2=child)
154+
assert value.item_1 is None
155+
assert value.item_2 == child
156+
157+
expected = """
158+
<document>
159+
<ns0:container xmlns:ns0="http://tests.python-zeep.org/">
160+
<ns0:item_2>
161+
<ns0:child_1>ha</ns0:child_1>
162+
<ns0:child_2>ho</ns0:child_2>
163+
</ns0:item_2>
164+
</ns0:container>
165+
</document>
166+
"""
167+
node = etree.Element('document')
168+
element.render(node, value)
169+
assert_nodes_equal(expected, node)
170+
171+
value = element.parse(node[0], schema)
172+
assert value.item_1 is None
173+
assert value.item_2.child_1 == 'ha'
174+
assert value.item_2.child_2 == 'ho'
175+
98176

99177
def test_choice_element_multiple():
100178
node = etree.fromstring("""

0 commit comments

Comments
 (0)