1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
|
#! /usr/bin/env python
#
# Introduction
#
# A python program that continuously polls for song info. Demonstrates how and where to handle errors
# Details
#
from mpd import MPDClient, MPDError, CommandError
import sys
class PollerError(Exception):
"""Fatal error in poller."""
class MPDPoller(object):
def __init__(self, host="localhost", port="6600", password=None):
self._host = host
self._port = port
self._password = password
self._client = MPDClient()
def connect(self):
try:
self._client.connect(self._host, self._port)
# Catch socket errors
except IOError as err:
errno, strerror = err
raise PollerError("Could not connect to '%s': %s" % (self._host, strerror))
# Catch all other possible errors
# ConnectionError and ProtocolError are always fatal. Others may not
# be, but we don't know how to handle them here, so treat them as if
# they are instead of ignoring them.
except MPDError as e:
raise PollerError("Could not connect to '%s': %s" % (self._host, e))
if self._password:
try:
self._client.password(self._password)
# Catch errors with the password command (e.g., wrong password)
except CommandError as e:
# On CommandErrors we have access to the parsed error response
# split into errno, offset, command and msg.
raise PollerError(
"Could not connect to '%s': "
"password commmand failed: [%d] %s" % (self._host, e.errno, e.msg)
)
# Catch all other possible errors
except (MPDError, IOError) as e:
raise PollerError(
"Could not connect to '%s': "
"error with password command: %s" % (self._host, e)
)
def disconnect(self):
# Try to tell MPD we're closing the connection first
try:
self._client.close()
# If that fails, don't worry, just ignore it and disconnect
except (MPDError, IOError):
pass
try:
self._client.disconnect()
# Disconnecting failed, so use a new client object instead
# This should never happen. If it does, something is seriously broken,
# and the client object shouldn't be trusted to be re-used.
except (MPDError, IOError):
self._client = MPDClient()
def poll(self):
try:
song = self._client.currentsong()
# Couldn't get the current song, so try reconnecting and retrying
except (MPDError, IOError):
# No error handling required here
# Our disconnect function catches all exceptions, and therefore
# should never raise any.
self.disconnect()
try:
self.connect()
# Reconnecting failed
except PollerError as e:
raise PollerError("Reconnecting failed: %s" % e)
try:
song = self._client.currentsong()
# Failed again, just give up
except (MPDError, IOError) as e:
raise PollerError("Couldn't retrieve current song: %s" % e)
# Hurray! We got the current song without any errors!
print(song)
def main():
from time import sleep
poller = MPDPoller()
poller.connect()
while True:
poller.poll()
sleep(3)
if __name__ == "__main__":
import sys
try:
main()
# Catch fatal poller errors
except PollerError as e:
print("Fatal poller error: %s" % e, file=sys.stderr)
sys.exit(1)
# Catch all other non-exit errors
except Exception as e:
print("Unexpected exception: %s" % e, file=sys.stderr)
sys.exit(1)
# Catch the remaining exit errors
except Exception:
sys.exit(0)
# vim: set expandtab shiftwidth=4 softtabstop=4 textwidth=79:
|