* added Rolling Charts: Monthly, Quaterly, Half-yearly and Yearly; Album, Artist, Track and Tag charts

* refactored the chart related code to mixins.chartable module
* made related changes in user, tag and group modules
master
Abhinav Sarkar 2009-03-28 07:24:24 +00:00
parent 42aa35fcbb
commit d709434a7b
6 changed files with 717 additions and 460 deletions

View File

@ -10,7 +10,7 @@ from lastfm.mixins import Cacheable
from operator import xor
class Chart(LastfmBase, Cacheable):
"""A class for representing the weekly charts"""
"""The base class for all the chart classes"""
def init(self, subject, start, end, stats = None):
self._subject = subject
@ -35,26 +35,16 @@ class Chart(LastfmBase, Cacheable):
return self._stats
@staticmethod
def create_from_data(api, subject, data):
return Chart(
subject = subject,
start = datetime.utcfromtimestamp(int(data.attrib['from'])),
end = datetime.utcfromtimestamp(int(data.attrib['to']))
)
@staticmethod
def _check_chart_params(params, start = None, end = None):
def _check_chart_params(params, subject, start = None, end = None):
if xor(start is None, end is None):
raise InvalidParametersError("both start and end have to be provided.")
if start is not None and end is not None:
if isinstance(start, datetime) and isinstance(end, datetime):
params.update({
'from': int(calendar.timegm(start.timetuple())),
'to': int(calendar.timegm(end.timetuple()))
})
else:
if not (isinstance(start, datetime) and isinstance(end, datetime)):
raise InvalidParametersError("start and end must be datetime.datetime instances")
params.update({
'from': int(calendar.timegm(start.timetuple())),
'to': int(calendar.timegm(end.timetuple()))
})
return params
@staticmethod
@ -71,10 +61,10 @@ class Chart(LastfmBase, Cacheable):
def __hash__(self):
return self.__class__._hash_func(
subject = self.subject,
start = self.start,
end = self.end
)
subject = self.subject,
start = self.start,
end = self.end
)
def __eq__(self, other):
return self.subject == other.subject and \
@ -99,21 +89,68 @@ class Chart(LastfmBase, Cacheable):
self.start.strftime("%x"),
self.end.strftime("%x"),
)
class WeeklyChart(Chart):
def init(self, subject, start, end, stats = None):
super(WeeklyChart, self).init(subject, start, end, stats)
class WeeklyAlbumChart(WeeklyChart):
"""A class for representing the weekly album charts"""
class AlbumChart(Chart):
def init(self, subject, start, end, stats, albums):
super(WeeklyAlbumChart, self).init(subject, start, end, stats)
super(AlbumChart, self).init(subject, start, end, stats)
self._albums = albums
@property
def albums(self):
return self._albums
class ArtistChart(Chart):
def init(self, subject, start, end, stats, artists):
super(ArtistChart, self).init(subject, start, end, stats)
self._artists = artists
@property
def artists(self):
return self._artists
class TrackChart(Chart):
def init(self, subject, start, end, tracks, stats):
super(TrackChart, self).init(subject, start, end, stats)
self._tracks = tracks
@property
def tracks(self):
return self._tracks
class TagChart(Chart):
def init(self, subject, start, end, tags, stats):
super(TagChart, self).init(subject, start, end, stats)
self._tags = tags
@property
def tags(self):
return self._tags
class WeeklyChart(Chart):
"""A class for representing the weekly charts"""
@staticmethod
def create_from_data(api, subject, data):
return WeeklyChart(
subject = subject,
start = datetime.utcfromtimestamp(int(data.attrib['from'])),
end = datetime.utcfromtimestamp(int(data.attrib['to']))
)
@staticmethod
def _check_chart_params(params, subject, start = None, end = None):
params = Chart._check_chart_params(params, subject, start, end)
if start is not None and end is not None:
wcl = subject.weekly_chart_list
is_valid = False
for wc in wcl:
if wc.start == start and wc.end == end:
is_valid = True
if not is_valid:
raise InvalidParametersError("%s - %s chart dates are invalid" % (start, end))
return params
class WeeklyAlbumChart(AlbumChart, WeeklyChart):
"""A class for representing the weekly album charts"""
@staticmethod
def create_from_data(api, subject, data):
w = WeeklyChart(
@ -158,16 +195,8 @@ class WeeklyAlbumChart(WeeklyChart):
]
)
class WeeklyArtistChart(WeeklyChart):
class WeeklyArtistChart(ArtistChart, WeeklyChart):
"""A class for representing the weekly artist charts"""
def init(self, subject, start, end, stats, artists):
super(WeeklyArtistChart, self).init(subject, start, end, stats)
self._artists = artists
@property
def artists(self):
return self._artists
@staticmethod
def create_from_data(api, subject, data):
w = WeeklyChart(
@ -208,16 +237,8 @@ class WeeklyArtistChart(WeeklyChart):
]
)
class WeeklyTrackChart(WeeklyChart):
class WeeklyTrackChart(TrackChart, WeeklyChart):
"""A class for representing the weekly track charts"""
def init(self, subject, start, end, tracks, stats):
super(WeeklyTrackChart, self).init(subject, start, end, stats)
self._tracks = tracks
@property
def tracks(self):
return self._tracks
@staticmethod
def create_from_data(api, subject, data):
w = WeeklyChart(
@ -261,16 +282,8 @@ class WeeklyTrackChart(WeeklyChart):
]
)
class WeeklyTagChart(WeeklyChart):
class WeeklyTagChart(TagChart, WeeklyChart):
"""A class for representing the weekly tag charts"""
def init(self, subject, start, end, tags, stats):
super(WeeklyTagChart, self).init(subject, start, end, stats)
self._tags = tags
@property
def tags(self):
return self._tags
@staticmethod
def create_from_data(api, subject, start, end):
w = WeeklyChart(
@ -356,77 +369,216 @@ class WeeklyTagChart(WeeklyChart):
return wtc
class RollingChart(Chart):
pass
"""Base class for the rolling charts classes"""
@classmethod
def _check_chart_params(cls, params, subject, start = None, end = None):
duration = cls._period['duration']
params = Chart._check_chart_params(params, subject, start, end)
if start is not None and end is not None:
mcl = MonthlyChart.get_chart_list(subject)
is_valid = False
for i in xrange(len(mcl)-(duration-1)):
if mcl[i].start == start and mcl[i+(duration-1)].end == end:
is_valid = True
if not is_valid:
raise InvalidParametersError("%s - %s chart dates are invalid" % (start, end))
return params
@classmethod
def create_from_data(cls, subject, key_func,
start = None, end = None):
chart_type = cls.mro()[0]._chart_type
period = cls.mro()[3]._period
globals()["%slyChart" % period['name'].title().replace(' ','')]._check_chart_params({}, subject, start, end)
mcl = MonthlyChart.get_chart_list(subject)
if start is None and end is None:
start = mcl[-period['duration']].start
end = mcl[-1].end
wcl = subject.weekly_chart_list
period_wcl = [wc for wc in wcl
if start < wc.start < end or start < wc.end < end]
period_wacl = []
for wc in period_wcl:
try:
period_wacl.append(
getattr(subject, "get_weekly_%s_chart" % chart_type)(wc.start, wc.end))
except LastfmError:
pass
stats_dict = period_wacl[0].__dict__["_%ss" % chart_type][0].stats.__dict__
count_attribute = [k for k in stats_dict.keys()
if stats_dict[k] is not None and k not in ['_rank', '_subject']][0]
items = {}
for wac in period_wacl:
for item in wac.__dict__["_%ss" % chart_type]:
key = key_func(item)
mw_start = max(wac.start, start)
mw_end = min(wac.end, end)
count = item.stats.__dict__[count_attribute] * (mw_end - mw_start).days / 7.0
if key in items:
items[key].stats.__dict__[count_attribute] += count
else:
items[key] = item
items[key].stats.__dict__[count_attribute] = count
items = items.values()
items = [a for a in items if a.stats.__dict__[count_attribute] >= 1]
items.sort(key = lambda a: a.stats.__dict__[count_attribute], reverse=True)
for i,item in enumerate(items):
item.stats._rank = i + 1
item.stats.__dict__[count_attribute] = int(item.stats.__dict__[count_attribute])
return globals()[
"%sly%sChart" % (
period['name'].title().replace(' ',''),
chart_type.capitalize()
)](
subject = subject,
start = start,
end = end,
stats = Stats(
subject = subject,
**{count_attribute[1:]: sum([a.stats.__dict__[count_attribute] for a in items])}
),
**{"%ss" % chart_type: items}
)
class RollingAlbumChart(AlbumChart):
@classmethod
def create_from_data(cls, subject, start = None, end = None):
key_func = lambda album: "::".join((album.name, album.artist.name))
return super(cls.mro()[3], cls).create_from_data(
subject, key_func, start, end)
class RollingArtistChart(ArtistChart):
@classmethod
def create_from_data(cls, subject, start = None, end = None):
key_func = lambda artist: artist.name
return super(cls.mro()[3], cls).create_from_data(
subject, key_func, start, end)
class RollingTrackChart(TrackChart):
@classmethod
def create_from_data(cls, subject, start = None, end = None):
key_func = lambda track: "::".join((track.name, track.artist.name))
return super(cls.mro()[3], cls).create_from_data(
subject, key_func, start, end)
class RollingTagChart(TagChart):
@classmethod
def create_from_data(cls, subject, start = None, end = None):
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])
for t in chart.tags:
t.stats.__dict__['_count'] /= count_sum
return chart
class MonthlyChart(RollingChart):
pass
"""A class for representing the monthly charts"""
_period = {'name': 'month', 'duration': 1}
@staticmethod
def get_chart_list(subject):
wcl = subject.weekly_chart_list
months = set()
for l in wcl:
months.add(l.start.replace(day=1, hour=12, minute=0, second=0))
months = list(months)
months.sort()
months[0] = wcl[0].start.replace(hour=12, minute=0, second=0)
months.append(wcl[-1].end.replace(hour=12, minute=0, second=0))
class MonthlyAlbumChart(MonthlyChart):
pass
return [MonthlyChart(
subject=subject,
start=months[i],
end=months[i+1]
)
for i in xrange(len(months)-1)]
class MonthlyAlbumChart(RollingAlbumChart, MonthlyChart):
"""A class for representing the monthly album charts"""
_chart_type = "album"
class MonthlyArtistChart(RollingArtistChart, MonthlyChart):
"""A class for representing the monthly artist charts"""
_chart_type = "artist"
class MonthlyArtistChart(MonthlyChart):
pass
class MonthlyTrackChart(RollingTrackChart, MonthlyChart):
"""A class for representing the monthly track charts"""
_chart_type = "track"
class MonthlyTrackChart(MonthlyChart):
pass
class MonthlyTagChart(RollingTagChart, MonthlyChart):
"""A class for representing the monthly tag charts"""
_chart_type = "tag"
class MonthlyTagChart(MonthlyChart):
pass
class QuaterlyChart(RollingChart):
"""A class for representing the three monthly charts"""
_period = {'name': 'quater', 'duration': 3}
class ThreeMonthlyChart(RollingChart):
pass
class QuaterlyAlbumChart(RollingAlbumChart, QuaterlyChart):
"""A class for representing the three monthly album charts"""
_chart_type = "album"
class ThreeMonthlyAlbumChart(ThreeMonthlyChart):
pass
class QuaterlyArtistChart(RollingArtistChart, QuaterlyChart):
"""A class for representing the three monthly artist charts"""
_chart_type = "artist"
class ThreeMonthlyArtistChart(ThreeMonthlyChart):
pass
class QuaterlyTrackChart(RollingTrackChart, QuaterlyChart):
"""A class for representing the three monthly track charts"""
_chart_type = "track"
class ThreeMonthlyTrackChart(ThreeMonthlyChart):
pass
class QuaterlyTagChart(RollingTagChart, QuaterlyChart):
"""A class for representing the three monthly tag charts"""
_chart_type = "tag"
class ThreeMonthlyTagChart(ThreeMonthlyChart):
pass
class HalfYearlyChart(RollingChart):
"""A class for representing the six monthly charts"""
_period = {'name': 'half year', 'duration': 6}
class SixMonthlyChart(RollingChart):
pass
class HalfYearlyAlbumChart(RollingAlbumChart, HalfYearlyChart):
"""A class for representing the six monthly album charts"""
_chart_type = "album"
class SixMonthlyAlbumChart(SixMonthlyChart):
pass
class HalfYearlyArtistChart(RollingArtistChart, HalfYearlyChart):
"""A class for representing the six monthly artist charts"""
_chart_type = "artist"
class SixMonthlyArtistChart(SixMonthlyChart):
pass
class HalfYearlyTrackChart(RollingTrackChart, HalfYearlyChart):
"""A class for representing the six monthly track charts"""
_chart_type = "track"
class SixMonthlyTrackChart(SixMonthlyChart):
pass
class SixMonthlyTagChart(SixMonthlyChart):
pass
class HalfYearlyTagChart(RollingTagChart, HalfYearlyChart):
"""A class for representing the six monthly tag charts"""
_chart_type = "tag"
class YearlyChart(RollingChart):
pass
"""A class for representing the yearly charts"""
_period = {'name': 'year', 'duration': 12}
class YearlyAlbumChart(YearlyChart):
pass
class YearlyAlbumChart(RollingAlbumChart, YearlyChart):
"""A class for representing the yearly album charts"""
_chart_type = "album"
class YearlyArtistChart(YearlyChart):
pass
class YearlyArtistChart(RollingArtistChart, YearlyChart):
"""A class for representing the yearly artist charts"""
_chart_type = "artist"
class YearlyTrackChart(YearlyChart):
pass
class YearlyTrackChart(RollingTrackChart, YearlyChart):
"""A class for representing the yearly track charts"""
_chart_type = "track"
class YearlyTagChart(YearlyChart):
pass
class YearlyTagChart(RollingTagChart, YearlyChart):
"""A class for representing the yearly tag charts"""
_chart_type = "tag"
__all__ = [
'WeeklyChart',
'WeeklyAlbumChart', 'WeeklyArtistChart', 'WeeklyTrackChart', 'WeeklyTagChart',
'MonthlyChart',
'MonthlyAlbumChart', 'MonthlyArtistChart', 'MonthlyTrackChart', 'MonthlyTagChart',
'ThreeMonthlyChart',
'ThreeMonthlyAlbumChart', 'ThreeMonthlyArtistChart', 'ThreeMonthlyTrackChart', 'ThreeMonthlyTagChart',
'SixMonthlyChart',
'SixMonthlyAlbumChart', 'SixMonthlyArtistChart', 'SixMonthlyTrackChart', 'SixMonthlyTagChart',
'QuaterlyChart',
'QuaterlyAlbumChart', 'QuaterlyArtistChart', 'QuaterlyTrackChart', 'QuaterlyTagChart',
'HalfYearlyChart',
'HalfYearlyAlbumChart', 'HalfYearlyArtistChart', 'HalfYearlyTrackChart', 'HalfYearlyTagChart',
'YearlyChart',
'YearlyAlbumChart', 'YearlyArtistChart', 'YearlyTrackChart', 'YearlyTagChart'
]
@ -435,7 +587,7 @@ import calendar
from lastfm.album import Album
from lastfm.artist import Artist
from lastfm.error import InvalidParametersError
from lastfm.error import InvalidParametersError, LastfmError
from lastfm.stats import Stats
from lastfm.track import Track
from lastfm.tag import Tag

View File

@ -7,11 +7,13 @@ __license__ = "GNU Lesser General Public License"
__package__ = "lastfm"
from lastfm.base import LastfmBase
from lastfm.mixins import Cacheable
from lastfm.lazylist import lazylist
from lastfm.mixins import (
Cacheable, AlbumChartable, ArtistChartable,
TrackChartable, TagChartable)
from lastfm.decorators import cached_property, depaginate
class Group(LastfmBase, Cacheable):
class Group(LastfmBase, Cacheable, AlbumChartable,
ArtistChartable, TrackChartable, TagChartable):
"""A class representing a group on last.fm."""
def init(self, api, name = None, **kwargs):
"""
@ -27,6 +29,11 @@ class Group(LastfmBase, Cacheable):
"""
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
@ -37,209 +44,6 @@ class Group(LastfmBase, Cacheable):
@rtype: L{str}
"""
return self._name
@cached_property
def weekly_chart_list(self):
"""
a list of available weekly charts for this group
@rtype: L{list} of L{WeeklyChart}
"""
params = self._default_params({'method': 'group.getWeeklyChartList'})
data = self._api._fetch_data(params).find('weeklychartlist')
return [
WeeklyChart.create_from_data(self._api, self, c)
for c in data.findall('chart')
]
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.
"""
params = self._default_params({'method': 'group.getWeeklyAlbumChart'})
params = WeeklyChart._check_chart_params(params, 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:
yield self.get_weekly_album_chart(wc.start, wc.end)
return gen()
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.
"""
params = self._default_params({'method': 'group.getWeeklyArtistChart'})
params = WeeklyChart._check_chart_params(params, 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:
yield self.get_weekly_artist_chart(wc.start, wc.end)
return gen()
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.
"""
params = self._default_params({'method': 'group.getWeeklyTrackChart'})
params = WeeklyChart._check_chart_params(params, 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:
yield self.get_weekly_track_chart(wc.start, wc.end)
return gen()
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.
"""
WeeklyChart._check_chart_params({}, 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()
@cached_property
@depaginate

View File

@ -10,5 +10,8 @@ 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)
__all__ = ['Cacheable', 'Searchable', 'Sharable', 'Shoutable', 'Taggable']
__all__ = ['Cacheable', 'Searchable', 'Sharable', 'Shoutable', 'Taggable'
'AlbumChartable', 'ArtistChartable', 'TrackChartable', 'TagChartable']

432
lastfm/mixins/chartable.py Normal file
View File

@ -0,0 +1,432 @@
#!/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

@ -6,11 +6,11 @@ __license__ = "GNU Lesser General Public License"
__package__ = "lastfm"
from lastfm.base import LastfmBase
from lastfm.mixins import Cacheable, Searchable
from lastfm.lazylist import lazylist
from lastfm.mixins import (
Cacheable, Searchable, ArtistChartable)
from lastfm.decorators import cached_property, top_property
class Tag(LastfmBase, Cacheable, Searchable):
class Tag(LastfmBase, Cacheable, Searchable, ArtistChartable):
"""A class representing a tag."""
def init(self,
api,
@ -21,6 +21,8 @@ class Tag(LastfmBase, Cacheable, Searchable):
**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
self._url = url
@ -172,44 +174,7 @@ class Tag(LastfmBase, Cacheable, Searchable):
def playlist(self):
return Playlist.fetch(self._api,
"lastfm://playlist/tag/%s/freetracks" % self.name)
@cached_property
def weekly_chart_list(self):
params = self._default_params({'method': 'tag.getWeeklyChartList'})
data = self._api._fetch_data(params).find('weeklychartlist')
return [
WeeklyChart.create_from_data(self._api, self, c)
for c in data.findall('chart')
]
def get_weekly_artist_chart(self,
start = None,
end = None,
limit = None):
params = self._default_params({'method': 'tag.getWeeklyArtistChart'})
if limit is not None:
params['limit'] = limit
params = WeeklyArtistChart._check_chart_params(params, 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):
return self.get_weekly_artist_chart()
@cached_property
def weekly_artist_chart_list(self):
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()
@staticmethod
def get_top_tags(api):
params = {'method': 'tag.getTopTags'}

View File

@ -6,12 +6,16 @@ __license__ = "GNU Lesser General Public License"
__package__ = "lastfm"
from lastfm.base import LastfmBase
from lastfm.mixins import Cacheable, Shoutable
from lastfm.lazylist import lazylist
from lastfm.mixins import (
Cacheable, Shoutable, AlbumChartable,
ArtistChartable, TrackChartable, TagChartable)
import lastfm.playlist
from lastfm.decorators import cached_property, top_property, authentication_required, depaginate
from lastfm.decorators import (
cached_property, top_property, authentication_required, depaginate)
class User(LastfmBase, Cacheable, Shoutable):
class User(LastfmBase, Cacheable, Shoutable,
AlbumChartable, ArtistChartable,
TrackChartable, TagChartable):
"""A class representing an user."""
def init(self,
api,
@ -24,6 +28,11 @@ class User(LastfmBase, Cacheable, Shoutable):
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
self._real_name = real_name
@ -478,113 +487,6 @@ class User(LastfmBase, Cacheable, Shoutable):
"""top tag of the user"""
pass
@cached_property
def weekly_chart_list(self):
params = self._default_params({'method': 'user.getWeeklyChartList'})
data = self._api._fetch_data(params).find('weeklychartlist')
return [
WeeklyChart.create_from_data(self._api, self, c)
for c in data.findall('chart')
]
def get_weekly_album_chart(self,
start = None,
end = None):
params = self._default_params({'method': 'user.getWeeklyAlbumChart'})
params = WeeklyChart._check_chart_params(params, 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):
return self.get_weekly_album_chart()
@cached_property
def weekly_album_chart_list(self):
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_weekly_artist_chart(self,
start = None,
end = None):
params = self._default_params({'method': 'user.getWeeklyArtistChart'})
params = WeeklyChart._check_chart_params(params, 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):
return self.get_weekly_artist_chart()
@cached_property
def weekly_artist_chart_list(self):
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_weekly_track_chart(self,
start = None,
end = None):
params = self._default_params({'method': 'user.getWeeklyTrackChart'})
params = WeeklyChart._check_chart_params(params, 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):
return self.get_weekly_track_chart()
@cached_property
def weekly_track_chart_list(self):
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_weekly_tag_chart(self,
start = None,
end = None):
WeeklyChart._check_chart_params({}, start, end)
return WeeklyTagChart.create_from_data(self._api, self, start, end)
@cached_property
def recent_weekly_tag_chart(self):
return self.get_weekly_tag_chart()
@cached_property
def weekly_tag_chart_list(self):
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 compare(self, other, limit = None):
if isinstance(other, User):
other = other.name
@ -920,4 +822,3 @@ from lastfm.stats import Stats
from lastfm.tag import Tag
from lastfm.tasteometer import Tasteometer
from lastfm.track import Track
from lastfm.chart import WeeklyChart, WeeklyAlbumChart, WeeklyArtistChart, WeeklyTrackChart, WeeklyTagChart