2010-09-22 5 views
0

J'écris une classe interface à un wiki MoinMoin via xmlrpc (code simplifié ci-dessous):façon pythonique pour envelopper xmlrpclib appelle à multicalls similaires

class MoinMoin(object): 
    token = None 

    def __init__(self, url, username=None, password=None): 
     self.wiki = xmlrpclib.ServerProxy(url + '/?action=xmlrpc2') 
     if username and password: 
      self.token = self.wiki.getAuthToken(username, password) 
    # some sample methods: 
    def searchPages(self, regexp): 
    def getPage(self, page): 
    def putPage(self, page): 

maintenant chacun de mes méthodes doit appeler la xmlrpc pertinente méthode seule s'il n'y a pas d'authentification impliquée, ou pour l'envelopper dans un multicall s'il y a auth. Exemple:

def getPage(self, page): 
    if not self.token: 
     result = self.wiki.getPage(page) 
    else: 
     mc = xmlrpclib.MultiCall(self.wiki) # build an XML-RPC multicall 
     mc.applyAuthToken(self.token)  # call 1 
     mc.getPage(page)     # call 2 
     result = mc()[-1]     # run both, keep result of the latter 
    return result 

est-il plus belle façon de le faire autre que de répéter ce genre de choses pour chaque méthode? Puisque je dois appeler des méthodes arbitraires, les emballer avec des trucs, puis appeler la méthode nommée identiquement sur une autre classe, sélectionner les résultats pertinents et les rendre, je soupçonne que la solution impliquerait des méta-classes ou similaire ésotérique (pour moi) des trucs. Je devrais probablement regarder les sources de xmlrpclib et voir comment c'est fait, alors peut-être sous-classer leur MultiCall pour ajouter mes trucs ...

Mais peut-être qu'il me manque quelque chose de plus facile. Le meilleur que je suis venu avec est quelque chose comme:

def _getMultiCall(self): 
    mc = xmlrpclib.MultiCall(self.wiki) 
    if self.token: 
     mc.applyAuthToken(self.token) 
    return mc 
def fooMethod(self, x): 
    mc = self._getMultiCall() 
    mc.fooMethod(x) 
    return mc()[-1] 

mais il répète toujours les mêmes trois lignes de code pour chaque méthode que je dois mettre en œuvre, en changeant juste le nom de la méthode appelée. Rien de mieux?

Répondre

1

La fonction Python est un objet qui permet de passer facilement d'une fonction à une autre.

def HandleAuthAndReturnResult(self, method, arg): 
    mc = xmlrpclib.MultiCall(self.wiki) 
    if self.token: 
     mc.applyAuthToken(self.token) 
    method(mc, arg) 
    return mc()[-1] 
def fooMethod(self, x): 
    HandleAuthAndReturnResult(xmlrpclib.MultiCall.fooMethod, x) 

Il peut y avoir d'autre moyen, mais je pense que cela devrait fonctionner. Bien sûr, la partie arg doit être alignée sur ce qui est nécessaire pour la méthode, mais toutes vos méthodes prennent un argument. Edit: Je n'ai pas compris que MultiCall était un objet proxy. Même si l'appel de la méthode réelle est finalement celui de votre ServerProxy, vous ne devriez pas passer cet objet de méthode au cas où MultiCall l'écrase (le définisse). Dans ce cas, vous pouvez utiliser la méthode getattribute avec le nom de la méthode que vous souhaitez appeler, puis appeler l'objet fonction retourné. Veillez à gérer l'exception AttributeError.

Méthodes serait maintenant ressembler à:

def HandleAuthAndReturnResult(self, methodName, arg): 
    mc = xmlrpclib.MultiCall(self.wiki) 
    if self.token: 
     mc.applyAuthToken(self.token) 

    try: 
     methodToCall = getattr(mc, methodName) 
    except AttributeError: 
     return None 

    methodToCall(arg) 
    return mc()[-1] 

def fooMethod(self, x): 
    HandleAuthAndReturnResult('fooMethod', x) 
+0

ne fonctionne pas. fooMethod() est une méthode distante, non présente dans la classe xmlrpclib.MultiCall (vous obtenez une AttributeError). Les instances de cette classe gèrent des noms de méthodes arbitraires car elles sont simplement transmises à l'extrémité distante, mais cela me laisse toujours dans une solution comme _getMultiCall() que j'ai décrite dans la question. – Luke404

+0

Mettez à jour la réponse pour qu'elle fonctionne avec l'objet MultiCall qui met en file d'attente les appels de fonction. –

Questions connexes