문제

Pythons Simplexmlrpcserver를 사용하여 원격 서비스로 노출하려는 수업이 있습니다. 서버 시작은 다음과 같습니다.

server = SimpleXMLRPCServer((serverSettings.LISTEN_IP,serverSettings.LISTEN_PORT))

service = Service()

server.register_instance(service)
server.serve_forever()

그런 다음 다음과 같은 것처럼 보이는 ServicerEmote 수업이 있습니다.

def __init__(self,ip,port):
    self.rpcClient = xmlrpclib.Server('http://%s:%d' %(ip,port))

def __getattr__(self, name):
    # forward all calls to the rpc client
    return getattr(self.rpcClient, name)

따라서 ServicerEMote 객체의 모든 호출은 XMLRPClib.server로 전달 된 다음 원격 서버로 전달됩니다. 문제는 Varargs라는 서비스의 방법입니다.

@useDb
def select(self, db, fields, **kwargs):
    pass

@usedb 데코레이터는 함수를 감싸서 호출 전에 DB를 생성 한 다음 열기 전에 결과를 반환하기 전에 전화를 한 후에 닫습니다.

이 방법을 호출하면 오류가 발생합니다. "전화() 예기치 않은 키워드 인수 '이름'을 얻었습니다. 따라서 원격으로 인수라는 변수를 취하는 메소드를 호출 할 수 있습니까? 아니면 필요한 각 메소드 변형에 대해 재정의를 만들어야합니다.


응답에 감사드립니다. 코드를 조금 바꾸어 질문이 더 이상 문제가되지 않습니다. 그러나 이제는 위치 인수를 구현하고 원격 호출을 지원해야한다면 나중에 참조 할 수 있습니다. 토마스와 프라 타크 접근 방식의 조합이 좋을 것이라고 생각합니다. xmlrpclient를 통해 kwargs를 클라이언트의 위치 arg로 전환하고, 메서드에 래퍼가 서서를 포장하여 위치 인수를 풀어줍니다.

도움이 되었습니까?

해결책

키워드 인수의 개념이 없기 때문에 일반 XMLRPC로는이 작업을 수행 할 수 없습니다. 그러나이를 XMLRPC 상단의 프로토콜로 겹쳐서 항상 첫 번째 인수로 목록을 전달하고 사전을 1 초로 전달한 다음 적절한 지원 코드를 제공하여 다음과 같은 예제에 대해 투명하게됩니다.

섬기는 사람

from SimpleXMLRPCServer import SimpleXMLRPCServer

class Server(object):
    def __init__(self, hostport):
        self.server = SimpleXMLRPCServer(hostport)

    def register_function(self, function, name=None):
        def _function(args, kwargs):
            return function(*args, **kwargs)
        _function.__name__ = function.__name__
        self.server.register_function(_function, name)

    def serve_forever(self):
        self.server.serve_forever()

#example usage
server = Server(('localhost', 8000))
def test(arg1, arg2):
    print 'arg1: %s arg2: %s' % (arg1, arg2)
    return 0
server.register_function(test)
server.serve_forever()

고객

import xmlrpclib

class ServerProxy(object):
    def __init__(self, url):
        self._xmlrpc_server_proxy = xmlrpclib.ServerProxy(url)
    def __getattr__(self, name):
        call_proxy = getattr(self._xmlrpc_server_proxy, name)
        def _call(*args, **kwargs):
            return call_proxy(args, kwargs)
        return _call

#example usage
server = ServerProxy('http://localhost:8000')
server.test(1, 2)
server.test(arg2=2, arg1=1)
server.test(1, arg2=2)
server.test(*[1,2])
server.test(**{'arg1':1, 'arg2':2})

다른 팁

XML-RPC에는 실제로 '키워드 인수'개념이 없으므로 XMLRPCLIB를 지원하려고 시도하지 않습니다. 컨벤션을 선택한 다음 XMLRPCLIB._METHOD를 수정하여 키워드 인수를 수락하고 해당 컨벤션을 사용하여 전달해야합니다.

예를 들어, 나는 XML-RPC 서버를 사용하여 키워드 인수를 '-keyword'와 실제 인수가 평평한 목록에서 전달되었습니다. 더 이상 Python에서 해당 XML-RPC 서버에 액세스하기 위해 작성한 코드에 액세스 할 수는 없지만 다음과 같이 상당히 간단했습니다.

import xmlrpclib

_orig_Method = xmlrpclib._Method

class KeywordArgMethod(_orig_Method):     
    def __call__(self, *args, **kwargs):
        if args and kwargs:
            raise TypeError, "Can't pass both positional and keyword args"
        args = list(args) 
        for key in kwargs:
            args.append('-%s' % key.upper())
            args.append(kwargs[key])
       return _orig_Method.__call__(self, *args)     

xmlrpclib._Method = KeywordArgMethod

ServerProxy 클래스에서 모듈 글로벌 및 이름을 조화 된 속성 (예 : __request)의 일부로 사용하기 때문에이 작업을 수행하는 가장 쉬운 방법이기 때문에 Monkeypatching을 사용합니다.

내가 아는 한, 기본 프로토콜은 Varargs (또는 그 문제에 대해 명명 된 Args)를 지원하지 않습니다. 이에 대한 해결 방법은 ** kwargs를 가져 와서 호출하려는 메소드에 일반 사전으로 전달하는 래퍼를 만드는 것입니다. 이 같은

서버 측:

def select_wrapper(self, db, fields, kwargs):
    """accepts an ordinary dict which can pass through xmlrpc"""
    return select(self,db,fields, **kwargs)

클라이언트 측에서 :

def select(self, db, fields, **kwargs):
    """you can call it with keyword arguments and they will be packed into a dict"""
    return self.rpcClient.select_wrapper(self,db,fields,kwargs)

면책 조항 :이 코드는 일반적인 아이디어를 보여 주므로 조금 더 깨끗하게 할 수 있습니다 (예 : 데코레이터를 작성하여이를 작성).

Thomas Wouters가 말했듯이 XML-RPC에는 키워드 주장이 없습니다. 프로토콜에 관한 한 인수의 순서 만 중요하며 XML에서 호출 할 수 있습니다 : Arg0, Arg1, Arg2는 같은 논증에 대한 치즈, 사탕 및 베이컨과 마찬가지로 완벽하게 괜찮습니다.

아마도 프로토콜 사용을 간단히 생각해야합니까? 문서/문자 그대로 비누와 같은 것을 사용하는 것은 여기에 다른 답변에 제시된 것과 같은 해결 방법보다 훨씬 낫습니다. 물론 이것은 실현 가능하지 않을 수 있습니다.

위의 조언을 사용하여 작업 코드를 만들었습니다.

서버 메소드 래퍼 :

def unwrap_kwargs(func):
    def wrapper(*args, **kwargs):
        print args
        if args and isinstance(args[-1], list) and len(args[-1]) == 2 and "kwargs" == args[-1][0]:
            func(*args[:-1], **args[-1][1])
        else:
            func(*args, **kwargs)
    return wrapper

클라이언트 설정 (한 번 수행) :

_orig_Method = xmlrpclib._Method

class KeywordArgMethod(_orig_Method):     
    def __call__(self, *args, **kwargs):
        args = list(args) 
        if kwargs:
            args.append(("kwargs", kwargs))
        return _orig_Method.__call__(self, *args)

xmlrpclib._Method = KeywordArgMethod

이것을 테스트했으며 고정, 위치 및 키워드 인수가있는 방법을 지원합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top