4

I am trying to hide some try/except complexity with a contextmanager. Here is an easy example:

from contextlib import contextmanager
import mpd

mpdclient = mpd.MPDClient()
mpdclient.connect("localhost", 6600)

@contextmanager
def mpdcontext():
  try:
    yield
  except mpd.ConnectionError:
    mpdclient.connect("localhost", 6600)

with mpdcontext():
  mpdclient.status()

with mpdcontext():
  mpdclient.lsinfo()

Now, as I understood, the block in the with statement is executed when yield is called. In my case, if this raises an exception, I reconnect to mpd. Can I somehow execute the with-block again after this reconnect?

Thanks

KrawallKurt
  • 449
  • 1
  • 5
  • 15

1 Answers1

9

Short answer is you can't yield twice from a context manager. You could consider using a decorator that wraps what you're trying to execute and will retry and reconnect a set number of times before giving up. Here's a trivial (non-production use) example just to illustrate:

import mpd
import functools

HOST = "localhost"
PORT = 6600
mpdclient = mpd.MPDClient()
mpdclient.connect(HOST, PORT)

def withreconnect(retries=1):
    def _wrapper(func):
        @functools.wraps(func)
        def wrapped(*args, **kwargs):
            for _ in range(retries + 1): # Loop retries + first attempt
                try:
                    return func(*args, **kwargs)
                except mpd.ConnectionError:
                    mpdclient.connect(HOST, PORT)
        return _wrapped
    return wrapped

@withreconnect() # Reconnect 1 time, default
def status():
    mpdclient.status()

@withreconnect(retries=3) # Reconnect 3 times
def lsinfo():
    mpdclient.lsinfo()

Edit: added call to decorator, in the no-argument case

user2561747
  • 1,333
  • 2
  • 16
  • 39
Serdmanczyk
  • 1,133
  • 7
  • 13