New Multicall interface
NOTE: This is a proposed feature, feel free to add your thoughts or opinions
Background Info
The previous implementation of the multi-call interface left much to be desired. It was clunky, not well documented, and required knowledge of how the underlying RPC call worked. Most importantly, it was not very flexible. When creating a Multicall object, it required a RPCObject subclass instance. The problem is that all added RPC calls had to be directed toward that single RPCObject. This meant you couldn't have a multi-call that performed a task more than one torrent, for example. This was fine for creating pseudo RPC calls that only involved one object, but it left users who wanted a true multi-call interface without a solution.
Proposed Solution
In this implementation, the multi-call interface (hereby known as, RPCCaller) requires only a RPCContext object on initialization to provide the connection to the client. The RPCCaller.add method would allow the user to specify an instance method of any RPCObject. This affords the user the same flexibility that the xmlrpc.client.MultiCall gives, while providing a much easier interface.
When the call method is invoked, a RPCResult object would be returned. RPCResult is a list-like object that stores the individual results in the same order in which they were invoked.
Example
For this example, assume rt is an instance of RTorrent and RPCContext, and t, t2 are instances of Torrent.
results = RPCCaller(rt)\
.add(rt.get_system_version)\
.add(t.get_priority)\
.add(t.set_priority, 'high')\
.add(t.get_priority)\
.add(t2.stop)\
.call()
print(results)
["0.9.3", "normal", True, "high", True]
Or we could write a snippet that would stop all torrents
# Assume get_torrents() returns a list of Torrent objects
caller = RPCCaller(rt)
for t in rt.get_torrents():
caller.add(t.stop)
caller.call()
Closing Remarks
Although I don't expect every user to need this low-level access, but it provides a tremendous amount of flexibility while still be familiar.