Fix return object formatting for multi-market searches (#527)

* resolve return object formatting issues referened in #526

* resolve comments from @ritiek

* create separate method to search multiple markets

* Use old description again

* market -> markets + fix test

* pep8

* Use break

Co-authored-by: Stephane Bruckert <contact@stephanebruckert.com>
This commit is contained in:
Nathan LeRoy 2020-07-07 02:20:23 -04:00 committed by GitHub
parent 7eb0eaaebc
commit f7fb8757e9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 90 additions and 67 deletions

View File

@ -508,40 +508,49 @@ class Spotify(object):
tlist = [self._get_id("episode", e) for e in episodes]
return self._get("episodes/?ids=" + ",".join(tlist), market=market)
def search(self, q, limit=10, offset=0, type="track", market=None, total=None):
def search(self, q, limit=10, offset=0, type="track", market=None):
""" searches for an item
Parameters:
- q - the search query (see how to write a query in the
official documentation https://developer.spotify.com/documentation/web-api/reference/search/search/) # noqa
- limit - the number of items to return (min = 1, default = 10, max = 50)
- offset - the index of the first item to return
- type - the type of item to return. One of 'artist', 'album',
'track', 'playlist', 'show', or 'episode'
- market - An ISO 3166-1 alpha-2 country code or the string
from_token.
"""
return self._get(
"search", q=q, limit=limit, offset=offset, type=type, market=market
)
def search_markets(self, q, limit=10, offset=0, type="track", markets=None, total=None):
""" searches multple markets for an item
Parameters:
- q - the search query (see how to write a query in the
official documentation https://developer.spotify.com/documentation/web-api/reference/search/search/) # noqa
- limit - the number of items to return (min = 1, default = 10, max = 50). If a search is to be done on multiple
markets, then this limit is applied to each market. (e.g. search US, CA, MX each with a limit of 10).
- offset - the index of the first item to return
- type - the type of item to return. One of 'artist', 'album',
'track', 'playlist', 'show', or 'episode'
- market - An ISO 3166-1 alpha-2 country code or the string
from_token. Can supply list of markets. Pass "ALL" to search all country codes.
- type - the type's of item's to return. One or more of 'artist', 'album',
'track', 'playlist', 'show', or 'episode'. If multiple types are desired, pass in a comma separated list.
- markets - A list of ISO 3166-1 alpha-2 country codes. Search all country markets by default.
- total - the total number of results to return if multiple markets are supplied in the search.
If multiple types are specified, this only applies to the first type.
"""
if not markets:
markets = self.country_codes
if (isinstance(market, str) and market.upper() == "ALL"):
warnings.warn(
"Searching all markets is poorly performing.",
UserWarning,
)
return self._search_multiple_markets(q, limit, offset, type, self.country_codes, total)
if not (isinstance(markets, list) or isinstance(markets, tuple)):
markets = []
elif isinstance(market, list) or isinstance(market, tuple):
warnings.warn(
"Searching multiple markets is poorly performing.",
UserWarning,
)
return self._search_multiple_markets(q, limit, offset, type, market, total)
else:
return self._get(
"search", q=q, limit=limit, offset=offset, type=type, market=market
)
warnings.warn(
"Searching multiple markets is poorly performing.",
UserWarning,
)
return self._search_multiple_markets(q, limit, offset, type, markets, total)
def user(self, user):
""" Gets basic profile information about a Spotify User
@ -1562,26 +1571,30 @@ class Spotify(object):
return "spotify:" + type + ":" + self._get_id(type, id)
def _search_multiple_markets(self, q, limit, offset, type, markets, total):
results = {
type + 's': {
'href': [],
'items': [],
'limit': limit,
'next': None,
'offset': 0,
'previous': None,
'total': 0
}
}
if total and limit > total:
limit = total
warnings.warn(
"limit was auto-adjusted to equal {} as it must not be higher than total".format(
total),
UserWarning,
)
results = {}
first_type = type.split(",")[0] + 's'
count = 0
for country in markets:
result = self._get(
"search", q=q, limit=limit, offset=offset, type=type, market=country
)
results[type + 's']['href'].append(result[type + 's']['href'])
results[type + 's']['items'] += result[type + 's']['items']
results[type + 's']['total'] += result[type + 's']['total']
if total and len(results[type + 's']['items']) >= total:
# splice 'items' to only include number of results requested
results[type + 's']['items'] = results[type + 's']['items'][:total]
return results
results[country] = result
count += len(result[first_type]['items'])
if total and count >= total:
break
if total and limit > total - count:
# when approaching `total` results, adjust `limit` to not request more
# items than needed
limit = total - count
return results

View File

@ -176,38 +176,48 @@ class AuthTestSpotipy(unittest.TestCase):
self.assertTrue(results['artists']['items'][0]['name'] == 'Weezer')
def test_artist_search_with_multiple_markets(self):
TOTAL = 3
results_single = self.spotify.search(q='weezer', type='artist', market='US')
results_multiple = self.spotify.search(q='weezer', type='artist',
market=['GB', 'US', 'AU'])
results_all = self.spotify.search(q='weezer', type='artist', market="ALL")
results_limited = self.spotify.search(q='weezer', type='artist',
market=['GB', 'US', 'AU'], total=TOTAL)
total = 5
countries_list = ['GB', 'US', 'AU']
countries_tuple = ('GB', 'US', 'AU')
results_tuple = self.spotify.search(q='weezer', type='artist',
market=('GB', 'US', 'AU'), total=TOTAL)
results_multiple = self.spotify.search_markets(q='weezer', type='artist',
markets=countries_list)
results_all = self.spotify.search_markets(q='weezer', type='artist')
results_tuple = self.spotify.search_markets(q='weezer', type='artist',
markets=countries_tuple)
results_limited = self.spotify.search_markets(q='weezer', limit=3, type='artist',
markets=countries_list, total=total)
self.assertTrue('artists' in results_multiple)
self.assertTrue('artists' in results_all)
self.assertTrue('artists' in results_limited)
self.assertTrue('artists' in results_tuple)
self.assertTrue(
all('artists' in results_multiple[country] for country in results_multiple))
self.assertTrue(all('artists' in results_all[country] for country in results_all))
self.assertTrue(all('artists' in results_tuple[country] for country in results_tuple))
self.assertTrue(all('artists' in results_limited[country] for country in results_limited))
self.assertTrue(len(results_multiple['artists']['items']) > 0)
self.assertTrue(len(results_all['artists']['items']) > 0)
self.assertTrue(len(results_limited['artists']['items']) > 0)
self.assertTrue(len(results_tuple['artists']['items']) > 0)
self.assertTrue(
all(len(results_multiple[country]['artists']['items']) > 0 for country in
results_multiple))
self.assertTrue(all(len(results_all[country]['artists']
['items']) > 0 for country in results_all))
self.assertTrue(
all(len(results_tuple[country]['artists']['items']) > 0 for country in results_tuple))
self.assertTrue(
all(len(results_limited[country]['artists']['items']) > 0 for country in
results_limited))
self.assertTrue(len(results_all['artists']['items']) >
len(results_multiple['artists']['items']))
self.assertTrue(len(results_multiple['artists']['items'])
> len(results_single['artists']['items']))
self.assertTrue(all(results_multiple[country]['artists']['items']
[0]['name'] == 'Weezer' for country in results_multiple))
self.assertTrue(all(results_all[country]['artists']['items']
[0]['name'] == 'Weezer' for country in results_all))
self.assertTrue(all(results_tuple[country]['artists']['items']
[0]['name'] == 'Weezer' for country in results_tuple))
self.assertTrue(all(results_limited[country]['artists']['items']
[0]['name'] == 'Weezer' for country in results_limited))
self.assertTrue(results_multiple['artists']['items'][0]['name'] == 'Weezer')
self.assertTrue(results_all['artists']['items'][0]['name'] == 'Weezer')
self.assertTrue(results_limited['artists']['items'][0]['name'] == 'Weezer')
self.assertTrue(results_tuple['artists']['items'][0]['name'] == 'Weezer')
self.assertTrue(len(results_limited['artists']['items']) <= TOTAL)
total_limited_results = 0
for country in results_limited:
total_limited_results += len(results_limited[country]['artists']['items'])
self.assertTrue(total_limited_results <= total)
def test_artist_albums(self):
results = self.spotify.artist_albums(self.weezer_urn)