扭曲的xmlrpc和numpy float 64异常

时间:2014-04-10 16:06:47

标签: python numpy twisted xml-rpc

我正在向一些员工使用numpy,然后通过twisted / XMLRPC服务器提供结果。如果结果是一个numpy浮动64,我得到一个异常原因可能扭曲无法处理这种类型。事实上,我将结果降级为float32,x = float(x),一切正常。 这不是很好的原因,如果我忘了这个workaroud某个地方,这是一个痛苦。 你有更好的解决方案吗?

服务器:

from twisted.web import xmlrpc, server
import numpy as np

class MioServer(xmlrpc.XMLRPC):
    """
    An example object to be published.
    """

    def xmlrpc_test_np(self):
        return np.sqrt(2)

if __name__ == '__main__':
    from twisted.internet import reactor
    r = MioServer()
    reactor.listenTCP(7080, server.Site(r))
    reactor.run()

客户端:

import xmlrpclib

if __name__=='__main__':
    x=xmlrpclib.ServerProxy('http://localhost:7080/')
    print x.test_np()

例外:

Traceback (most recent call last):
  File "C:\Users\Stone\.eclipse\org.eclipse.platform_4.3.0_1709980481_win32_win32_x86\plugins\org.python.pydev_2.8.2.2013090511\pysrc\pydevd.py", line 1446, in <module>
    debugger.run(setup['file'], None, None)
  File "C:\Users\Stone\.eclipse\org.eclipse.platform_4.3.0_1709980481_win32_win32_x86\plugins\org.python.pydev_2.8.2.2013090511\pysrc\pydevd.py", line 1092, in run
    pydev_imports.execfile(file, globals, locals) #execute the script
  File "C:\Users\Stone\Documents\FastDose\src\Beagle\Prove e test\xmlrpc_client.py", line 28, in <module>
    print x.test_np()
  File "C:\Python27\lib\xmlrpclib.py", line 1224, in __call__
    return self.__send(self.__name, args)
  File "C:\Python27\lib\xmlrpclib.py", line 1578, in __request
    verbose=self.__verbose
  File "C:\Python27\lib\xmlrpclib.py", line 1264, in request
    return self.single_request(host, handler, request_body, verbose)
  File "C:\Python27\lib\xmlrpclib.py", line 1297, in single_request
    return self.parse_response(response)
  File "C:\Python27\lib\xmlrpclib.py", line 1473, in parse_response
    return u.close()
  File "C:\Python27\lib\xmlrpclib.py", line 793, in close
    raise Fault(**self._stack[0])
xmlrpclib.Fault: <Fault 8002: "Can't serialize output: cannot marshal <type 'numpy.float64'> objects">

3 个答案:

答案 0 :(得分:1)

这与扭曲无关。如果您阅读了发布的错误消息,则会在xmlrpclib.py中看到错误发生的结尾。

xml-rpc实现使用marshal来序列化对象。但是,xml-rpc does not support handling third party objects完成了编组,例如numpy.ndarray。转换为float时它起作用的原因是支持内置浮点类型

在提供我的解决方案之前,我应该指出,在谷歌(1 2)很容易找到的几个地方已经在其他地方询问了同样的事情,我从那里偷了我的答案。

要执行您想要的操作,您可以将numpy数组转换为可序列化的数组。最简单的方法是编写flatten / unflatten函数。然后你会打电话然后在发送时调用flattener,并在接收时调用unflattener。这是一个例子(取自this post):

from cStringIO import StringIO
from numpy.lib import format

def unflatten(s):
    f = StringIO(s)
    arr = format.read_array(f)
    return arr

def flatten(arr):
    f = StringIO()
    format.write_array(f, arr)
    s = f.getvalue()
    return s        

更简单的事情就是打电话

<the array you want to send>.tolist()

在发送端转换为python列表,然后调用

np.array(<the list you received>)

在接收方。

这样做的唯一缺点是,在发送和接收数据时,必须明确调用flattener和unflattener。虽然这有点打字,但并不多,如果你忘了程序会大声失败(你已经经历过相同的错误),而不是默默地做错事。

我从你的问题中收集到你不喜欢这个,并且宁愿找到一种方法来使numpy数组直接使用xml-rpc而不需要任何明确的展平/不平整。我认为这可能是不可能的,因为xml-rpc文档明确指出可以序列化的第三方对象是具有__dict__属性的新样式类,并且在这种情况下,键必须是字符串,值必须是其他符合类型。

所以你看,如果你想直接支持numpy数组,似乎你必须修改xml-rpc的编组工作方式。如果您可以将某种方法添加到ndarray的子类以支持被编组,那将是很好的,但看起来它不是它的工作方式。

我希望这有助于您了解正在发生的事情,以及现有解决方案为何使用明确的扁平化/不平整。

-Daniel

P.S。这让我对如何在python中扩展xml-rpc以支持其他类型的对象感到好奇,所以我发布了my own question

答案 1 :(得分:0)

我发现了这种方式:在发送结果之前,我将其传递给funcion to_float()

def iterable(x):
    try:
        iter(x)
    except: # not iterable
        return False
    else: # iterable
        return True


def to_float(x):
    from numpy import float64,ndarray
    if type(x) == dict:
        res = dict()
        for name in iter(x):
            res[name] = to_float(x[name])
        return res
    elif type(x) == ndarray:
        return map(float, x.tolist())
    elif type(x) == float64:  
        return float(x)  
    elif iterable(x) and not isinstance(x,str):    
        res=[]
        for item in x:
            if type(item) == float64: 
                res.append(float(item))
            elif type(x) == ndarray:
                res.append(map(float, x.tolist()))
            else:
                res.append(item)
        return res
    else:
        return x

答案 2 :(得分:0)

尝试了相当长的时间才能使用xmlrpc传输640x480x3图像。提议的“ tolist()”或“ flatten”解决方案都不适合我。终于找到了这个解决方案:

发件人:

def getCamPic():
  cam = cv2.VideoCapture(0)
  img = cam.read()
  transferImg = img.tostring()
  return transferImg

接收器:

transferImg = proxy.getCamPic()
rawImg = np.fromstring(transferImg.data,dtype=np.uint8) 
img = np.reshape(rawImg,(640,480,3))

我知道我的凸轮分辨率,硬编码对我来说不是问题。改进的版本可能在transferImg中包含此信息?