* converted all mixin classes to class decorator functions

* renamed all mixin modules to avoid name conflict
* removed mixin classes from class inheritence list and put then as class decorators
master
Abhinav Sarkar 2009-03-31 03:39:23 +00:00
parent d709434a7b
commit c36d689690
21 changed files with 585 additions and 547 deletions

View File

@ -7,10 +7,13 @@ __license__ = "GNU Lesser General Public License"
__package__ = "lastfm"
from lastfm.base import LastfmBase
from lastfm.mixins import Cacheable, Searchable, Taggable
from lastfm.mixins import cacheable, searchable, taggable
from lastfm.decorators import cached_property, top_property
class Album(LastfmBase, Cacheable, Searchable, Taggable):
@taggable
@searchable
@cacheable
class Album(LastfmBase):
"""A class representing an album."""
def init(self,
api,
@ -58,7 +61,6 @@ class Album(LastfmBase, Cacheable, Searchable, Taggable):
"""
if not isinstance(api, Api):
raise InvalidParametersError("api reference must be supplied as an argument")
Taggable.init(self, api)
self._api = api
self._name = name
self._artist = artist

View File

@ -7,10 +7,15 @@ __license__ = "GNU Lesser General Public License"
__package__ = "lastfm"
from lastfm.base import LastfmBase
from lastfm.mixins import Cacheable, Searchable, Sharable, Shoutable, Taggable
from lastfm.mixins import cacheable, searchable, sharable, shoutable, taggable
from lastfm.decorators import cached_property, top_property
class Artist(LastfmBase, Cacheable, Sharable, Shoutable, Searchable, Taggable):
@shoutable
@sharable
@taggable
@searchable
@cacheable
class Artist(LastfmBase):
"""A class representing an artist."""
def init(self,
api,
@ -55,9 +60,6 @@ class Artist(LastfmBase, Cacheable, Sharable, Shoutable, Searchable, Taggable):
"""
if not isinstance(api, Api):
raise InvalidParametersError("api reference must be supplied as an argument")
Sharable.init(self, api)
Shoutable.init(self, api)
Taggable.init(self, api)
self._api = api
self._name = name
@ -402,16 +404,16 @@ class Artist(LastfmBase, Cacheable, Sharable, Shoutable, Searchable, Taggable):
listeners = int(data.findtext('stats/listeners')),
playcount = int(data.findtext('stats/playcount'))
)
self._similar = [
Artist(
self._api,
subject = self,
name = a.findtext('name'),
url = a.findtext('url'),
image = dict([(i.get('size'), i.text) for i in a.findall('image')])
)
for a in data.findall('similar/artist')
]
# self._similar = [
# Artist(
# self._api,
# subject = self,
# name = a.findtext('name'),
# url = a.findtext('url'),
# image = dict([(i.get('size'), i.text) for i in a.findall('image')])
# )
# for a in data.findall('similar/artist')
# ]
self._top_tags = [
Tag(
self._api,

View File

@ -6,10 +6,11 @@ __license__ = "GNU Lesser General Public License"
__package__ = "lastfm"
from lastfm.base import LastfmBase
from lastfm.mixins import Cacheable
from lastfm.mixins import cacheable
from operator import xor
class Chart(LastfmBase, Cacheable):
@cacheable
class Chart(LastfmBase):
"""The base class for all the chart classes"""
def init(self, subject, start, end, stats = None):
@ -435,7 +436,7 @@ class RollingChart(Chart):
end = end,
stats = Stats(
subject = subject,
**{count_attribute[1:]: sum([a.stats.__dict__[count_attribute] for a in items])}
**{count_attribute[1:]: sum(a.stats.__dict__[count_attribute] for a in items)}
),
**{"%ss" % chart_type: items}
)
@ -467,7 +468,7 @@ class RollingTagChart(TagChart):
key_func = lambda tag: tag.name
chart = super(cls.mro()[3], cls).create_from_data(
subject, key_func, start, end)
count_sum = sum([t.stats.count for t in chart.tags])
count_sum = sum(t.stats.count for t in chart.tags)
for t in chart.tags:
t.stats.__dict__['_count'] /= count_sum
return chart

View File

@ -7,9 +7,12 @@ __license__ = "GNU Lesser General Public License"
__package__ = "lastfm"
from lastfm.base import LastfmBase
from lastfm.mixins import Cacheable, Sharable, Shoutable
from lastfm.mixins import cacheable, sharable, shoutable
class Event(LastfmBase, Cacheable, Sharable, Shoutable):
@shoutable
@sharable
@cacheable
class Event(LastfmBase):
"""A class representing an event."""
STATUS_ATTENDING = 0
STATUS_MAYBE = 1
@ -59,8 +62,6 @@ class Event(LastfmBase, Cacheable, Sharable, Shoutable):
"""
if not isinstance(api, Api):
raise InvalidParametersError("api reference must be supplied as an argument")
Sharable.init(self, api)
Shoutable.init(self, api)
self._api = api
self._id = id

View File

@ -7,7 +7,7 @@ __license__ = "GNU Lesser General Public License"
__package__ = "lastfm"
from lastfm.base import LastfmBase
from lastfm.mixins import Cacheable
from lastfm.mixins import cacheable
from lastfm.decorators import cached_property, top_property, depaginate
class Geo(object):
@ -145,7 +145,8 @@ class Geo(object):
for t in data.findall('track')
]
class Location(LastfmBase, Cacheable):
@cacheable
class Location(LastfmBase):
"""A class representing a location of an event"""
XMLNS = "http://www.w3.org/2003/01/geo/wgs84_pos#"
@ -324,7 +325,8 @@ class Location(LastfmBase, Cacheable):
else:
return "<lastfm.geo.Location: %s>" % self.city
class Country(LastfmBase, Cacheable):
@cacheable
class Country(LastfmBase):
"""A class representing a country."""
ISO_CODES = {
'AD': 'Andorra',

View File

@ -7,13 +7,12 @@ __license__ = "GNU Lesser General Public License"
__package__ = "lastfm"
from lastfm.base import LastfmBase
from lastfm.mixins import (
Cacheable, AlbumChartable, ArtistChartable,
TrackChartable, TagChartable)
from lastfm.mixins import cacheable, chartable
from lastfm.decorators import cached_property, depaginate
class Group(LastfmBase, Cacheable, AlbumChartable,
ArtistChartable, TrackChartable, TagChartable):
@chartable(['album', 'artist', 'track', 'tag'])
@cacheable
class Group(LastfmBase):
"""A class representing a group on last.fm."""
def init(self, api, name = None, **kwargs):
"""
@ -29,11 +28,7 @@ class Group(LastfmBase, Cacheable, AlbumChartable,
"""
if not isinstance(api, Api):
raise InvalidParametersError("api reference must be supplied as an argument")
AlbumChartable.init(self, api)
ArtistChartable.init(self, api)
TrackChartable.init(self, api)
TagChartable.init(self, api)
self._api = api
self._name = name

View File

@ -5,13 +5,12 @@ __version__ = "0.2"
__license__ = "GNU Lesser General Public License"
__package__ = "lastfm.mixins"
from lastfm.mixins.cacheable import Cacheable
from lastfm.mixins.searchable import Searchable
from lastfm.mixins.sharable import Sharable
from lastfm.mixins.shoutable import Shoutable
from lastfm.mixins.taggable import Taggable
from lastfm.mixins.chartable import (
AlbumChartable, ArtistChartable, TrackChartable, TagChartable)
from lastfm.mixins._cacheable import cacheable
from lastfm.mixins._searchable import searchable
from lastfm.mixins._sharable import sharable
from lastfm.mixins._shoutable import shoutable
from lastfm.mixins._taggable import taggable
from lastfm.mixins._chartable import chartable
__all__ = ['Cacheable', 'Searchable', 'Sharable', 'Shoutable', 'Taggable'
'AlbumChartable', 'ArtistChartable', 'TrackChartable', 'TagChartable']
__all__ = ['cacheable', 'searchable', 'sharable', 'shoutable', 'taggable'
'chartable']

View File

@ -10,11 +10,25 @@ try:
except ImportError:
from dummy_threading import Lock
class Cacheable(object):
registry = {}
_lock = Lock()
registry = {}
_lock = Lock()
def register(ob, key):
if not ob.__class__ in registry:
registry[ob.__class__] = {}
if key in registry[ob.__class__]:
ob = registry[ob.__class__][key]
#print "already registered: %s" % repr(ob)
return (ob, True)
else:
#print "not already registered: %s" % ob.__class__
registry[ob.__class__][key] = ob
return (ob, False)
def cacheable(cls):
@classmethod
def __new__(cls, *args, **kwds):
args = args[1:]
subject = None
if 'subject' in kwds and not cls.__name__.startswith('Weekly'):
subject = kwds['subject']
@ -29,29 +43,19 @@ class Cacheable(object):
key = cls._hash_func(*args, **kwds)
if subject is not None:
key = (hash(subject), key)
Cacheable._lock.acquire()
try:
inst, already_registered = Cacheable.register(object.__new__(cls), key)
with _lock:
inst, already_registered = register(object.__new__(cls), key)
if not already_registered:
inst.init(*args, **kwds)
finally:
Cacheable._lock.release()
return inst
@staticmethod
def register(ob, key):
if not ob.__class__ in Cacheable.registry:
Cacheable.registry[ob.__class__] = {}
if key in Cacheable.registry[ob.__class__]:
ob = Cacheable.registry[ob.__class__][key]
#print "already registered: %s" % repr(ob)
return (ob, True)
else:
#print "not already registered: %s" % ob.__class__
Cacheable.registry[ob.__class__][key] = ob
return (ob, False)
@staticmethod
def _hash_func(*args, **kwds):
raise NotImplementedError("The subclass must override this method")
cls.__new__ = __new__
if not hasattr(cls, '_hash_func'):
cls._hash_func = _hash_func
return cls

445
lastfm/mixins/_chartable.py Normal file
View File

@ -0,0 +1,445 @@
#!/usr/bin/env python
__author__ = "Abhinav Sarkar <abhinav@abhinavsarkar.net>"
__version__ = "0.2"
__license__ = "GNU Lesser General Public License"
__package__ = "lastfm.mixins"
from lastfm.lazylist import lazylist
from lastfm.decorators import cached_property
def chartable(chart_types):
def wrapper(cls):
@cached_property
def weekly_chart_list(self):
"""
a list of available weekly charts for this group
@rtype: L{list} of L{WeeklyChart}
"""
from lastfm.chart import WeeklyChart
params = self._default_params(
{'method': '%s.getWeeklyChartList' % self.__class__.__name__.lower()})
data = self._api._fetch_data(params).find('weeklychartlist')
return [
WeeklyChart.create_from_data(self._api, self, c)
for c in data.findall('chart')
]
@cached_property
def monthly_chart_list(self):
from lastfm.chart import MonthlyChart
return MonthlyChart.get_chart_list(self)
def _default_params(self, extra_params = None):
if extra_params is not None:
return extra_params
else:
return {}
def get_weekly_album_chart(self, start = None, end = None):
"""
Get an album chart for the group, for a given date range.
If no date range is supplied, it will return the most
recent album chart for the group.
@param start: the date at which the chart should start from (optional)
@type start: C{datetime.datetime}
@param end: the date at which the chart should end on (optional)
@type end: C{datetime.datetime}
@return: an album chart for the group
@rtype: L{WeeklyAlbumChart}
@raise InvalidParametersError: Both start and end parameter have to be either
provided or not provided. Providing only one of
them will raise an exception.
"""
from lastfm.chart import WeeklyChart, WeeklyAlbumChart
params = self._default_params(
{'method': '%s.getWeeklyAlbumChart' % self.__class__.__name__.lower()})
params = WeeklyChart._check_chart_params(params, self, start, end)
data = self._api._fetch_data(params).find('weeklyalbumchart')
return WeeklyAlbumChart.create_from_data(self._api, self, data)
@cached_property
def recent_weekly_album_chart(self):
"""
most recent album chart for the group
@rtype: L{WeeklyAlbumChart}
"""
return self.get_weekly_album_chart()
@cached_property
def weekly_album_chart_list(self):
"""
a list of all album charts for this group in reverse-chronological
order. (that means 0th chart is the most recent chart)
@rtype: L{lazylist} of L{WeeklyAlbumChart}
"""
wcl = list(self.weekly_chart_list)
wcl.reverse()
@lazylist
def gen(lst):
for wc in wcl:
try:
yield self.get_weekly_album_chart(wc.start, wc.end)
except LastfmError:
pass
return gen()
def get_monthly_album_chart(self, start = None, end = None):
from lastfm.chart import MonthlyAlbumChart
return MonthlyAlbumChart.create_from_data(self, start, end)
@cached_property
def recent_monthly_album_chart(self):
return self.get_monthly_album_chart()
@cached_property
def monthly_album_chart_list(self):
mcl = list(self.monthly_chart_list)
mcl.reverse()
@lazylist
def gen(lst):
for mc in mcl:
try:
yield self.get_monthly_album_chart(mc.start, mc.end)
except LastfmError:
pass
return gen()
def get_quaterly_album_chart(self, start = None, end = None):
from lastfm.chart import QuaterlyAlbumChart
return QuaterlyAlbumChart.create_from_data(self, start, end)
@cached_property
def recent_quaterly_album_chart(self):
return self.get_quaterly_album_chart()
def get_half_yearly_album_chart(self, start = None, end = None):
from lastfm.chart import HalfYearlyAlbumChart
return HalfYearlyAlbumChart.create_from_data(self, start, end)
@cached_property
def recent_half_yearly_album_chart(self):
return self.get_half_yearly_album_chart()
def get_yearly_album_chart(self, start = None, end = None):
from lastfm.chart import YearlyAlbumChart
return YearlyAlbumChart.create_from_data(self, start, end)
@cached_property
def recent_yearly_album_chart(self):
return self.get_yearly_album_chart()
def get_weekly_artist_chart(self, start = None, end = None):
"""
Get an artist chart for the group, for a given date range.
If no date range is supplied, it will return the most
recent artist chart for the group.
@param start: the date at which the chart should start from (optional)
@type start: C{datetime.datetime}
@param end: the date at which the chart should end on (optional)
@type end: C{datetime.datetime}
@return: an artist chart for the group
@rtype: L{WeeklyArtistChart}
@raise InvalidParametersError: Both start and end parameter have to be either
provided or not provided. Providing only one of
them will raise an exception.
"""
from lastfm.chart import WeeklyChart, WeeklyArtistChart
params = self._default_params(
{'method': '%s.getWeeklyArtistChart' % self.__class__.__name__.lower()})
params = WeeklyChart._check_chart_params(params, self, start, end)
data = self._api._fetch_data(params).find('weeklyartistchart')
return WeeklyArtistChart.create_from_data(self._api, self, data)
@cached_property
def recent_weekly_artist_chart(self):
"""
most recent artist chart for the group
@rtype: L{WeeklyArtistChart}
"""
return self.get_weekly_artist_chart()
@cached_property
def weekly_artist_chart_list(self):
"""
a list of all artist charts for this group in reverse-chronological
order. (that means 0th chart is the most recent chart)
@rtype: L{lazylist} of L{WeeklyArtistChart}
"""
wcl = list(self.weekly_chart_list)
wcl.reverse()
@lazylist
def gen(lst):
for wc in wcl:
try:
yield self.get_weekly_artist_chart(wc.start, wc.end)
except LastfmError:
pass
return gen()
def get_monthly_artist_chart(self, start = None, end = None):
from lastfm.chart import MonthlyArtistChart
return MonthlyArtistChart.create_from_data(self, start, end)
@cached_property
def recent_monthly_artist_chart(self):
return self.get_monthly_artist_chart()
@cached_property
def monthly_artist_chart_list(self):
mcl = list(self.monthly_chart_list)
mcl.reverse()
@lazylist
def gen(lst):
for mc in mcl:
try:
yield self.get_monthly_artist_chart(mc.start, mc.end)
except LastfmError:
pass
return gen()
def get_quaterly_artist_chart(self, start = None, end = None):
from lastfm.chart import QuaterlyArtistChart
return QuaterlyArtistChart.create_from_data(self, start, end)
@cached_property
def recent_quaterly_artist_chart(self):
return self.get_quaterly_artist_chart()
def get_half_yearly_artist_chart(self, start = None, end = None):
from lastfm.chart import HalfYearlyArtistChart
return HalfYearlyArtistChart.create_from_data(self, start, end)
@cached_property
def recent_half_yearly_artist_chart(self):
return self.get_half_yearly_artist_chart()
def get_yearly_artist_chart(self, start = None, end = None):
from lastfm.chart import YearlyArtistChart
return YearlyArtistChart.create_from_data(self, start, end)
@cached_property
def recent_yearly_artist_chart(self):
return self.get_yearly_artist_chart()
def get_weekly_track_chart(self, start = None, end = None):
"""
Get a track chart for the group, for a given date range.
If no date range is supplied, it will return the most
recent artist chart for the group.
@param start: the date at which the chart should start from (optional)
@type start: C{datetime.datetime}
@param end: the date at which the chart should end on (optional)
@type end: C{datetime.datetime}
@return: a track chart for the group
@rtype: L{WeeklyTrackChart}
@raise InvalidParametersError: Both start and end parameter have to be either
provided or not provided. Providing only one of
them will raise an exception.
"""
from lastfm.chart import WeeklyChart, WeeklyTrackChart
params = self._default_params(
{'method': '%s.getWeeklyTrackChart' % self.__class__.__name__.lower()})
params = WeeklyChart._check_chart_params(params, self, start, end)
data = self._api._fetch_data(params).find('weeklytrackchart')
return WeeklyTrackChart.create_from_data(self._api, self, data)
@cached_property
def recent_weekly_track_chart(self):
"""
most recent track chart for the group
@rtype: L{WeeklyTrackChart}
"""
return self.get_weekly_track_chart()
@cached_property
def weekly_track_chart_list(self):
"""
a list of all track charts for this group in reverse-chronological
order. (that means 0th chart is the most recent chart)
@rtype: L{lazylist} of L{WeeklyTrackChart}
"""
wcl = list(self.weekly_chart_list)
wcl.reverse()
@lazylist
def gen(lst):
for wc in wcl:
try:
yield self.get_weekly_track_chart(wc.start, wc.end)
except LastfmError:
pass
return gen()
def get_monthly_track_chart(self, start = None, end = None):
from lastfm.chart import MonthlyTrackChart
return MonthlyTrackChart.create_from_data(self, start, end)
@cached_property
def recent_monthly_track_chart(self):
return self.get_monthly_track_chart()
@cached_property
def monthly_track_chart_list(self):
mcl = list(self.monthly_chart_list)
mcl.reverse()
@lazylist
def gen(lst):
for mc in mcl:
try:
yield self.get_monthly_track_chart(mc.start, mc.end)
except LastfmError:
pass
return gen()
def get_quaterly_track_chart(self, start = None, end = None):
from lastfm.chart import QuaterlyTrackChart
return QuaterlyTrackChart.create_from_data(self, start, end)
@cached_property
def recent_quaterly_track_chart(self):
return self.get_quaterly_track_chart()
def get_half_yearly_track_chart(self, start = None, end = None):
from lastfm.chart import HalfYearlyTrackChart
return HalfYearlyTrackChart.create_from_data(self, start, end)
@cached_property
def recent_half_yearly_track_chart(self):
return self.get_half_yearly_track_chart()
def get_yearly_track_chart(self, start = None, end = None):
from lastfm.chart import YearlyTrackChart
return YearlyTrackChart.create_from_data(self, start, end)
@cached_property
def recent_yearly_track_chart(self):
return self.get_yearly_track_chart()
def get_weekly_tag_chart(self, start = None, end = None):
"""
Get a tag chart for the group, for a given date range.
If no date range is supplied, it will return the most
recent tag chart for the group.
@param start: the date at which the chart should start from (optional)
@type start: C{datetime.datetime}
@param end: the date at which the chart should end on (optional)
@type end: C{datetime.datetime}
@return: a tag chart for the group
@rtype: L{WeeklyTagChart}
@raise InvalidParametersError: Both start and end parameter have to be either
provided or not provided. Providing only one of
them will raise an exception.
@note: This method is a composite method. It is not provided directly by the
last.fm API. It uses other methods to collect the data, analyzes it and
creates a chart. So this method is a little heavy to call, as it does
mulitple calls to the API.
"""
from lastfm.chart import WeeklyChart, WeeklyTagChart
WeeklyChart._check_chart_params({}, self, start, end)
return WeeklyTagChart.create_from_data(self._api, self, start, end)
@cached_property
def recent_weekly_tag_chart(self):
"""
most recent tag chart for the group
@rtype: L{WeeklyTagChart}
"""
return self.get_weekly_tag_chart()
@cached_property
def weekly_tag_chart_list(self):
"""
a list of all tag charts for this group in reverse-chronological
order. (that means 0th chart is the most recent chart)
@rtype: L{lazylist} of L{WeeklyTagChart}
"""
wcl = list(self.weekly_chart_list)
wcl.reverse()
@lazylist
def gen(lst):
for wc in wcl:
try:
yield self.get_weekly_tag_chart(wc.start, wc.end)
except LastfmError:
pass
return gen()
def get_monthly_tag_chart(self, start = None, end = None):
from lastfm.chart import MonthlyTagChart
return MonthlyTagChart.create_from_data(self, start, end)
@cached_property
def recent_monthly_tag_chart(self):
return self.get_monthly_tag_chart()
@cached_property
def monthly_tag_chart_list(self):
mcl = list(self.monthly_chart_list)
mcl.reverse()
@lazylist
def gen(lst):
for mc in mcl:
try:
yield self.get_monthly_tag_chart(mc.start, mc.end)
except LastfmError:
pass
return gen()
def get_quaterly_tag_chart(self, start = None, end = None):
from lastfm.chart import QuaterlyTagChart
return QuaterlyTagChart.create_from_data(self, start, end)
@cached_property
def recent_quaterly_tag_chart(self):
return self.get_quaterly_tag_chart()
def get_half_yearly_tag_chart(self, start = None, end = None):
from lastfm.chart import HalfYearlyTagChart
return HalfYearlyTagChart.create_from_data(self, start, end)
@cached_property
def recent_half_yearly_tag_chart(self):
return self.get_half_yearly_tag_chart()
def get_yearly_tag_chart(self, start = None, end = None):
from lastfm.chart import YearlyTagChart
return YearlyTagChart.create_from_data(self, start, end)
@cached_property
def recent_yearly_tag_chart(self):
return self.get_yearly_tag_chart()
cls.weekly_chart_list = weekly_chart_list
cls.monthly_chart_list = monthly_chart_list
if not hasattr(cls, '_default_params'):
cls._default_params = _default_params
method_names = [
'get_weekly_%s_chart', 'recent_weekly_%s_chart', 'weekly_%s_chart_list',
'get_monthly_%s_chart', 'recent_monthly_%s_chart', 'monthly_%s_chart_list',
'get_quaterly_%s_chart', 'recent_quaterly_%s_chart',
'get_half_yearly_%s_chart', 'recent_half_yearly_%s_chart',
'get_yearly_%s_chart', 'recent_yearly_%s_chart'
]
for chart_type in chart_types:
for method_name in method_names:
setattr(cls, method_name % chart_type, locals()[method_name % chart_type])
return cls
return wrapper
from lastfm.error import LastfmError

View File

@ -7,7 +7,7 @@ __package__ = "lastfm.mixins"
from lastfm.decorators import depaginate
class Searchable(object):
def searchable(cls):
@classmethod
@depaginate
def search(cls,
@ -40,4 +40,10 @@ class Searchable(object):
@staticmethod
def _search_yield_func(api, search_term):
pass
raise NotImplementedError("the subclass should implement this method")
cls.search = search
if not hasattr(cls, '_search_yield_func'):
cls._search_yield_func = _search_yield_func
return cls

View File

@ -5,10 +5,7 @@ __version__ = "0.2"
__license__ = "GNU Lesser General Public License"
__package__ = "lastfm.mixins"
class Sharable(object):
def init(self, api):
self._api = api
def sharable(cls):
def share(self, recipient, message = None):
from lastfm.user import User
params = self._default_params({'method': '%s.share' % self.__class__.__name__.lower()})
@ -28,4 +25,10 @@ class Sharable(object):
if extra_params is not None:
return extra_params
else:
return {}
return {}
cls.share = share
if not hasattr(cls, '_default_params'):
cls._default_params = _default_params
return cls

View File

@ -7,13 +7,10 @@ __package__ = "lastfm.mixins"
from lastfm.decorators import cached_property, top_property
class Shoutable(object):
def init(self, api):
self._api = api
def shoutable(cls):
@cached_property
def shouts(self):
"""shouts for this ssubject"""
"""shouts for this %s""" % cls.__name__.lower()
from lastfm.shout import Shout
from lastfm.user import User
params = self._default_params({'method': '%s.getShouts' % self.__class__.__name__.lower()})
@ -30,7 +27,7 @@ class Shoutable(object):
@top_property("shouts")
def recent_shout(self):
"""recent shout for this subject"""
"""recent shout for this %s""" % cls.__name__.lower()
pass
def _default_params(self, extra_params = None):
@ -38,6 +35,13 @@ class Shoutable(object):
return extra_params
else:
return {}
cls.shouts = shouts
cls.recent_shout = recent_shout
if not hasattr(cls, '_default_params'):
cls._default_params = _default_params
return cls
from datetime import datetime
import time

View File

@ -8,10 +8,7 @@ __package__ = "lastfm.mixins"
from lastfm.safelist import SafeList
from lastfm.decorators import cached_property, authentication_required
class Taggable(object):
def init(self, api):
self._api = api
def taggable(cls):
@cached_property
@authentication_required
def tags(self):
@ -69,4 +66,12 @@ class Taggable(object):
if extra_params is not None:
return extra_params
else:
return {}
return {}
cls.tags = tags
cls.add_tags = add_tags
cls.remove_tag = remove_tag
if not hasattr(cls, '_default_params'):
cls._default_params = _default_params
return cls

View File

@ -1,432 +0,0 @@
#!/usr/bin/env python
__author__ = "Abhinav Sarkar <abhinav@abhinavsarkar.net>"
__version__ = "0.2"
__license__ = "GNU Lesser General Public License"
__package__ = "lastfm.mixins"
from lastfm.lazylist import lazylist
from lastfm.decorators import cached_property
class Chartable(object):
def init(self, api):
self._api = api
@cached_property
def weekly_chart_list(self):
"""
a list of available weekly charts for this group
@rtype: L{list} of L{WeeklyChart}
"""
from lastfm.chart import WeeklyChart
params = self._default_params(
{'method': '%s.getWeeklyChartList' % self.__class__.__name__.lower()})
data = self._api._fetch_data(params).find('weeklychartlist')
return [
WeeklyChart.create_from_data(self._api, self, c)
for c in data.findall('chart')
]
@cached_property
def monthly_chart_list(self):
from lastfm.chart import MonthlyChart
return MonthlyChart.get_chart_list(self)
def _default_params(self, extra_params = None):
if extra_params is not None:
return extra_params
else:
return {}
class AlbumChartable(Chartable):
def get_weekly_album_chart(self, start = None, end = None):
"""
Get an album chart for the group, for a given date range.
If no date range is supplied, it will return the most
recent album chart for the group.
@param start: the date at which the chart should start from (optional)
@type start: C{datetime.datetime}
@param end: the date at which the chart should end on (optional)
@type end: C{datetime.datetime}
@return: an album chart for the group
@rtype: L{WeeklyAlbumChart}
@raise InvalidParametersError: Both start and end parameter have to be either
provided or not provided. Providing only one of
them will raise an exception.
"""
from lastfm.chart import WeeklyChart, WeeklyAlbumChart
params = self._default_params(
{'method': '%s.getWeeklyAlbumChart' % self.__class__.__name__.lower()})
params = WeeklyChart._check_chart_params(params, self, start, end)
data = self._api._fetch_data(params).find('weeklyalbumchart')
return WeeklyAlbumChart.create_from_data(self._api, self, data)
@cached_property
def recent_weekly_album_chart(self):
"""
most recent album chart for the group
@rtype: L{WeeklyAlbumChart}
"""
return self.get_weekly_album_chart()
@cached_property
def weekly_album_chart_list(self):
"""
a list of all album charts for this group in reverse-chronological
order. (that means 0th chart is the most recent chart)
@rtype: L{lazylist} of L{WeeklyAlbumChart}
"""
wcl = list(self.weekly_chart_list)
wcl.reverse()
@lazylist
def gen(lst):
for wc in wcl:
try:
yield self.get_weekly_album_chart(wc.start, wc.end)
except LastfmError:
pass
return gen()
def get_monthly_album_chart(self, start = None, end = None):
from lastfm.chart import MonthlyAlbumChart
return MonthlyAlbumChart.create_from_data(self, start, end)
@cached_property
def recent_monthly_album_chart(self):
return self.get_monthly_album_chart()
@cached_property
def monthly_album_chart_list(self):
mcl = list(self.monthly_chart_list)
mcl.reverse()
@lazylist
def gen(lst):
for mc in mcl:
try:
yield self.get_monthly_album_chart(mc.start, mc.end)
except LastfmError:
pass
return gen()
def get_quaterly_album_chart(self, start = None, end = None):
from lastfm.chart import QuaterlyAlbumChart
return QuaterlyAlbumChart.create_from_data(self, start, end)
@cached_property
def recent_quaterly_album_chart(self):
return self.get_quaterly_album_chart()
def get_half_yearly_album_chart(self, start = None, end = None):
from lastfm.chart import HalfYearlyAlbumChart
return HalfYearlyAlbumChart.create_from_data(self, start, end)
@cached_property
def recent_half_yearly_album_chart(self):
return self.get_half_yearly_album_chart()
def get_yearly_album_chart(self, start = None, end = None):
from lastfm.chart import YearlyAlbumChart
return YearlyAlbumChart.create_from_data(self, start, end)
@cached_property
def recent_yearly_album_chart(self):
return self.get_yearly_album_chart()
class ArtistChartable(Chartable):
def get_weekly_artist_chart(self, start = None, end = None):
"""
Get an artist chart for the group, for a given date range.
If no date range is supplied, it will return the most
recent artist chart for the group.
@param start: the date at which the chart should start from (optional)
@type start: C{datetime.datetime}
@param end: the date at which the chart should end on (optional)
@type end: C{datetime.datetime}
@return: an artist chart for the group
@rtype: L{WeeklyArtistChart}
@raise InvalidParametersError: Both start and end parameter have to be either
provided or not provided. Providing only one of
them will raise an exception.
"""
from lastfm.chart import WeeklyChart, WeeklyArtistChart
params = self._default_params(
{'method': '%s.getWeeklyArtistChart' % self.__class__.__name__.lower()})
params = WeeklyChart._check_chart_params(params, self, start, end)
data = self._api._fetch_data(params).find('weeklyartistchart')
return WeeklyArtistChart.create_from_data(self._api, self, data)
@cached_property
def recent_weekly_artist_chart(self):
"""
most recent artist chart for the group
@rtype: L{WeeklyArtistChart}
"""
return self.get_weekly_artist_chart()
@cached_property
def weekly_artist_chart_list(self):
"""
a list of all artist charts for this group in reverse-chronological
order. (that means 0th chart is the most recent chart)
@rtype: L{lazylist} of L{WeeklyArtistChart}
"""
wcl = list(self.weekly_chart_list)
wcl.reverse()
@lazylist
def gen(lst):
for wc in wcl:
try:
yield self.get_weekly_artist_chart(wc.start, wc.end)
except LastfmError:
pass
return gen()
def get_monthly_artist_chart(self, start = None, end = None):
from lastfm.chart import MonthlyArtistChart
return MonthlyArtistChart.create_from_data(self, start, end)
@cached_property
def recent_monthly_artist_chart(self):
return self.get_monthly_artist_chart()
@cached_property
def monthly_artist_chart_list(self):
mcl = list(self.monthly_chart_list)
mcl.reverse()
@lazylist
def gen(lst):
for mc in mcl:
try:
yield self.get_monthly_artist_chart(mc.start, mc.end)
except LastfmError:
pass
return gen()
def get_quaterly_artist_chart(self, start = None, end = None):
from lastfm.chart import QuaterlyArtistChart
return QuaterlyArtistChart.create_from_data(self, start, end)
@cached_property
def recent_quaterly_artist_chart(self):
return self.get_quaterly_artist_chart()
def get_half_yearly_artist_chart(self, start = None, end = None):
from lastfm.chart import HalfYearlyArtistChart
return HalfYearlyArtistChart.create_from_data(self, start, end)
@cached_property
def recent_half_yearly_artist_chart(self):
return self.get_half_yearly_artist_chart()
def get_yearly_artist_chart(self, start = None, end = None):
from lastfm.chart import YearlyArtistChart
return YearlyArtistChart.create_from_data(self, start, end)
@cached_property
def recent_yearly_album_chart(self):
return self.get_yearly_artist_chart()
class TrackChartable(Chartable):
def get_weekly_track_chart(self, start = None, end = None):
"""
Get a track chart for the group, for a given date range.
If no date range is supplied, it will return the most
recent artist chart for the group.
@param start: the date at which the chart should start from (optional)
@type start: C{datetime.datetime}
@param end: the date at which the chart should end on (optional)
@type end: C{datetime.datetime}
@return: a track chart for the group
@rtype: L{WeeklyTrackChart}
@raise InvalidParametersError: Both start and end parameter have to be either
provided or not provided. Providing only one of
them will raise an exception.
"""
from lastfm.chart import WeeklyChart, WeeklyTrackChart
params = self._default_params(
{'method': '%s.getWeeklyTrackChart' % self.__class__.__name__.lower()})
params = WeeklyChart._check_chart_params(params, self, start, end)
data = self._api._fetch_data(params).find('weeklytrackchart')
return WeeklyTrackChart.create_from_data(self._api, self, data)
@cached_property
def recent_weekly_track_chart(self):
"""
most recent track chart for the group
@rtype: L{WeeklyTrackChart}
"""
return self.get_weekly_track_chart()
@cached_property
def weekly_track_chart_list(self):
"""
a list of all track charts for this group in reverse-chronological
order. (that means 0th chart is the most recent chart)
@rtype: L{lazylist} of L{WeeklyTrackChart}
"""
wcl = list(self.weekly_chart_list)
wcl.reverse()
@lazylist
def gen(lst):
for wc in wcl:
try:
yield self.get_weekly_track_chart(wc.start, wc.end)
except LastfmError:
pass
return gen()
def get_monthly_track_chart(self, start = None, end = None):
from lastfm.chart import MonthlyTrackChart
return MonthlyTrackChart.create_from_data(self, start, end)
@cached_property
def recent_monthly_track_chart(self):
return self.get_monthly_track_chart()
@cached_property
def monthly_track_chart_list(self):
mcl = list(self.monthly_chart_list)
mcl.reverse()
@lazylist
def gen(lst):
for mc in mcl:
try:
yield self.get_monthly_track_chart(mc.start, mc.end)
except LastfmError:
pass
return gen()
def get_quaterly_track_chart(self, start = None, end = None):
from lastfm.chart import QuaterlyTrackChart
return QuaterlyTrackChart.create_from_data(self, start, end)
@cached_property
def recent_quaterly_track_chart(self):
return self.get_quaterly_track_chart()
def get_half_yearly_track_chart(self, start = None, end = None):
from lastfm.chart import HalfYearlyTrackChart
return HalfYearlyTrackChart.create_from_data(self, start, end)
@cached_property
def recent_half_yearly_artist_chart(self):
return self.get_half_yearly_track_chart()
def get_yearly_track_chart(self, start = None, end = None):
from lastfm.chart import YearlyTrackChart
return YearlyTrackChart.create_from_data(self, start, end)
@cached_property
def recent_yearly_album_chart(self):
return self.get_yearly_track_chart()
class TagChartable(Chartable):
def get_weekly_tag_chart(self, start = None, end = None):
"""
Get a tag chart for the group, for a given date range.
If no date range is supplied, it will return the most
recent tag chart for the group.
@param start: the date at which the chart should start from (optional)
@type start: C{datetime.datetime}
@param end: the date at which the chart should end on (optional)
@type end: C{datetime.datetime}
@return: a tag chart for the group
@rtype: L{WeeklyTagChart}
@raise InvalidParametersError: Both start and end parameter have to be either
provided or not provided. Providing only one of
them will raise an exception.
@note: This method is a composite method. It is not provided directly by the
last.fm API. It uses other methods to collect the data, analyzes it and
creates a chart. So this method is a little heavy to call, as it does
mulitple calls to the API.
"""
from lastfm.chart import WeeklyChart, WeeklyTagChart
WeeklyChart._check_chart_params({}, self, start, end)
return WeeklyTagChart.create_from_data(self._api, self, start, end)
@cached_property
def recent_weekly_tag_chart(self):
"""
most recent tag chart for the group
@rtype: L{WeeklyTagChart}
"""
return self.get_weekly_tag_chart()
@cached_property
def weekly_tag_chart_list(self):
"""
a list of all tag charts for this group in reverse-chronological
order. (that means 0th chart is the most recent chart)
@rtype: L{lazylist} of L{WeeklyTagChart}
"""
wcl = list(self.weekly_chart_list)
wcl.reverse()
@lazylist
def gen(lst):
for wc in wcl:
try:
yield self.get_weekly_tag_chart(wc.start, wc.end)
except LastfmError:
pass
return gen()
def get_monthly_tag_chart(self, start = None, end = None):
from lastfm.chart import MonthlyTagChart
return MonthlyTagChart.create_from_data(self, start, end)
@cached_property
def recent_monthly_tag_chart(self):
return self.get_monthly_tag_chart()
@cached_property
def monthly_tag_chart_list(self):
mcl = list(self.monthly_chart_list)
mcl.reverse()
@lazylist
def gen(lst):
for mc in mcl:
try:
yield self.get_monthly_tag_chart(mc.start, mc.end)
except LastfmError:
pass
return gen()
def get_quaterly_tag_chart(self, start = None, end = None):
from lastfm.chart import QuaterlyTagChart
return QuaterlyTagChart.create_from_data(self, start, end)
@cached_property
def recent_quaterly_tag_chart(self):
return self.get_quaterly_tag_chart()
def get_half_yearly_tag_chart(self, start = None, end = None):
from lastfm.chart import HalfYearlyTagChart
return HalfYearlyTagChart.create_from_data(self, start, end)
@cached_property
def recent_half_yearly_artist_chart(self):
return self.get_half_yearly_tag_chart()
def get_yearly_tag_chart(self, start = None, end = None):
from lastfm.chart import YearlyTagChart
return YearlyTagChart.create_from_data(self, start, end)
@cached_property
def recent_yearly_album_chart(self):
return self.get_yearly_tag_chart()
from lastfm.error import LastfmError

View File

@ -7,7 +7,7 @@ __package__ = "lastfm"
from lastfm.album import Album
from lastfm.artist import Artist
from lastfm.mixins import Cacheable
from lastfm.mixins import _cacheable
from lastfm.error import InvalidParametersError
from lastfm.event import Event
from lastfm.geo import Location, Country
@ -29,7 +29,7 @@ class ObjectCache(object):
raise InvalidParametersError("Key does not correspond to a valid class")
else:
try:
vals = Cacheable.registry[eval(name)].values()
vals = _cacheable.registry[eval(name)].values()
vals.sort()
return vals
except KeyError:

View File

@ -6,10 +6,11 @@ __license__ = "GNU Lesser General Public License"
__package__ = "lastfm"
from lastfm.base import LastfmBase
from lastfm.mixins import Cacheable
from lastfm.mixins import cacheable
from lastfm.decorators import cached_property
class Playlist(LastfmBase, Cacheable):
@cacheable
class Playlist(LastfmBase):
"""A class representing an XPSF playlist."""
def init(self, api, url, **kwargs):
self._api = api

View File

@ -6,10 +6,11 @@ __license__ = "GNU Lesser General Public License"
__package__ = "lastfm"
from lastfm.base import LastfmBase
from lastfm.mixins import Cacheable
from lastfm.mixins import cacheable
from lastfm.decorators import cached_property
class Shout(LastfmBase, Cacheable):
@cacheable
class Shout(LastfmBase):
"""A class representing a shout."""
def init(self,

View File

@ -6,11 +6,13 @@ __license__ = "GNU Lesser General Public License"
__package__ = "lastfm"
from lastfm.base import LastfmBase
from lastfm.mixins import (
Cacheable, Searchable, ArtistChartable)
from lastfm.mixins import cacheable, searchable, chartable
from lastfm.decorators import cached_property, top_property
class Tag(LastfmBase, Cacheable, Searchable, ArtistChartable):
@chartable(['artist'])
@searchable
@cacheable
class Tag(LastfmBase):
"""A class representing a tag."""
def init(self,
api,
@ -21,7 +23,6 @@ class Tag(LastfmBase, Cacheable, Searchable, ArtistChartable):
**kwargs):
if not isinstance(api, Api):
raise InvalidParametersError("api reference must be supplied as an argument")
ArtistChartable.init(self, api)
self._api = api
self._name = name

View File

@ -6,10 +6,14 @@ __license__ = "GNU Lesser General Public License"
__package__ = "lastfm"
from lastfm.base import LastfmBase
from lastfm.mixins import Cacheable, Searchable, Sharable, Taggable
from lastfm.mixins import cacheable, searchable, sharable, taggable
from lastfm.decorators import cached_property, top_property
class Track(LastfmBase, Cacheable, Sharable, Searchable, Taggable):
@sharable
@taggable
@searchable
@cacheable
class Track(LastfmBase):
"""A class representing a track."""
def init(self,
api,
@ -30,8 +34,6 @@ class Track(LastfmBase, Cacheable, Sharable, Searchable, Taggable):
subject = None):
if not isinstance(api, Api):
raise InvalidParametersError("api reference must be supplied as an argument")
Taggable.init(self, api)
Sharable.init(self, api)
self._api = api
self._id = id
self._name = name

View File

@ -6,16 +6,15 @@ __license__ = "GNU Lesser General Public License"
__package__ = "lastfm"
from lastfm.base import LastfmBase
from lastfm.mixins import (
Cacheable, Shoutable, AlbumChartable,
ArtistChartable, TrackChartable, TagChartable)
from lastfm.mixins import cacheable, shoutable, chartable
import lastfm.playlist
from lastfm.decorators import (
cached_property, top_property, authentication_required, depaginate)
class User(LastfmBase, Cacheable, Shoutable,
AlbumChartable, ArtistChartable,
TrackChartable, TagChartable):
@chartable(['album', 'artist', 'track', 'tag'])
@shoutable
@cacheable
class User(LastfmBase):
"""A class representing an user."""
def init(self,
api,
@ -27,11 +26,6 @@ class User(LastfmBase, Cacheable, Shoutable,
**kwargs):
if not isinstance(api, Api):
raise InvalidParametersError("api reference must be supplied as an argument")
Shoutable.init(self, api)
AlbumChartable.init(self, api)
ArtistChartable.init(self, api)
TrackChartable.init(self, api)
TagChartable.init(self, api)
self._api = api
self._name = name

View File

@ -6,10 +6,12 @@ __license__ = "GNU Lesser General Public License"
__package__ = "lastfm"
from lastfm.base import LastfmBase
from lastfm.mixins import Cacheable, Searchable
from lastfm.mixins import cacheable, searchable
from lastfm.decorators import cached_property, depaginate
class Venue(LastfmBase, Cacheable, Searchable):
@searchable
@cacheable
class Venue(LastfmBase):
"""A class representing a venue of an event"""
def init(self,
api,