Implemented Authentication API and some auth methods in Track class.

master
Abhinav Sarkar 2008-09-03 14:43:32 +00:00
parent f0734f8a3c
commit fd7d7f1b12
11 changed files with 270 additions and 140 deletions

View File

@ -6,7 +6,7 @@ __license__ = "GNU Lesser General Public License"
METADATA = dict(
name='lastfm',
version='0.1',
version='0.2',
description="a pure python interface to the Last.fm Webservices API",
long_description="""a pure python interface to the Last.fm Webservices API version 2.0,
located at http://ws.audioscrobbler.com/2.0/ .""",

View File

@ -93,7 +93,7 @@ class Album(LastfmBase):
@LastfmBase.cachedProperty
def topTags(self):
"""top tags for the album"""
params = {'method': 'album.getinfo'}
params = {'method': 'album.getInfo'}
if self.artist and self.name:
params.update({'artist': self.artist.name, 'album': self.name})
elif self.mbid:
@ -123,7 +123,7 @@ class Album(LastfmBase):
artist = None,
album = None,
mbid = None):
params = {'method': 'album.getinfo'}
params = {'method': 'album.getInfo'}
if not ((artist and album) or mbid):
raise LastfmInvalidParametersError("either (artist and album) or mbid has to be given as argument.")
if artist and album:

View File

@ -4,6 +4,8 @@ __author__ = "Abhinav Sarkar <abhinav@abhinavsarkar.net>"
__version__ = "0.2"
__license__ = "GNU Lesser General Public License"
from base import LastfmBase
class Api(object):
"""The class representing the last.fm web services API."""
@ -14,11 +16,15 @@ class Api(object):
def __init__(self,
apiKey,
secret = None,
sessionKey = None,
input_encoding=None,
request_headers=None,
no_cache = False,
debug = False):
self.__apiKey = apiKey
self.__secret = secret
self.__sessionKey = sessionKey
self._cache = FileCache()
self._urllib = urllib2
self._cache_timeout = Api.DEFAULT_CACHE_TIMEOUT
@ -29,9 +35,33 @@ class Api(object):
self._debug = debug
self._lastFetchTime = datetime.now()
def getApiKey(self):
@property
def apiKey(self):
return self.__apiKey
@property
def secret(self):
return self.__secret
@property
def sessionKey(self):
return self.__sessionKey
def setSessionKey(self):
params = {'method': 'auth.getSession', 'token': self.authToken}
self.__sessionKey = self._fetchData(params, sign = True).findtext('session/key')
self.__authToken = None
@LastfmBase.cachedProperty
def authToken(self):
params = {'method': 'auth.getToken'}
return self._fetchData(params, sign = True).findtext('token')
@LastfmBase.cachedProperty
def authUrl(self):
return "http://www.last.fm/api/auth/?api_key=%s&token=%s" % (self.apiKey, self.authToken)
def setCache(self, cache):
'''Override the default cache. Set to None to prevent caching.
@ -64,6 +94,83 @@ class Api(object):
'''
self._request_headers['User-Agent'] = user_agent
def getAlbum(self,
artist = None,
album = None,
mbid = None):
if isinstance(artist, Artist):
artist = artist.name
return Album.getInfo(self, artist, album, mbid)
def getArtist(self,
artist = None,
mbid = None):
return Artist.getInfo(self, artist, mbid)
def searchArtist(self,
artist,
limit = None):
return Artist.search(self, artist, limit)
def getEvent(self, event):
return Event.getInfo(self, event)
def getLocation(self, name):
return Location(self, name = name)
def getCountry(self, name):
return Country(self, name = name)
def getGroup(self, name):
return Group(self, name = name)
def fetchPlaylist(self, url):
return Playlist.fetch(self, url)
def getTag(self, name):
return Tag(self, name = name)
def getGlobalTopTags(self):
return Tag.getTopTags(self)
def searchTag(self,
tag,
limit = None):
return Tag.search(self, tag, limit)
def compareTaste(self,
type1, type2,
value1, value2,
limit = None):
return Tasteometer.compare(self, type1, type2, value1, value2, limit)
def getTrack(self, track, artist):
if isinstance(artist, Artist):
artist = artist.name
result = Track.search(self, track, artist)
try:
result[0]
except IndexError:
raise LastfmInvalidResourceError("'%s' by %s: no such track found" % (track, artist))
return result[0]
def searchTrack(self,
track,
artist = None,
limit = None):
if isinstance(artist, Artist):
artist = artist.name
return Track.search(self, track, artist, limit)
def getUser(self, name):
user = None
try:
user = User(self, name = name)
user.friends
except LastfmError, e:
raise e
return user
def _BuildUrl(self, url, path_elements=None, extra_params=None):
# Break url into consituent parts
(scheme, netloc, path, params, query, fragment) = urlparse.urlparse(url)
@ -127,83 +234,17 @@ class Api(object):
return None
else:
return urllib.urlencode(dict([(k, self._Encode(v)) for k, v in parameters.items() if v is not None]))
def getAlbum(self,
artist = None,
album = None,
mbid = None):
if isinstance(artist, Artist):
artist = artist.name
return Album.getInfo(self, artist, album, mbid)
def getArtist(self,
artist = None,
mbid = None):
return Artist.getInfo(self, artist, mbid)
def searchArtist(self,
artist,
limit = None):
return Artist.search(self, artist, limit)
def getEvent(self, event):
return Event.getInfo(self, event)
def getLocation(self, name):
return Location(self, name = name)
def getCountry(self, name):
return Country(self, name = name)
def getGroup(self, name):
return Group(self, name = name)
def fetchPlaylist(self, url):
return Playlist.fetch(self, url)
def getTag(self, name):
return Tag(self, name = name)
def getGlobalTopTags(self):
return Tag.getTopTags(self)
def searchTag(self,
tag,
limit = None):
return Tag.search(self, tag, limit)
def compareTaste(self,
type1, type2,
value1, value2,
limit = None):
return Tasteometer.compare(self, type1, type2, value1, value2, limit)
def getTrack(self, track, artist):
if isinstance(artist, Artist):
artist = artist.name
result = Track.search(self, track, artist)
if len(result.matches) == 0:
raise LastfmInvalidResourceError("'%s' by %s: no such track found" % (track, artist))
return result.matches[0]
def searchTrack(self,
track,
artist = None,
limit = None):
if isinstance(artist, Artist):
artist = artist.name
return Track.search(self, track, artist, limit)
def getUser(self, name):
user = None
try:
user = User(self, name = name)
user.friends
except LastfmError, e:
raise e
return user
def _ReadUrlData(self, opener, url, data = None):
now = datetime.now()
delta = now - self._lastFetchTime
delta = delta.seconds + float(delta.microseconds)/1000000
if delta < Api.FETCH_INTERVAL:
time.sleep(Api.FETCH_INTERVAL - delta)
url_data = opener.open(url, data).read()
self._lastFetchTime = datetime.now()
return url_data
def _fetchUrl(self,
url,
parameters = None,
@ -226,20 +267,10 @@ class Api(object):
# Get a url opener that can handle basic auth
opener = self._GetOpener(url)
def readUrlData():
now = datetime.now()
delta = now - self._lastFetchTime
delta = delta.seconds + float(delta.microseconds)/1000000
if delta < Api.FETCH_INTERVAL:
time.sleep(Api.FETCH_INTERVAL - delta)
url_data = opener.open(url).read()
self._lastFetchTime = datetime.now()
return url_data
# Open and return the URL immediately if we're not going to cache
if no_cache or not self._cache or not self._cache_timeout:
try:
url_data = readUrlData()
url_data = self._ReadUrlData(opener, url)
except urllib2.HTTPError, e:
url_data = e.read()
else:
@ -252,7 +283,7 @@ class Api(object):
# If the cached version is outdated then fetch another and store it
if not last_cached or time.time() >= last_cached + self._cache_timeout:
try:
url_data = readUrlData()
url_data = self._ReadUrlData(opener, url)
except urllib2.HTTPError, e:
url_data = e.read()
self._cache.Set(key, url_data)
@ -264,10 +295,55 @@ class Api(object):
def _fetchData(self,
params,
sign = False,
session = False,
no_cache = False):
params.update({'api_key': self.__apiKey})
params.update({'api_key': self.apiKey})
if session:
params.update({'sk': self.sessionKey})
if sign:
keys = params.keys()[:]
keys.sort()
sig = unicode()
for name in keys:
sig += (name + params[name])
sig += self.secret
hashed_sig = md5.new(sig).hexdigest()
params.update({'api_sig': hashed_sig})
xml = self._fetchUrl(Api.API_ROOT_URL, params, no_cache = self._no_cache or no_cache)
#print xml
return self._checkXML(xml)
def _postUrl(self,
url,
parameters):
url = self._BuildUrl(url)
if self._debug:
print url
data = self._EncodeParameters(parameters)
opener = self._GetOpener(url)
url_data = self._ReadUrlData(opener, url, data)
return url_data
def _postData(self, params):
params.update({'api_key': self.apiKey, 'sk': self.sessionKey})
keys = params.keys()[:]
keys.sort()
sig = unicode()
for name in keys:
sig += (name + params[name])
sig += self.secret
hashed_sig = md5.new(sig).hexdigest()
params.update({'api_sig': hashed_sig})
xml = self._postUrl(Api.API_ROOT_URL, params)
return self._checkXML(xml)
def _checkXML(self, xml):
data = None
try:
data = ElementTree.XML(xml)
except SyntaxError, e:
@ -285,6 +361,7 @@ class Api(object):
return "<lastfm.Api: %s>" % self.__apiKey
from datetime import datetime
import md5
import sys
import time
import urllib

View File

@ -85,7 +85,7 @@ class Artist(LastfmBase):
return self.__stats
def getSimilar(self, limit = None):
params = {'method': 'artist.getsimilar', 'artist': self.__name}
params = {'method': 'artist.getSimilar', 'artist': self.__name}
if limit is not None:
params.update({'limit': limit})
data = self.__api._fetchData(params).find('similarartists')
@ -123,7 +123,7 @@ class Artist(LastfmBase):
"""top tags for the artist"""
if self.__topTags is None or len(self.__topTags) < 6:
params = {
'method': 'artist.gettoptags',
'method': 'artist.getTopTags',
'artist': self.__name
}
data = self.__api._fetchData(params).find('toptags')
@ -153,7 +153,7 @@ class Artist(LastfmBase):
@LastfmBase.cachedProperty
def events(self):
"""events for the artist"""
params = {'method': 'artist.getevents', 'artist': self.name}
params = {'method': 'artist.getEvents', 'artist': self.name}
data = self.__api._fetchData(params).find('events')
return [
@ -164,7 +164,7 @@ class Artist(LastfmBase):
@LastfmBase.cachedProperty
def topAlbums(self):
"""top albums of the artist"""
params = {'method': 'artist.gettopalbums', 'artist': self.name}
params = {'method': 'artist.getTopAlbums', 'artist': self.name}
data = self.__api._fetchData(params).find('topalbums')
return [
@ -193,7 +193,7 @@ class Artist(LastfmBase):
@LastfmBase.cachedProperty
def topFans(self):
"""top fans of the artist"""
params = {'method': 'artist.gettopfans', 'artist': self.name}
params = {'method': 'artist.getTopFans', 'artist': self.name}
data = self.__api._fetchData(params).find('topfans')
return [
User(
@ -218,7 +218,7 @@ class Artist(LastfmBase):
@LastfmBase.cachedProperty
def topTracks(self):
"""top tracks of the artist"""
params = {'method': 'artist.gettoptracks', 'artist': self.name}
params = {'method': 'artist.getTopTracks', 'artist': self.name}
data = self.__api._fetchData(params).find('toptracks')
return [
Track(
@ -284,7 +284,7 @@ class Artist(LastfmBase):
def _fetchData(api,
artist = None,
mbid = None):
params = {'method': 'artist.getinfo'}
params = {'method': 'artist.getInfo'}
if not (artist or mbid):
raise LastfmInvalidParametersError("either artist or mbid has to be given as argument.")
if artist:

View File

@ -1,5 +0,0 @@
#!/usr/bin/env python
__author__ = "Abhinav Sarkar <abhinav@abhinavsarkar.net>"
__version__ = "0.2"
__license__ = "GNU Lesser General Public License"

View File

@ -98,7 +98,7 @@ class Event(LastfmBase):
@staticmethod
def getInfo(api, event):
params = {'method': 'event.getinfo', 'event': event}
params = {'method': 'event.getInfo', 'event': event}
data = api._fetchData(params).find('event')
return Event.createFromData(api, data)

View File

@ -15,7 +15,7 @@ class Geo(object):
latitude = None,
longitude = None,
distance = None):
params = {'method': 'geo.getevents', 'location': location}
params = {'method': 'geo.getEvents', 'location': location}
if distance is not None:
params.update({'distance': distance})
@ -44,7 +44,7 @@ class Geo(object):
@staticmethod
def getTopArtists(api, country):
params = {'method': 'geo.gettopartists', 'country': country}
params = {'method': 'geo.getTopArtists', 'country': country}
data = api._fetchData(params).find('topartists')
return [
Artist(
@ -64,7 +64,7 @@ class Geo(object):
@staticmethod
def getTopTracks(api, country, location = None):
params = {'method': 'geo.gettoptracks', 'country': country}
params = {'method': 'geo.getTopTracks', 'country': country}
if location is not None:
params.update({'location': location})

View File

@ -23,7 +23,7 @@ class Group(LastfmBase):
@LastfmBase.cachedProperty
def weeklyChartList(self):
params = {'method': 'group.getweeklychartlist', 'group': self.name}
params = {'method': 'group.getWeeklyChartList', 'group': self.name}
data = self.__api._fetchData(params).find('weeklychartlist')
return [
WeeklyChart.createFromData(self.__api, self, c)
@ -33,7 +33,7 @@ class Group(LastfmBase):
def getWeeklyAlbumChart(self,
start = None,
end = None):
params = {'method': 'group.getweeklyalbumchart', 'group': self.name}
params = {'method': 'group.getWeeklyAlbumChart', 'group': self.name}
params = WeeklyChart._checkWeeklyChartParams(params, start, end)
data = self.__api._fetchData(params).find('weeklyalbumchart')
return WeeklyAlbumChart.createFromData(self.__api, self, data)
@ -55,7 +55,7 @@ class Group(LastfmBase):
def getWeeklyArtistChart(self,
start = None,
end = None):
params = {'method': 'group.getweeklyartistchart', 'group': self.name}
params = {'method': 'group.getWeeklyArtistChart', 'group': self.name}
params = WeeklyChart._checkWeeklyChartParams(params, start, end)
data = self.__api._fetchData(params).find('weeklyartistchart')
return WeeklyArtistChart.createFromData(self.__api, self, data)
@ -77,7 +77,7 @@ class Group(LastfmBase):
def getWeeklyTrackChart(self,
start = None,
end = None):
params = {'method': 'group.getweeklytrackchart', 'group': self.name}
params = {'method': 'group.getWeeklyTrackChart', 'group': self.name}
params = WeeklyChart._checkWeeklyChartParams(params, start, end)
data = self.__api._fetchData(params).find('weeklytrackchart')
return WeeklyTrackChart.createFromData(self.__api, self, data)

View File

@ -48,7 +48,7 @@ class Tag(LastfmBase):
@LastfmBase.cachedProperty
def similar(self):
"""tags similar to this tag"""
params = {'method': 'tag.getsimilar', 'tag': self.name}
params = {'method': 'tag.getSimilar', 'tag': self.name}
data = self.__api._fetchData(params).find('similartags')
return [
Tag(
@ -69,7 +69,7 @@ class Tag(LastfmBase):
@LastfmBase.cachedProperty
def topAlbums(self):
"""top albums for the tag"""
params = {'method': 'tag.gettopalbums', 'tag': self.name}
params = {'method': 'tag.getTopAlbums', 'tag': self.name}
data = self.__api._fetchData(params).find('topalbums')
return [
Album(
@ -103,7 +103,7 @@ class Tag(LastfmBase):
@LastfmBase.cachedProperty
def topArtists(self):
"""top artists for the tag"""
params = {'method': 'tag.gettopartists', 'tag': self.name}
params = {'method': 'tag.getTopArtists', 'tag': self.name}
data = self.__api._fetchData(params).find('topartists')
return [
Artist(
@ -131,7 +131,7 @@ class Tag(LastfmBase):
@LastfmBase.cachedProperty
def topTracks(self):
"""top tracks for the tag"""
params = {'method': 'tag.gettoptracks', 'tag': self.name}
params = {'method': 'tag.getTopTracks', 'tag': self.name}
data = self.__api._fetchData(params).find('toptracks')
return [
Track(

View File

@ -42,6 +42,7 @@ class Track(LastfmBase):
self.__fullTrack = fullTrack
self.__playedOn = playedOn
self.__lovedOn = lovedOn
self.__tags = None
@property
def name(self):
@ -116,7 +117,7 @@ class Track(LastfmBase):
def similar(self):
"""tracks similar to this track"""
params = self.__checkParams(
{'method': 'track.getsimilar'},
{'method': 'track.getSimilar'},
self.artist.name,
self.name,
self.mbid
@ -155,7 +156,7 @@ class Track(LastfmBase):
def topFans(self):
"""top fans of the track"""
params = self.__checkParams(
{'method': 'track.gettopfans'},
{'method': 'track.getTopFans'},
self.artist.name,
self.name,
self.mbid
@ -185,7 +186,7 @@ class Track(LastfmBase):
def topTags(self):
"""top tags for the track"""
params = self.__checkParams(
{'method': 'track.gettoptags'},
{'method': 'track.getTopTags'},
self.artist.name,
self.name,
self.mbid
@ -209,6 +210,63 @@ class Track(LastfmBase):
def topTag(self):
"""topmost tag for the track"""
pass
def getTags(self):
if self.__tags is None:
if not (self.artist and self.name):
raise LastfmInvalidParametersError("artist and track name have to be provided.")
params = {'method': 'track.getTags', 'artist': self.artist.name, 'track': self.name}
data = self.__api._fetchData(params, sign = True, session = True, no_cache = True).find('tags')
self.__tags = [
Tag(
self.__api,
name = t.findtext('name'),
url = t.findtext('url')
)
for t in data.findall('tag')
]
return self.__tags
def addTags(self, tags):
while(len(tags) > 10):
section = tags[0:9]
tags = tags[9:]
self.addTags(section)
if len(tags) == 0: return
tagnames = []
for tag in tags:
if isinstance(tag, Tag):
tagnames.append(tag.name)
elif isinstance(tag, str):
tagnames.append(tag)
params = {
'method': 'track.addTags',
'artist': self.artist.name,
'track': self.name,
'tags': ",".join(tagnames)
}
self.__api._postData(params)
self.__tags = None
def removeTag(self, tag):
if isinstance(tag, Tag):
tag = tag.name
params = {
'method': 'track.removeTag',
'artist': self.artist.name,
'track': self.name,
'tag': tag
}
self.__api._postData(params)
self.__tags = None
def love(self):
params = {'method': 'track.love', 'artist': self.artist.name, 'track': self.name}
self.__api._postData(params)
@staticmethod
def search(api,

View File

@ -51,7 +51,7 @@ class User(LastfmBase):
@LastfmBase.cachedProperty
def events(self):
params = {'method': 'user.getevents', 'user': self.name}
params = {'method': 'user.getEvents', 'user': self.name}
data = self.__api._fetchData(params).find('events')
return [
@ -61,7 +61,7 @@ class User(LastfmBase):
def getPastEvents(self,
limit = None):
params = {'method': 'user.getpastevents', 'user': self.name}
params = {'method': 'user.getPastEvents', 'user': self.name}
if limit is not None:
params.update({'limit': limit})
@ -91,7 +91,7 @@ class User(LastfmBase):
def getFriends(self,
limit = None):
params = {'method': 'user.getfriends', 'user': self.name}
params = {'method': 'user.getFriends', 'user': self.name}
if limit is not None:
params.update({'limit': limit})
data = self.__api._fetchData(params).find('friends')
@ -113,7 +113,7 @@ class User(LastfmBase):
return self.getFriends()
def getNeighbours(self, limit = None):
params = {'method': 'user.getneighbours', 'user': self.name}
params = {'method': 'user.getNeighbours', 'user': self.name}
if limit is not None:
params.update({'limit': limit})
data = self.__api._fetchData(params).find('neighbours')
@ -166,7 +166,7 @@ class User(LastfmBase):
@LastfmBase.cachedProperty
def lovedTracks(self):
params = {'method': 'user.getlovedtracks', 'user': self.name}
params = {'method': 'user.getLovedTracks', 'user': self.name}
data = self.__api._fetchData(params).find('lovedtracks')
return [
Track(
@ -193,7 +193,7 @@ class User(LastfmBase):
]
def getRecentTracks(self, limit = None):
params = {'method': 'user.getrecenttracks', 'user': self.name}
params = {'method': 'user.getRecentTracks', 'user': self.name}
data = self.__api._fetchData(params, no_cache = True).find('recenttracks')
return [
Track(
@ -243,7 +243,7 @@ class User(LastfmBase):
pass
def getTopAlbums(self, period = None):
params = {'method': 'user.gettopalbums', 'user': self.name}
params = {'method': 'user.getTopAlbums', 'user': self.name}
if period is not None:
params.update({'period': period})
data = self.__api._fetchData(params).find('topalbums')
@ -283,7 +283,7 @@ class User(LastfmBase):
pass
def getTopArtists(self, period = None):
params = {'method': 'user.gettopartists', 'user': self.name}
params = {'method': 'user.getTopArtists', 'user': self.name}
if period is not None:
params.update({'period': period})
data = self.__api._fetchData(params).find('topartists')
@ -317,7 +317,7 @@ class User(LastfmBase):
pass
def getTopTracks(self, period = None):
params = {'method': 'user.gettoptracks', 'user': self.name}
params = {'method': 'user.getTopTracks', 'user': self.name}
if period is not None:
params.update({'period': period})
data = self.__api._fetchData(params).find('toptracks')
@ -357,7 +357,7 @@ class User(LastfmBase):
return (len(self.topTracks) and self.topTracks[0] or None)
def getTopTags(self, limit = None):
params = {'method': 'user.gettoptags', 'user': self.name}
params = {'method': 'user.getTopTags', 'user': self.name}
if limit is not None:
params.update({'limit': limit})
data = self.__api._fetchData(params).find('toptags')
@ -387,7 +387,7 @@ class User(LastfmBase):
@LastfmBase.cachedProperty
def weeklyChartList(self):
params = {'method': 'user.getweeklychartlist', 'user': self.name}
params = {'method': 'user.getWeeklyChartList', 'user': self.name}
data = self.__api._fetchData(params).find('weeklychartlist')
return [
WeeklyChart.createFromData(self.__api, self, c)
@ -397,7 +397,7 @@ class User(LastfmBase):
def getWeeklyAlbumChart(self,
start = None,
end = None):
params = {'method': 'user.getweeklyalbumchart', 'user': self.name}
params = {'method': 'user.getWeeklyAlbumChart', 'user': self.name}
params = WeeklyChart._checkWeeklyChartParams(params, start, end)
data = self.__api._fetchData(params).find('weeklyalbumchart')
return WeeklyAlbumChart.createFromData(self.__api, self, data)
@ -422,7 +422,7 @@ class User(LastfmBase):
def getWeeklyArtistChart(self,
start = None,
end = None):
params = {'method': 'user.getweeklyartistchart', 'user': self.name}
params = {'method': 'user.getWeeklyArtistChart', 'user': self.name}
params = WeeklyChart._checkWeeklyChartParams(params, start, end)
data = self.__api._fetchData(params).find('weeklyartistchart')
return WeeklyArtistChart.createFromData(self.__api, self, data)
@ -447,7 +447,7 @@ class User(LastfmBase):
def getWeeklyTrackChart(self,
start = None,
end = None):
params = {'method': 'user.getweeklytrackchart', 'user': self.name}
params = {'method': 'user.getWeeklyTrackChart', 'user': self.name}
params = WeeklyChart._checkWeeklyChartParams(params, start, end)
data = self.__api._fetchData(params).find('weeklytrackchart')
return WeeklyTrackChart.createFromData(self.__api, self, data)
@ -552,7 +552,7 @@ class User(LastfmBase):
def getAlbums(self,
limit = None):
params = {'method': 'library.getalbums', 'user': self.user.name}
params = {'method': 'library.getAlbums', 'user': self.user.name}
if limit is not None:
params.update({'limit': limit})
@ -601,7 +601,7 @@ class User(LastfmBase):
def getArtists(self,
limit = None):
params = {'method': 'library.getartists', 'user': self.user.name}
params = {'method': 'library.getArtists', 'user': self.user.name}
if limit is not None:
params.update({'limit': limit})
@ -644,7 +644,7 @@ class User(LastfmBase):
def getTracks(self,
limit = None):
params = {'method': 'library.gettracks', 'user': self.user.name}
params = {'method': 'library.getTracks', 'user': self.user.name}
if limit is not None:
params.update({'limit': limit})