SoCo/SoCo — pull request #49 by lawrenceakka (2013-12-02 22:32:57+00:00)
Title: New XML generating code

[resubmitting - sorry - had serious git problems earlier]

This branch introduces dynamic generation of XML commands so there is no need for most of the constants at the end of core.py. Deals (in part) with https://github.com/SoCo/SoCo/pull/41#issuecomment-26453765

A Services base class is included which represents a UPnP service. This is subclassed to provide AVTransport, AlarmClock, ContentDirectory services and all the others. Adding new services is easy. Any command can be sent to a service by invoking a method on that service. For example, soco.AVTransport.Play(...) will send the Play command to the AVTransport service, generating all XML automatically. Available commands are not hardcoded, but are entirely dynamic, allowing new commands to be added. If asked, Service subclasses can query the UPnP xml files on the Sonos devices and return a list of all available commands, with their arguments and argument types, e.g.

```python
>>> s = SoCo('192.168.1.101') # Your IP address here
>>> for action, in_args, out_args in soco.QPlay.iter_actions():
... print action, in_args, out_args
```
Arguments are passed as a list of tuples to the method. Results are parsed automatically, and returned in an easy to use dict. Errors are raised with the official UPnP error codes.

```python
>>> print s.RenderingControl.GetMute([('InstanceID', 0),
... ('Channel', 'Master')])

>>> r = s.ContentDirectory.Browse([
... ('ObjectID', '0'),
... ('BrowseFlag', 'BrowseDirectChildren'),
... ('Filter', '*'),
... ('StartingIndex', '0'),
... ('RequestedCount', '100'),
... ('SortCriteria', '')
... ])
>>> print r
```

By way of example, I have changed the Play command in core.py to use this new code. PLAY_ACTION, PLAY_BODY and PLAY_RESPONSE could also be deleted, but I haven't done that.

Let me know what you think, or if you would like any more explanation.

Tests to follow ...