From 21f591a45092f153d9a20869f9d6820c585090a3 Mon Sep 17 00:00:00 2001 From: Abhinav Sarkar Date: Tue, 30 Dec 2008 13:51:04 +0000 Subject: [PATCH] more changes for PEP8 compliance --- src/album.py | 153 ++++++++-------- src/api.py | 85 +++++---- src/artist.py | 257 +++++++++++++------------- src/base.py | 53 +++--- src/error.py | 10 +- src/event.py | 73 ++++---- src/geo.py | 126 ++++++------- src/group.py | 55 +++--- src/playlist.py | 23 ++- src/safelist.py | 32 ++-- src/searchable.py | 16 +- src/sharable.py | 7 +- src/stats.py | 42 ++--- src/tag.py | 113 ++++++------ src/taggable.py | 20 +-- src/tasteometer.py | 12 +- src/track.py | 287 +++++++++++++++-------------- src/user.py | 440 +++++++++++++++++++++++---------------------- src/weeklychart.py | 32 ++-- src/wiki.py | 16 +- 20 files changed, 937 insertions(+), 915 deletions(-) diff --git a/src/album.py b/src/album.py index 74e23ce..42ba6b1 100644 --- a/src/album.py +++ b/src/album.py @@ -23,76 +23,76 @@ class Album(Taggable, LastfmBase): 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 - self.__id = id - self.__mbid = mbid - self.__url = url - self.__release_date = release_date - self.__image = image - self.__stats = stats and Stats( + self._api = api + self._name = name + self._artist = artist + self._id = id + self._mbid = mbid + self._url = url + self._release_date = release_date + self._image = image + self._stats = stats and Stats( subject = self, listeners = stats.listeners, playcount = stats.playcount, match = stats.match, rank = stats.rank ) - self.__top_tags = top_tags + self._top_tags = top_tags @property def name(self): """name of the album""" - return self.__name + return self._name @property def artist(self): """artist of the album""" - return self.__artist + return self._artist @property def id(self): """id of the album""" - if self.__id is None: + if self._id is None: self._fill_info() - return self.__id + return self._id @property def mbid(self): """mbid of the album""" - if self.__mbid is None: + if self._mbid is None: self._fill_info() - return self.__mbid + return self._mbid @property def url(self): """url of the album's page""" - if self.__url is None: + if self._url is None: self._fill_info() - return self.__url + return self._url @property def release_date(self): """release date of the album""" - if self.__release_date is None: + if self._release_date is None: self._fill_info() - return self.__release_date + return self._release_date @property def image(self): """cover images of the album""" - if self.__image is None: + if self._image is None: self._fill_info() - return self.__image + return self._image @property def stats(self): """stats related to the album""" - if self.__stats is None: + if self._stats is None: self._fill_info() - return self.__stats + return self._stats - @LastfmBase.cachedProperty + @LastfmBase.cached_property def top_tags(self): """top tags for the album""" params = {'method': 'album.getInfo'} @@ -100,10 +100,10 @@ class Album(Taggable, LastfmBase): params.update({'artist': self.artist.name, 'album': self.name}) elif self.mbid: params.update({'mbid': self.mbid}) - data = self.__api._fetch_data(params).find('album') + data = self._api._fetch_data(params).find('album') return [ Tag( - self.__api, + self._api, subject = self, name = t.findtext('name'), url = t.findtext('url') @@ -111,60 +111,15 @@ class Album(Taggable, LastfmBase): for t in data.findall('toptags/tag') ] - @LastfmBase.topProperty("top_tags") + @LastfmBase.top_property("top_tags") def top_tag(self): """top tag for the album""" pass - @LastfmBase.cachedProperty + @LastfmBase.cached_property def playlist(self): - return Playlist.fetch(self.__api, "lastfm://playlist/album/%s" % self.id) + return Playlist.fetch(self._api, "lastfm://playlist/album/%s" % self.id) - def _default_params(self, extra_params = None): - if not (self.artist and self.name): - raise InvalidParametersError("artist and album have to be provided.") - params = {'artist': self.artist.name, 'album': self.name} - if extra_params is not None: - params.update(extra_params) - return params - - @staticmethod - def _fetch_data(api, - artist = None, - album = None, - mbid = None): - params = {'method': 'album.getInfo'} - if not ((artist and album) or mbid): - raise InvalidParametersError("either (artist and album) or mbid has to be given as argument.") - if artist and album: - params.update({'artist': artist, 'album': album}) - elif mbid: - params.update({'mbid': mbid}) - return api._fetch_data(params).find('album') - - def _fill_info(self): - data = Album._fetch_data(self.__api, self.artist.name, self.name) - self.__id = int(data.findtext('id')) - self.__mbid = data.findtext('mbid') - self.__url = data.findtext('url') - self.__release_date = data.findtext('releasedate') and data.findtext('releasedate').strip() and \ - datetime(*(time.strptime(data.findtext('releasedate').strip(), '%d %b %Y, 00:00')[0:6])) - self.__image = dict([(i.get('size'), i.text) for i in data.findall('image')]) - self.__stats = Stats( - subject = self, - listeners = int(data.findtext('listeners')), - playcount = int(data.findtext('playcount')), - ) - self.__top_tags = [ - Tag( - self.__api, - subject = self, - name = t.findtext('name'), - url = t.findtext('url') - ) - for t in data.findall('toptags/tag') - ] - @staticmethod def get_info(api, artist = None, @@ -182,15 +137,59 @@ class Album(Taggable, LastfmBase): a._fill_info() return a + def _default_params(self, extra_params = {}): + if not (self.artist and self.name): + raise InvalidParametersError("artist and album have to be provided.") + params = {'artist': self.artist.name, 'album': self.name} + params.update(extra_params) + return params + @staticmethod - def hash_func(*args, **kwds): + def _fetch_data(api, + artist = None, + album = None, + mbid = None): + params = {'method': 'album.getInfo'} + if not ((artist and album) or mbid): + raise InvalidParametersError("either (artist and album) or mbid has to be given as argument.") + if artist and album: + params.update({'artist': artist, 'album': album}) + elif mbid: + params.update({'mbid': mbid}) + return api._fetch_data(params).find('album') + + def _fill_info(self): + data = Album._fetch_data(self._api, self.artist.name, self.name) + self._id = int(data.findtext('id')) + self._mbid = data.findtext('mbid') + self._url = data.findtext('url') + self._release_date = data.findtext('releasedate') and data.findtext('releasedate').strip() and \ + datetime(*(time.strptime(data.findtext('releasedate').strip(), '%d %b %Y, 00:00')[0:6])) + self._image = dict([(i.get('size'), i.text) for i in data.findall('image')]) + self._stats = Stats( + subject = self, + listeners = int(data.findtext('listeners')), + playcount = int(data.findtext('playcount')), + ) + self._top_tags = [ + Tag( + self._api, + subject = self, + name = t.findtext('name'), + url = t.findtext('url') + ) + for t in data.findall('toptags/tag') + ] + + @staticmethod + def _hash_func(*args, **kwds): try: return hash("%s%s" % (kwds['name'], hash(kwds['artist']))) except KeyError: raise InvalidParametersError("name and artist have to be provided for hashing") def __hash__(self): - return self.__class__.hash_func(name = self.name, artist = self.artist) + return self.__class__._hash_func(name = self.name, artist = self.artist) def __eq__(self, other): if self.id and other.id: diff --git a/src/api.py b/src/api.py index f8ac37c..068bf43 100644 --- a/src/api.py +++ b/src/api.py @@ -22,9 +22,9 @@ class Api(object): request_headers=None, no_cache = False, debug = False): - self.__api_key = api_key - self.__secret = secret - self.__session_key = session_key + self._api_key = api_key + self._secret = secret + self._session_key = session_key self._cache = FileCache() self._urllib = urllib2 self._cache_timeout = Api.DEFAULT_CACHE_TIMEOUT @@ -37,36 +37,36 @@ class Api(object): @property def api_key(self): - return self.__api_key - + return self._api_key + @property def secret(self): - return self.__secret - + return self._secret + @property def session_key(self): - return self.__session_key - + return self._session_key + def set_session_key(self): params = {'method': 'auth.getSession', 'token': self.auth_token} - self.__session_key = self._fetch_data(params, sign = True).findtext('session/key') - self.__auth_token = None - - @LastfmBase.cachedProperty + self._session_key = self._fetch_data(params, sign = True).findtext('session/key') + self._auth_token = None + + @LastfmBase.cached_property def auth_token(self): params = {'method': 'auth.getToken'} return self._fetch_data(params, sign = True).findtext('token') - - @LastfmBase.cachedProperty + + @LastfmBase.cached_property def auth_url(self): return "http://www.last.fm/api/auth/?api_key=%s&token=%s" % (self.api_key, self.auth_token) - - + + def set_cache(self, cache): '''Override the default cache. Set to None to prevent caching. Args: - cache: an instance that supports the same API as the audioscrobblerws.FileCache + cache: an instance that supports the same API as the lastfm.FileCache ''' self._cache = cache @@ -124,7 +124,7 @@ class Api(object): def get_group(self, name): return Group(self, name = name) - def fetch_playlist(self, url): + def get_playlist(self, url): return Playlist.fetch(self, url) def get_tag(self, name): @@ -165,7 +165,7 @@ class Api(object): except Error, e: raise e return user - + def get_authenticated_user(self): if self.session_key is not None: return User.get_authenticated_user(self) @@ -238,7 +238,7 @@ class Api(object): keys = parameters.keys() keys.sort() return urllib.urlencode([(k, self._encode(parameters[k])) for k in keys if parameters[k] is not None]) - + def _read_url_data(self, opener, url, data = None): now = datetime.now() delta = now - self._last_fetch_time @@ -247,8 +247,8 @@ class Api(object): time.sleep(Api.FETCH_INTERVAL - delta) url_data = opener.open(url, data).read() self._last_fetch_time = datetime.now() - return url_data - + return url_data + def _fetch_url(self, url, parameters = None, @@ -303,19 +303,19 @@ class Api(object): session = False, no_cache = False): params['api_key'] = self.api_key - + if session: if self.session_key is not None: params['sk'] = self.session_key else: raise AuthenticationFailedError("session key must be present to call this method") - + if sign: params['api_sig'] = self._get_api_sig(params) - + xml = self._fetch_url(Api.API_ROOT_URL, params, no_cache = self._no_cache or no_cache) - return self._check_XML(xml) - + return self._check_xml(xml) + def _post_url(self, url, parameters): @@ -326,24 +326,24 @@ class Api(object): opener = self._get_opener(url) url_data = self._read_url_data(opener, url, data) return url_data - + def _post_data(self, params): params['api_key'] = self.api_key - + if self.session_key is not None: params['sk'] = self.session_key else: raise AuthenticationFailedError("session key must be present to call this method") - - params['api_sig'] = self._get_api_sig(params) + + params['api_sig'] = self._get_api_sig(params) xml = self._post_url(Api.API_ROOT_URL, params) - return self._check_XML(xml) - + return self._check_xml(xml) + def _get_api_sig(self, params): if self.secret is not None: keys = params.keys()[:] keys.sort() - sig = unicode() + sig = unicode() for name in keys: sig += ("%s%s" % (name, params[name])) sig += self.secret @@ -352,7 +352,7 @@ class Api(object): else: raise AuthenticationFailedError("api secret must be present to call this method") - def _check_XML(self, xml): + def _check_xml(self, xml): data = None try: data = ElementTree.XML(xml) @@ -361,18 +361,18 @@ class Api(object): if data.get('status') != "ok": code = int(data.find("error").get('code')) message = data.findtext('error') - if code in errorMap.keys(): - raise errorMap[code](message, code) + if code in error_map.keys(): + raise error_map[code](message, code) else: raise Error(message, code) return data def __repr__(self): - return "" % self.__api_key + return "" % self._api_key from datetime import datetime import md5 -import platform +import sys import time import urllib import urllib2 @@ -380,7 +380,7 @@ import urlparse from album import Album from artist import Artist -from error import errorMap, Error, OperationFailedError, AuthenticationFailedError +from error import error_map, Error, OperationFailedError, AuthenticationFailedError from event import Event from filecache import FileCache from geo import Location, Country @@ -391,8 +391,7 @@ from tasteometer import Tasteometer from track import Track from user import User -python_version = platform.python_version_tuple() -if python_version[0] == 2 and python_version[1] >= 5: +if sys.version_info >= (2, 5): import xml.etree.cElementTree as ElementTree else: try: diff --git a/src/artist.py b/src/artist.py index b53e9f5..87b31c8 100644 --- a/src/artist.py +++ b/src/artist.py @@ -27,22 +27,22 @@ class Artist(LastfmBase, Taggable, Sharable, Searchable): raise InvalidParametersError("api reference must be supplied as an argument") Taggable.init(self, api) Sharable.init(self, api) - self.__api = api - self.__name = name - self.__mbid = mbid - self.__url = url - self.__image = image - self.__streamable = streamable - self.__stats = stats and Stats( + self._api = api + self._name = name + self._mbid = mbid + self._url = url + self._image = image + self._streamable = streamable + self._stats = stats and Stats( subject = self, listeners = stats.listeners, playcount = stats.playcount, match = stats.match, rank = stats.rank ) - self.__similar = similar - self.__top_tags = top_tags - self.__bio = bio and Wiki( + self._similar = similar + self._top_tags = top_tags + self._bio = bio and Wiki( subject = self, published = bio.published, summary = bio.summary, @@ -52,59 +52,51 @@ class Artist(LastfmBase, Taggable, Sharable, Searchable): @property def name(self): """name of the artist""" - return self.__name + return self._name @property def mbid(self): """mbid of the artist""" - if self.__mbid is None: + if self._mbid is None: self._fill_info() - return self.__mbid + return self._mbid @property def url(self): """url of the artist's page""" - if self.__url is None: + if self._url is None: self._fill_info() - return self.__url + return self._url @property def image(self): """images of the artist""" - if self.__image is None: + if self._image is None: self._fill_info() - return self.__image + return self._image @property def streamable(self): """is the artist streamable""" - if self.__streamable is None: + if self._streamable is None: self._fill_info() - return self.__streamable + return self._streamable @property def stats(self): """stats for the artist""" - if self.__stats is None: + if self._stats is None: self._fill_info() - return self.__stats + return self._stats - def _default_params(self, extraParams = None): - if not self.name: - raise InvalidParametersError("artist has to be provided.") - params = {'artist': self.name} - if extraParams is not None: - params.update(extraParams) - return params - def get_similar(self, limit = None): params = self._default_params({'method': 'artist.getSimilar'}) if limit is not None: params.update({'limit': limit}) - data = self.__api._fetch_data(params).find('similarartists') - self.__similar = [ + data = self._api._fetch_data(params).find('similarartists') + self._similar = [ Artist( - self.__api, + self._api, subject = self, name = a.findtext('name'), mbid = a.findtext('mbid'), @@ -117,16 +109,16 @@ class Artist(LastfmBase, Taggable, Sharable, Searchable): ) for a in data.findall('artist') ] - return self.__similar[:] + return self._similar[:] @property def similar(self): """artists similar to this artist""" - if self.__similar is None or len(self.__similar) < 6: + if self._similar is None or len(self._similar) < 6: return self.get_similar() - return self.__similar[:] + return self._similar[:] - @LastfmBase.topProperty("similar") + @LastfmBase.top_property("similar") def most_similar(self): """artist most similar to this artist""" pass @@ -134,21 +126,21 @@ class Artist(LastfmBase, Taggable, Sharable, Searchable): @property def top_tags(self): """top tags for the artist""" - if self.__top_tags is None or len(self.__top_tags) < 6: + if self._top_tags is None or len(self._top_tags) < 6: params = self._default_params({'method': 'artist.getTopTags'}) - data = self.__api._fetch_data(params).find('toptags') - self.__top_tags = [ + data = self._api._fetch_data(params).find('toptags') + self._top_tags = [ Tag( - self.__api, + self._api, subject = self, name = t.findtext('name'), url = t.findtext('url') ) for t in data.findall('tag') ] - return self.__top_tags[:] + return self._top_tags[:] - @LastfmBase.topProperty("top_tags") + @LastfmBase.top_property("top_tags") def top_tag(self): """top tag for the artist""" pass @@ -156,30 +148,30 @@ class Artist(LastfmBase, Taggable, Sharable, Searchable): @property def bio(self): """biography of the artist""" - if self.__bio is None: + if self._bio is None: self._fill_info() - return self.__bio + return self._bio - @LastfmBase.cachedProperty + @LastfmBase.cached_property def events(self): """events for the artist""" params = self._default_params({'method': 'artist.getEvents'}) - data = self.__api._fetch_data(params).find('events') + data = self._api._fetch_data(params).find('events') return [ - Event.create_from_data(self.__api, e) + Event.create_from_data(self._api, e) for e in data.findall('event') ] - @LastfmBase.cachedProperty + @LastfmBase.cached_property def top_albums(self): """top albums of the artist""" params = self._default_params({'method': 'artist.getTopAlbums'}) - data = self.__api._fetch_data(params).find('topalbums') + data = self._api._fetch_data(params).find('topalbums') return [ Album( - self.__api, + self._api, subject = self, name = a.findtext('name'), artist = self, @@ -195,19 +187,19 @@ class Artist(LastfmBase, Taggable, Sharable, Searchable): for a in data.findall('album') ] - @LastfmBase.topProperty("top_albums") + @LastfmBase.top_property("top_albums") def top_album(self): """top album of the artist""" pass - @LastfmBase.cachedProperty + @LastfmBase.cached_property def top_fans(self): """top fans of the artist""" params = self._default_params({'method': 'artist.getTopFans'}) - data = self.__api._fetch_data(params).find('topfans') + data = self._api._fetch_data(params).find('topfans') return [ User( - self.__api, + self._api, subject = self, name = u.findtext('name'), url = u.findtext('url'), @@ -219,20 +211,20 @@ class Artist(LastfmBase, Taggable, Sharable, Searchable): ) for u in data.findall('user') ] - - @LastfmBase.topProperty("top_fans") + + @LastfmBase.top_property("top_fans") def top_fan(self): """top fan of the artist""" pass - @LastfmBase.cachedProperty + @LastfmBase.cached_property def top_tracks(self): """top tracks of the artist""" params = self._default_params({'method': 'artist.getTopTracks'}) - data = self.__api._fetch_data(params).find('toptracks') + data = self._api._fetch_data(params).find('toptracks') return [ Track( - self.__api, + self._api, subject = self, name = t.findtext('name'), artist = self, @@ -243,17 +235,88 @@ class Artist(LastfmBase, Taggable, Sharable, Searchable): rank = int(t.attrib['rank']) ), streamable = (t.findtext('streamable') == '1'), - fullTrack = (t.find('streamable').attrib['fulltrack'] == '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 data.findall('track') ] - - @LastfmBase.topProperty("top_tracks") + + @LastfmBase.top_property("top_tracks") def top_track(self): """topmost fan of the artist""" pass + @staticmethod + def get_info(api, + artist = None, + mbid = None): + data = Artist._fetch_data(api, artist, mbid) + + a = Artist(api, name = data.findtext('name')) + a._fill_info() + return a + + def _default_params(self, extra_params = {}): + if not self.name: + raise InvalidParametersError("artist has to be provided.") + params = {'artist': self.name} + params.update(extra_params) + return params + + @staticmethod + def _fetch_data(api, + artist = None, + mbid = None): + params = {'method': 'artist.getInfo'} + if not (artist or mbid): + raise InvalidParametersError("either artist or mbid has to be given as argument.") + if artist: + params.update({'artist': artist}) + elif mbid: + params.update({'mbid': mbid}) + return api._fetch_data(params).find('artist') + + def _fill_info(self): + data = Artist._fetch_data(self._api, self.name) + self._name = data.findtext('name') + self._mbid = data.findtext('mbid') + self._url = data.findtext('url') + self._image = dict([(i.get('size'), i.text) for i in data.findall('image')]) + self._streamable = (data.findtext('streamable') == 1) + self._stats = Stats( + subject = self, + 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._top_tags = [ + Tag( + self._api, + subject = self, + name = t.findtext('name'), + url = t.findtext('url') + ) + for t in data.findall('tags/tag') + ] + self._bio = Wiki( + self, + published = datetime(*(time.strptime( + data.findtext('bio/published').strip(), + '%a, %d %b %Y %H:%M:%S +0000' + )[0:6])), + summary = data.findtext('bio/summary'), + content = data.findtext('bio/content') + ) + @staticmethod def _search_yield_func(api, artist): return Artist( @@ -265,71 +328,7 @@ class Artist(LastfmBase, Taggable, Sharable, Searchable): streamable = (artist.findtext('streamable') == '1'), ) @staticmethod - def _fetch_data(api, - artist = None, - mbid = None): - params = {'method': 'artist.get_info'} - if not (artist or mbid): - raise InvalidParametersError("either artist or mbid has to be given as argument.") - if artist: - params.update({'artist': artist}) - elif mbid: - params.update({'mbid': mbid}) - return api._fetch_data(params).find('artist') - - def _fill_info(self): - data = Artist._fetch_data(self.__api, self.name) - self.__name = data.findtext('name') - self.__mbid = data.findtext('mbid') - self.__url = data.findtext('url') - self.__image = dict([(i.get('size'), i.text) for i in data.findall('image')]) - self.__streamable = (data.findtext('streamable') == 1) - self.__stats = Stats( - subject = self, - 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.__top_tags = [ - Tag( - self.__api, - subject = self, - name = t.findtext('name'), - url = t.findtext('url') - ) - for t in data.findall('tags/tag') - ] - self.__bio = Wiki( - self, - published = datetime(*(time.strptime( - data.findtext('bio/published').strip(), - '%a, %d %b %Y %H:%M:%S +0000' - )[0:6])), - summary = data.findtext('bio/summary'), - content = data.findtext('bio/content') - ) - - @staticmethod - def get_info(api, - artist = None, - mbid = None): - data = Artist._fetch_data(api, artist, mbid) - - a = Artist(api, name = data.findtext('name')) - a._fill_info() - return a - - @staticmethod - def hash_func(*args, **kwds): + def _hash_func(*args, **kwds): try: return hash(kwds['name'].lower()) except KeyError: @@ -339,7 +338,7 @@ class Artist(LastfmBase, Taggable, Sharable, Searchable): raise InvalidParametersError("name has to be provided for hashing") def __hash__(self): - return self.__class__.hash_func(name = self.name) + return self.__class__._hash_func(name = self.name) def __eq__(self, other): if self.mbid and other.mbid: @@ -352,7 +351,7 @@ class Artist(LastfmBase, Taggable, Sharable, Searchable): return self.name < other.name def __repr__(self): - return "" % self.__name + return "" % self._name from datetime import datetime import time diff --git a/src/base.py b/src/base.py index 977819d..169a25c 100644 --- a/src/base.py +++ b/src/base.py @@ -20,21 +20,21 @@ class LastfmBase(object): if 'subject' in kwds and not cls.__name__.startswith('Weekly'): subject = kwds['subject'] del kwds['subject'] - - if 'bypassRegistry' in kwds: - del kwds['bypassRegistry'] + + if 'bypass_registry' in kwds: + del kwds['bypass_registry'] inst = object.__new__(cls) inst.init(*args, **kwds) return inst - key = cls.hash_func(*args, **kwds) + key = cls._hash_func(*args, **kwds) if subject is not None: key = (hash(subject), key) - + LastfmBase._lock.acquire() try: - inst, alreadyRegistered = LastfmBase.register(object.__new__(cls), key) - if not alreadyRegistered: + inst, already_registered = LastfmBase.register(object.__new__(cls), key) + if not already_registered: inst.init(*args, **kwds) finally: LastfmBase._lock.release() @@ -52,34 +52,32 @@ class LastfmBase(object): #print "not already registered: %s" % ob.__class__ LastfmBase.registry[ob.__class__][key] = ob return (ob, False) - - @staticmethod - def topProperty(listPropertyName): + + @staticmethod + def top_property(list_property_name): def decorator(func): def wrapper(ob): - topList = getattr(ob, listPropertyName) - return (len(topList) and topList[0] or None) + top_list = getattr(ob, list_property_name) + return (len(top_list) and top_list[0] or None) return property(fget = wrapper, doc = func.__doc__) return decorator - + @staticmethod - def cachedProperty(func): - frame = sys._getframe(1) - classname = frame.f_code.co_name - funcName = func.func_code.co_name - attributeName = "_%s__%s" % (classname, funcName) - + def cached_property(func): + func_name = func.func_code.co_name + attribute_name = "_%s" % func_name + def wrapper(ob): - cacheAttribute = getattr(ob, attributeName, None) - if cacheAttribute is None: - cacheAttribute = func(ob) - setattr(ob, attributeName, cacheAttribute) + cache_attribute = getattr(ob, attribute_name, None) + if cache_attribute is None: + cache_attribute = func(ob) + setattr(ob, attribute_name, cache_attribute) try: - cp = copy.copy(cacheAttribute) + cp = copy.copy(cache_attribute) return cp except Error: - return cacheAttribute - + return cache_attribute + return property(fget = wrapper, doc = func.__doc__) def __gt__(self, other): @@ -94,6 +92,5 @@ class LastfmBase(object): def __le__(self, other): return not self.__gt__(other) -import sys import copy -from error import Error \ No newline at end of file +from error import Error diff --git a/src/error.py b/src/error.py index df29ebe..8edc1db 100644 --- a/src/error.py +++ b/src/error.py @@ -10,16 +10,16 @@ class BaseError(Exception): message = None, code = None): super(BaseError, self).__init__() - self.__code = code - self.__message = message + self._code = code + self._message = message @property def code(self): - return self.__code + return self._code @property def message(self): - return self.__message + return self._message def __str__(self): return "%s" % self.message @@ -65,7 +65,7 @@ class TokenNotAuthorizedError(BaseError):#14 class TokenExpiredError(BaseError):#15 pass -errorMap = { +error_map = { 1: Error, 2: InvalidServiceError, 3: InvalidMethodError, diff --git a/src/event.py b/src/event.py index ff72423..af36e9d 100644 --- a/src/event.py +++ b/src/event.py @@ -12,7 +12,7 @@ class Event(LastfmBase, Sharable): STATUS_ATTENDING = 0 STATUS_MAYBE = 1 STATUS_NOT = 2 - + def init(self, api, id = None, @@ -29,91 +29,83 @@ class Event(LastfmBase, Sharable): if not isinstance(api, Api): raise InvalidParametersError("api reference must be supplied as an argument") Sharable.init(self, api) - self.__api = api - self.__id = id - self.__title = title - self.__artists = artists - self.__headliner = headliner - self.__venue = venue - self.__start_date = start_date - self.__description = description - self.__image = image - self.__url = url - self.__stats = stats and Stats( + self._api = api + self._id = id + self._title = title + self._artists = artists + self._headliner = headliner + self._venue = venue + self._start_date = start_date + self._description = description + self._image = image + self._url = url + self._stats = stats and Stats( subject = self, attendance = stats.attendance, reviews = stats.reviews ) - self.__tag = tag + self._tag = tag @property def id(self): """id of the event""" - return self.__id + return self._id @property def title(self): """title of the event""" - return self.__title + return self._title @property def artists(self): """artists performing in the event""" - return self.__artists + return self._artists @property def headliner(self): """headliner artist of the event""" - return self.__headliner + return self._headliner @property def venue(self): """venue of the event""" - return self.__venue + return self._venue @property def start_date(self): """start date of the event""" - return self.__start_date + return self._start_date @property def description(self): """description of the event""" - return self.__description + return self._description @property def image(self): """poster of the event""" - return self.__image + return self._image @property def url(self): """url of the event's page""" - return self.__url + return self._url @property def stats(self): """stats of the event""" - return self.__stats + return self._stats @property def tag(self): """tags for the event""" - return self.__tag - + return self._tag + def attend(self, status = STATUS_ATTENDING): if status not in [Event.STATUS_ATTENDING, Event.STATUS_MAYBE, Event.STATUS_NOT]: InvalidParametersError("status has to be 0, 1 or 2") params = self._default_params({'method': 'event.attend', 'status': status}) - self.__api._post_data(params) - - def _default_params(self, extra_params = None): - if not self.id: - raise InvalidParametersError("id has to be provided.") - params = {'event': self.id} - if extra_params is not None: - params.update(extra_params) - return params + self._api._post_data(params) @staticmethod def get_info(api, event): @@ -171,7 +163,7 @@ class Event(LastfmBase, Sharable): name = data.findtext('venue/location/country') ), street = data.findtext('venue/location/street'), - postalCode = data.findtext('venue/location/postalcode'), + postal_code = data.findtext('venue/location/postalcode'), latitude = float(data.findtext( 'venue/location/{%s}point/{%s}lat' % ((Location.XMLNS,)*2) )), @@ -194,15 +186,22 @@ class Event(LastfmBase, Sharable): tag = data.findtext('tag') ) + def _default_params(self, extra_params = []): + if not self.id: + raise InvalidParametersError("id has to be provided.") + params = {'event': self.id} + params.update(extra_params) + return params + @staticmethod - def hash_func(*args, **kwds): + def _hash_func(*args, **kwds): try: return hash(kwds['id']) except KeyError: raise InvalidParametersError("id has to be provided for hashing") def __hash__(self): - return Event.hash_func(id = self.id) + return Event._hash_func(id = self.id) def __eq__(self, other): return self.id == other.id diff --git a/src/geo.py b/src/geo.py index 513c852..f849817 100644 --- a/src/geo.py +++ b/src/geo.py @@ -18,28 +18,28 @@ class Geo(object): params = {'method': 'geo.getEvents', 'location': location} if distance is not None: params.update({'distance': distance}) - + if latitude is not None and longitude is not None: params.update({'latitude': latitude, 'longitude': longitude}) - + @lazylist def gen(lst): data = api._fetch_data(params).find('events') - totalPages = int(data.attrib['totalpages']) - + 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, totalPages+1): + + 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 + yield e return gen() @staticmethod @@ -67,7 +67,7 @@ class Geo(object): params = {'method': 'geo.getTopTracks', 'country': country} if location is not None: params.update({'location': location}) - + data = api._fetch_data(params).find('toptracks') return [ Track( @@ -86,7 +86,7 @@ class Geo(object): playcount = int(t.findtext('playcount')) ), streamable = (t.findtext('streamable') == '1'), - fullTrack = (t.find('streamable').attrib['fulltrack'] == '1'), + full_track = (t.find('streamable').attrib['fulltrack'] == '1'), url = 'http://' + t.findtext('url'), image = {'large': t.findtext('image')} ) @@ -99,34 +99,34 @@ class Venue(LastfmBase): name = None, location = None, url = None): - self.__name = name - self.__location = location - self.__url = url + self._name = name + self._location = location + self._url = url @property def name(self): """name of the venue""" - return self.__name + return self._name @property def location(self): """location of the event""" - return self.__location + return self._location @property def url(self): """url of the event's page""" - return self.__url + return self._url @staticmethod - def hash_func(*args, **kwds): + def _hash_func(*args, **kwds): try: return hash(kwds['url']) except KeyError: raise InvalidParametersError("url has to be provided for hashing") def __hash__(self): - return self.__class__.hash_func(url = self.url) + return self.__class__._hash_func(url = self.url) def __eq__(self, other): return self.url == other.url @@ -152,77 +152,77 @@ class Location(LastfmBase): timezone = None): if not isinstance(api, Api): raise InvalidParametersError("api reference must be supplied as an argument") - self.__api = api - self.__city = city - self.__country = country - self.__street = street - self.__postalCode = postal_code - self.__latitude = latitude - self.__longitude = longitude - self.__timezone = timezone + self._api = api + self._city = city + self._country = country + self._street = street + self._postal_code = postal_code + self._latitude = latitude + self._longitude = longitude + self._timezone = timezone @property def city(self): """city in which the location is situated""" - return self.__city + return self._city @property def country(self): """country in which the location is situated""" - return self.__country + return self._country @property def street(self): """street in which the location is situated""" - return self.__street + return self._street @property - def postalCode(self): + def postal_code(self): """postal code of the location""" - return self.__postalCode + return self._postal_code @property def latitude(self): """latitude of the location""" - return self.__latitude + return self._latitude @property def longitude(self): """longitude of the location""" - return self.__longitude + return self._longitude @property def timezone(self): """timezone in which the location is situated""" - return self.__timezone - - @LastfmBase.cachedProperty + return self._timezone + + @LastfmBase.cached_property def top_tracks(self): """top tracks of the location""" if self.country is None or self.city is None: raise InvalidParametersError("country and city of this location are required for calling this method") - return Geo.get_top_tracks(self.__api, self.country.name, self.city) - - @LastfmBase.topProperty("top_tracks") + return Geo.get_top_tracks(self._api, self.country.name, self.city) + + @LastfmBase.top_property("top_tracks") def top_track(self): """top track of the location""" pass - + def get_events(self, distance = None): - return Geo.get_events(self.__api, + return Geo.get_events(self._api, self.city, self.latitude, self.longitude, distance) - @LastfmBase.cachedProperty + @LastfmBase.cached_property def events(self): """events taking place at/around the location""" return self.get_events() - + @staticmethod - def hash_func(*args, **kwds): + def _hash_func(*args, **kwds): try: return hash("latlong%s%s" % (kwds['latitude'], kwds['longitude'])) except KeyError: @@ -233,11 +233,11 @@ class Location(LastfmBase): def __hash__(self): if not self.city: - return self.__class__.hash_func( + return self.__class__._hash_func( latitude = self.latitude, longitude = self.longitude) else: - return self.__class__.hash_func(name = self.city) + return self.__class__._hash_func(name = self.city) def __eq__(self, other): return self.latitude == other.latitude and self.longitude == other.longitude @@ -261,51 +261,51 @@ class Country(LastfmBase): name = None): if not isinstance(api, Api): raise InvalidParametersError("api reference must be supplied as an argument") - self.__api = api - self.__name = name + self._api = api + self._name = name @property def name(self): """name of the country""" - return self.__name + return self._name - @LastfmBase.cachedProperty + @LastfmBase.cached_property def top_artists(self): """top artists of the country""" - return Geo.get_top_artists(self.__api, self.name) - - @LastfmBase.topProperty("top_artists") + return Geo.get_top_artists(self._api, self.name) + + @LastfmBase.top_property("top_artists") def top_artist(self): """top artist of the country""" pass def get_top_tracks(self, location = None): - return Geo.get_top_tracks(self.__api, self.name, location) - - @LastfmBase.cachedProperty + return Geo.get_top_tracks(self._api, self.name, location) + + @LastfmBase.cached_property def top_tracks(self): """top tracks of the country""" return self.get_top_tracks() - - @LastfmBase.topProperty("top_tracks") + + @LastfmBase.top_property("top_tracks") def top_track(self): """top track of the country""" pass - @LastfmBase.cachedProperty + @LastfmBase.cached_property def events(self): """events taking place at/around the location""" - return Geo.get_events(self.__api, self.name) - + return Geo.get_events(self._api, self.name) + @staticmethod - def hash_func(*args, **kwds): + def _hash_func(*args, **kwds): try: return hash(kwds['name']) except KeyError: raise InvalidParametersError("name has to be provided for hashing") def __hash__(self): - return self.__class__.hash_func(name = self.name) + return self.__class__._hash_func(name = self.name) def __eq__(self, other): return self.name == other.name diff --git a/src/group.py b/src/group.py index 798b2b2..8f3d48a 100644 --- a/src/group.py +++ b/src/group.py @@ -14,35 +14,35 @@ class Group(LastfmBase): name = None): if not isinstance(api, Api): raise InvalidParametersError("api reference must be supplied as an argument") - self.__api = api - self.__name = name + self._api = api + self._name = name @property def name(self): - return self.__name + return self._name - @LastfmBase.cachedProperty + @LastfmBase.cached_property def weekly_chart_list(self): - params = {'method': 'group.getWeeklyChartList', 'group': self.name} - data = self.__api._fetch_data(params).find('weeklychartlist') + params = self._default_params({'method': 'group.getWeeklyChartList'}) + data = self._api._fetch_data(params).find('weeklychartlist') return [ - WeeklyChart.create_from_data(self.__api, self, c) + 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 = {'method': 'group.getWeeklyAlbumChart', 'group': self.name} + params = self._default_params({'method': 'group.getWeeklyAlbumChart'}) params = WeeklyChart._check_weekly_chart_params(params, start, end) - data = self.__api._fetch_data(params).find('weeklyalbumchart') - return WeeklyAlbumChart.create_from_data(self.__api, self, data) + data = self._api._fetch_data(params).find('weeklyalbumchart') + return WeeklyAlbumChart.create_from_data(self._api, self, data) - @LastfmBase.cachedProperty + @LastfmBase.cached_property def recent_weekly_album_chart(self): return self.get_weekly_album_chart() - @LastfmBase.cachedProperty + @LastfmBase.cached_property def weekly_album_chart_list(self): wcl = list(self.weekly_chart_list) wcl.reverse() @@ -55,16 +55,16 @@ class Group(LastfmBase): def get_weekly_artist_chart(self, start = None, end = None): - params = {'method': 'group.getWeeklyArtistChart', 'group': self.name} + params = self._default_params({'method': 'group.getWeeklyArtistChart'}) params = WeeklyChart._check_weekly_chart_params(params, start, end) - data = self.__api._fetch_data(params).find('weeklyartistchart') - return WeeklyArtistChart.create_from_data(self.__api, self, data) + data = self._api._fetch_data(params).find('weeklyartistchart') + return WeeklyArtistChart.create_from_data(self._api, self, data) - @LastfmBase.cachedProperty + @LastfmBase.cached_property def recent_weekly_artist_chart(self): return self.get_weekly_artist_chart() - @LastfmBase.cachedProperty + @LastfmBase.cached_property def weekly_artist_chart_list(self): wcl = list(self.weekly_chart_list) wcl.reverse() @@ -77,16 +77,16 @@ class Group(LastfmBase): def get_weekly_track_chart(self, start = None, end = None): - params = {'method': 'group.getWeeklyTrackChart', 'group': self.name} + params = self._default_params({'method': 'group.getWeeklyTrackChart'}) params = WeeklyChart._check_weekly_chart_params(params, start, end) - data = self.__api._fetch_data(params).find('weeklytrackchart') - return WeeklyTrackChart.create_from_data(self.__api, self, data) + data = self._api._fetch_data(params).find('weeklytrackchart') + return WeeklyTrackChart.create_from_data(self._api, self, data) - @LastfmBase.cachedProperty + @LastfmBase.cached_property def recent_weekly_track_chart(self): return self.get_weekly_track_chart() - @LastfmBase.cachedProperty + @LastfmBase.cached_property def weekly_track_chart_list(self): wcl = list(self.weekly_chart_list) wcl.reverse() @@ -96,15 +96,22 @@ class Group(LastfmBase): yield self.get_weekly_track_chart(wc.start, wc.end) return gen() + def _default_params(self, extra_params = {}): + if not self.name: + raise InvalidParametersError("group has to be provided.") + params = {'group': self.name} + params.update(extra_params) + return params + @staticmethod - def hash_func(*args, **kwds): + def _hash_func(*args, **kwds): try: return hash(kwds['name']) except KeyError: raise InvalidParametersError("name has to be provided for hashing") def __hash__(self): - return self.__class__.hash_func(name = self.name) + return self.__class__._hash_func(name = self.name) def __eq__(self, other): return self.name == other.name diff --git a/src/playlist.py b/src/playlist.py index f1ac7ac..348261e 100644 --- a/src/playlist.py +++ b/src/playlist.py @@ -9,36 +9,36 @@ from base import LastfmBase class Playlist(LastfmBase): """A class representing an XPSF playlist.""" def init(self, api, url): - self.__api = api - self.__data = None - self.__url = url + self._api = api + self._data = None + self._url = url - @LastfmBase.cachedProperty + @LastfmBase.cached_property def data(self): """playlist's data""" - params = {'method': 'playlist.fetch', 'playlistURL': self.__url} + params = {'method': 'playlist.fetch', 'playlistURL': self._url} tmp = StringIO.StringIO() - ElementTree.ElementTree(self.__api._fetch_data(params)[0]).write(tmp) + ElementTree.ElementTree(self._api._fetch_data(params)[0]).write(tmp) return tmp.getvalue() @property def url(self): """url of the playlist""" - return self.__url + return self._url @staticmethod def fetch(api, url): return Playlist(api, url = url) @staticmethod - def hash_func(*args, **kwds): + def _hash_func(*args, **kwds): try: return hash(kwds['url']) except KeyError: raise InvalidParametersError("url has to be provided for hashing") def __hash__(self): - return self.__class__.hash_func(url = self.url) + return self.__class__._hash_func(url = self.url) def __eq__(self, other): return self.url == other.url @@ -50,11 +50,10 @@ class Playlist(LastfmBase): return "" % self.url import StringIO -import platform +import sys from error import InvalidParametersError -python_version = platform.python_version_tuple() -if python_version[0] == 2 and python_version[1] >= 5: +if sys.version_info >= (2, 5): import xml.etree.cElementTree as ElementTree else: try: diff --git a/src/safelist.py b/src/safelist.py index 7dce0f8..67164ef 100644 --- a/src/safelist.py +++ b/src/safelist.py @@ -6,26 +6,26 @@ __license__ = "GNU Lesser General Public License" import sys class SafeList(object): - def __init__(self, lst, addFunc, removeFunc): + def __init__(self, lst, add_func, remove_func): self._list = lst - self._addFunc = addFunc - self._removeFunc = removeFunc - + self._add_func = add_func + self._remove_func = remove_func + def add(self, lst): if not isinstance(lst, (list, tuple)): lst = [lst] - self._addFunc(lst) - + self._add_func(lst) + def remove(self, lst): if not isinstance(lst, (list, tuple)): lst = [lst] for l in lst: - self._removeFunc(l) - + self._remove_func(l) + def __iter__(self): for i in xrange(len(self._list)): yield self._list[i] - + def _tuple_from_slice(self, i): """ Get (start, end, step) tuple from slice object. @@ -40,7 +40,7 @@ class SafeList(object): step = None return (start, end, step) - + def __getitem__(self, i): if isinstance(i, slice): (start, end, step) = self._tuple_from_slice(i) @@ -51,7 +51,7 @@ class SafeList(object): return [self._list[i] for i in indices] else: return self._list[i] - + def index(self, x, i=0, j=None): if i != 0 or j is not None: (i, j, ignore) = self._tuple_from_slice(slice(i, j)) @@ -61,10 +61,10 @@ class SafeList(object): if self._list[k] == x: return k raise ValueError('index(x): x not in list') - + # Define sort() as appropriate for the Python version. if sys.version_info[:3] < (2, 4, 0): - def sort(self, cmpfunc=None): + def sort(self, cmpfunc=None): ans = list(self._list) ans.sort(cmpfunc) self._list[:] = ans @@ -78,9 +78,9 @@ class SafeList(object): else: ans.sort(cmpfunc) self._list[:] = ans - + def __len__(self): return len(self._list) - + def __repr__(self): - return repr(self._list) \ No newline at end of file + return repr(self._list) diff --git a/src/searchable.py b/src/searchable.py index bd64336..b3422b2 100644 --- a/src/searchable.py +++ b/src/searchable.py @@ -24,28 +24,28 @@ class Searchable(object): if limit: params.update({'limit': limit}) - + @lazylist def gen(lst): data = api._fetch_data(params).find('results') - totalPages = int(data.findtext("{%s}totalResults" % Api.SEARCH_XMLNS))/ \ + 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, totalPages+1): + + 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() - + @staticmethod def _search_yield_func(api, search_term): - pass \ No newline at end of file + pass diff --git a/src/sharable.py b/src/sharable.py index ea386c5..11eeb37 100644 --- a/src/sharable.py +++ b/src/sharable.py @@ -6,7 +6,7 @@ __license__ = "GNU Lesser General Public License" class Sharable(object): def init(self, api): - self.__api = api + self._api = api def share(self, recipient, message = None): from user import User @@ -21,4 +21,7 @@ class Sharable(object): if isinstance(recipient[i], User): recipient[i] = recipient[i].name params['recipient'] = ",".join(recipient) - self.__api._post_data(params) \ No newline at end of file + self._api._post_data(params) + + def _default_params(self, extra_params = {}): + return extra_params \ No newline at end of file diff --git a/src/stats.py b/src/stats.py index 4d75850..2b9ef9e 100644 --- a/src/stats.py +++ b/src/stats.py @@ -17,67 +17,67 @@ class Stats(object): weight = None, attendance = None, reviews = None,): - self.__subject = subject - self.__listeners = listeners - self.__playcount = playcount - self.__tagcount = tagcount - self.__count = count - self.__match = match - self.__rank = rank - self.__weight = weight - self.__attendance = attendance - self.__reviews = reviews + self._subject = subject + self._listeners = listeners + self._playcount = playcount + self._tagcount = tagcount + self._count = count + self._match = match + self._rank = rank + self._weight = weight + self._attendance = attendance + self._reviews = reviews @property def subject(self): """subject of the stats""" - return self.__subject + return self._subject @property def rank(self): """rank of the subject""" - return self.__rank + return self._rank @property def listeners(self): """number of listeners of the subject""" - return self.__listeners + return self._listeners @property def playcount(self): """playcount of the subject""" - return self.__playcount + return self._playcount @property def tagcount(self): """tagcount of the subject""" - return self.__tagcount + return self._tagcount @property def count(self): """count of the subject""" - return self.__count + return self._count @property def match(self): """match of the subject""" - return self.__match + return self._match @property def weight(self): """weight of the subject""" - return self.__weight + return self._weight @property def attendance(self): """attendance of the subject""" - return self.__attendance + return self._attendance @property def reviews(self): """reviews of the subject""" - return self.__reviews + return self._reviews def __repr__(self): - return "" % self.__subject.name + return "" % self._subject.name \ No newline at end of file diff --git a/src/tag.py b/src/tag.py index dbfd770..7eff527 100644 --- a/src/tag.py +++ b/src/tag.py @@ -18,42 +18,42 @@ class Tag(LastfmBase, Searchable): stats = None): if not isinstance(api, Api): raise InvalidParametersError("api reference must be supplied as an argument") - self.__api = api - self.__name = name - self.__url = url - self.__streamable = streamable - self.__stats = stats and Stats( + self._api = api + self._name = name + self._url = url + self._streamable = streamable + self._stats = stats and Stats( subject = self, count = stats.count ) - + @property def name(self): """name of the tag""" - return self.__name + return self._name @property def url(self): """url of the tag's page""" - return self.__url - + return self._url + @property def streamable(self): """is the tag streamable""" - return self.__streamable - + return self._streamable + @property def stats(self): - return self.__stats - - @LastfmBase.cachedProperty + return self._stats + + @LastfmBase.cached_property def similar(self): """tags similar to this tag""" - params = {'method': 'tag.getSimilar', 'tag': self.name} - data = self.__api._fetch_data(params).find('similartags') + params = self._default_params({'method': 'tag.getSimilar'}) + data = self._api._fetch_data(params).find('similartags') return [ Tag( - self.__api, + self._api, subject = self, name = t.findtext('name'), url = t.findtext('url'), @@ -61,24 +61,24 @@ class Tag(LastfmBase, Searchable): ) for t in data.findall('tag') ] - - @LastfmBase.topProperty("similar") + + @LastfmBase.top_property("similar") def most_similar(self): """most similar tag to this tag""" pass - - @LastfmBase.cachedProperty + + @LastfmBase.cached_property def top_albums(self): """top albums for the tag""" - params = {'method': 'tag.getTopAlbums', 'tag': self.name} - data = self.__api._fetch_data(params).find('topalbums') + params = self._default_params({'method': 'tag.getTopAlbums'}) + data = self._api._fetch_data(params).find('topalbums') return [ Album( - self.__api, + self._api, subject = self, name = a.findtext('name'), artist = Artist( - self.__api, + self._api, subject = self, name = a.findtext('artist/name'), mbid = a.findtext('artist/mbid'), @@ -96,19 +96,19 @@ class Tag(LastfmBase, Searchable): for a in data.findall('album') ] - @LastfmBase.topProperty("top_albums") + @LastfmBase.top_property("top_albums") def top_album(self): """top album for the tag""" pass - - @LastfmBase.cachedProperty + + @LastfmBase.cached_property def top_artists(self): """top artists for the tag""" - params = {'method': 'tag.getTopArtists', 'tag': self.name} - data = self.__api._fetch_data(params).find('topartists') + params = self._default_params({'method': 'tag.getTopArtists'}) + data = self._api._fetch_data(params).find('topartists') return [ Artist( - self.__api, + self._api, subject = self, name = a.findtext('name'), mbid = a.findtext('mbid'), @@ -124,23 +124,23 @@ class Tag(LastfmBase, Searchable): for a in data.findall('artist') ] - @LastfmBase.topProperty("top_artists") + @LastfmBase.top_property("top_artists") def top_artist(self): """top artist for the tag""" pass - - @LastfmBase.cachedProperty + + @LastfmBase.cached_property def top_tracks(self): """top tracks for the tag""" - params = {'method': 'tag.getTopTracks', 'tag': self.name} - data = self.__api._fetch_data(params).find('toptracks') + params = self._default_params({'method': 'tag.getTopTracks'}) + data = self._api._fetch_data(params).find('toptracks') return [ Track( - self.__api, + self._api, subject = self, name = t.findtext('name'), artist = Artist( - self.__api, + self._api, subject = self, name = t.findtext('artist/name'), mbid = t.findtext('artist/mbid'), @@ -153,22 +153,22 @@ class Tag(LastfmBase, Searchable): tagcount = t.findtext('tagcount') and int(t.findtext('tagcount')) or None ), streamable = (t.findtext('streamable') == '1'), - fullTrack = (t.find('streamable').attrib['fulltrack'] == '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 data.findall('track') ] - @LastfmBase.topProperty("top_tracks") + @LastfmBase.top_property("top_tracks") def top_track(self): """top track for the tag""" pass - - @LastfmBase.cachedProperty + + @LastfmBase.cached_property def playlist(self): - return Playlist.fetch(self.__api, + return Playlist.fetch(self._api, "lastfm://playlist/tag/%s/freetracks" % self.name) - + @staticmethod def get_top_tags(api): params = {'method': 'tag.getTopTags'} @@ -185,7 +185,14 @@ class Tag(LastfmBase, Searchable): ) for t in data.findall('tag') ] - + + def _default_params(self, extra_params = {}): + if not self.name: + raise InvalidParametersError("tag has to be provided.") + params = {'tag': self.name} + params.update(extra_params) + return params + @staticmethod def _search_yield_func(api, tag): return Tag( @@ -197,23 +204,23 @@ class Tag(LastfmBase, Searchable): count = int(tag.findtext('count')), ) ) - + @staticmethod - def hash_func(*args, **kwds): + def _hash_func(*args, **kwds): try: return hash(kwds['name']) except KeyError: raise InvalidParametersError("name has to be provided for hashing") - + def __hash__(self): - return self.__class__.hash_func(name = self.name) - + return self.__class__._hash_func(name = self.name) + def __eq__(self, other): return self.name == other.name - + def __lt__(self, other): return self.name < other.name - + def __repr__(self): return "" % self.name @@ -223,4 +230,4 @@ from artist import Artist from error import InvalidParametersError from playlist import Playlist from stats import Stats -from track import Track \ No newline at end of file +from track import Track diff --git a/src/taggable.py b/src/taggable.py index 7255585..d0bf62a 100644 --- a/src/taggable.py +++ b/src/taggable.py @@ -9,16 +9,16 @@ from safelist import SafeList class Taggable(object): def init(self, api): - self.__api = api + self._api = api - @LastfmBase.cachedProperty + @LastfmBase.cached_property def tags(self): from tag import Tag params = self._default_params({'method': '%s.getTags' % self.__class__.__name__.lower()}) - data = self.__api._fetch_data(params, sign = True, session = True, no_cache = True).find('tags') + data = self._api._fetch_data(params, sign = True, session = True, no_cache = True).find('tags') return SafeList([ Tag( - self.__api, + self._api, name = t.findtext('name'), url = t.findtext('url') ) @@ -46,8 +46,8 @@ class Taggable(object): 'method': '%s.addTags' % self.__class__.__name__.lower(), 'tags': ",".join(tagnames) }) - self.__api._post_data(params) - self.__tags = None + self._api._post_data(params) + self._tags = None def remove_tag(self, tag): from tag import Tag @@ -58,8 +58,8 @@ class Taggable(object): 'method': '%s.removeTag' % self.__class__.__name__.lower(), 'tag': tag }) - self.__api._post_data(params) - self.__tags = None + self._api._post_data(params) + self._tags = None - def _default_params(self, extra_params): - pass \ No newline at end of file + def _default_params(self, extra_params = {}): + return extra_params \ No newline at end of file diff --git a/src/tasteometer.py b/src/tasteometer.py index f3aaf35..4a1c361 100644 --- a/src/tasteometer.py +++ b/src/tasteometer.py @@ -10,24 +10,24 @@ class Tasteometer(object): score = None, matches = None, artists = None): - self.__score = score - self.__matches = matches - self.__artists = artists + self._score = score + self._matches = matches + self._artists = artists @property def score(self): """score of the comparison""" - return self.__score + return self._score @property def matches(self): """matches for the comparison""" - return self.__matches + return self._matches @property def artists(self): """artists for the comparison""" - return self.__artists + return self._artists @staticmethod def compare(api, diff --git a/src/track.py b/src/track.py index f333314..4735370 100644 --- a/src/track.py +++ b/src/track.py @@ -32,130 +32,122 @@ class Track(LastfmBase, Taggable, Sharable, Searchable): 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 - self.__mbid = mbid - self.__url = url - self.__duration = duration - self.__streamable = streamable - self.__full_track = full_track - self.__artist = artist - self.__album = album - self.__position = position - self.__image = image - self.__stats = stats and Stats( + self._api = api + self._id = id + self._name = name + self._mbid = mbid + self._url = url + self._duration = duration + self._streamable = streamable + self._full_track = full_track + self._artist = artist + self._album = album + self._position = position + self._image = image + self._stats = stats and Stats( subject = self, match = stats.match, playcount = stats.playcount, rank = stats.rank, listeners = stats.listeners, ) - self.__played_on = played_on - self.__loved_on = loved_on - self.__wiki = wiki and Wiki( + self._played_on = played_on + self._loved_on = loved_on + self._wiki = wiki and Wiki( subject = self, published = wiki.published, summary = wiki.summary, content = wiki.content ) - + @property def id(self): """id of the track""" - return self.__id - + return self._id + @property def name(self): """name of the track""" - return self.__name + return self._name @property def mbid(self): """mbid of the track""" - return self.__mbid + return self._mbid @property def url(self): """url of the tracks's page""" - return self.__url - + return self._url + @property def duration(self): """duration of the tracks's page""" - return self.__duration + return self._duration @property def streamable(self): """is the track streamable""" - if self.__streamable is None: + if self._streamable is None: self._fill_info() - return self.__streamable + return self._streamable @property def full_track(self): """is the full track streamable""" - if self.__full_track is None: + if self._full_track is None: self._fill_info() - return self.__full_track - + return self._full_track + @property def artist(self): """artist of the track""" - return self.__artist + return self._artist @property def album(self): """artist of the track""" - if self.__album is None: + if self._album is None: self._fill_info() - return self.__album + return self._album @property def position(self): """position of the track""" - if self.__position is None: + if self._position is None: self._fill_info() - return self.__position - + return self._position + @property def image(self): """image of the track's album cover""" - return self.__image + return self._image @property def stats(self): """stats of the track""" - return self.__stats + return self._stats @property - def playedOn(self): + def played_on(self): """datetime the track was last played""" - return self.__played_on + return self._played_on @property - def lovedOn(self): + def loved_on(self): """datetime the track was marked 'loved'""" - return self.__loved_on - + return self._loved_on + @property def wiki(self): """wiki of the track""" - if self.__wiki == "na": + if self._wiki == "na": return None - if self.__wiki is None: + if self._wiki is None: self._fill_info() - return self.__wiki - - def _default_params(self, extra_params = None): - if not (self.artist and self.name): - raise InvalidParametersError("artist and track have to be provided.") - params = {'artist': self.artist.name, 'track': self.name} - if extra_params is not None: - params.update(extra_params) - return params + return self._wiki - @LastfmBase.cachedProperty + @LastfmBase.cached_property def similar(self): """tracks similar to this track""" params = Track._check_params( @@ -164,14 +156,14 @@ class Track(LastfmBase, Taggable, Sharable, Searchable): self.name, self.mbid ) - data = self.__api._fetch_data(params).find('similartracks') + data = self._api._fetch_data(params).find('similartracks') return [ Track( - self.__api, + self._api, subject = self, name = t.findtext('name'), artist = Artist( - self.__api, + self._api, subject = self, name = t.findtext('artist/name'), mbid = t.findtext('artist/mbid'), @@ -183,18 +175,18 @@ class Track(LastfmBase, Taggable, Sharable, Searchable): match = float(t.findtext('match')) ), streamable = (t.findtext('streamable') == '1'), - fullTrack = (t.find('streamable').attrib['fulltrack'] == '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 data.findall('track') ] - @LastfmBase.topProperty("similar") + @LastfmBase.top_property("similar") def most_similar(self): """track most similar to this track""" pass - @LastfmBase.cachedProperty + @LastfmBase.cached_property def top_fans(self): """top fans of the track""" params = Track._check_params( @@ -203,10 +195,10 @@ class Track(LastfmBase, Taggable, Sharable, Searchable): self.name, self.mbid ) - data = self.__api._fetch_data(params).find('topfans') + data = self._api._fetch_data(params).find('topfans') return [ User( - self.__api, + self._api, subject = self, name = u.findtext('name'), url = u.findtext('url'), @@ -219,12 +211,12 @@ class Track(LastfmBase, Taggable, Sharable, Searchable): for u in data.findall('user') ] - @LastfmBase.topProperty("top_fans") + @LastfmBase.top_property("top_fans") def top_fan(self): """topmost fan of the track""" pass - @LastfmBase.cachedProperty + @LastfmBase.cached_property def top_tags(self): """top tags for the track""" params = Track._check_params( @@ -233,10 +225,10 @@ class Track(LastfmBase, Taggable, Sharable, Searchable): self.name, self.mbid ) - data = self.__api._fetch_data(params).find('toptags') + data = self._api._fetch_data(params).find('toptags') return [ Tag( - self.__api, + self._api, subject = self, name = t.findtext('name'), url = t.findtext('url'), @@ -248,89 +240,19 @@ class Track(LastfmBase, Taggable, Sharable, Searchable): for t in data.findall('tag') ] - @LastfmBase.topProperty("top_tags") + @LastfmBase.top_property("top_tags") def top_tag(self): """topmost tag for the track""" pass - + def love(self): params = self._default_params({'method': 'track.love'}) - self.__api._post_data(params) - + self._api._post_data(params) + def ban(self): params = self._default_params({'method': 'track.ban'}) - self.__api._post_data(params) + self._api._post_data(params) - @staticmethod - def _search_yield_func(api, track): - return Track( - api, - name = track.findtext('name'), - artist = Artist( - api, - name=track.findtext('artist') - ), - url = track.findtext('url'), - stats = Stats( - subject=track.findtext('name'), - listeners=int(track.findtext('listeners')) - ), - streamable = (track.findtext('streamable') == '1'), - fullTrack = (track.find('streamable').attrib['fulltrack'] == '1'), - image = dict([(i.get('size'), i.text) for i in track.findall('image')]), - ) - - @staticmethod - def _fetch_data(api, - artist = None, - track = None, - mbid = None): - params = Track._check_params({'method': 'track.getInfo'}, artist, track, mbid) - return api._fetch_data(params).find('track') - - def _fill_info(self): - data = Track._fetch_data(self.__api, self.artist.name, self.name) - self.__id = int(data.findtext('id')) - self.__mbid = data.findtext('mbid') - self.__url = data.findtext('url') - self.__duration = int(data.findtext('duration')) - self.__streamable = (data.findtext('streamable') == '1'), - self.__full_track = (data.find('streamable').attrib['fulltrack'] == '1'), - - self.__image = dict([(i.get('size'), i.text) for i in data.findall('image')]) - self.__stats = Stats( - subject = self, - listeners = int(data.findtext('listeners')), - playcount = int(data.findtext('playcount')), - ) - self.__artist = Artist( - self.__api, - name = data.findtext('artist/name'), - mbid = data.findtext('artist/mbid'), - url = data.findtext('artist/url') - ) - self.__album = Album( - self.__api, - artist = self.__artist, - name = data.findtext('album/title'), - mbid = data.findtext('album/mbid'), - url = data.findtext('album/url'), - image = dict([(i.get('size'), i.text) for i in data.findall('album/image')]) - ) - self.__position = int(data.find('album').attrib['position']) - if data.find('wiki') is not None: - self.__wiki = Wiki( - self, - published = datetime(*(time.strptime( - data.findtext('wiki/published').strip(), - '%a, %d %b %Y %H:%M:%S +0000' - )[0:6])), - summary = data.findtext('wiki/summary'), - content = data.findtext('wiki/content') - ) - else: - self.__wiki = 'na' - @staticmethod def get_info(api, artist = None, @@ -348,6 +270,83 @@ class Track(LastfmBase, Taggable, Sharable, Searchable): t._fill_info() return t + def _default_params(self, extra_params = {}): + if not (self.artist and self.name): + raise InvalidParametersError("artist and track have to be provided.") + params = {'artist': self.artist.name, 'track': self.name} + params.update(extra_params) + return params + + @staticmethod + def _search_yield_func(api, track): + return Track( + api, + name = track.findtext('name'), + artist = Artist( + api, + name=track.findtext('artist') + ), + url = track.findtext('url'), + stats = Stats( + subject=track.findtext('name'), + listeners=int(track.findtext('listeners')) + ), + streamable = (track.findtext('streamable') == '1'), + full_track = (track.find('streamable').attrib['fulltrack'] == '1'), + image = dict([(i.get('size'), i.text) for i in track.findall('image')]), + ) + + @staticmethod + def _fetch_data(api, + artist = None, + track = None, + mbid = None): + params = Track._check_params({'method': 'track.getInfo'}, artist, track, mbid) + return api._fetch_data(params).find('track') + + def _fill_info(self): + data = Track._fetch_data(self._api, self.artist.name, self.name) + self._id = int(data.findtext('id')) + self._mbid = data.findtext('mbid') + self._url = data.findtext('url') + self._duration = int(data.findtext('duration')) + self._streamable = (data.findtext('streamable') == '1'), + self._full_track = (data.find('streamable').attrib['fulltrack'] == '1'), + + self._image = dict([(i.get('size'), i.text) for i in data.findall('image')]) + self._stats = Stats( + subject = self, + listeners = int(data.findtext('listeners')), + playcount = int(data.findtext('playcount')), + ) + self._artist = Artist( + self._api, + name = data.findtext('artist/name'), + mbid = data.findtext('artist/mbid'), + url = data.findtext('artist/url') + ) + self._album = Album( + self._api, + artist = self._artist, + name = data.findtext('album/title'), + mbid = data.findtext('album/mbid'), + url = data.findtext('album/url'), + image = dict([(i.get('size'), i.text) for i in data.findall('album/image')]) + ) + self._position = int(data.find('album').attrib['position']) + if data.find('wiki') is not None: + self._wiki = Wiki( + self, + published = datetime(*(time.strptime( + data.findtext('wiki/published').strip(), + '%a, %d %b %Y %H:%M:%S +0000' + )[0:6])), + summary = data.findtext('wiki/summary'), + content = data.findtext('wiki/content') + ) + else: + self._wiki = 'na' + @staticmethod def _check_params(params, artist = None, @@ -363,14 +362,14 @@ class Track(LastfmBase, Taggable, Sharable, Searchable): return params @staticmethod - def hash_func(*args, **kwds): + def _hash_func(*args, **kwds): try: return hash("%s%s" % (kwds['name'], hash(kwds['artist']))) except KeyError: raise InvalidParametersError("name and artist have to be provided for hashing") def __hash__(self): - return self.__class__.hash_func(name = self.name, artist = self.artist) + return self.__class__._hash_func(name = self.name, artist = self.artist) def __eq__(self, other): if self.mbid and other.mbid: @@ -397,4 +396,4 @@ from error import InvalidParametersError from stats import Stats from tag import Tag from user import User -from wiki import Wiki \ No newline at end of file +from wiki import Wiki diff --git a/src/user.py b/src/user.py index 55641d2..1211eb8 100644 --- a/src/user.py +++ b/src/user.py @@ -23,117 +23,117 @@ class User(LastfmBase): subscriber = None): if not isinstance(api, Api): raise InvalidParametersError("api reference must be supplied as an argument") - self.__api = api - self.__name = name - self.__url = url - self.__image = image - self.__stats = stats and Stats( + self._api = api + self._name = name + self._url = url + self._image = image + self._stats = stats and Stats( subject = self, match = stats.match, weight = stats.weight, playcount = stats.playcount ) - self.__library = User.Library(api, self) - self.__language = language - self.__country = country - self.__age = age - self.__gender = gender - self.__subscriber = subscriber + self._library = User.Library(api, self) + self._language = language + self._country = country + self._age = age + self._gender = gender + self._subscriber = subscriber @property def name(self): """name of the user""" - return self.__name + return self._name @property def url(self): """url of the user's page""" - return self.__url + return self._url @property def image(self): """image of the user""" - return self.__image + return self._image @property def stats(self): """stats for the user""" - return self.__stats - + return self._stats + @property def language(self): """lang for the user""" - return self.__language - + return self._language + @property def country(self): """country for the user""" - return self.__country - + return self._country + @property def age(self): """age for the user""" - return self.__age - + return self._age + @property def gender(self): """stats for the user""" - return self.__gender - + return self._gender + @property def subscriber(self): """is the user a subscriber""" - return self.__subscriber + return self._subscriber - @LastfmBase.cachedProperty + @LastfmBase.cached_property def events(self): - params = {'method': 'user.getEvents', 'user': self.name} - data = self.__api._fetch_data(params).find('events') + params = self._default_params({'method': 'user.getEvents'}) + data = self._api._fetch_data(params).find('events') return [ - Event.create_from_data(self.__api, e) + Event.create_from_data(self._api, e) for e in data.findall('event') ] - + def get_past_events(self, limit = None): - params = {'method': 'user.getPastEvents', 'user': self.name} + params = self._default_params({'method': 'user.getPastEvents'}) if limit is not None: params.update({'limit': limit}) - + @lazylist def gen(lst): - data = self.__api._fetch_data(params).find('events') - totalPages = int(data.attrib['totalPages']) - + 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) - + yield Event.create_from_data(self._api, e) + for e in gen2(data): yield e - - for page in xrange(2, totalPages+1): + + for page in xrange(2, total_pages+1): params.update({'page': page}) - data = self.__api._fetch_data(params).find('events') + data = self._api._fetch_data(params).find('events') for e in gen2(data): - yield e + yield e return gen() - - @LastfmBase.cachedProperty + + @LastfmBase.cached_property def past_events(self): return self.get_past_events() def get_friends(self, limit = None): - params = {'method': 'user.getFriends', 'user': self.name} + params = self._default_params({'method': 'user.getFriends'}) if limit is not None: params.update({'limit': limit}) - data = self.__api._fetch_data(params).find('friends') + data = self._api._fetch_data(params).find('friends') return [ User( - self.__api, + self._api, subject = self, name = u.findtext('name'), image = dict([(i.get('size'), i.text) for i in u.findall('image')]), @@ -143,19 +143,19 @@ class User(LastfmBase): ] - @LastfmBase.cachedProperty + @LastfmBase.cached_property def friends(self): """friends of the user""" return self.get_friends() - + def get_neighbours(self, limit = None): - params = {'method': 'user.getNeighbours', 'user': self.name} + params = self._default_params({'method': 'user.getNeighbours'}) if limit is not None: params.update({'limit': limit}) - data = self.__api._fetch_data(params).find('neighbours') + data = self._api._fetch_data(params).find('neighbours') return [ User( - self.__api, + self._api, subject = self, name = u.findtext('name'), image = {'medium': u.findtext('image')}, @@ -168,24 +168,24 @@ class User(LastfmBase): for u in data.findall('user') ] - @LastfmBase.cachedProperty + @LastfmBase.cached_property def neighbours(self): """neighbours of the user""" return self.get_neighbours() - - @LastfmBase.topProperty("neighbours") + + @LastfmBase.top_property("neighbours") def nearest_neighbour(self): """nearest neightbour of the user""" pass - - @LastfmBase.cachedProperty + + @LastfmBase.cached_property def playlists(self): """playlists of the user""" - params = {'method': 'user.getPlaylists', 'user': self.name} - data = self.__api._fetch_data(params).find('playlists') + params = self._default_params({'method': 'user.getPlaylists'}) + data = self._api._fetch_data(params).find('playlists') return [ User.Playlist( - self.__api, + self._api, id = int(p.findtext('id')), title = p.findtext('title'), date = datetime(*( @@ -200,17 +200,17 @@ class User(LastfmBase): for p in data.findall('playlist') ] - @LastfmBase.cachedProperty + @LastfmBase.cached_property def loved_tracks(self): - params = {'method': 'user.getLovedTracks', 'user': self.name} - data = self.__api._fetch_data(params).find('lovedtracks') + params = self._default_params({'method': 'user.getLovedTracks'}) + data = self._api._fetch_data(params).find('lovedtracks') return [ Track( - self.__api, + self._api, subject = self, name = t.findtext('name'), artist = Artist( - self.__api, + self._api, subject = self, name = t.findtext('artist/name'), mbid = t.findtext('artist/mbid'), @@ -218,7 +218,7 @@ class User(LastfmBase): ), mbid = t.findtext('mbid'), image = dict([(i.get('size'), i.text) for i in t.findall('image')]), - lovedOn = datetime(*( + loved_on = datetime(*( time.strptime( t.findtext('date').strip(), '%d %b %Y, %H:%M' @@ -227,27 +227,27 @@ class User(LastfmBase): ) for t in data.findall('track') ] - + def get_recent_tracks(self, limit = None): - params = {'method': 'user.getRecentTracks', 'user': self.name} - data = self.__api._fetch_data(params, no_cache = True).find('recenttracks') + params = self._default_params({'method': 'user.getRecentTracks'}) + data = self._api._fetch_data(params, no_cache = True).find('recenttracks') return [ Track( - self.__api, + self._api, subject = self, name = t.findtext('name'), artist = Artist( - self.__api, + self._api, subject = self, name = t.findtext('artist'), mbid = t.find('artist').attrib['mbid'], ), album = Album( - self.__api, + self._api, subject = self, name = t.findtext('album'), artist = Artist( - self.__api, + self._api, subject = self, name = t.findtext('artist'), mbid = t.find('artist').attrib['mbid'], @@ -258,7 +258,7 @@ class User(LastfmBase): streamable = (t.findtext('streamable') == '1'), url = t.findtext('url'), image = dict([(i.get('size'), i.text) for i in t.findall('image')]), - playedOn = datetime(*( + played_on = datetime(*( time.strptime( t.findtext('date').strip(), '%d %b %Y, %H:%M' @@ -273,24 +273,24 @@ class User(LastfmBase): """recent tracks played by the user""" return self.get_recent_tracks() - @LastfmBase.topProperty("recent_tracks") + @LastfmBase.top_property("recent_tracks") def most_recent_track(self): """most recent track played by the user""" pass def get_top_albums(self, period = None): - params = {'method': 'user.getTopAlbums', 'user': self.name} + params = self._default_params({'method': 'user.getTopAlbums'}) if period is not None: params.update({'period': period}) - data = self.__api._fetch_data(params).find('topalbums') + data = self._api._fetch_data(params).find('topalbums') return [ Album( - self.__api, + self._api, subject = self, name = a.findtext('name'), artist = Artist( - self.__api, + self._api, subject = self, name = a.findtext('artist/name'), mbid = a.findtext('artist/mbid'), @@ -308,25 +308,25 @@ class User(LastfmBase): for a in data.findall('album') ] - @LastfmBase.cachedProperty + @LastfmBase.cached_property def top_albums(self): """overall top albums of the user""" return self.get_top_albums() - - @LastfmBase.topProperty("top_albums") + + @LastfmBase.top_property("top_albums") def top_album(self): """overall top most album of the user""" pass def get_top_artists(self, period = None): - params = {'method': 'user.getTopArtists', 'user': self.name} + params = self._default_params({'method': 'user.getTopArtists'}) if period is not None: params.update({'period': period}) - data = self.__api._fetch_data(params).find('topartists') - + data = self._api._fetch_data(params).find('topartists') + return [ Artist( - self.__api, + self._api, subject = self, name = a.findtext('name'), mbid = a.findtext('mbid'), @@ -342,28 +342,28 @@ class User(LastfmBase): for a in data.findall('artist') ] - @LastfmBase.cachedProperty + @LastfmBase.cached_property def top_artists(self): """top artists of the user""" return self.get_top_artists() - - @LastfmBase.topProperty("top_artists") + + @LastfmBase.top_property("top_artists") def top_artist(self): """top artist of the user""" pass def get_top_tracks(self, period = None): - params = {'method': 'user.getTopTracks', 'user': self.name} + params = self._default_params({'method': 'user.getTopTracks'}) if period is not None: params.update({'period': period}) - data = self.__api._fetch_data(params).find('toptracks') + data = self._api._fetch_data(params).find('toptracks') return [ Track( - self.__api, + self._api, subject = self, name = t.findtext('name'), artist = Artist( - self.__api, + self._api, subject = self, name = t.findtext('artist/name'), mbid = t.findtext('artist/mbid'), @@ -376,30 +376,30 @@ class User(LastfmBase): playcount = t.findtext('playcount') and int(t.findtext('playcount')) or None ), streamable = (t.findtext('streamable') == '1'), - fullTrack = (t.find('streamable').attrib['fulltrack'] == '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 data.findall('track') ] - @LastfmBase.cachedProperty + @LastfmBase.cached_property def top_tracks(self): """top tracks of the user""" return self.get_top_tracks() - - @LastfmBase.topProperty("top_tracks") + + @LastfmBase.top_property("top_tracks") def top_track(self): """top track of the user""" return (len(self.top_tracks) and self.top_tracks[0] or None) def get_top_tags(self, limit = None): - params = {'method': 'user.getTopTags', 'user': self.name} + params = self._default_params({'method': 'user.getTopTags'}) if limit is not None: params.update({'limit': limit}) - data = self.__api._fetch_data(params).find('toptags') + data = self._api._fetch_data(params).find('toptags') return [ Tag( - self.__api, + self._api, subject = self, name = t.findtext('name'), url = t.findtext('url'), @@ -407,42 +407,42 @@ class User(LastfmBase): subject = t.findtext('name'), count = int(t.findtext('count')) ) - ) + ) for t in data.findall('tag') ] - @LastfmBase.cachedProperty + @LastfmBase.cached_property def top_tags(self): """top tags of the user""" return self.get_top_tags() - - @LastfmBase.topProperty("top_tags") + + @LastfmBase.top_property("top_tags") def top_tag(self): """top tag of the user""" pass - @LastfmBase.cachedProperty + @LastfmBase.cached_property def weekly_chart_list(self): - params = {'method': 'user.getWeeklyChartList', 'user': self.name} - data = self.__api._fetch_data(params).find('weeklychartlist') + params = self._default_params({'method': 'user.getWeeklyChartList'}) + data = self._api._fetch_data(params).find('weeklychartlist') return [ - WeeklyChart.create_from_data(self.__api, self, c) + 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 = {'method': 'user.getWeeklyAlbumChart', 'user': self.name} - params = WeeklyChart._check_weekly_chart_params(params, start, end) - data = self.__api._fetch_data(params).find('weeklyalbumchart') - return WeeklyAlbumChart.create_from_data(self.__api, self, data) + params = self._default_params({'method': 'user.getWeeklyAlbumChart'}) + params = WeeklyChart._check_weekly_chart_params(params, start, end) + data = self._api._fetch_data(params).find('weeklyalbumchart') + return WeeklyAlbumChart.create_from_data(self._api, self, data) - @LastfmBase.cachedProperty + @LastfmBase.cached_property def recent_weekly_album_chart(self): return self.get_weekly_album_chart() - - @LastfmBase.cachedProperty + + @LastfmBase.cached_property def weekly_album_chart_list(self): wcl = list(self.weekly_chart_list) wcl.reverse() @@ -458,16 +458,16 @@ class User(LastfmBase): def get_weekly_artist_chart(self, start = None, end = None): - params = {'method': 'user.getWeeklyArtistChart', 'user': self.name} + params = self._default_params({'method': 'user.getWeeklyArtistChart'}) params = WeeklyChart._check_weekly_chart_params(params, start, end) - data = self.__api._fetch_data(params).find('weeklyartistchart') - return WeeklyArtistChart.create_from_data(self.__api, self, data) + data = self._api._fetch_data(params).find('weeklyartistchart') + return WeeklyArtistChart.create_from_data(self._api, self, data) - @LastfmBase.cachedProperty + @LastfmBase.cached_property def recent_weekly_artist_chart(self): return self.get_weekly_artist_chart() - - @LastfmBase.cachedProperty + + @LastfmBase.cached_property def weekly_artist_chart_list(self): wcl = list(self.weekly_chart_list) wcl.reverse() @@ -483,16 +483,16 @@ class User(LastfmBase): def get_weekly_track_chart(self, start = None, end = None): - params = {'method': 'user.getWeeklyTrackChart', 'user': self.name} + params = self._default_params({'method': 'user.getWeeklyTrackChart'}) params = WeeklyChart._check_weekly_chart_params(params, start, end) - data = self.__api._fetch_data(params).find('weeklytrackchart') - return WeeklyTrackChart.create_from_data(self.__api, self, data) + data = self._api._fetch_data(params).find('weeklytrackchart') + return WeeklyTrackChart.create_from_data(self._api, self, data) - @LastfmBase.cachedProperty + @LastfmBase.cached_property def recent_weekly_track_chart(self): return self.get_weekly_track_chart() - - @LastfmBase.cachedProperty + + @LastfmBase.cached_property def weekly_track_chart_list(self): wcl = list(self.weekly_chart_list) wcl.reverse() @@ -504,16 +504,16 @@ class User(LastfmBase): except Error: pass return gen() - + def compare(self, other, limit = None): - return Tasteometer.compare(self.__api, + return Tasteometer.compare(self._api, 'user', 'user', self.name, other.name, limit) @property def library(self): - return self.__library - + return self._library + @staticmethod def get_authenticated_user(api): data = api._fetch_data({'method': 'user.getInfo'}, sign = True, session = True).find('user') @@ -532,15 +532,22 @@ class User(LastfmBase): ) ) + def _default_params(self, extra_params = {}): + if not self.name: + raise InvalidParametersError("user has to be provided.") + params = {'user': self.name} + params.update(extra_params) + return params + @staticmethod - def hash_func(*args, **kwds): + def _hash_func(*args, **kwds): try: return hash(kwds['name']) except KeyError: raise InvalidParametersError("name has to be provided for hashing") def __hash__(self): - return self.__class__.hash_func(name = self.name) + return self.__class__._hash_func(name = self.name) def __eq__(self, other): return self.name == other.name @@ -550,89 +557,89 @@ class User(LastfmBase): def __repr__(self): return "" % self.name - + class Playlist(playlist.Playlist): """A class representing a playlist belonging to the user.""" def init(self, api, id, title, date, size, creator): super(User.Playlist, self).init(api, "lastfm://playlist/%s" % id) - self.__id = id - self.__title = title - self.__date = date - self.__size = size - self.__creator = creator - + self._id = id + self._title = title + self._date = date + self._size = size + self._creator = creator + @property def id(self): - return self.__id - + return self._id + @property def title(self): - return self.__title - + return self._title + @property def date(self): - return self.__date - + return self._date + @property def size(self): - return self.__size - + return self._size + @property def creator(self): - return self.__creator - - def addTrack(self, track): + return self._creator + + def add_track(self, track): params = {'method': 'playlist.addTrack', 'playlistID': self.id} if not isinstance(track, Track): - track = self.__api.search_track(track)[0] - + track = self._api.search_track(track)[0] + params['artist'] = track.artist.name params['track'] = track.name - self.__api._post_data(params) - + self._api._post_data(params) + @staticmethod - def hash_func(*args, **kwds): + def _hash_func(*args, **kwds): try: return hash(kwds['id']) except KeyError: raise InvalidParametersError("id has to be provided for hashing") - + def __hash__(self): - return self.__class__.hash_func(id = self.id) - + return self.__class__._hash_func(id = self.id) + def __repr__(self): return "" % self.title - + class Library(object): """A class representing the music library of the user.""" def __init__(self, api, user): - self.__api = api - self.__user = user - + self._api = api + self._user = user + @property def user(self): - return self.__user - + return self._user + def get_albums(self, limit = None): - params = {'method': 'library.getAlbums', 'user': self.user.name} + params = self._default_params({'method': 'library.getAlbums'}) if limit is not None: params.update({'limit': limit}) - + @lazylist def gen(lst): - data = self.__api._fetch_data(params).find('albums') + 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, + self._api, subject = self, name = a.findtext('name'), artist = Artist( - self.__api, + self._api, subject = self, name = a.findtext('artist/name'), mbid = a.findtext('artist/mbid'), @@ -646,41 +653,41 @@ class User(LastfmBase): 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') + data = self._api._fetch_data(params).find('albums') except Error: continue for a in gen2(data): - yield a + yield a return gen() - - @LastfmBase.cachedProperty + + @LastfmBase.cached_property def albums(self): return self.get_albums() def get_artists(self, limit = None): - params = {'method': 'library.getArtists', 'user': self.user.name} + params = self._default_params({'method': 'library.getArtists'}) if limit is not None: params.update({'limit': limit}) - + @lazylist def gen(lst): - data = self.__api._fetch_data(params).find('artists') + 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, + self._api, subject = self, name = a.findtext('name'), mbid = a.findtext('mbid'), @@ -692,45 +699,45 @@ class User(LastfmBase): 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') + data = self._api._fetch_data(params).find('artists') except Error: continue for a in gen2(data): - yield a + yield a return gen() - - @LastfmBase.cachedProperty + + @LastfmBase.cached_property def artists(self): return self.get_artists() - + def get_tracks(self, limit = None): - params = {'method': 'library.getTracks', 'user': self.user.name} + params = self._default_params({'method': 'library.getTracks'}) if limit is not None: params.update({'limit': limit}) - + @lazylist def gen(lst): - data = self.__api._fetch_data(params).find('tracks') - totalPages = int(data.attrib['totalPages']) - + 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, + self._api, subject = self, name = t.findtext('name'), artist = Artist( - self.__api, + self._api, subject = self, name = t.findtext('artist/name'), mbid = t.findtext('artist/mbid'), @@ -743,38 +750,45 @@ class User(LastfmBase): tagcount = t.findtext('tagcount') and int(t.findtext('tagcount')) or None ), streamable = (t.findtext('streamable') == '1'), - fullTrack = (t.find('streamable').attrib['fulltrack'] == '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, totalPages+1): + + for page in xrange(2, total_pages+1): params.update({'page': page}) data = None try: - data = self.__api._fetch_data(params).find('tracks') + data = self._api._fetch_data(params).find('tracks') except Error: continue for t in gen2(data): - yield t + yield t return gen() - - @LastfmBase.cachedProperty + + @LastfmBase.cached_property def tracks(self): return self.get_tracks() - + + def _default_params(self, extra_params = {}): + if not self.user.name: + raise InvalidParametersError("user has to be provided.") + params = {'user': self.user.name} + params.update(extra_params) + return params + @staticmethod - def hash_func(*args, **kwds): + def _hash_func(*args, **kwds): try: return hash(kwds['user']) except KeyError: raise InvalidParametersError("user has to be provided for hashing") - + def __hash__(self): - return self.__class__.hash_func(user = self.user) - + return self.__class__._hash_func(user = self.user) + def __repr__(self): return "" % self.user.name @@ -791,4 +805,4 @@ from stats import Stats from tag import Tag from tasteometer import Tasteometer from track import Track -from weeklychart import WeeklyChart, WeeklyAlbumChart, WeeklyArtistChart, WeeklyTrackChart \ No newline at end of file +from weeklychart import WeeklyChart, WeeklyAlbumChart, WeeklyArtistChart, WeeklyTrackChart diff --git a/src/weeklychart.py b/src/weeklychart.py index 24c643f..0e9ba8d 100644 --- a/src/weeklychart.py +++ b/src/weeklychart.py @@ -11,26 +11,26 @@ class WeeklyChart(LastfmBase): def init(self, subject, start, end, stats = None): - self.__subject = subject - self.__start = start - self.__end = end - self.__stats = stats + self._subject = subject + self._start = start + self._end = end + self._stats = stats @property def subject(self): - return self.__subject + return self._subject @property def start(self): - return self.__start + return self._start @property def end(self): - return self.__end + return self._end @property def stats(self): - return self.__stats + return self._stats @staticmethod def create_from_data(api, subject, data): @@ -56,7 +56,7 @@ class WeeklyChart(LastfmBase): return params @staticmethod - def hash_func(*args, **kwds): + def _hash_func(*args, **kwds): try: return hash("%s%s%s%s" % ( kwds['subject'].__class__.__name__, @@ -68,7 +68,7 @@ class WeeklyChart(LastfmBase): raise InvalidParametersError("subject, start and end have to be provided for hashing") def __hash__(self): - return self.__class__.hash_func( + return self.__class__._hash_func( subject = self.subject, start = self.start, end = self.end @@ -102,11 +102,11 @@ class WeeklyAlbumChart(WeeklyChart): """A class for representing the weekly album charts""" def init(self, subject, start, end, stats, albums): super(WeeklyAlbumChart, self).init(subject, start, end, stats) - self.__albums = albums + self._albums = albums @property def albums(self): - return self.__albums + return self._albums @staticmethod def create_from_data(api, subject, data): @@ -156,11 +156,11 @@ class WeeklyArtistChart(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 + self._artists = artists @property def artists(self): - return self.__artists + return self._artists @staticmethod def create_from_data(api, subject, data): @@ -204,11 +204,11 @@ class WeeklyTrackChart(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 + self._tracks = tracks @property def tracks(self): - return self.__tracks + return self._tracks @staticmethod def create_from_data(api, subject, data): diff --git a/src/wiki.py b/src/wiki.py index 6017986..35170e7 100644 --- a/src/wiki.py +++ b/src/wiki.py @@ -11,30 +11,30 @@ class Wiki(object): published = None, summary = None, content = None): - self.__subject = subject - self.__published = published - self.__summary = summary - self.__content = content + self._subject = subject + self._published = published + self._summary = summary + self._content = content @property def subject(self): """artist for which the biography is""" - return self.__subject + return self._subject @property def published(self): """publication time of the biography""" - return self.__published + return self._published @property def summary(self): """summary of the biography""" - return self.__summary + return self._summary @property def content(self): """content of the biography""" - return self.__content + return self._content def __repr__(self): return "" % (self.subject.__class__.__name__, self.subject.name) \ No newline at end of file