julienc
julienc

Reputation: 20325

Default int value with xmlrpclib

I tried to execute the following code, but xmlrpclib is raising an exception:

>>> import xmlrpclib
>>> data = """<?xml version="1.0"?> 
... <methodCall>
...     <methodName>test_method</methodName>
...     <params>
...         <param>
...             <value>
...                 <int/>
...             </value>
...         </param>
...     </params>
... </methodCall>"""
>>> xmlrpclib.loads(data)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib64/python2.7/xmlrpclib.py", line 1141, in loads
    p.feed(data)
  File "/usr/lib64/python2.7/xmlrpclib.py", line 558, in feed
    self._parser.Parse(data, 0)
  File "/usr/lib64/python2.7/xmlrpclib.py", line 829, in end
    return f(self, join(self._data, ""))
  File "/usr/lib64/python2.7/xmlrpclib.py", line 864, in end_int
    self.append(int(data))
ValueError: invalid literal for int() with base 10: ''

If I replace <int/> by <int></int>, the error is the same; but with <int>0</int> no exception is raised. Same results in python3 with xmlrpc.client.

I tried to do the same thing with PHP, and it worked without any trouble:

php > $data = '<?xml version="1.0"?><methodCall><methodName>test_method</methodName><params><param><value><int/></value></param></params></methodCall>';
php > print_r(xmlrpc_decode($data));
Array
(
    [0] => 0
)

The documentation from the .NET implementation also implies that <int/> would be translated to 0:

If an XML-RPC struct member is missing its corresponding .NET struct member will be set to null instead of the default value for the type if a non-nullable type had been used, for example null instead of zero for an integer.

Is this behaviour a bug from the Python implementation?

Upvotes: 1

Views: 396

Answers (1)

val
val

Reputation: 21

Without passing judgement on Python implementation :) this monkey patch fixes the way end_int() handles empty data. In your example before calling xmlrpclib.loads(data):

class MyUnmarshaller(xmlrpclib.Unmarshaller):

    def end_int(self, data):
        self.append(int(data or "0"))
        self._value = 0
    dispatch = xmlrpclib.Unmarshaller.dispatch
    dispatch["i4"] = end_int
    dispatch["i8"] = end_int
    dispatch["int"] = end_int

xmlrpclib.Unmarshaller = MyUnmarshaller

Upvotes: 2

Related Questions