added async_callback decorator for supporting asynchronous calls. applied it to get_* methods in Api class.
parent
d1656c1a84
commit
238d88f7e8
|
@ -6,7 +6,7 @@ __version__ = "0.2"
|
|||
__license__ = "GNU Lesser General Public License"
|
||||
__package__ = "lastfm"
|
||||
|
||||
from lastfm.decorators import cached_property
|
||||
from lastfm.decorators import cached_property, async_callback
|
||||
|
||||
class Api(object):
|
||||
"""The class representing the last.fm web services API."""
|
||||
|
@ -169,6 +169,7 @@ class Api(object):
|
|||
"""
|
||||
self._request_headers['User-Agent'] = user_agent
|
||||
|
||||
@async_callback
|
||||
def get_album(self,
|
||||
album = None,
|
||||
artist = None,
|
||||
|
@ -196,6 +197,7 @@ class Api(object):
|
|||
artist = artist.name
|
||||
return Album.get_info(self, artist, album, mbid)
|
||||
|
||||
@async_callback
|
||||
def search_album(self, album, limit = None):
|
||||
"""
|
||||
Search for an album by name.
|
||||
|
@ -212,6 +214,7 @@ class Api(object):
|
|||
"""
|
||||
return Album.search(self, search_item = album, limit = limit)
|
||||
|
||||
@async_callback
|
||||
def get_artist(self,
|
||||
artist = None,
|
||||
mbid = None):
|
||||
|
@ -233,6 +236,7 @@ class Api(object):
|
|||
"""
|
||||
return Artist.get_info(self, artist, mbid)
|
||||
|
||||
@async_callback
|
||||
def search_artist(self,
|
||||
artist,
|
||||
limit = None):
|
||||
|
@ -251,6 +255,7 @@ class Api(object):
|
|||
"""
|
||||
return Artist.search(self, search_item = artist, limit = limit)
|
||||
|
||||
@async_callback
|
||||
def get_event(self, event):
|
||||
"""
|
||||
Get an event object.
|
||||
|
@ -267,6 +272,7 @@ class Api(object):
|
|||
"""
|
||||
return Event.get_info(self, event)
|
||||
|
||||
@async_callback
|
||||
def get_location(self, city):
|
||||
"""
|
||||
Get a location object.
|
||||
|
@ -279,6 +285,7 @@ class Api(object):
|
|||
"""
|
||||
return Location(self, city = city)
|
||||
|
||||
@async_callback
|
||||
def get_country(self, name):
|
||||
"""
|
||||
Get a country object.
|
||||
|
@ -291,6 +298,7 @@ class Api(object):
|
|||
"""
|
||||
return Country(self, name = name)
|
||||
|
||||
@async_callback
|
||||
def get_group(self, name):
|
||||
"""
|
||||
Get a group object.
|
||||
|
@ -303,6 +311,7 @@ class Api(object):
|
|||
"""
|
||||
return Group(self, name = name)
|
||||
|
||||
@async_callback
|
||||
def get_playlist(self, url):
|
||||
"""
|
||||
Get a playlist object.
|
||||
|
@ -317,6 +326,7 @@ class Api(object):
|
|||
"""
|
||||
return Playlist.fetch(self, url)
|
||||
|
||||
@async_callback
|
||||
def get_tag(self, name):
|
||||
"""
|
||||
Get a tag object.
|
||||
|
@ -329,6 +339,7 @@ class Api(object):
|
|||
"""
|
||||
return Tag(self, name = name)
|
||||
|
||||
@async_callback
|
||||
def get_global_top_tags(self):
|
||||
"""
|
||||
Get the top global tags on Last.fm, sorted by popularity (number of times used).
|
||||
|
@ -338,6 +349,7 @@ class Api(object):
|
|||
"""
|
||||
return Tag.get_top_tags(self)
|
||||
|
||||
@async_callback
|
||||
def search_tag(self,
|
||||
tag,
|
||||
limit = None):
|
||||
|
@ -356,6 +368,7 @@ class Api(object):
|
|||
"""
|
||||
return Tag.search(self, search_item = tag, limit = limit)
|
||||
|
||||
@async_callback
|
||||
def compare_taste(self,
|
||||
type1, type2,
|
||||
value1, value2,
|
||||
|
@ -383,6 +396,7 @@ class Api(object):
|
|||
"""
|
||||
return Tasteometer.compare(self, type1, type2, value1, value2, limit)
|
||||
|
||||
@async_callback
|
||||
def get_track(self, track, artist = None, mbid = None):
|
||||
"""
|
||||
Get a track object.
|
||||
|
@ -406,10 +420,8 @@ class Api(object):
|
|||
artist = artist.name
|
||||
return Track.get_info(self, artist, track, mbid)
|
||||
|
||||
def search_track(self,
|
||||
track,
|
||||
artist = None,
|
||||
limit = None):
|
||||
@async_callback
|
||||
def search_track(self, track, artist = None, limit = None):
|
||||
"""
|
||||
Search for a track by name.
|
||||
|
||||
|
@ -429,6 +441,7 @@ class Api(object):
|
|||
artist = artist.name
|
||||
return Track.search(self, search_item = track, limit = limit, artist = artist)
|
||||
|
||||
@async_callback
|
||||
def get_user(self, name):
|
||||
"""
|
||||
Get an user object.
|
||||
|
@ -445,6 +458,7 @@ class Api(object):
|
|||
"""
|
||||
return User.get_info(self, name = name)
|
||||
|
||||
@async_callback
|
||||
def get_authenticated_user(self):
|
||||
"""
|
||||
Get the currently authenticated user.
|
||||
|
@ -459,6 +473,7 @@ class Api(object):
|
|||
else:
|
||||
raise AuthenticationFailedError("session key must be present to call this method")
|
||||
|
||||
@async_callback
|
||||
def get_venue(self, venue):
|
||||
"""
|
||||
Get a venue object.
|
||||
|
@ -478,6 +493,7 @@ class Api(object):
|
|||
except IndexError:
|
||||
raise InvalidParametersError("No such venue exists")
|
||||
|
||||
@async_callback
|
||||
def search_venue(self, venue, limit = None, country = None):
|
||||
"""
|
||||
Search for a venue by name.
|
||||
|
|
|
@ -100,6 +100,16 @@ def authenticate(func):
|
|||
return wrapper
|
||||
|
||||
def depaginate(func):
|
||||
"""
|
||||
A decorator to depaginate the search results.
|
||||
|
||||
@param func: a function that returns the first page of search results
|
||||
@type func: C{function}
|
||||
|
||||
@return: a function that wraps the original function and returns
|
||||
a L{lazylist} of all search results (all pages)
|
||||
@rtype: C{function}
|
||||
"""
|
||||
from lastfm.lazylist import lazylist
|
||||
def wrapper(*args, **kwargs):
|
||||
@lazylist
|
||||
|
@ -118,5 +128,82 @@ def depaginate(func):
|
|||
wrapper.__doc__ = func.__doc__
|
||||
return wrapper
|
||||
|
||||
def async_callback(func):
|
||||
"""
|
||||
A decorator to convert a synchronous (blocking) function into
|
||||
an asynchronous (non-blocking) function.
|
||||
|
||||
Pass a callback function as a keyword argument
|
||||
(C{func(other argument... , callback = callback)}) or positional argument
|
||||
(C{func(other argument... , callback)}) to the function to activate the
|
||||
asynchronous behaviour. The callback function is called with the return value
|
||||
of the original function when it returns. If an exception is raised in the
|
||||
original function, then the callback function is called with that exception.
|
||||
If the callback function is not given then the original function is called
|
||||
synchronously (it blocks the caller function) and its return value is returned.
|
||||
|
||||
All the functions on which this decorator is applied get the signature:
|
||||
C{func(self, *args, **kwargs)}. Refer to the documentation or source code of
|
||||
the original function for the correct function signature.
|
||||
|
||||
@param func: a synchronous (blocking) function
|
||||
@type func: C{function}
|
||||
|
||||
@return: an asynchronous (non-blocking) function that wraps the
|
||||
original synchronous (blocking) function
|
||||
@rtype: C{function}
|
||||
"""
|
||||
from threading import Thread
|
||||
def wrapper(self, *args, **kwargs):
|
||||
callback = None
|
||||
for a in args:
|
||||
if callable(a):
|
||||
callback = a
|
||||
args = list(args)
|
||||
args.remove(a)
|
||||
args = tuple(args)
|
||||
break
|
||||
if 'callback' in kwargs:
|
||||
callback = kwargs['callback']
|
||||
del kwargs['callback']
|
||||
|
||||
if (callback is not None and callable(callback)):
|
||||
def async_call():
|
||||
result = None
|
||||
try:
|
||||
result = func(self, *args, **kwargs)
|
||||
except Exception, e:
|
||||
result = e
|
||||
callback(result)
|
||||
thread = Thread(target = async_call)
|
||||
thread.start()
|
||||
return
|
||||
return func(self, *args, **kwargs)
|
||||
|
||||
wrapper.__doc__ = "%s\n @see: L{async_callback}" % func.__doc__
|
||||
return wrapper
|
||||
|
||||
def _get_arg_string(argspecs):
|
||||
arg_str = ""
|
||||
args = argspecs.args
|
||||
args.remove('self')
|
||||
defaults = argspecs.defaults
|
||||
|
||||
if defaults is not None:
|
||||
defargs = args[-len(defaults):]
|
||||
nondefargs = args[:-len(defaults)]
|
||||
nondefargs_str = ", ".join(nondefargs)
|
||||
defargs_str = ", ".join(["%s = %s" % (defargs[i], defaults[i]) for i in xrange(len(defargs))])
|
||||
if nondefargs_str != '' and defargs_str != '':
|
||||
arg_str = "%s, %s" % (nondefargs_str, defargs_str)
|
||||
elif nondefargs_str != '':
|
||||
arg_str = nondefargs_str
|
||||
elif defargs_str != '':
|
||||
arg_str = defargs_str
|
||||
else:
|
||||
arg_str = ", ".join(args)
|
||||
print arg_str
|
||||
return arg_str
|
||||
|
||||
import copy
|
||||
from lastfm.error import LastfmError, AuthenticationFailedError
|
|
@ -176,7 +176,9 @@ class WeeklyArtistChart(WeeklyChart):
|
|||
def get_count_attribute(artist):
|
||||
return {count_attribute: int(eval(artist.findtext(count_attribute)))}
|
||||
def get_count_attribute_sum(artists):
|
||||
return {count_attribute: reduce(lambda x,y:(x + int(eval(y.findtext(count_attribute)))), artists, 0)}
|
||||
return {count_attribute: reduce(
|
||||
lambda x, y:(x + int(eval(y.findtext(count_attribute)))), artists, 0
|
||||
)}
|
||||
|
||||
return WeeklyArtistChart(
|
||||
subject = subject,
|
||||
|
|
Loading…
Reference in New Issue