Class proxying in Python

I am using the python-mpd2 module to control a raspberry Pi media player in a graphics application. Thus, I would like to gracefully handle connection errors and timeouts (for example, this player misses MPD connections after 60 seconds) in the background. However, the MPD module does not have a single entry point through which all commands are sent or information that I could correct is retrieved.

I need a class that allows access to all the same methods as mpd.MPDClient, but let me add my own error handling. In other words, if I do this:

client.play()

And there is a connectione error, I would like to catch it and resend the same command. In addition to the slight delay caused by reconnecting to the server, the user should not notice that something is wrong.

So far, here is the solution I came up with. It works in my application but does not fulfill my goals.

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

I could add a method to this class for each MPD command, for example:

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

But this seems far from the best way to achieve it.

+4
source share
1 answer

91 , , - . , , .

OTOH, 91 . , , __getattr__, :

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

, , @MatToufoutu ( ). , / ... , .

+4

Source: https://habr.com/ru/post/1536249/


All Articles