通过pyAMF通道发送kwargs

1 投票
2 回答
642 浏览
提问于 2025-04-15 17:46

我正在使用 cherrypy 服务器,通过 pyAMF 通道接收来自 Python 客户端的请求。我开始时用下面的示例,运行得很好:

服务器:

import cherrypy
from pyamf.remoting.gateway.wsgi import WSGIGateway

def echo(*args, **kwargs):
    return (args, kwargs)

class Root(object):
    def index(self):
        return "running"
    index.exposed = True

services = {
   'myService.echo': echo,
}

gateway = WSGIGateway(services, debug=True)

cherrypy.tree.graft(gateway, "/gateway/")
cherrypy.quickstart(Root())

客户端:

from pyamf.remoting.client import RemotingService

path = 'http://localhost:8080/gateway/'
gw = RemotingService(path)
service = gw.getService('myService')

print service.echo('one=1, two=3')

结果: [[u'one=1, two=3'], {}]

现在,如果我不使用:

def echo(*args, **kwargs):
    return (args, kwargs)

而是使用:

def echo(**kwargs):
    return kwargs

然后发送相同的请求,我就会遇到以下错误:

TypeError: echo() 需要 0 个参数(给了 1 个)

同时:

>>> def f(**kwargs): return kwargs
... 
>>> f(one=1, two=3)
{'two': 3, 'one': 1}
>>> 

问题: 为什么会这样?请分享一些见解

我使用的是:python 2.5.2,cherrypy 3.1.2,pyamf 0.5.1

2 个回答

2

注意到你第一次使用echo函数时,只有这样调用它才能得到你想要的结果:

echo(u"one=1, two=3")
# in words: one unicode string literal, as a positional arg

# *very* different from:
echo(one=1, two=3) # which seems to be what you expect

因此,你必须让echo函数能够接受位置参数,或者改变它的调用方式。

1

默认情况下,WSGIGateway会把expose_request=True设置为开启状态,这意味着WSGI环境字典会作为第一个参数传递给这个网关里的任何服务方法。

这就意味着,回声(echo)函数应该这样写:

def echo(environ, *args):
    return args

PyAMF提供了一个装饰器,可以强制让请求被暴露,即使expose_request=False,下面是一个例子:

from pyamf.remoting.gateway import expose_request
from pyamf.remoting.gateway.wsgi import WSGIGateway

@expose_request
def some_service_method(request, *args):
    return ['some', 'thing']

services = {
    'a_service_method': some_service_method
}

gw = WSGIGateway(services, expose_request=False)

希望这能帮助你理解为什么在这种情况下会出现TypeError错误。

你正确指出,不能直接在PyAMF的客户端/服务器调用中提供**kwargs,但你可以使用默认的命名参数:

def update(obj, force=False):
    pass

然后你就可以访问这个服务了:

from pyamf.remoting.client import RemotingService

path = 'http://localhost:8080/gateway/'
gw = RemotingService(path)
service = gw.getService('myService')

print service.update('foo', True)

撰写回答