refactored pagination behaviour in 'paginate' decorator

master
Abhinav Sarkar 2009-03-17 18:34:06 +00:00
parent 4b1dc47b24
commit 394310c60f
6 changed files with 201 additions and 294 deletions

View File

@ -4,6 +4,7 @@
__author__ = "Abhinav Sarkar <abhinav@abhinavsarkar.net>"
__version__ = "0.2"
__license__ = "GNU Lesser General Public License"
__package__ = "lastfm"
def top_property(list_property_name):
"""
@ -95,6 +96,26 @@ def authenticate(func):
pass
raise AuthenticationFailedError(
"user '%s' does not have permissions to access the service" % username)
wrapper.__doc__ = func.__doc__
return wrapper
def depaginate(func):
from lastfm.lazylist import lazylist
def wrapper(*args, **kwargs):
@lazylist
def generator(lst):
gen = func(*args, **kwargs)
total_pages = gen.next()
for e in gen:
yield e
for page in xrange(2, total_pages+1):
kwargs['page'] = page
gen = func(*args, **kwargs)
gen.next()
for e in gen:
yield e
return generator()
wrapper.__doc__ = func.__doc__
return wrapper
import copy

View File

@ -8,17 +8,18 @@ __package__ = "lastfm"
from lastfm.base import LastfmBase
from lastfm.mixins import Cacheable
from lastfm.lazylist import lazylist
from lastfm.decorators import cached_property, top_property
from lastfm.decorators import cached_property, top_property, depaginate
class Geo(object):
"""A class representing an geographic location"""
@staticmethod
@depaginate
def get_events(api,
location,
latitude = None,
longitude = None,
distance = None):
distance = None,
page = None):
"""
Get the events for a location.
@ -52,26 +53,15 @@ class Geo(object):
if latitude is not None and longitude is not None:
params.update({'lat': latitude, 'long': longitude})
@lazylist
def gen(lst):
data = api._fetch_data(params).find('events')
total_pages = int(data.attrib['totalpages'])
@lazylist
def gen2(lst, data):
for e in data.findall('event'):
yield Event.create_from_data(api, e)
for e in gen2(data):
yield e
for page in xrange(2, total_pages+1):
params.update({'page': page})
data = api._fetch_data(params).find('events')
for e in gen2(data):
yield e
return gen()
if page is not None:
params.update({'page': page})
data = api._fetch_data(params).find('events')
total_pages = int(data.attrib['totalpages'])
yield total_pages
for e in data.findall('event'):
yield Event.create_from_data(api, e)
@staticmethod
def get_top_artists(api, country):

View File

@ -9,7 +9,7 @@ __package__ = "lastfm"
from lastfm.base import LastfmBase
from lastfm.mixins import Cacheable
from lastfm.lazylist import lazylist
from lastfm.decorators import cached_property, top_property
from lastfm.decorators import cached_property, top_property, depaginate
class Group(LastfmBase, Cacheable):
"""A class representing a group on last.fm."""
@ -194,38 +194,26 @@ class Group(LastfmBase, Cacheable):
return gen()
@cached_property
def members(self):
@depaginate
def members(self, page = None):
"""
members of the group
@rtype: L{lazylist} of L{User}
"""
params = self._default_params({'method': 'group.getMembers'})
@lazylist
def gen(lst):
data = self._api._fetch_data(params).find('members')
total_pages = int(data.attrib['totalPages'])
@lazylist
def gen2(lst, data):
for u in data.findall('user'):
yield User(
self._api,
name = u.findtext('name'),
real_name = u.findtext('realname'),
image = dict([(i.get('size'), i.text) for i in u.findall('image')]),
url = u.findtext('url')
)
for u in gen2(data):
yield u
for page in xrange(1, total_pages+1):
params.update({'page': page})
data = self._api._fetch_data(params).find('members')
for u in gen2(data):
yield u
return gen()
if page is not None:
params.update({'page': page})
data = self._api._fetch_data(params).find('members')
total_pages = int(data.attrib['totalPages'])
yield total_pages
for u in data.findall('user'):
yield User(
self._api,
name = u.findtext('name'),
real_name = u.findtext('realname'),
image = dict([(i.get('size'), i.text) for i in u.findall('image')]),
url = u.findtext('url')
)
def _default_params(self, extra_params = {}):
if not self.name:

View File

@ -5,14 +5,16 @@ __version__ = "0.2"
__license__ = "GNU Lesser General Public License"
__package__ = "lastfm.mixins"
from lastfm.lazylist import lazylist
from lastfm.decorators import depaginate
class Searchable(object):
@classmethod
@depaginate
def search(cls,
api,
search_item,
limit = None,
page = None,
**kwds):
from lastfm.api import Api
cls_name = cls.__name__.lower()
@ -26,27 +28,15 @@ class Searchable(object):
if limit:
params.update({'limit': limit})
@lazylist
def gen(lst):
data = api._fetch_data(params).find('results')
total_pages = int(data.findtext("{%s}totalResults" % Api.SEARCH_XMLNS))/ \
if page is not None:
params.update({'page': page})
data = api._fetch_data(params).find('results')
total_pages = int(data.findtext("{%s}totalResults" % Api.SEARCH_XMLNS))/ \
int(data.findtext("{%s}itemsPerPage" % Api.SEARCH_XMLNS)) + 1
@lazylist
def gen2(lst, data):
for a in data.findall('%smatches/%s'%(cls_name, cls_name)):
yield cls._search_yield_func(api, a)
for a in gen2(data):
yield a
for page in xrange(2, total_pages+1):
params.update({'page': page})
data = api._fetch_data(params).find('results')
for a in gen2(data):
yield a
return gen()
yield total_pages
for a in data.findall('%smatches/%s'%(cls_name, cls_name)):
yield cls._search_yield_func(api, a)
@staticmethod
def _search_yield_func(api, search_term):

View File

@ -9,7 +9,7 @@ from lastfm.base import LastfmBase
from lastfm.mixins import Cacheable, Shoutable
from lastfm.lazylist import lazylist
import lastfm.playlist
from lastfm.decorators import cached_property, top_property, authenticate
from lastfm.decorators import cached_property, top_property, authenticate, depaginate
class User(LastfmBase, Cacheable, Shoutable):
"""A class representing an user."""
@ -110,62 +110,38 @@ class User(LastfmBase, Cacheable, Shoutable):
Event.create_from_data(self._api, e)
for e in data.findall('event')
]
def get_past_events(self,
limit = None):
@depaginate
def get_past_events(self, limit = None, page = None):
params = self._default_params({'method': 'user.getPastEvents'})
if limit is not None:
params.update({'limit': limit})
if page is not None:
params.update({'page': page})
@lazylist
def gen(lst):
data = self._api._fetch_data(params).find('events')
total_pages = int(data.attrib['totalPages'])
@lazylist
def gen2(lst, data):
for e in data.findall('event'):
yield Event.create_from_data(self._api, e)
for e in gen2(data):
yield e
for page in xrange(2, total_pages+1):
params.update({'page': page})
data = self._api._fetch_data(params).find('events')
for e in gen2(data):
yield e
return gen()
data = self._api._fetch_data(params).find('events')
total_pages = int(data.attrib['totalPages'])
yield total_pages
for e in data.findall('event'):
yield Event.create_from_data(self._api, e)
@cached_property
def past_events(self):
return self.get_past_events()
@authenticate
def get_recommended_events(self, limit = None):
@depaginate
def get_recommended_events(self, limit = None, page = None):
params = {'method': 'user.getRecommendedEvents'}
if limit is not None:
params.update({'limit': limit})
@lazylist
def gen(lst):
data = self._api._fetch_data(params, sign = True, session = True).find('events')
total_pages = int(data.attrib['totalPages'])
@lazylist
def gen2(lst, data):
for e in data.findall('event'):
yield Event.create_from_data(self._api, e)
for e in gen2(data):
yield e
for page in xrange(2, total_pages+1):
params.update({'page': page})
data = self._api._fetch_data(params, sign = True, session = True).find('events')
for e in gen2(data):
yield e
return gen()
if page is not None:
params.update({'page': page})
data = self._api._fetch_data(params, sign = True, session = True).find('events')
total_pages = int(data.attrib['totalPages'])
yield total_pages
for e in data.findall('event'):
yield Event.create_from_data(self._api, e)
@cached_property
def recommended_events(self):
@ -411,35 +387,25 @@ class User(LastfmBase, Cacheable, Shoutable):
@cached_property
@authenticate
def recommended_artists(self):
@depaginate
def recommended_artists(self, page = None):
params = {'method': 'user.getRecommendedArtists'}
@lazylist
def gen(lst):
data = self._api._fetch_data(params, sign = True, session = True).find('recommendations')
total_pages = int(data.attrib['totalPages'])
if page is not None:
params.update({'page': page})
data = self._api._fetch_data(params, sign = True, session = True).find('recommendations')
total_pages = int(data.attrib['totalPages'])
yield total_pages
@lazylist
def gen2(lst, data):
for a in data.findall('artist'):
yield Artist(
self._api,
name = a.findtext('name'),
mbid = a.findtext('mbid'),
url = a.findtext('url'),
streamable = (a.findtext('streamable') == "1"),
image = dict([(i.get('size'), i.text) for i in a.findall('image')]),
)
for a in gen2(data):
yield a
for page in xrange(2, total_pages+1):
params.update({'page': page})
data = self._api._fetch_data(params, sign = True, session = True).find('recommendations')
for a in gen2(data):
yield a
return gen()
for a in data.findall('artist'):
yield Artist(
self._api,
name = a.findtext('name'),
mbid = a.findtext('mbid'),
url = a.findtext('url'),
streamable = (a.findtext('streamable') == "1"),
image = dict([(i.get('size'), i.text) for i in a.findall('image')]),
)
def get_top_tracks(self, period = None):
params = self._default_params({'method': 'user.getTopTracks'})
@ -755,53 +721,41 @@ class User(LastfmBase, Cacheable, Shoutable):
def user(self):
return self._user
def get_albums(self,
limit = None):
@depaginate
def get_albums(self, limit = None, page = None):
params = self._default_params({'method': 'library.getAlbums'})
if limit is not None:
params.update({'limit': limit})
if page is not None:
params.update({'page': page})
@lazylist
def gen(lst):
data = self._api._fetch_data(params).find('albums')
try:
data = self._api._fetch_data(params).find('albums')
total_pages = int(data.attrib['totalPages'])
@lazylist
def gen2(lst, data):
for a in data.findall('album'):
yield Album(
self._api,
subject = self,
name = a.findtext('name'),
artist = Artist(
self._api,
subject = self,
name = a.findtext('artist/name'),
mbid = a.findtext('artist/mbid'),
url = a.findtext('artist/url'),
),
mbid = a.findtext('mbid'),
url = a.findtext('url'),
image = dict([(i.get('size'), i.text) for i in a.findall('image')]),
stats = Stats(
subject = a.findtext('name'),
playcount = int(a.findtext('playcount')),
)
)
for a in gen2(data):
yield a
for page in xrange(2, total_pages+1):
params.update({'page': page})
try:
data = self._api._fetch_data(params).find('albums')
except LastfmError:
continue
for a in gen2(data):
yield a
return gen()
yield total_pages
for a in data.findall('album'):
yield Album(
self._api,
subject = self,
name = a.findtext('name'),
artist = Artist(
self._api,
subject = self,
name = a.findtext('artist/name'),
mbid = a.findtext('artist/mbid'),
url = a.findtext('artist/url'),
),
mbid = a.findtext('mbid'),
url = a.findtext('url'),
image = dict([(i.get('size'), i.text) for i in a.findall('image')]),
stats = Stats(
subject = a.findtext('name'),
playcount = int(a.findtext('playcount')),
)
)
except LastfmError:
return
@cached_property
def albums(self):
@ -825,47 +779,36 @@ class User(LastfmBase, Cacheable, Shoutable):
self._api._post_data(params)
self._albums = None
def get_artists(self,
limit = None):
@depaginate
def get_artists(self, limit = None, page = None):
params = self._default_params({'method': 'library.getArtists'})
if limit is not None:
params.update({'limit': limit})
if page is not None:
params.update({'page': page})
@lazylist
def gen(lst):
try:
data = self._api._fetch_data(params).find('artists')
total_pages = int(data.attrib['totalPages'])
@lazylist
def gen2(lst, data):
for a in data.findall('artist'):
yield Artist(
self._api,
subject = self,
name = a.findtext('name'),
mbid = a.findtext('mbid'),
stats = Stats(
subject = a.findtext('name'),
playcount = a.findtext('playcount') and int(a.findtext('playcount')) or None,
tagcount = a.findtext('tagcount') and int(a.findtext('tagcount')) or None
),
url = a.findtext('url'),
streamable = (a.findtext('streamable') == "1"),
image = dict([(i.get('size'), i.text) for i in a.findall('image')]),
)
for a in gen2(data):
yield a
for page in xrange(2, total_pages+1):
params.update({'page': page})
try:
data = self._api._fetch_data(params).find('artists')
except LastfmError:
continue
for a in gen2(data):
yield a
return gen()
yield total_pages
for a in data.findall('artist'):
yield Artist(
self._api,
subject = self,
name = a.findtext('name'),
mbid = a.findtext('mbid'),
stats = Stats(
subject = a.findtext('name'),
playcount = a.findtext('playcount') and int(a.findtext('playcount')) or None,
tagcount = a.findtext('tagcount') and int(a.findtext('tagcount')) or None
),
url = a.findtext('url'),
streamable = (a.findtext('streamable') == "1"),
image = dict([(i.get('size'), i.text) for i in a.findall('image')]),
)
except LastfmError:
return
@cached_property
def artists(self):
@ -881,55 +824,43 @@ class User(LastfmBase, Cacheable, Shoutable):
self._api._post_data(params)
self._artists = None
def get_tracks(self,
limit = None):
@depaginate
def get_tracks(self, limit = None, page = None):
params = self._default_params({'method': 'library.getTracks'})
if limit is not None:
params.update({'limit': limit})
@lazylist
def gen(lst):
if page is not None:
params.update({'page': page})
try:
data = self._api._fetch_data(params).find('tracks')
total_pages = int(data.attrib['totalPages'])
@lazylist
def gen2(lst, data):
for t in data.findall('track'):
yield Track(
self._api,
subject = self,
name = t.findtext('name'),
artist = Artist(
self._api,
subject = self,
name = t.findtext('artist/name'),
mbid = t.findtext('artist/mbid'),
url = t.findtext('artist/url'),
),
mbid = t.findtext('mbid'),
stats = Stats(
subject = t.findtext('name'),
playcount = t.findtext('playcount') and int(t.findtext('playcount')) or None,
tagcount = t.findtext('tagcount') and int(t.findtext('tagcount')) or None
),
streamable = (t.findtext('streamable') == '1'),
full_track = (t.find('streamable').attrib['fulltrack'] == '1'),
image = dict([(i.get('size'), i.text) for i in t.findall('image')]),
)
for t in gen2(data):
yield t
for page in xrange(2, total_pages+1):
params.update({'page': page})
data = None
try:
data = self._api._fetch_data(params).find('tracks')
except LastfmError:
continue
for t in gen2(data):
yield t
return gen()
yield total_pages
for t in data.findall('track'):
yield Track(
self._api,
subject = self,
name = t.findtext('name'),
artist = Artist(
self._api,
subject = self,
name = t.findtext('artist/name'),
mbid = t.findtext('artist/mbid'),
url = t.findtext('artist/url'),
),
mbid = t.findtext('mbid'),
stats = Stats(
subject = t.findtext('name'),
playcount = t.findtext('playcount') and int(t.findtext('playcount')) or None,
tagcount = t.findtext('tagcount') and int(t.findtext('tagcount')) or None
),
streamable = (t.findtext('streamable') == '1'),
full_track = (t.find('streamable').attrib['fulltrack'] == '1'),
image = dict([(i.get('size'), i.text) for i in t.findall('image')]),
)
except LastfmError:
return
@cached_property
def tracks(self):

View File

@ -7,8 +7,7 @@ __package__ = "lastfm"
from lastfm.base import LastfmBase
from lastfm.mixins import Cacheable, Searchable
from lastfm.lazylist import lazylist
from lastfm.decorators import cached_property
from lastfm.decorators import cached_property, depaginate
class Venue(LastfmBase, Cacheable, Searchable):
"""A class representing a venue of an event"""
@ -56,32 +55,21 @@ class Venue(LastfmBase, Cacheable, Searchable):
Event.create_from_data(self._api, e)
for e in data.findall('event')
]
def get_past_events(self,
limit = None):
@depaginate
def get_past_events(self, limit = None, page = None):
params = self._default_params({'method': 'venue.getPastEvents'})
if limit is not None:
params.update({'limit': limit})
if page is not None:
params.update({'page': page})
@lazylist
def gen(lst):
data = self._api._fetch_data(params).find('events')
total_pages = int(data.attrib['totalPages'])
data = self._api._fetch_data(params).find('events')
total_pages = int(data.attrib['totalPages'])
yield total_pages
@lazylist
def gen2(lst, data):
for e in data.findall('event'):
yield Event.create_from_data(self._api, e)
for e in gen2(data):
yield e
for page in xrange(2, total_pages+1):
params.update({'page': page})
data = self._api._fetch_data(params).find('events')
for e in gen2(data):
yield e
return gen()
for e in data.findall('event'):
yield Event.create_from_data(self._api, e)
@cached_property
def past_events(self):
@ -96,6 +84,9 @@ class Venue(LastfmBase, Cacheable, Searchable):
@staticmethod
def _search_yield_func(api, venue):
latitude = venue.findtext('location/{%s}point/{%s}lat' % ((Location.XMLNS,)*2))
longitude = venue.findtext('location/{%s}point/{%s}long' % ((Location.XMLNS,)*2))
return Venue(
api,
id = int(venue.findtext('id')),
@ -109,13 +100,9 @@ class Venue(LastfmBase, Cacheable, Searchable):
),
street = venue.findtext('location/street'),
postal_code = venue.findtext('location/postalcode'),
latitude = float(venue.findtext(
'location/{%s}point/{%s}lat' % ((Location.XMLNS,)*2)
)),
longitude = float(venue.findtext(
'location/{%s}point/{%s}long' % ((Location.XMLNS,)*2)
)),
),
latitude = (latitude.strip()!= '') and float(latitude) or None,
longitude = (longitude.strip()!= '') and float(longitude) or None,
),
url = venue.findtext('url')
)