Frage

Ich habe eine Klasse, die ich als Remote-Service aussetzen möchte, mit Pythons SimpleXMLRPCServer. Der Serverstart sieht wie folgt aus:

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

service = Service()

server.register_instance(service)
server.serve_forever()

Ich habe dann eine ServiceRemote Klasse, die wie folgt aussieht:

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)

So werden alle Anrufe auf dem ServiceRemote Objekt zu xmlrpclib.Server weitergeleitet werden, die dann an den Remote-Server weiterleitet. Das Problem ist ein Verfahren, in dem Dienst, varargs benannt nimmt:

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

Der @useDb Dekorateur wickelt die Funktion, die DB vor dem Aufruf zu schaffen und öffnet sie, dann ist es nach dem Aufruf Schließen erfolgt, bevor das Ergebnis zurück.

Wenn ich diese Methode aufrufen, erhalte ich die Fehlermeldung " Anruf () bekam ein unerwartetes Stichwort Argument 'name'". So ist es möglich, Methoden aufrufen remote Variable mit dem Namen Argumente zu nehmen? Oder muss ich eine Überschreibung für jede Verfahrensvariante erstellen ich brauche.


Danke für die Antworten. Ich änderte meinen Code um ein bisschen so die Frage ist nicht länger ein Problem. Aber jetzt weiß ich, das für die Zukunft, wenn ich in die Tat Positionsargumente müssen implementieren und Remote-Aufruf zu unterstützen. Ich denke, dass eine Kombination von Thomas und praptaks Ansätze wäre gut. Drehen kwargs in Positions args auf dem Client durch xmlrpclient, und mit einem Wrapper auf Methoden server zu Positionsargumente auszupacken.

War es hilfreich?

Lösung

Sie können dies nicht mit einfachen xmlrpc da sie keine Ahnung von Keyword-Argumente hat. Sie können jedoch diese als Protokoll oben auf xmlrpc superimpose, die immer eine Liste als erstes Argument und einem Wörterbuch als zweite passieren würde, und dann die richtige Unterstützung Code bereitzustellen, so wird diese transparent für Ihre Nutzung, zB unter:

Server

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()

Client

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})

Andere Tipps

XML-RPC hat nicht wirklich einen Begriff ‚Schlüsselwort-Argumente‘, so xmlrpclib nicht, sie zu unterstützen nicht versuchen. Sie müssten eine Konvention holen, dann xmlrpclib._Method ändern Schlüsselwort Argumente zu akzeptieren und geben sie diese Konvention zusammen verwendet wird.

Zum Beispiel habe ich mit einem XML-RPC-Server zu arbeiten, die Keyword-Argumente als zwei Argumente übergeben, ‚-Keyword‘ durch das tatsächliche Argument gefolgt, in einer einfachen Liste. Ich habe keinen Zugriff mehr auf den Code, den ich aus Python, dass die XML-RPC-Server zugreifen schrieb, aber es war ziemlich einfach, entlang der Linien von:

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

Es verwendet monkeypatching denn das ist bei weitem der einfachste Methode, dies zu tun, weil einige klobig Verwendungen von Modul Globals und Namen entstellten Attributen (__request, zum Beispiel) in der ServerProxy Klasse.

Soweit ich weiß, ist das zugrundeliegende Protokoll nicht genannt varargs (oder alle benannten Argumente für diese Angelegenheit) unterstützen. Die Abhilfe für dieses ist ein Wrapper zu erstellen, die die ** kwargs nehmen und es als ein gewöhnliches Wörterbuch der Methode übergeben Sie anrufen möchten. So etwas wie diese

Server-Seite:

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

Auf der Client-Seite:

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)

Hinweis: der Code die allgemeine Idee zeigt, können Sie es ein wenig Reinigungsmittel (zum Beispiel ein Dekorateur Schreiben zu tun) tun

.

Wie Thomas Wouters sagte, XML-RPC nicht über Keyword-Argumente. Nur die Reihenfolge der Argumente zählt, soweit das Protokoll betroffen ist, und sie können alles in XML genannt werden: arg0, arg1, arg2 ist völlig in Ordnung, wie Käse, Süßigkeiten und Speck für die gleichen Argumente

.

Vielleicht sollte man einfach überdenken Ihre Nutzung des Protokolls? Mit so etwas wie document / literal SOAP wäre viel besser, als dieses Problem zu umgehen, wie die in anderen Antworten hier Beschenkten. Natürlich ist dies nicht möglich sein kann.

die oben genannten Ratschläge verwenden, habe ich einige Arbeitscode.

Server Methode Wrapper:

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

Client Setup (nicht einmal):

_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

Getestet habe ich diese und unterstützt Verfahren mit festen, Lage- und Keyword-Argumente.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top