Question

J'utilise le module Python-MPD2 pour contrôler un lecteur multimédia sur un PI de framboise dans une application GUI. Ainsi, je voudrais gérer gracieusement les erreurs de raccordement et les délais d'attente (le joueur en question goutte à des connexions MPD après 60 secondes) en arrière-plan. Cependant, le module MPD n'a aucun point d'entrée unique à travers lequel toutes les commandes sont envoyées ou des informations sont récupérées que je pouvais patcher.

Je voudrais une classe qui permet d'accéder à toutes les mêmes méthodes que mpd.mpdclient, mais laissez-moi ajouter ma propre gestion des erreurs. En d'autres termes, si je fais:

client.play()

Et une erreur de connexion est lancée, je voudrais attraper et renvoyer la même commande. Autre que le petit retard causé par avoir à se reconnecter au serveur, l'utilisateur ne doit pas remarquer que rien n'est abs.

Jusqu'à présent, voici la solution que j'ai proposée. Cela fonctionne dans ma demande, mais ne remplit pas vraiment mes objectifs.

from functools import partial
from mpd import MPDClient, ConnectionError

class PersistentMPDClient(object):
    def __init__(self, host, port):
        self.host = host
        self.port = port
        self.client = MPDClient()
        self.client.connect(self.host, self.port)

    def command(self, cmd, *args, **kwargs):
        command_callable = partial(self.client.__getattribute__(cmd), *args, **kwargs)
        try:
            return command_callable()
        except ConnectionError:
            # Mopidy drops our connection after a while, so reconnect to send the command
            self.client._soc = None
            self.client.connect(self.host, self.port)
            return command_callable()

Je pourrais ajouter une méthode à cette classe pour chaque commande MPD, par exemple:

def play(self):
    return self.command("play")

Mais cela semble loin de la meilleure façon de l'accomplir.

Était-ce utile?

La solution

Si cela ne vous dérange pas de créer une liste de toutes les 91 chaînes formant noms de commande , vous pouvez faire quelque chose sur les lignes de Cette réponse .Je crois que cette approche présente de nombreux avantages car cela implique moins de magie.

OTOH, 91 est vraiment beaucoup.Donc, voici une solution automagique, utilise un généracodagcode personnalisé, qui retourne une enveloppe:

from functools import partial
import types

class DummyClient(object):
    def connect(self, *a, **kw): print 'connecting %r %r' % (a, kw)
    def play(self): print 'playing'
    def stop(self): print 'stopping'

class PersistentMPDClient(object):
    def __init__(self, host, port):
        self.host = host
        self.port = port
        self.client = DummyClient()
        self.client.connect(self.host, self.port)

    def __getattr__(self, attr, *args):
        cmd = getattr(self.client, attr, *args)
        if isinstance(cmd, types.MethodType):
            # a method -- wrap
            return lambda *a, **kw: self.command(attr, *a, **kw)
        else:
            # anything else -- return unchanged
            return cmd

    def command(self, cmd, *args, **kwargs):
        command_callable = partial(self.client.__getattribute__(cmd), *args, **kwargs)
        try:
            return command_callable()
        except ConnectionError:
            # Mopidy drops our connection after a while, so reconnect to send the command
            self.client._soc = None
            self.client.connect(self.host, self.port)
            return command_callable()

c = PersistentMPDClient(hostname, port)
c.play()
c.stop()

Comme je l'écrivais, j'ai remarqué que @Mattoufoutu avait posté une solution similaire (il y a des différences, cependant).Je ne sais pas pourquoi il / il l'a supprimé ... Si cette réponse devient undrotled, je lui donnerais volontiers le crédit qu'il mérite.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top