Add linter, solves #348 (#415)

This commit is contained in:
Stéphane Bruckert 2020-01-12 13:19:40 +00:00 committed by GitHub
parent 5928981e3b
commit f54830e272
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 324 additions and 248 deletions

View File

@ -4,6 +4,7 @@ import spotipy
''' shows the albums and tracks for a given artist. ''' shows the albums and tracks for a given artist.
''' '''
def get_artist(name): def get_artist(name):
results = sp.search(q='artist:' + name, type='artist') results = sp.search(q='artist:' + name, type='artist')
items = results['artists']['items'] items = results['artists']['items']
@ -12,6 +13,7 @@ def get_artist(name):
else: else:
return None return None
def show_artist_albums(artist): def show_artist_albums(artist):
albums = [] albums = []
results = sp.artist_albums(artist['id'], album_type='album') results = sp.artist_albums(artist['id'], album_type='album')
@ -19,7 +21,7 @@ def show_artist_albums(artist):
while results['next']: while results['next']:
results = sp.next(results) results = sp.next(results)
albums.extend(results['items']) albums.extend(results['items'])
seen = set() # to avoid dups seen = set() # to avoid dups
albums.sort(key=lambda album: album['name'].lower()) albums.sort(key=lambda album: album['name'].lower())
for album in albums: for album in albums:
name = album['name'] name = album['name']
@ -27,6 +29,7 @@ def show_artist_albums(artist):
print((' ' + name)) print((' ' + name))
seen.add(name) seen.add(name)
if __name__ == '__main__': if __name__ == '__main__':
sp = spotipy.Spotify() sp = spotipy.Spotify()

View File

@ -4,6 +4,7 @@ import spotipy
''' shows the albums and tracks for a given artist. ''' shows the albums and tracks for a given artist.
''' '''
def get_artist(name): def get_artist(name):
results = sp.search(q='artist:' + name, type='artist') results = sp.search(q='artist:' + name, type='artist')
items = results['artists']['items'] items = results['artists']['items']
@ -12,6 +13,7 @@ def get_artist(name):
else: else:
return None return None
def show_album_tracks(album): def show_album_tracks(album):
tracks = [] tracks = []
results = sp.album_tracks(album['id']) results = sp.album_tracks(album['id'])
@ -24,6 +26,7 @@ def show_album_tracks(album):
print() print()
print(track) print(track)
def show_artist_albums(id): def show_artist_albums(id):
albums = [] albums = []
results = sp.artist_albums(artist['id'], album_type='album') results = sp.artist_albums(artist['id'], album_type='album')
@ -35,17 +38,19 @@ def show_artist_albums(id):
unique = set() # skip duplicate albums unique = set() # skip duplicate albums
for album in albums: for album in albums:
name = album['name'].lower() name = album['name'].lower()
if not name in unique: if name not in unique:
print(name) print(name)
unique.add(name) unique.add(name)
show_album_tracks(album) show_album_tracks(album)
def show_artist(artist): def show_artist(artist):
print('====', artist['name'], '====') print('====', artist['name'], '====')
print('Popularity: ', artist['popularity']) print('Popularity: ', artist['popularity'])
if len(artist['genres']) > 0: if len(artist['genres']) > 0:
print('Genres: ', ','.join(artist['genres'])) print('Genres: ', ','.join(artist['genres']))
if __name__ == '__main__': if __name__ == '__main__':
sp = spotipy.Spotify() sp = spotipy.Spotify()
sp.trace = False sp.trace = False

View File

@ -7,7 +7,8 @@ import spotipy
from spotipy.oauth2 import SpotifyClientCredentials from spotipy.oauth2 import SpotifyClientCredentials
client_credentials_manager = SpotifyClientCredentials() client_credentials_manager = SpotifyClientCredentials()
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager) sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
sp.trace=False sp.trace = False
def get_artist(name): def get_artist(name):
results = sp.search(q='artist:' + name, type='artist') results = sp.search(q='artist:' + name, type='artist')
@ -17,11 +18,12 @@ def get_artist(name):
else: else:
return None return None
def show_recommendations_for_artist(artist): def show_recommendations_for_artist(artist):
albums = []
results = sp.recommendations(seed_artists=[artist['id']]) results = sp.recommendations(seed_artists=[artist['id']])
for track in results['tracks']: for track in results['tracks']:
print track['name'], '-', track['artists'][0]['name'] print(track['name'], '-', track['artists'][0]['name'])
if __name__ == '__main__': if __name__ == '__main__':
if len(sys.argv) < 2: if len(sys.argv) < 2:
@ -32,4 +34,4 @@ if __name__ == '__main__':
if artist: if artist:
show_recommendations_for_artist(artist) show_recommendations_for_artist(artist)
else: else:
print "Can't find that artist", name print("Can't find that artist", name)

View File

@ -11,7 +11,7 @@ import sys
client_credentials_manager = SpotifyClientCredentials() client_credentials_manager = SpotifyClientCredentials()
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager) sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
sp.trace=False sp.trace = False
if len(sys.argv) > 1: if len(sys.argv) > 1:
artist_name = ' '.join(sys.argv[1:]) artist_name = ' '.join(sys.argv[1:])

View File

@ -12,7 +12,7 @@ import sys
client_credentials_manager = SpotifyClientCredentials() client_credentials_manager = SpotifyClientCredentials()
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager) sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
sp.trace=True sp.trace = True
if len(sys.argv) > 1: if len(sys.argv) > 1:
tids = sys.argv[1:] tids = sys.argv[1:]

View File

@ -25,7 +25,7 @@ if len(sys.argv) > 3:
else: else:
print("Usage: %s username playlist_id name [public collaborative " print("Usage: %s username playlist_id name [public collaborative "
"description]" % (sys.argv[0])) "description]" % (sys.argv[0]))
sys.exit() sys.exit()
scope = 'playlist-modify-public playlist-modify-private' scope = 'playlist-modify-public playlist-modify-private'
@ -37,6 +37,6 @@ if token:
results = sp.user_playlist_change_details( results = sp.user_playlist_change_details(
username, playlist_id, name=name, public=public, username, playlist_id, name=name, public=public,
collaborative=collaborative, description=description) collaborative=collaborative, description=description)
print results print(results)
else: else:
print "Can't get token for", username print("Can't get token for"), username

View File

@ -12,7 +12,9 @@ if len(sys.argv) > 2:
playlist_name = sys.argv[2] playlist_name = sys.argv[2]
playlist_description = sys.argv[3] playlist_description = sys.argv[3]
else: else:
print("Usage: %s username playlist-name playlist-description" % (sys.argv[0],)) print(
"Usage: %s username playlist-name playlist-description" %
(sys.argv[0],))
sys.exit() sys.exit()
scope = "playlist-modify-public" scope = "playlist-modify-public"

View File

@ -7,7 +7,7 @@ import spotipy
client_credentials_manager = SpotifyClientCredentials() client_credentials_manager = SpotifyClientCredentials()
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager) sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
sp.trace=True sp.trace = True
try: try:
print('bad call 0') print('bad call 0')
bad_artist_call = sp.artist('spotify:artist:12341234') bad_artist_call = sp.artist('spotify:artist:12341234')
@ -17,4 +17,3 @@ except spotipy.client.SpotifyException:
print('bad call 1') print('bad call 1')
bad_artist_call = sp.artist('spotify:artist:12341234') bad_artist_call = sp.artist('spotify:artist:12341234')
print('bad artist', bad_artist_call) print('bad artist', bad_artist_call)

View File

@ -19,6 +19,6 @@ if token:
sp.trace = False sp.trace = False
results = sp.current_user_playlists(limit=50) results = sp.current_user_playlists(limit=50)
for i, item in enumerate(results['items']): for i, item in enumerate(results['items']):
print("%d %s" %(i, item['name'])) print("%d %s" % (i, item['name']))
else: else:
print("Can't get token for", username) print("Can't get token for", username)

View File

@ -1,11 +1,9 @@
# Shows the top artists for a user # Shows the top artists for a user
import pprint
import sys import sys
import spotipy import spotipy
import spotipy.util as util import spotipy.util as util
import simplejson as json
if len(sys.argv) > 1: if len(sys.argv) > 1:
username = sys.argv[1] username = sys.argv[1]
@ -21,10 +19,10 @@ if token:
sp.trace = False sp.trace = False
ranges = ['short_term', 'medium_term', 'long_term'] ranges = ['short_term', 'medium_term', 'long_term']
for range in ranges: for range in ranges:
print ("range:", range) print("range:", range)
results = sp.current_user_top_artists(time_range=range, limit=50) results = sp.current_user_top_artists(time_range=range, limit=50)
for i, item in enumerate(results['items']): for i, item in enumerate(results['items']):
print (i, item['name']) print(i, item['name'])
print () print()
else: else:
print("Can't get token for", username) print("Can't get token for", username)

View File

@ -1,11 +1,9 @@
# Shows the top tracks for a user # Shows the top tracks for a user
import pprint
import sys import sys
import spotipy import spotipy
import spotipy.util as util import spotipy.util as util
import simplejson as json
if len(sys.argv) > 1: if len(sys.argv) > 1:
username = sys.argv[1] username = sys.argv[1]
@ -21,11 +19,11 @@ if token:
sp.trace = False sp.trace = False
ranges = ['short_term', 'medium_term', 'long_term'] ranges = ['short_term', 'medium_term', 'long_term']
for range in ranges: for range in ranges:
print ("range:", range) print("range:", range)
results = sp.current_user_top_tracks(time_range=range, limit=50) results = sp.current_user_top_tracks(time_range=range, limit=50)
for i, item in enumerate(results['items']): for i, item in enumerate(results['items']):
print (i, item['name'], '//', item['artists'][0]['name']) print(i, item['name'], '//', item['artists'][0]['name'])
print () print()
else: else:
print("Can't get token for", username) print("Can't get token for", username)

View File

@ -10,4 +10,4 @@ username = uri.split(':')[2]
playlist_id = uri.split(':')[4] playlist_id = uri.split(':')[4]
results = sp.user_playlist(username, playlist_id) results = sp.user_playlist(username, playlist_id)
print (json.dumps(results, indent=4)) print(json.dumps(results, indent=4))

View File

@ -15,7 +15,9 @@ if len(sys.argv) > 3:
tid, pos = t_pos.split(',') tid, pos = t_pos.split(',')
track_ids.append({"uri": tid, "positions": [int(pos)]}) track_ids.append({"uri": tid, "positions": [int(pos)]})
else: else:
print("Usage: %s username playlist_id track_id,pos track_id,pos ..." % (sys.argv[0],)) print(
"Usage: %s username playlist_id track_id,pos track_id,pos ..." %
(sys.argv[0],))
sys.exit() sys.exit()
scope = 'playlist-modify-public' scope = 'playlist-modify-public'
@ -24,7 +26,8 @@ token = util.prompt_for_user_token(username, scope)
if token: if token:
sp = spotipy.Spotify(auth=token) sp = spotipy.Spotify(auth=token)
sp.trace = False sp.trace = False
results = sp.user_playlist_remove_specific_occurrences_of_tracks(username, playlist_id, track_ids) results = sp.user_playlist_remove_specific_occurrences_of_tracks(
username, playlist_id, track_ids)
pprint.pprint(results) pprint.pprint(results)
else: else:
print("Can't get token for", username) print("Can't get token for", username)

View File

@ -20,7 +20,8 @@ token = util.prompt_for_user_token(username, scope)
if token: if token:
sp = spotipy.Spotify(auth=token) sp = spotipy.Spotify(auth=token)
sp.trace = False sp.trace = False
results = sp.user_playlist_remove_all_occurrences_of_tracks(username, playlist_id, track_ids) results = sp.user_playlist_remove_all_occurrences_of_tracks(
username, playlist_id, track_ids)
pprint.pprint(results) pprint.pprint(results)
else: else:
print("Can't get token for", username) print("Can't get token for", username)

View File

@ -22,6 +22,5 @@ try:
print('Related artists for', name) print('Related artists for', name)
for artist in related['artists']: for artist in related['artists']:
print(' ', artist['name']) print(' ', artist['name'])
except: except BaseException:
print("usage show_related.py [artist-name]") print("usage show_related.py [artist-name]")

View File

@ -19,6 +19,3 @@ if __name__ == '__main__':
results = sp.tracks(tids[start: start + max_tracks_per_call]) results = sp.tracks(tids[start: start + max_tracks_per_call])
for track in results['tracks']: for track in results['tracks']:
print(track['name'] + ' - ' + track['artists'][0]['name']) print(track['name'] + ' - ' + track['artists'][0]['name'])

View File

@ -14,4 +14,3 @@ sp = spotipy.Spotify()
sp.trace = True sp.trace = True
user = sp.user(username) user = sp.user(username)
pprint.pprint(user) pprint.pprint(user)

View File

@ -14,4 +14,3 @@ while results['next']:
for album in albums: for album in albums:
print((album['name'])) print((album['name']))

View File

@ -15,4 +15,3 @@ items = results['artists']['items']
if len(items) > 0: if len(items) > 0:
artist = items[0] artist = items[0]
print(artist['name'], artist['images'][0]['url']) print(artist['name'], artist['images'][0]['url'])

View File

@ -1,6 +1,5 @@
import spotipy import spotipy
import random import random
import simplejson as json
''' '''
generates a list of songs where the first word in each subsequent song generates a list of songs where the first word in each subsequent song
@ -14,13 +13,14 @@ skiplist = set(['dm', 'remix'])
max_offset = 500 max_offset = 500
seen = set() seen = set()
def find_songs_that_start_with_word(word): def find_songs_that_start_with_word(word):
max_titles = 20 max_titles = 20
max_offset = 200 max_offset = 200
offset = 0 offset = 0
out = [] out = []
while offset < max_offset and len(out) < max_titles: while offset < max_offset and len(out) < max_titles:
results = sp.search(q=word, type='track', limit=50, offset=offset) results = sp.search(q=word, type='track', limit=50, offset=offset)
if len(results['tracks']['items']) == 0: if len(results['tracks']['items']) == 0:
break break
@ -37,27 +37,29 @@ def find_songs_that_start_with_word(word):
if '/' in name: if '/' in name:
continue continue
words = name.split() words = name.split()
if len(words) > 1 and words[0] == word and words[-1] not in skiplist: if len(words) > 1 and words[0] == word \
#print " ", name, len(out) and words[-1] not in skiplist:
# print " ", name, len(out)
out.append(item) out.append(item)
offset += 50 offset += 50
#print "found", len(out), "matches" # print "found", len(out), "matches"
return out return out
def make_chain(word): def make_chain(word):
which = 1 which = 1
while True: while True:
songs = find_songs_that_start_with_word(word) songs = find_songs_that_start_with_word(word)
if len(songs) > 0: if len(songs) > 0:
song = random.choice(songs) song = random.choice(songs)
print which, song['name'] + " by " + song['artists'][0]['name'] print(which, song['name'] + " by " + song['artists'][0]['name'])
which += 1 which += 1
word = song['name'].lower().split()[-1] word = song['name'].lower().split()[-1]
else: else:
break break
if __name__ == '__main__': if __name__ == '__main__':
import sys import sys
title = ' '.join(sys.argv[1:]) title = ' '.join(sys.argv[1:])
make_chain(sys.argv[1].lower()) make_chain(sys.argv[1].lower())

View File

@ -4,10 +4,13 @@ import sys
import spotipy import spotipy
import spotipy.util as util import spotipy.util as util
def show_tracks(results): def show_tracks(results):
for i, item in enumerate(results['items']): for i, item in enumerate(results['items']):
track = item['track'] track = item['track']
print(" %d %32.32s %s" % (i, track['artists'][0]['name'], track['name'])) print(
" %d %32.32s %s" %
(i, track['artists'][0]['name'], track['name']))
if __name__ == '__main__': if __name__ == '__main__':
@ -28,7 +31,8 @@ if __name__ == '__main__':
print() print()
print(playlist['name']) print(playlist['name'])
print(' total tracks', playlist['tracks']['total']) print(' total tracks', playlist['tracks']['total'])
results = sp.user_playlist(username, playlist['id'], fields="tracks,next") results = sp.user_playlist(
username, playlist['id'], fields="tracks,next")
tracks = results['tracks'] tracks = results['tracks']
show_tracks(tracks) show_tracks(tracks)
while tracks['next']: while tracks['next']:
@ -36,4 +40,3 @@ if __name__ == '__main__':
show_tracks(tracks) show_tracks(tracks)
else: else:
print("Can't get token for", username) print("Can't get token for", username)

View File

@ -18,7 +18,13 @@ playlists = sp.user_playlists(user)
while playlists: while playlists:
for i, playlist in enumerate(playlists['items']): for i, playlist in enumerate(playlists['items']):
print("%4d %s %s" % (i + 1 + playlists['offset'], playlist['uri'], playlist['name'])) print(
"%4d %s %s" %
(i +
1 +
playlists['offset'],
playlist['uri'],
playlist['name']))
if playlists['next']: if playlists['next']:
playlists = sp.next(playlists) playlists = sp.next(playlists)
else: else:

View File

@ -3,9 +3,7 @@
""" """
import pprint
import sys import sys
import json
import spotipy import spotipy
import spotipy.util as util import spotipy.util as util

View File

@ -5,7 +5,6 @@ import spotipy
import spotipy.util as util import spotipy.util as util
if len(sys.argv) > 1: if len(sys.argv) > 1:
username = sys.argv[1] username = sys.argv[1]
else: else:

View File

@ -1,9 +1,11 @@
from setuptools import setup from setuptools import setup
desc = """### A light weight Python library for the Spotify Web API"""
setup( setup(
name='spotipy', name='spotipy',
version='2.5.0', version='2.5.0',
long_description="""### A light weight Python library for the Spotify Web API""", long_description=desc,
long_description_content_type='text/markdown', long_description_content_type='text/markdown',
author="@plamere", author="@plamere",
author_email="paul@echonest.com", author_email="paul@echonest.com",
@ -12,7 +14,6 @@ setup(
'mock>=2.0.0', 'mock>=2.0.0',
'requests>=2.3.0', 'requests>=2.3.0',
'six>=1.10.0', 'six>=1.10.0',
'simplejson==3.13.2', ],
],
license='LICENSE.txt', license='LICENSE.txt',
packages=['spotipy']) packages=['spotipy'])

View File

@ -1,3 +1,3 @@
from .client import * from .client import * # noqa
from .oauth2 import * from .oauth2 import * # noqa
from .util import * from .util import * # noqa

View File

@ -17,7 +17,6 @@ import requests
import six import six
class SpotifyException(Exception): class SpotifyException(Exception):
def __init__(self, http_status, code, msg, headers=None): def __init__(self, http_status, code, msg, headers=None):
self.http_status = http_status self.http_status = http_status
@ -58,7 +57,8 @@ class Spotify(object):
max_get_retries = 10 max_get_retries = 10
def __init__(self, auth=None, requests_session=True, def __init__(self, auth=None, requests_session=True,
client_credentials_manager=None, proxies=None, requests_timeout=None): client_credentials_manager=None, proxies=None,
requests_timeout=None):
""" """
Creates a Spotify API client. Creates a Spotify API client.
@ -73,7 +73,8 @@ class Spotify(object):
:param proxies: :param proxies:
Definition of proxies (optional) Definition of proxies (optional)
:param requests_timeout: :param requests_timeout:
Tell Requests to stop waiting for a response after a given number of seconds Tell Requests to stop waiting for a response after a given
number of seconds
""" """
self.prefix = 'https://api.spotify.com/v1/' self.prefix = 'https://api.spotify.com/v1/'
self._auth = auth self._auth = auth
@ -112,26 +113,33 @@ class Spotify(object):
if self.trace_out: if self.trace_out:
print(url) print(url)
r = self._session.request(method, url, headers=headers, proxies=self.proxies, **args) r = self._session.request(
method,
url,
headers=headers,
proxies=self.proxies,
**args)
if self.trace: # pragma: no cover if self.trace: # pragma: no cover
print() print()
print ('headers', headers) print('headers', headers)
print ('http status', r.status_code) print('http status', r.status_code)
print(method, r.url) print(method, r.url)
if payload: if payload:
print("DATA", json.dumps(payload)) print("DATA", json.dumps(payload))
try: try:
r.raise_for_status() r.raise_for_status()
except: except BaseException:
if r.text and len(r.text) > 0 and r.text != 'null': if r.text and len(r.text) > 0 and r.text != 'null':
msg = '%s:\n %s' % (r.url, r.json()['error']['message'])
raise SpotifyException(r.status_code, raise SpotifyException(r.status_code,
-1, '%s:\n %s' % (r.url, r.json()['error']['message']), -1, msg,
headers=r.headers) headers=r.headers)
else: else:
raise SpotifyException(r.status_code, raise SpotifyException(r.status_code,
-1, '%s:\n %s' % (r.url, 'error'), headers=r.headers) -1, '%s:\n %s' % (r.url, 'error'),
headers=r.headers)
finally: finally:
if hasattr(r, "connection"): if hasattr(r, "connection"):
r.connection.close() r.connection.close()
@ -160,21 +168,22 @@ class Spotify(object):
if retries < 0: if retries < 0:
raise raise
else: else:
sleep_seconds = int(e.headers.get('Retry-After', delay)) sleep_seconds = int(
print ('retrying ...' + str(sleep_seconds) + 'secs') e.headers.get('Retry-After', delay))
print('retrying ...' + str(sleep_seconds) + 'secs')
time.sleep(sleep_seconds + 1) time.sleep(sleep_seconds + 1)
delay += 1 delay += 1
else: else:
raise raise
except Exception as e: except Exception as e:
raise raise
print ('exception', str(e)) print('exception', str(e))
# some other exception. Requests have # some other exception. Requests have
# been know to throw a BadStatusLine exception # been know to throw a BadStatusLine exception
retries -= 1 retries -= 1
if retries >= 0: if retries >= 0:
sleep_seconds = int(e.headers.get('Retry-After', delay)) sleep_seconds = int(e.headers.get('Retry-After', delay))
print ('retrying ...' + str(delay) + 'secs') print('retrying ...' + str(delay) + 'secs')
time.sleep(sleep_seconds + 1) time.sleep(sleep_seconds + 1)
delay += 1 delay += 1
else: else:
@ -233,7 +242,7 @@ class Spotify(object):
trid = self._get_id('track', track_id) trid = self._get_id('track', track_id)
return self._get('tracks/' + trid) return self._get('tracks/' + trid)
def tracks(self, tracks, market = None): def tracks(self, tracks, market=None):
""" returns a list of tracks given a list of track IDs, URIs, or URLs """ returns a list of tracks given a list of track IDs, URIs, or URLs
Parameters: Parameters:
@ -242,7 +251,7 @@ class Spotify(object):
""" """
tlist = [self._get_id('track', t) for t in tracks] tlist = [self._get_id('track', t) for t in tracks]
return self._get('tracks/?ids=' + ','.join(tlist), market = market) return self._get('tracks/?ids=' + ','.join(tlist), market=market)
def artist(self, artist_id): def artist(self, artist_id):
""" returns a single artist given the artist's ID, URI or URL """ returns a single artist given the artist's ID, URI or URL
@ -345,9 +354,11 @@ class Spotify(object):
- offset - the index of the first item to return - offset - the index of the first item to return
- type - the type of item to return. One of 'artist', 'album', - type - the type of item to return. One of 'artist', 'album',
'track' or 'playlist' 'track' or 'playlist'
- market - An ISO 3166-1 alpha-2 country code or the string from_token. - 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) return self._get('search', q=q, limit=limit,
offset=offset, type=type, market=market)
def user(self, user): def user(self, user):
""" Gets basic profile information about a Spotify User """ Gets basic profile information about a Spotify User
@ -394,12 +405,12 @@ class Spotify(object):
Parameters: Parameters:
- playlist - the id of the playlist - playlist - the id of the playlist
- fields - which fields to return - fields - which fields to return
- market - An ISO 3166-1 alpha-2 country code or the string from_token. - market - An ISO 3166-1 alpha-2 country code or the string
from_token.
""" """
plid = self._get_id('playlist', playlist_id) plid = self._get_id('playlist', playlist_id)
return self._get("playlists/%s" % (plid), fields=fields) return self._get("playlists/%s" % (plid), fields=fields)
def user_playlist_tracks(self, user, playlist_id=None, fields=None, def user_playlist_tracks(self, user, playlist_id=None, fields=None,
limit=100, offset=0, market=None): limit=100, offset=0, market=None):
""" Get full details of the tracks of a playlist owned by a user. """ Get full details of the tracks of a playlist owned by a user.
@ -417,7 +428,6 @@ class Spotify(object):
limit=limit, offset=offset, fields=fields, limit=limit, offset=offset, fields=fields,
market=market) market=market)
def user_playlist_create(self, user, name, public=True, description=''): def user_playlist_create(self, user, name, public=True, description=''):
""" Creates a playlist for a user """ Creates a playlist for a user
@ -429,7 +439,6 @@ class Spotify(object):
""" """
data = {'name': name, 'public': public, 'description': description} data = {'name': name, 'public': public, 'description': description}
return self._post("users/%s/playlists" % (user,), payload=data) return self._post("users/%s/playlists" % (user,), payload=data)
def user_playlist_change_details( def user_playlist_change_details(
@ -465,7 +474,8 @@ class Spotify(object):
- user - the id of the user - user - the id of the user
- name - the name of the playlist - name - the name of the playlist
""" """
return self._delete("users/%s/playlists/%s/followers" % (user, playlist_id)) return self._delete("users/%s/playlists/%s/followers" %
(user, playlist_id))
def user_playlist_add_tracks(self, user, playlist_id, tracks, def user_playlist_add_tracks(self, user, playlist_id, tracks,
position=None): position=None):
@ -505,8 +515,10 @@ class Spotify(object):
- user - the id of the user - user - the id of the user
- playlist_id - the id of the playlist - playlist_id - the id of the playlist
- range_start - the position of the first track to be reordered - range_start - the position of the first track to be reordered
- range_length - optional the number of tracks to be reordered (default: 1) - range_length - optional the number of tracks to be reordered
- insert_before - the position where the tracks should be inserted (default: 1)
- insert_before - the position where the tracks should be
inserted
- snapshot_id - optional playlist's snapshot ID - snapshot_id - optional playlist's snapshot ID
""" """
plid = self._get_id('playlist', playlist_id) plid = self._get_id('playlist', playlist_id)
@ -575,9 +587,12 @@ class Spotify(object):
- playlist_id - the id of the playlist - playlist_id - the id of the playlist
""" """
return self._put("users/{}/playlists/{}/followers".format(playlist_owner_id, playlist_id)) return self._put(
"users/{}/playlists/{}/followers".format(playlist_owner_id,
playlist_id))
def user_playlist_is_following(self, playlist_owner_id, playlist_id, user_ids): def user_playlist_is_following(
self, playlist_owner_id, playlist_id, user_ids):
""" """
Check to see if the given users are following the given playlist Check to see if the given users are following the given playlist
@ -588,7 +603,10 @@ class Spotify(object):
if they follow the playlist. Maximum: 5 ids. if they follow the playlist. Maximum: 5 ids.
""" """
return self._get("users/{}/playlists/{}/followers/contains?ids={}".format(playlist_owner_id, playlist_id, ','.join(user_ids))) endpoint = "users/{}/playlists/{}/followers/contains?ids={}"
return self._get(endpoint.format(playlist_owner_id,
playlist_id,
','.join(user_ids)))
def me(self): def me(self):
""" Get detailed profile information about the current user. """ Get detailed profile information about the current user.
@ -623,7 +641,8 @@ class Spotify(object):
Parameters: Parameters:
- limit - the number of artists to return - limit - the number of artists to return
- after - the last artist ID retrieved from the previous request - after - the last artist ID retrieved from the previous
request
""" """
return self._get('me/following', type='artist', limit=limit, return self._get('me/following', type='artist', limit=limit,
@ -858,17 +877,18 @@ class Spotify(object):
- seed_tracks - a list of track IDs, URIs or URLs - seed_tracks - a list of track IDs, URIs or URLs
- seed_genres - a list of genre names. Available genres for - seed_genres - a list of genre names. Available genres for
recommendations can be found by calling recommendation_genre_seeds recommendations can be found by calling
recommendation_genre_seeds
- country - An ISO 3166-1 alpha-2 country code. If provided, all - country - An ISO 3166-1 alpha-2 country code. If provided,
results will be playable in this country. all results will be playable in this country.
- limit - The maximum number of items to return. Default: 20. - limit - The maximum number of items to return. Default: 20.
Minimum: 1. Maximum: 100 Minimum: 1. Maximum: 100
- min/max/target_<attribute> - For the tuneable track attributes listed - min/max/target_<attribute> - For the tuneable track
in the documentation, these values provide filters and targeting on attributes listed in the documentation, these values
results. provide filters and targeting on results.
""" """
params = dict(limit=limit) params = dict(limit=limit)
if seed_artists: if seed_artists:
@ -928,23 +948,23 @@ class Spotify(object):
''' '''
return self._get("me/player/devices") return self._get("me/player/devices")
def current_playback(self, market = None): def current_playback(self, market=None):
''' Get information about user's current playback. ''' Get information about user's current playback.
Parameters: Parameters:
- market - an ISO 3166-1 alpha-2 country code. - market - an ISO 3166-1 alpha-2 country code.
''' '''
return self._get("me/player", market = market) return self._get("me/player", market=market)
def currently_playing(self, market = None): def currently_playing(self, market=None):
''' Get user's currently playing track. ''' Get user's currently playing track.
Parameters: Parameters:
- market - an ISO 3166-1 alpha-2 country code. - market - an ISO 3166-1 alpha-2 country code.
''' '''
return self._get("me/player/currently-playing", market = market) return self._get("me/player/currently-playing", market=market)
def transfer_playback(self, device_id, force_play = True): def transfer_playback(self, device_id, force_play=True):
''' Transfer playback to another device. ''' Transfer playback to another device.
Note that the API accepts a list of device ids, but only Note that the API accepts a list of device ids, but only
actually supports one. actually supports one.
@ -960,7 +980,8 @@ class Spotify(object):
} }
return self._put("me/player", payload=data) return self._put("me/player", payload=data)
def start_playback(self, device_id = None, context_uri = None, uris = None, offset = None): def start_playback(self, device_id=None,
context_uri=None, uris=None, offset=None):
''' Start or resume user's playback. ''' Start or resume user's playback.
Provide a `context_uri` to start playback or a album, Provide a `context_uri` to start playback or a album,
@ -991,9 +1012,10 @@ class Spotify(object):
data['uris'] = uris data['uris'] = uris
if offset is not None: if offset is not None:
data['offset'] = offset data['offset'] = offset
return self._put(self._append_device_id("me/player/play", device_id), payload=data) return self._put(self._append_device_id(
"me/player/play", device_id), payload=data)
def pause_playback(self, device_id = None): def pause_playback(self, device_id=None):
''' Pause user's playback. ''' Pause user's playback.
Parameters: Parameters:
@ -1001,7 +1023,7 @@ class Spotify(object):
''' '''
return self._put(self._append_device_id("me/player/pause", device_id)) return self._put(self._append_device_id("me/player/pause", device_id))
def next_track(self, device_id = None): def next_track(self, device_id=None):
''' Skip user's playback to next track. ''' Skip user's playback to next track.
Parameters: Parameters:
@ -1009,15 +1031,16 @@ class Spotify(object):
''' '''
return self._post(self._append_device_id("me/player/next", device_id)) return self._post(self._append_device_id("me/player/next", device_id))
def previous_track(self, device_id = None): def previous_track(self, device_id=None):
''' Skip user's playback to previous track. ''' Skip user's playback to previous track.
Parameters: Parameters:
- device_id - device target for playback - device_id - device target for playback
''' '''
return self._post(self._append_device_id("me/player/previous", device_id)) return self._post(self._append_device_id(
"me/player/previous", device_id))
def seek_track(self, position_ms, device_id = None): def seek_track(self, position_ms, device_id=None):
''' Seek to position in current track. ''' Seek to position in current track.
Parameters: Parameters:
@ -1027,9 +1050,10 @@ class Spotify(object):
if not isinstance(position_ms, int): if not isinstance(position_ms, int):
self._warn('position_ms must be an integer') self._warn('position_ms must be an integer')
return return
return self._put(self._append_device_id("me/player/seek?position_ms=%s" % position_ms, device_id)) return self._put(self._append_device_id(
"me/player/seek?position_ms=%s" % position_ms, device_id))
def repeat(self, state, device_id = None): def repeat(self, state, device_id=None):
''' Set repeat mode for playback. ''' Set repeat mode for playback.
Parameters: Parameters:
@ -1039,9 +1063,12 @@ class Spotify(object):
if state not in ['track', 'context', 'off']: if state not in ['track', 'context', 'off']:
self._warn('invalid state') self._warn('invalid state')
return return
self._put(self._append_device_id("me/player/repeat?state=%s" % state, device_id)) self._put(
self._append_device_id(
"me/player/repeat?state=%s" %
state, device_id))
def volume(self, volume_percent, device_id = None): def volume(self, volume_percent, device_id=None):
''' Set playback volume. ''' Set playback volume.
Parameters: Parameters:
@ -1054,9 +1081,12 @@ class Spotify(object):
if volume_percent < 0 or volume_percent > 100: if volume_percent < 0 or volume_percent > 100:
self._warn('volume must be between 0 and 100, inclusive') self._warn('volume must be between 0 and 100, inclusive')
return return
self._put(self._append_device_id("me/player/volume?volume_percent=%s" % volume_percent, device_id)) self._put(
self._append_device_id(
"me/player/volume?volume_percent=%s" %
volume_percent, device_id))
def shuffle(self, state, device_id = None): def shuffle(self, state, device_id=None):
''' Toggle playback shuffling. ''' Toggle playback shuffling.
Parameters: Parameters:
@ -1067,7 +1097,10 @@ class Spotify(object):
self._warn('state must be a boolean') self._warn('state must be a boolean')
return return
state = str(state).lower() state = str(state).lower()
self._put(self._append_device_id("me/player/shuffle?state=%s" % state, device_id)) self._put(
self._append_device_id(
"me/player/shuffle?state=%s" %
state, device_id))
def _append_device_id(self, path, device_id): def _append_device_id(self, path, device_id):
''' Append device ID to API path. ''' Append device ID to API path.

View File

@ -27,7 +27,11 @@ class SpotifyOauthError(Exception):
def _make_authorization_headers(client_id, client_secret): def _make_authorization_headers(client_id, client_secret):
auth_header = base64.b64encode(six.text_type(client_id + ':' + client_secret).encode('ascii')) auth_header = base64.b64encode(
six.text_type(
client_id +
':' +
client_secret).encode('ascii'))
return {'Authorization': 'Basic %s' % auth_header.decode('ascii')} return {'Authorization': 'Basic %s' % auth_header.decode('ascii')}
@ -77,12 +81,14 @@ class SpotifyClientCredentials(object):
def _request_access_token(self): def _request_access_token(self):
"""Gets client credentials access token """ """Gets client credentials access token """
payload = { 'grant_type': 'client_credentials'} payload = {'grant_type': 'client_credentials'}
headers = _make_authorization_headers(self.client_id, self.client_secret) headers = _make_authorization_headers(
self.client_id, self.client_secret)
response = requests.post(self.OAUTH_TOKEN_URL, data=payload, response = requests.post(self.OAUTH_TOKEN_URL, data=payload,
headers=headers, verify=True, proxies=self.proxies) headers=headers, verify=True,
proxies=self.proxies)
if response.status_code != 200: if response.status_code != 200:
raise SpotifyOauthError(response.reason) raise SpotifyOauthError(response.reason)
token_info = response.json() token_info = response.json()
@ -109,7 +115,7 @@ class SpotifyOAuth(object):
OAUTH_TOKEN_URL = 'https://accounts.spotify.com/api/token' OAUTH_TOKEN_URL = 'https://accounts.spotify.com/api/token'
def __init__(self, client_id, client_secret, redirect_uri, def __init__(self, client_id, client_secret, redirect_uri,
state=None, scope=None, cache_path=None, proxies=None): state=None, scope=None, cache_path=None, proxies=None):
''' '''
Creates a SpotifyOAuth object Creates a SpotifyOAuth object
@ -125,9 +131,9 @@ class SpotifyOAuth(object):
self.client_id = client_id self.client_id = client_id
self.client_secret = client_secret self.client_secret = client_secret
self.redirect_uri = redirect_uri self.redirect_uri = redirect_uri
self.state=state self.state = state
self.cache_path = cache_path self.cache_path = cache_path
self.scope=self._normalize_scope(scope) self.scope = self._normalize_scope(scope)
self.proxies = proxies self.proxies = proxies
def get_cached_token(self): def get_cached_token(self):
@ -142,11 +148,13 @@ class SpotifyOAuth(object):
token_info = json.loads(token_info_string) token_info = json.loads(token_info_string)
# if scopes don't match, then bail # if scopes don't match, then bail
if 'scope' not in token_info or not self._is_scope_subset(self.scope, token_info['scope']): if 'scope' not in token_info or not self._is_scope_subset(
self.scope, token_info['scope']):
return None return None
if self.is_token_expired(token_info): if self.is_token_expired(token_info):
token_info = self.refresh_access_token(token_info['refresh_token']) token_info = self.refresh_access_token(
token_info['refresh_token'])
except IOError: except IOError:
pass pass
@ -164,7 +172,8 @@ class SpotifyOAuth(object):
def _is_scope_subset(self, needle_scope, haystack_scope): def _is_scope_subset(self, needle_scope, haystack_scope):
needle_scope = set(needle_scope.split()) if needle_scope else set() needle_scope = set(needle_scope.split()) if needle_scope else set()
haystack_scope = set(haystack_scope.split()) if haystack_scope else set() haystack_scope = set(
haystack_scope.split()) if haystack_scope else set()
return needle_scope <= haystack_scope return needle_scope <= haystack_scope
def is_token_expired(self, token_info): def is_token_expired(self, token_info):
@ -222,7 +231,8 @@ class SpotifyOAuth(object):
headers = self._make_authorization_headers() headers = self._make_authorization_headers()
response = requests.post(self.OAUTH_TOKEN_URL, data=payload, response = requests.post(self.OAUTH_TOKEN_URL, data=payload,
headers=headers, verify=True, proxies=self.proxies) headers=headers, verify=True,
proxies=self.proxies)
if response.status_code != 200: if response.status_code != 200:
raise SpotifyOauthError(response.reason) raise SpotifyOauthError(response.reason)
token_info = response.json() token_info = response.json()
@ -232,30 +242,29 @@ class SpotifyOAuth(object):
def _normalize_scope(self, scope): def _normalize_scope(self, scope):
if scope: if scope:
scopes = scope.split() scopes = sorted(scope.split())
scopes.sort()
return ' '.join(scopes) return ' '.join(scopes)
else: else:
return None return None
def refresh_access_token(self, refresh_token): def refresh_access_token(self, refresh_token):
payload = { 'refresh_token': refresh_token, payload = {'refresh_token': refresh_token,
'grant_type': 'refresh_token'} 'grant_type': 'refresh_token'}
headers = self._make_authorization_headers() headers = self._make_authorization_headers()
response = requests.post(self.OAUTH_TOKEN_URL, data=payload, response = requests.post(self.OAUTH_TOKEN_URL, data=payload,
headers=headers, proxies=self.proxies) headers=headers, proxies=self.proxies)
if response.status_code != 200: if response.status_code != 200:
if False: # debugging code if False: # debugging code
print('headers', headers) print('headers', headers)
print('request', response.url) print('request', response.url)
self._warn("couldn't refresh token: code:%d reason:%s" \ self._warn("couldn't refresh token: code:%d reason:%s"
% (response.status_code, response.reason)) % (response.status_code, response.reason))
return None return None
token_info = response.json() token_info = response.json()
token_info = self._add_custom_values_to_token_info(token_info) token_info = self._add_custom_values_to_token_info(token_info)
if not 'refresh_token' in token_info: if 'refresh_token' not in token_info:
token_info['refresh_token'] = refresh_token token_info['refresh_token'] = refresh_token
self._save_token_info(token_info) self._save_token_info(token_info)
return token_info return token_info
@ -271,4 +280,3 @@ class SpotifyOAuth(object):
def _warn(self, msg): def _warn(self, msg):
print('warning:' + msg, file=sys.stderr) print('warning:' + msg, file=sys.stderr)

View File

@ -22,8 +22,10 @@ CLIENT_CREDS_ENV_VARS = {
'redirect_uri': 'SPOTIPY_REDIRECT_URI' 'redirect_uri': 'SPOTIPY_REDIRECT_URI'
} }
def prompt_for_user_token(username, scope=None, client_id = None,
client_secret = None, redirect_uri = None, cache_path = None): def prompt_for_user_token(username, scope=None, client_id=None,
client_secret=None, redirect_uri=None,
cache_path=None):
''' prompts the user to login if necessary and returns ''' prompts the user to login if necessary and returns
the user token suitable for use with the spotipy.Spotify the user token suitable for use with the spotipy.Spotify
constructor constructor
@ -64,7 +66,7 @@ def prompt_for_user_token(username, scope=None, client_id = None,
cache_path = cache_path or ".cache-" + username cache_path = cache_path or ".cache-" + username
sp_oauth = oauth2.SpotifyOAuth(client_id, client_secret, redirect_uri, sp_oauth = oauth2.SpotifyOAuth(client_id, client_secret, redirect_uri,
scope=scope, cache_path=cache_path) scope=scope, cache_path=cache_path)
# try to get a valid token for this user, from the cache, # try to get a valid token for this user, from the cache,
# if not in the cache, the create a new (this will send # if not in the cache, the create a new (this will send
@ -87,7 +89,7 @@ def prompt_for_user_token(username, scope=None, client_id = None,
import webbrowser import webbrowser
webbrowser.open(auth_url) webbrowser.open(auth_url)
print("Opened %s in your browser" % auth_url) print("Opened %s in your browser" % auth_url)
except: except BaseException:
print("Please navigate here: %s" % auth_url) print("Please navigate here: %s" % auth_url)
print() print()

View File

@ -14,27 +14,23 @@ following environment variables
from __future__ import print_function from __future__ import print_function
import os
from pprint import pprint
import sys
import unittest
import simplejson as json
sys.path.insert(0, os.path.abspath(os.pardir))
from spotipy import ( from spotipy import (
CLIENT_CREDS_ENV_VARS as CCEV, CLIENT_CREDS_ENV_VARS as CCEV,
prompt_for_user_token, prompt_for_user_token,
Spotify, Spotify,
SpotifyException, SpotifyException,
) )
import os
import sys
import unittest
sys.path.insert(0, os.path.abspath(os.pardir))
class AuthTestSpotipy(unittest.TestCase): class AuthTestSpotipy(unittest.TestCase):
""" """
These tests require user authentication - provide client credentials using the These tests require user authentication - provide client credentials using
following environment variables the following environment variables
:: ::
@ -47,30 +43,32 @@ class AuthTestSpotipy(unittest.TestCase):
playlist = "spotify:user:plamere:playlist:2oCEWyyAPbZp9xhVSxZavx" playlist = "spotify:user:plamere:playlist:2oCEWyyAPbZp9xhVSxZavx"
playlist_new_id = "spotify:playlist:7GlxpQjjxRjmbb3RP2rDqI" playlist_new_id = "spotify:playlist:7GlxpQjjxRjmbb3RP2rDqI"
four_tracks = ["spotify:track:6RtPijgfPKROxEzTHNRiDp", four_tracks = ["spotify:track:6RtPijgfPKROxEzTHNRiDp",
"spotify:track:7IHOIqZUUInxjVkko181PB", "spotify:track:7IHOIqZUUInxjVkko181PB",
"4VrWlk8IQxevMvERoX08iC", "4VrWlk8IQxevMvERoX08iC",
"http://open.spotify.com/track/3cySlItpiPiIAzU3NyHCJf"] "http://open.spotify.com/track/3cySlItpiPiIAzU3NyHCJf"]
two_tracks = ["spotify:track:6RtPijgfPKROxEzTHNRiDp", two_tracks = ["spotify:track:6RtPijgfPKROxEzTHNRiDp",
"spotify:track:7IHOIqZUUInxjVkko181PB"] "spotify:track:7IHOIqZUUInxjVkko181PB"]
other_tracks=["spotify:track:2wySlB6vMzCbQrRnNGOYKa", other_tracks = ["spotify:track:2wySlB6vMzCbQrRnNGOYKa",
"spotify:track:29xKs5BAHlmlX1u4gzQAbJ", "spotify:track:29xKs5BAHlmlX1u4gzQAbJ",
"spotify:track:1PB7gRWcvefzu7t3LJLUlf"] "spotify:track:1PB7gRWcvefzu7t3LJLUlf"]
album_ids = ["spotify:album:6kL09DaURb7rAoqqaA51KU", album_ids = ["spotify:album:6kL09DaURb7rAoqqaA51KU",
"spotify:album:6RTzC0rDbvagTSJLlY7AKl"] "spotify:album:6RTzC0rDbvagTSJLlY7AKl"]
bad_id = 'BAD_ID' bad_id = 'BAD_ID'
@classmethod @classmethod
def setUpClass(self): def setUpClass(self):
missing = list(filter(lambda var: not os.getenv(CCEV[var]), CCEV)) missing = list(filter(lambda var: not os.getenv(CCEV[var]), CCEV))
if missing: if missing:
raise Exception('Please set the client credentials for the test application using the following environment variables: {}'.format(CCEV.values())) raise Exception(
('Please set the client credentials for the test application'
' using the following environment variables: {}').format(
CCEV.values()))
self.username = os.getenv(CCEV['client_username']) self.username = os.getenv(CCEV['client_username'])
@ -121,14 +119,12 @@ class AuthTestSpotipy(unittest.TestCase):
results = self.spotify.user_playlist_tracks(user, pid) results = self.spotify.user_playlist_tracks(user, pid)
self.assertTrue(len(results['items']) >= 0) self.assertTrue(len(results['items']) >= 0)
def user_playlist_tracks(self, user, playlist_id = None, fields=None, # known API issue currently causes this test to fail
limit=100, offset=0): # the issue is that the API doesn't currently respect the
# limit parameter
# known API issue currently causes this test to fail # def user_playlist_tracks(self, user, playlist_id=None, fields=None,
# the issue is that the API doesn't currently respect the # limit=100, offset=0):
# limit parameter # self.assertTrue(len(playlists['items']) == 5)
self.assertTrue(len(playlists['items']) == 5)
def test_current_user_saved_albums(self): def test_current_user_saved_albums(self):
# List # List
@ -139,7 +135,10 @@ class AuthTestSpotipy(unittest.TestCase):
self.spotify.current_user_saved_albums_add(self.album_ids) self.spotify.current_user_saved_albums_add(self.album_ids)
# Contains # Contains
self.assertTrue(self.spotify.current_user_saved_albums_contains(self.album_ids) == [True, True]) self.assertTrue(
self.spotify.current_user_saved_albums_contains(
self.album_ids) == [
True, True])
# Remove # Remove
self.spotify.current_user_saved_albums_delete(self.album_ids) self.spotify.current_user_saved_albums_delete(self.album_ids)
@ -152,14 +151,20 @@ class AuthTestSpotipy(unittest.TestCase):
self.assertTrue(len(playlists['items']) == 10) self.assertTrue(len(playlists['items']) == 10)
def test_user_playlist_follow(self): def test_user_playlist_follow(self):
self.spotify.user_playlist_follow_playlist('plamere', '4erXB04MxwRAVqcUEpu30O') self.spotify.user_playlist_follow_playlist(
follows = self.spotify.user_playlist_is_following('plamere', '4erXB04MxwRAVqcUEpu30O', [self.spotify.current_user()['id']]) 'plamere', '4erXB04MxwRAVqcUEpu30O')
follows = self.spotify.user_playlist_is_following(
'plamere', '4erXB04MxwRAVqcUEpu30O', [
self.spotify.current_user()['id']])
self.assertTrue(len(follows) == 1, 'proper follows length') self.assertTrue(len(follows) == 1, 'proper follows length')
self.assertTrue(follows[0], 'is following') self.assertTrue(follows[0], 'is following')
self.spotify.user_playlist_unfollow('plamere', '4erXB04MxwRAVqcUEpu30O') self.spotify.user_playlist_unfollow(
'plamere', '4erXB04MxwRAVqcUEpu30O')
follows = self.spotify.user_playlist_is_following('plamere', '4erXB04MxwRAVqcUEpu30O', [self.spotify.current_user()['id']]) follows = self.spotify.user_playlist_is_following(
'plamere', '4erXB04MxwRAVqcUEpu30O', [
self.spotify.current_user()['id']])
self.assertTrue(len(follows) == 1, 'proper follows length') self.assertTrue(len(follows) == 1, 'proper follows length')
self.assertFalse(follows[0], 'is no longer following') self.assertFalse(follows[0], 'is no longer following')
@ -176,7 +181,8 @@ class AuthTestSpotipy(unittest.TestCase):
new_total = tracks['total'] new_total = tracks['total']
self.assertTrue(new_total - total == len(self.four_tracks)) self.assertTrue(new_total - total == len(self.four_tracks))
tracks = self.spotify.current_user_saved_tracks_delete(self.four_tracks) tracks = self.spotify.current_user_saved_tracks_delete(
self.four_tracks)
tracks = self.spotify.current_user_saved_tracks() tracks = self.spotify.current_user_saved_tracks()
new_total = tracks['total'] new_total = tracks['total']
self.assertTrue(new_total == total) self.assertTrue(new_total == total)
@ -224,37 +230,45 @@ class AuthTestSpotipy(unittest.TestCase):
if item['name'] == playlist_name: if item['name'] == playlist_name:
return item['id'] return item['id']
playlists = self.spotify.next(playlists) playlists = self.spotify.next(playlists)
playlist = self.spotify.user_playlist_create(self.username, playlist_name) playlist = self.spotify.user_playlist_create(
self.username, playlist_name)
playlist_id = playlist['uri'] playlist_id = playlist['uri']
return playlist_id return playlist_id
def test_user_playlist_ops(self): def test_user_playlist_ops(self):
sp = self.spotify
# create empty playlist # create empty playlist
playlist_id = self.get_or_create_spotify_playlist('spotipy-testing-playlist-1') playlist_id = self.get_or_create_spotify_playlist(
'spotipy-testing-playlist-1')
# remove all tracks from it # remove all tracks from it
self.spotify.user_playlist_replace_tracks(self.username, playlist_id,[]) sp.user_playlist_replace_tracks(
playlist = self.spotify.user_playlist(self.username, playlist_id) self.username, playlist_id, [])
playlist = sp.user_playlist(self.username, playlist_id)
self.assertTrue(playlist['tracks']['total'] == 0) self.assertTrue(playlist['tracks']['total'] == 0)
self.assertTrue(len(playlist['tracks']['items']) == 0) self.assertTrue(len(playlist['tracks']['items']) == 0)
# add tracks to it # add tracks to it
self.spotify.user_playlist_add_tracks(self.username, playlist_id, self.four_tracks) sp.user_playlist_add_tracks(
playlist = self.spotify.user_playlist(self.username, playlist_id) self.username, playlist_id, self.four_tracks)
playlist = sp.user_playlist(self.username, playlist_id)
self.assertTrue(playlist['tracks']['total'] == 4) self.assertTrue(playlist['tracks']['total'] == 4)
self.assertTrue(len(playlist['tracks']['items']) == 4) self.assertTrue(len(playlist['tracks']['items']) == 4)
# remove two tracks from it # remove two tracks from it
self.spotify.user_playlist_remove_all_occurrences_of_tracks (self.username,
playlist_id, self.two_tracks) sp.user_playlist_remove_all_occurrences_of_tracks(self.username,
playlist = self.spotify.user_playlist(self.username, playlist_id) playlist_id,
self.two_tracks)
playlist = sp.user_playlist(self.username, playlist_id)
self.assertTrue(playlist['tracks']['total'] == 2) self.assertTrue(playlist['tracks']['total'] == 2)
self.assertTrue(len(playlist['tracks']['items']) == 2) self.assertTrue(len(playlist['tracks']['items']) == 2)
# replace with 3 other tracks # replace with 3 other tracks
self.spotify.user_playlist_replace_tracks(self.username, sp.user_playlist_replace_tracks(self.username,
playlist_id, self.other_tracks) playlist_id,
playlist = self.spotify.user_playlist(self.username, playlist_id) self.other_tracks)
playlist = sp.user_playlist(self.username, playlist_id)
self.assertTrue(playlist['tracks']['total'] == 3) self.assertTrue(playlist['tracks']['total'] == 3)
self.assertTrue(len(playlist['tracks']['items']) == 3) self.assertTrue(len(playlist['tracks']['items']) == 3)
@ -293,5 +307,6 @@ class AuthTestSpotipy(unittest.TestCase):
# Unfollow these 2 users # Unfollow these 2 users
self.spotify.user_unfollow_users(users) self.spotify.user_unfollow_users(users)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()

View File

@ -12,25 +12,21 @@ following environment variables
'SPOTIPY_REDIRECT_URI' 'SPOTIPY_REDIRECT_URI'
""" """
import os
import pprint
import sys
import unittest
import simplejson as json
sys.path.insert(0, os.path.abspath(os.pardir))
from spotipy import ( from spotipy import (
Spotify, Spotify,
SpotifyClientCredentials, SpotifyClientCredentials,
) )
import os
import sys
import unittest
sys.path.insert(0, os.path.abspath(os.pardir))
class AuthTestSpotipy(unittest.TestCase): class AuthTestSpotipy(unittest.TestCase):
""" """
These tests require user authentication - provide client credentials using the These tests require user authentication - provide client credentials using
following environment variables the following environment variables
:: ::
@ -42,22 +38,23 @@ class AuthTestSpotipy(unittest.TestCase):
playlist = "spotify:user:plamere:playlist:2oCEWyyAPbZp9xhVSxZavx" playlist = "spotify:user:plamere:playlist:2oCEWyyAPbZp9xhVSxZavx"
four_tracks = ["spotify:track:6RtPijgfPKROxEzTHNRiDp", four_tracks = ["spotify:track:6RtPijgfPKROxEzTHNRiDp",
"spotify:track:7IHOIqZUUInxjVkko181PB", "spotify:track:7IHOIqZUUInxjVkko181PB",
"4VrWlk8IQxevMvERoX08iC", "4VrWlk8IQxevMvERoX08iC",
"http://open.spotify.com/track/3cySlItpiPiIAzU3NyHCJf"] "http://open.spotify.com/track/3cySlItpiPiIAzU3NyHCJf"]
two_tracks = ["spotify:track:6RtPijgfPKROxEzTHNRiDp", two_tracks = ["spotify:track:6RtPijgfPKROxEzTHNRiDp",
"spotify:track:7IHOIqZUUInxjVkko181PB"] "spotify:track:7IHOIqZUUInxjVkko181PB"]
other_tracks=["spotify:track:2wySlB6vMzCbQrRnNGOYKa", other_tracks = ["spotify:track:2wySlB6vMzCbQrRnNGOYKa",
"spotify:track:29xKs5BAHlmlX1u4gzQAbJ", "spotify:track:29xKs5BAHlmlX1u4gzQAbJ",
"spotify:track:1PB7gRWcvefzu7t3LJLUlf"] "spotify:track:1PB7gRWcvefzu7t3LJLUlf"]
bad_id = 'BAD_ID' bad_id = 'BAD_ID'
@classmethod @classmethod
def setUpClass(self): def setUpClass(self):
self.spotify = Spotify(client_credentials_manager=SpotifyClientCredentials()) self.spotify = Spotify(
client_credentials_manager=SpotifyClientCredentials())
self.spotify.trace = False self.spotify.trace = False
def test_audio_analysis(self): def test_audio_analysis(self):
@ -77,15 +74,18 @@ class AuthTestSpotipy(unittest.TestCase):
results = self.spotify.audio_features(input) results = self.spotify.audio_features(input)
self.assertTrue(len(results) == len(input)) self.assertTrue(len(results) == len(input))
for track in results[:-1]: for track in results[:-1]:
if track != None: if track is not None:
assert('speechiness' in track) assert('speechiness' in track)
self.assertTrue(results[-1] == None) self.assertTrue(results[-1] is None)
def test_recommendations(self): def test_recommendations(self):
results = self.spotify.recommendations(seed_tracks=self.four_tracks, min_danceability=0, max_loudness=0, target_popularity=50) results = self.spotify.recommendations(
seed_tracks=self.four_tracks,
min_danceability=0,
max_loudness=0,
target_popularity=50)
self.assertTrue(len(results['tracks']) == 20) self.assertTrue(len(results['tracks']) == 20)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()

View File

@ -2,22 +2,21 @@
""" Client Credentials Requests Tests """ """ Client Credentials Requests Tests """
from spotipy import (
Spotify,
SpotifyClientCredentials,
)
import os import os
import sys import sys
import unittest import unittest
sys.path.insert(0, os.path.abspath(os.pardir)) sys.path.insert(0, os.path.abspath(os.pardir))
from spotipy import (
Spotify,
SpotifyClientCredentials,
)
class ClientCredentialsTestSpotipy(unittest.TestCase): class ClientCredentialsTestSpotipy(unittest.TestCase):
""" """
These tests require user authentication - provide client credentials using the These tests require user authentication - provide client credentials using
following environment variables the following environment variables
:: ::
@ -29,7 +28,8 @@ class ClientCredentialsTestSpotipy(unittest.TestCase):
@classmethod @classmethod
def setUpClass(self): def setUpClass(self):
self.spotify = Spotify(client_credentials_manager=SpotifyClientCredentials()) self.spotify = Spotify(
client_credentials_manager=SpotifyClientCredentials())
self.spotify.trace = False self.spotify.trace = False
muse_urn = 'spotify:artist:12Chz98pHFMPJEknJQMWvI' muse_urn = 'spotify:artist:12Chz98pHFMPJEknJQMWvI'
@ -40,5 +40,4 @@ class ClientCredentialsTestSpotipy(unittest.TestCase):
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()

View File

@ -1,5 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import six.moves.urllib.parse as urllibparse
from spotipy import SpotifyOAuth
import io import io
import json import json
import os import os
@ -8,13 +10,11 @@ import unittest
sys.path.insert(0, os.path.abspath(os.pardir)) sys.path.insert(0, os.path.abspath(os.pardir))
from spotipy import SpotifyOAuth
try: try:
import unittest.mock as mock import unittest.mock as mock
except ImportError: except ImportError:
import mock import mock
import six.moves.urllib.parse as urllibparse
patch = mock.patch patch = mock.patch
DEFAULT = mock.DEFAULT DEFAULT = mock.DEFAULT

View File

@ -1,27 +1,25 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import os
import pprint
import sys
import unittest
import requests
sys.path.insert(0, os.path.abspath(os.pardir))
from spotipy import ( from spotipy import (
CLIENT_CREDS_ENV_VARS as CCEV, CLIENT_CREDS_ENV_VARS as CCEV,
prompt_for_user_token, prompt_for_user_token,
Spotify, Spotify,
SpotifyException, SpotifyException,
) )
import os
import sys
import unittest
import requests
sys.path.insert(0, os.path.abspath(os.pardir))
class TestSpotipy(unittest.TestCase): class TestSpotipy(unittest.TestCase):
""" """
These tests require user authentication - provide client credentials using the These tests require user authentication - provide client credentials using
following environment variables the following environment variables
:: ::
@ -42,7 +40,6 @@ class TestSpotipy(unittest.TestCase):
radiohead_urn = 'spotify:artist:4Z8W4fKeB5YxbusRsdQVPb' radiohead_urn = 'spotify:artist:4Z8W4fKeB5YxbusRsdQVPb'
angeles_haydn_urn = 'spotify:album:1vAbqAeuJVWNAe7UR00bdM' angeles_haydn_urn = 'spotify:album:1vAbqAeuJVWNAe7UR00bdM'
bad_id = 'BAD_ID' bad_id = 'BAD_ID'
@classmethod @classmethod
@ -50,7 +47,10 @@ class TestSpotipy(unittest.TestCase):
missing = list(filter(lambda var: not os.getenv(CCEV[var]), CCEV)) missing = list(filter(lambda var: not os.getenv(CCEV[var]), CCEV))
if missing: if missing:
raise Exception('Please set the client credentials for the test application using the following environment variables: {}'.format(CCEV.values())) raise Exception(
('Please set the client credentials for the test '
'the following environment variables: {}').format(
CCEV.values()))
self.username = os.getenv(CCEV['client_username']) self.username = os.getenv(CCEV['client_username'])
@ -82,14 +82,16 @@ class TestSpotipy(unittest.TestCase):
tracks = results['items'] tracks = results['items']
total, received = results['total'], len(tracks) total, received = results['total'], len(tracks)
while received < total: while received < total:
results = self.spotify.album_tracks(self.angeles_haydn_urn, offset=received) results = self.spotify.album_tracks(
self.angeles_haydn_urn, offset=received)
tracks.extend(results['items']) tracks.extend(results['items'])
received = len(tracks) received = len(tracks)
self.assertEqual(received, total) self.assertEqual(received, total)
def test_albums(self): def test_albums(self):
results = self.spotify.albums([self.pinkerton_urn, self.pablo_honey_urn]) results = self.spotify.albums(
[self.pinkerton_urn, self.pablo_honey_urn])
self.assertTrue('albums' in results) self.assertTrue('albums' in results)
self.assertTrue(len(results['albums']) == 2) self.assertTrue(len(results['albums']) == 2)
@ -107,7 +109,7 @@ class TestSpotipy(unittest.TestCase):
def test_track_bad_urn(self): def test_track_bad_urn(self):
try: try:
track = self.spotify.track(self.el_scorcho_bad_urn) self.spotify.track(self.el_scorcho_bad_urn)
self.assertTrue(False) self.assertTrue(False)
except SpotifyException: except SpotifyException:
self.assertTrue(True) self.assertTrue(True)
@ -158,17 +160,17 @@ class TestSpotipy(unittest.TestCase):
def test_search_timeout(self): def test_search_timeout(self):
sp = Spotify(auth=self.token, requests_timeout=.01) sp = Spotify(auth=self.token, requests_timeout=.01)
try: try:
results = sp.search(q='my*', type='track') sp.search(q='my*', type='track')
self.assertTrue(False, 'unexpected search timeout') self.assertTrue(False, 'unexpected search timeout')
except requests.Timeout: except requests.Timeout:
self.assertTrue(True, 'expected search timeout') self.assertTrue(True, 'expected search timeout')
def test_album_search(self): def test_album_search(self):
results = self.spotify.search(q='weezer pinkerton', type='album') results = self.spotify.search(q='weezer pinkerton', type='album')
self.assertTrue('albums' in results) self.assertTrue('albums' in results)
self.assertTrue(len(results['albums']['items']) > 0) self.assertTrue(len(results['albums']['items']) > 0)
self.assertTrue(results['albums']['items'][0]['name'].find('Pinkerton') >= 0) self.assertTrue(results['albums']['items'][0]
['name'].find('Pinkerton') >= 0)
def test_track_search(self): def test_track_search(self):
results = self.spotify.search(q='el scorcho weezer', type='track') results = self.spotify.search(q='el scorcho weezer', type='track')
@ -182,34 +184,34 @@ class TestSpotipy(unittest.TestCase):
def test_track_bad_id(self): def test_track_bad_id(self):
try: try:
track = self.spotify.track(self.bad_id) self.spotify.track(self.bad_id)
self.assertTrue(False)
except SpotifyException:
self.assertTrue(True)
def test_track_bad_id(self):
try:
track = self.spotify.track(self.bad_id)
self.assertTrue(False) self.assertTrue(False)
except SpotifyException: except SpotifyException:
self.assertTrue(True) self.assertTrue(True)
def test_unauthenticated_post_fails(self): def test_unauthenticated_post_fails(self):
with self.assertRaises(SpotifyException) as cm: with self.assertRaises(SpotifyException) as cm:
self.spotify.user_playlist_create("spotify", "Best hits of the 90s") self.spotify.user_playlist_create(
"spotify", "Best hits of the 90s")
self.assertTrue(cm.exception.http_status == 401 or self.assertTrue(cm.exception.http_status == 401 or
cm.exception.http_status == 403) cm.exception.http_status == 403)
def test_custom_requests_session(self): def test_custom_requests_session(self):
sess = requests.Session() sess = requests.Session()
sess.headers["user-agent"] = "spotipy-test" sess.headers["user-agent"] = "spotipy-test"
with_custom_session = Spotify(auth=self.token, requests_session=sess) with_custom_session = Spotify(auth=self.token, requests_session=sess)
self.assertTrue(with_custom_session.user(user="akx")["uri"] == "spotify:user:akx") self.assertTrue(
with_custom_session.user(
user="akx")["uri"] == "spotify:user:akx")
def test_force_no_requests_session(self): def test_force_no_requests_session(self):
with_no_session = Spotify(auth=self.token, requests_session=False) with_no_session = Spotify(auth=self.token, requests_session=False)
self.assertFalse(isinstance(with_no_session._session, requests.Session)) self.assertFalse(
self.assertTrue(with_no_session.user(user="akx")["uri"] == "spotify:user:akx") isinstance(
with_no_session._session,
requests.Session))
self.assertTrue(with_no_session.user(user="akx")
["uri"] == "spotify:user:akx")
''' '''
@ -220,5 +222,4 @@ class TestSpotipy(unittest.TestCase):
''' '''
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()

View File

@ -7,3 +7,8 @@ deps=
six six
py27: mock py27: mock
commands=python -m unittest discover -v tests commands=python -m unittest discover -v tests
[flake8]
exclude=
.git,
dist,
docs