Merge pull request #414 from plamere/main-fork-progress

Harrison97 fork progress
This commit is contained in:
Stéphane Bruckert 2020-01-11 23:38:01 +00:00 committed by GitHub
commit 4595b29bd5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 799 additions and 527 deletions

3
.gitignore vendored
View File

@ -52,6 +52,5 @@ coverage.xml
# Sphinx documentation
docs/_build/
.*
archive
archive

37
CHANGELOG.md Normal file
View File

@ -0,0 +1,37 @@
- 1.0 - 04/05/2014 - Initial release
- 1.1 - 05/18/2014 - Repackaged for saner imports
- 1.4.1 - 06/17/2014 - Updates to match released API
- 1.4.2 - 06/21/2014 - Added support for retrieving starred playlists
- v1.40, June 12, 2014 -- Initial public release.
- v1.42, June 19, 2014 -- Removed dependency on simplejson
- v1.43, June 27, 2014 -- Fixed JSON handling issue
- v1.44, July 3, 2014 -- Added show tracks.py example
- v1.45, July 7, 2014 -- Support for related artists endpoint. Don't use cache auth codes when scope changes
- v1.49, July 23, 2014 -- Support for "Your Music" tracks (add, delete, get), with examples
- v1.50, August 14, 2014 -- Refactored util out of examples and into the main package
- v1.301, August 19, 2014 -- Upgraded version number to take precedence over previously botched release (sigh)
- v1.310, August 20, 2014 -- Added playlist replace and remove methods. Added auth tests. Improved API docs
- v2.0 - August 22, 2014 -- Upgraded APIs and docs to make it be a real library
- v2.0.2 - August 25, 2014 -- Moved to spotipy at pypi
- v2.1.0 - October 25, 2014 -- Added support for new_releases and featured_playlists
- v2.2.0 - November 15, 2014 -- Added support for user_playlist_tracks
- v2.3.0 - January 5, 2015 -- Added session support added by akx.
- v2.3.2 - March 31, 2015 -- Added auto retry logic
- v2.3.3 - April 1, 2015 -- added client credential flow
- v2.3.5 - April 28, 2015 -- Fixed bug in auto retry logic
- v2.3.6 - June 3, 2015 -- Support for offset/limit with album_tracks API
- v2.3.7 - August 10, 2015 -- Added current_user_followed_artists
- v2.3.8 - March 30, 2016 -- Added recs, audio features, user top lists
- v2.4.0 - December 31, 2016 -- Incorporated a number of PRs
- v2.4.1 - January 2, 2017 -- Incorporated proxy support
- v2.4.2 - January 2, 2017 -- support getting audio features for a single track
- v2.4.3 - January 2, 2017 -- fixed proxy issue in standard auth flow
- v2.4.4 - January 4, 2017 -- python 3 fix
- v2.5.0 - January 11, 2020 -- Added follow and player endpoints
- Unreleased
- Added:
- support for `playlist()`
- support for `current_user_saved_albums_delete()`
- support for `current_user_saved_albums_contains()`
- support for `user_unfollow_artists()`
- support for `user_unfollow_users()`

View File

@ -1,16 +0,0 @@
v1.40, June 12, 2014 -- Initial public release.
v1.42, June 19, 2014 -- Removed dependency on simplejson
v1.43, June 27, 2014 -- Fixed JSON handling issue
v1.44, July 3, 2014 -- Added show_tracks.py exampole
v1.45, July 7, 2014 -- Support for related artists endpoint. Don't use
cache auth codes when scope changes
v1.50, August 14, 2014 -- Refactored util out of examples and into the main
package
v2.301, August 19, 2014 -- Upgraded version number to take precedence over
previously botched release (sigh)
v2.310, August 20, 2014 -- Added playlist replace and remove methods. Added auth
tests. Improved API docs
v2.310, January 5, 2015 -- Added session support
v2.3.1, March 28, 2015 -- Auto retry support
v2.3.5, April 28, 2015 -- Fixed bug in auto retry support
v2.3.6, June 3, 2015 -- Support for offset/limit with album_tracks API

View File

@ -51,37 +51,4 @@ A full set of examples can be found in the [online documentation](http://spotipy
## Reporting Issues
If you have suggestions, bugs or other issues specific to this library, file them [here](https://github.com/plamere/spotipy/issues). Or just send me a pull request.
## Version
- 1.0 - 04/05/2014 - Initial release
- 1.1 - 05/18/2014 - Repackaged for saner imports
- 1.4.1 - 06/17/2014 - Updates to match released API
- 1.4.2 - 06/21/2014 - Added support for retrieving starred playlists
- v1.40, June 12, 2014 -- Initial public release.
- v1.42, June 19, 2014 -- Removed dependency on simplejson
- v1.43, June 27, 2014 -- Fixed JSON handling issue
- v1.44, July 3, 2014 -- Added show tracks.py example
- v1.45, July 7, 2014 -- Support for related artists endpoint. Don't use cache auth codes when scope changes
- v1.49, July 23, 2014 -- Support for "Your Music" tracks (add, delete, get), with examples
- v1.50, August 14, 2014 -- Refactored util out of examples and into the main package
- v1.301, August 19, 2014 -- Upgraded version number to take precedence over previously botched release (sigh)
- v1.310, August 20, 2014 -- Added playlist replace and remove methods. Added auth tests. Improved API docs
- v2.0 - August 22, 2014 -- Upgraded APIs and docs to make it be a real library
- v2.0.2 - August 25, 2014 -- Moved to spotipy at pypi
- v2.1.0 - October 25, 2014 -- Added support for new_releases and featured_playlists
- v2.2.0 - November 15, 2014 -- Added support for user_playlist_tracks
- v2.3.0 - January 5, 2015 -- Added session support added by akx.
- v2.3.2 - March 31, 2015 -- Added auto retry logic
- v2.3.3 - April 1, 2015 -- added client credential flow
- v2.3.5 - April 28, 2015 -- Fixed bug in auto retry logic
- v2.3.6 - June 3, 2015 -- Support for offset/limit with album_tracks API
- v2.3.7 - August 10, 2015 -- Added current_user_followed_artists
- v2.3.8 - March 30, 2016 -- Added recs, audio features, user top lists
- v2.4.0 - December 31, 2016 -- Incorporated a number of PRs
- v2.4.1 - January 2, 2017 -- Incorporated proxy support
- v2.4.2 - January 2, 2017 -- support getting audio features for a single track
- v2.4.3 - January 2, 2017 -- fixed proxy issue in standard auth flow
- v2.4.4 - January 4, 2017 -- python 3 fix
- v2.5.0 - January 11, 2020 -- Added follow and player endpoints
If you have suggestions, bugs or other issues specific to this library, file them [here](https://github.com/plamere/spotipy/issues). Or just send me a pull request.

7
deploy
View File

@ -1,6 +1,6 @@
#
# sudo python setup.py develop --uninstall
# sudo python setup.py install
# sudo python setup.py install
# How do deploy
# - run tests
@ -9,11 +9,10 @@
# - Update README.md with updated version info
# - leave development mode
# sudo python setup.py develop --uninstall
# sudo python setup.py install
# sudo python setup.py install
# - upload dist
# sudo python setup.py sdist upload
# docs should automatically be updated. verify them at
# http://spotipy.readthedocs.org/en/latest/
sudo python setup.py sdist upload
sudo python setup.py sdist upload

View File

@ -5,7 +5,7 @@ Welcome to Spotipy!
===================================
*Spotipy* is a lightweight Python library for the `Spotify Web API
<https://developer.spotify.com/web-api/>`_. With *Spotipy*
you get full access to all of the music data provided by the Spotify platform.
you get full access to all of the music data provided by the Spotify platform.
Here's a quick example of using *Spotipy* to list the names of all the albums
released by the artist 'Birdy'::
@ -27,6 +27,7 @@ released by the artist 'Birdy'::
Here's another example showing how to get 30 second samples and cover art
for the top 10 tracks for Led Zeppelin::
from __future__ import print_function
import spotipy
lz_uri = 'spotify:artist:36QJpDe2go2KgaRleHCDTp'
@ -35,14 +36,15 @@ for the top 10 tracks for Led Zeppelin::
results = spotify.artist_top_tracks(lz_uri)
for track in results['tracks'][:10]:
print 'track : ' + track['name']
print 'audio : ' + track['preview_url']
print 'cover art: ' + track['album']['images'][0]['url']
print
print('track : ' + track['name'])
print('audio : ' + track['preview_url'])
print('cover art: ' + track['album']['images'][0]['url'])
print()
Finally, here's an example that will get the URL for an artist image given the
artist's name::
from __future__ import print_function
import spotipy
import sys
@ -57,7 +59,7 @@ artist's name::
items = results['artists']['items']
if len(items) > 0:
artist = items[0]
print artist['name'], artist['images'][0]['url']
print(artist['name'], artist['images'][0]['url'])
Features
@ -87,10 +89,11 @@ Non-Authorized requests
For methods that do not require authorization, simply create a Spotify object
and start making method calls like so::
from __future__ import print_function
import spotipy
spotify = spotipy.Spotify()
results = spotify.search(q='artist:' + name, type='artist')
print results
print(results)
Authorized requests
=======================
@ -103,17 +106,17 @@ Even if your script does not have an accessible URL you need to specify one
when registering your application where the spotify authentication API will
redirect to after successful login. The URL doesn't need to work or be
accessible, you can specify "http://localhost/", after successful login you
just need to copy the "http://localhost/?code=..." URL from your browser
just need to copy the "http://localhost/?code=..." URL from your browser
and paste it to the console where your script is running.
Register your app at
Register your app at
`My Applications
<https://developer.spotify.com/my-applications/#!/applications>`_.
*spotipy* supports two authorization flows:
- The **Authorization Code flow** This method is suitable for long-running applications
- The **Authorization Code flow** This method is suitable for long-running applications
which the user logs into once. It provides an access token that can be refreshed.
- The **Client Credentials flow** The method makes it possible
@ -127,16 +130,16 @@ To support the **Authorization Code Flow** *Spotipy* provides a
utility method ``util.prompt_for_user_token`` that will attempt to authorize the
user. You can pass your app credentials directly into the method as arguments::
util.prompt_for_user_token(username,scope,client_id='your-app-redirect-url',client_secret='your-app-redirect-url',redirect_uri='your-app-redirect-url')
util.prompt_for_user_token(username,scope,client_id='your-spotify-client-id',client_secret='your-spotify-client-secret',redirect_uri='your-app-redirect-url')
or if you are reluctant to immortalize your app credentials in your source code,
or if you are reluctant to immortalize your app credentials in your source code,
you can set environment variables like so::
export SPOTIPY_CLIENT_ID='your-spotify-client-id'
export SPOTIPY_CLIENT_SECRET='your-spotify-client-secret'
export SPOTIPY_REDIRECT_URI='your-app-redirect-url'
Call ``util.prompt_for_user_token`` method with the username and the
Call ``util.prompt_for_user_token`` method with the username and the
desired scope (see `Using
Scopes <https://developer.spotify.com/web-api/using-scopes/>`_ for information
about scopes) and credentials. This will coordinate the user authorization via
@ -146,6 +149,7 @@ are used to automatically re-authorized expired tokens.
Here's an example of getting user authorization to read a user's saved tracks::
from __future__ import print_function
import sys
import spotipy
import spotipy.util as util
@ -155,7 +159,7 @@ Here's an example of getting user authorization to read a user's saved tracks::
if len(sys.argv) > 1:
username = sys.argv[1]
else:
print "Usage: %s username" % (sys.argv[0],)
print("Usage: %s username" % (sys.argv[0],))
sys.exit()
token = util.prompt_for_user_token(username, scope)
@ -165,9 +169,9 @@ Here's an example of getting user authorization to read a user's saved tracks::
results = sp.current_user_saved_tracks()
for item in results['items']:
track = item['track']
print track['name'] + ' - ' + track['artists'][0]['name']
print(track['name'] + ' - ' + track['artists'][0]['name'])
else:
print "Can't get token for", username
print("Can't get token for", username)
Client Credentials Flow
=======================
@ -191,8 +195,8 @@ class SpotifyClientCredentials that can be used to authenticate requests like so
playlists = None
Client credentials flow is appropriate for requests that do not require access to a
user's private data. Even if you are only making calls that do not require
authorization, using this flow yields the benefit of a higher rate limit
user's private data. Even if you are only making calls that do not require
authorization, using this flow yields the benefit of a higher rate limit
IDs URIs and URLs
=======================
@ -217,6 +221,7 @@ Here are a few more examples of using *Spotipy*.
Add tracks to a playlist::
from __future__ import print_function
import pprint
import sys
@ -228,7 +233,7 @@ Add tracks to a playlist::
playlist_id = sys.argv[2]
track_ids = sys.argv[3:]
else:
print "Usage: %s username playlist_id track_id ..." % (sys.argv[0],)
print("Usage: %s username playlist_id track_id ..." % (sys.argv[0],))
sys.exit()
scope = 'playlist-modify-public'
@ -238,15 +243,16 @@ Add tracks to a playlist::
sp = spotipy.Spotify(auth=token)
sp.trace = False
results = sp.user_playlist_add_tracks(username, playlist_id, track_ids)
print results
print(results)
else:
print "Can't get token for", username
print("Can't get token for", username)
Shows the contents of every playlist owned by a user::
# shows a user's playlists (need to be authenticated via oauth)
from __future__ import print_function
import sys
import spotipy
import spotipy.util as util
@ -254,16 +260,16 @@ Shows the contents of every playlist owned by a user::
def show_tracks(tracks):
for i, item in enumerate(tracks['items']):
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 len(sys.argv) > 1:
username = sys.argv[1]
else:
print "Whoops, need your username!"
print "usage: python user_playlists.py [username]"
print("Whoops, need your username!")
print("usage: python user_playlists.py [username]")
sys.exit()
token = util.prompt_for_user_token(username)
@ -273,10 +279,10 @@ Shows the contents of every playlist owned by a user::
playlists = sp.user_playlists(username)
for playlist in playlists['items']:
if playlist['owner']['id'] == username:
print
print playlist['name']
print ' total tracks', playlist['tracks']['total']
results = sp.user_playlist(username, playlist['id'],
print()
print(playlist['name'])
print (' total tracks', playlist['tracks']['total'])
results = sp.user_playlist(username, playlist['id'],
fields="tracks,next")
tracks = results['tracks']
show_tracks(tracks)
@ -284,7 +290,7 @@ Shows the contents of every playlist owned by a user::
tracks = sp.next(tracks)
show_tracks(tracks)
else:
print "Can't get token for", username
print("Can't get token for", username)
More Examples
@ -292,7 +298,7 @@ More Examples
There are many more examples of how to use *Spotipy* in the `Examples
Directory <https://github.com/plamere/spotipy/tree/master/examples>`_ on Github
API Reference
API Reference
==============
:mod:`client` Module
@ -330,7 +336,7 @@ You can ask questions about Spotipy on Stack Overflow. Dont forget to add t
http://stackoverflow.com/questions/ask
If you think you've found a bug, let us know at
If you think you've found a bug, let us know at
`Spotify Issues <https://github.com/plamere/spotipy/issues>`_
@ -338,24 +344,25 @@ Contribute
==========
Spotipy authored by Paul Lamere (plamere) with contributions by:
- Daniel Beaudry // danbeaudry
- Faruk Emre Sahin // fsahin
- George // rogueleaderr
- Henry Greville // sethaurus
- Hugo // hugovk
- José Manuel Pérez // JMPerez
- Lucas Nunno // lnunno
- Lynn Root // econchick
- Matt Dennewitz // mattdennewitz
- Matthew Duck // mattduck
- Michael Thelin // thelinmichael
- Ryan Choi // ryankicks
- Simon Metson // drsm79
- Daniel Beaudry // danbeaudry
- Faruk Emre Sahin // fsahin
- George // rogueleaderr
- Henry Greville // sethaurus
- Hugo // hugovk
- José Manuel Pérez // JMPerez
- Lucas Nunno // lnunno
- Lynn Root // econchick
- Matt Dennewitz // mattdennewitz
- Matthew Duck // mattduck
- Michael Thelin // thelinmichael
- Ryan Choi // ryankicks
- Simon Metson // drsm79
- Steve Winton // swinton
- Tim Balzer // timbalzer
- corycorycory // corycorycory
- Tim Balzer // timbalzer
- corycorycory // corycorycory
- Nathan Coleman // nathancoleman
- Michael Birtwell // mbirtwell
- Harrison Hayes // Harrison97
License
=======

View File

@ -35,7 +35,7 @@ def show_artist_albums(id):
unique = set() # skip duplicate albums
for album in albums:
name = album['name'].lower()
if not name in unique:
if not name in unique:
print(name)
unique.add(name)
show_album_tracks(album)

View File

@ -10,7 +10,7 @@ if len(sys.argv) > 2:
username = sys.argv[1]
tids = sys.argv[2:]
else:
print("Usage: %s username track-id ..." % (sys.argv[0],))
print("Usage: %s username track-id ..." % (sys.argv[0],))
sys.exit()
token = util.prompt_for_user_token(username, scope)

View File

@ -1,4 +1,4 @@
# Shows the top artists for a user
# Shows a user's playlists
import pprint
import sys

View File

@ -21,10 +21,10 @@ if token:
sp.trace = False
ranges = ['short_term', 'medium_term', 'long_term']
for range in ranges:
print "range:", range
print ("range:", range)
results = sp.current_user_top_artists(time_range=range, limit=50)
for i, item in enumerate(results['items']):
print i, item['name']
print
print (i, item['name'])
print ()
else:
print("Can't get token for", username)

View File

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

View File

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

View File

@ -1,5 +1,4 @@
# Adds tracks to a playlist
# removes tracks from a playlist
import pprint
import sys

View File

@ -1,5 +1,4 @@
# Adds tracks to a playlist
# removes tracks to a playlist
import pprint
import sys

View File

@ -1,4 +1,3 @@
# Replaces all tracks in a playlist
import pprint

View File

@ -2,6 +2,7 @@
# shows album info for a URN or URL
import spotipy
from spotipy.oauth2 import SpotifyClientCredentials
import sys
import pprint
@ -11,6 +12,7 @@ else:
urn = 'spotify:album:5yTx83u3qerZF7GRJu7eFk'
sp = spotipy.Spotify()
client_credentials_manager = SpotifyClientCredentials()
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
album = sp.album(urn)
pprint.pprint(album)

View File

@ -1,6 +1,7 @@
# shows artist info for a URN or URL
import spotipy
from spotipy.oauth2 import SpotifyClientCredentials
import sys
import pprint
@ -9,7 +10,8 @@ if len(sys.argv) > 1:
else:
urn = 'spotify:artist:3jOstUTkEu2JkjvRdBA5Gu'
sp = spotipy.Spotify()
client_credentials_manager = SpotifyClientCredentials()
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
artist = sp.artist(urn)

View File

@ -1,6 +1,7 @@
# shows artist info for a URN or URL
import spotipy
from spotipy.oauth2 import SpotifyClientCredentials
import sys
import pprint
@ -9,7 +10,8 @@ if len(sys.argv) > 1:
else:
urn = 'spotify:artist:3jOstUTkEu2JkjvRdBA5Gu'
sp = spotipy.Spotify()
client_credentials_manager = SpotifyClientCredentials()
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
response = sp.artist_top_tracks(urn)
for track in response['tracks']:

View File

@ -2,6 +2,7 @@
# shows related artists for the given seed artist
import spotipy
from spotipy.oauth2 import SpotifyClientCredentials
import sys
import pprint
@ -10,7 +11,9 @@ if len(sys.argv) > 1:
else:
artist_name = 'weezer'
sp = spotipy.Spotify()
client_credentials_manager = SpotifyClientCredentials()
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
result = sp.search(q='artist:' + artist_name, type='artist')
try:
name = result['artists']['items'][0]['name']

View File

@ -1,6 +1,7 @@
# shows track info for a URN or URL
import spotipy
from spotipy.oauth2 import SpotifyClientCredentials
import sys
import pprint
@ -9,6 +10,7 @@ if len(sys.argv) > 1:
else:
urn = 'spotify:track:0Svkvt5I79wficMFgaqEQJ'
sp = spotipy.Spotify()
client_credentials_manager = SpotifyClientCredentials()
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
track = sp.track(urn)
pprint.pprint(track)

View File

@ -1,5 +1,8 @@
import spotipy
sp = spotipy.Spotify()
from spotipy.oauth2 import SpotifyClientCredentials
client_credentials_manager = SpotifyClientCredentials()
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
results = sp.search(q='weezer', limit=20)
for i, t in enumerate(results['tracks']['items']):

View File

@ -1,14 +1,15 @@
import spotipy
from spotipy.oauth2 import SpotifyClientCredentials
birdy_uri = 'spotify:artist:2WX2uTcsvV5OnS0inACecP'
spotify = spotipy.Spotify()
client_credentials_manager = SpotifyClientCredentials()
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
results = spotify.artist_albums(birdy_uri, album_type='album')
results = sp.artist_albums(birdy_uri, album_type='album')
albums = results['items']
while results['next']:
results = spotify.next(results)
results = sp.next(results)
albums.extend(results['items'])
for album in albums:

View File

@ -1,12 +1,14 @@
import spotipy
from spotipy.oauth2 import SpotifyClientCredentials
lz_uri = 'spotify:artist:36QJpDe2go2KgaRleHCDTp'
spotify = spotipy.Spotify()
client_credentials_manager = SpotifyClientCredentials()
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
results = spotify.artist_top_tracks(lz_uri)
results = sp.artist_top_tracks(lz_uri)
for track in results['tracks'][:10]:
print('track : ' + track['name'])

View File

@ -1,14 +1,16 @@
import spotipy
from spotipy.oauth2 import SpotifyClientCredentials
import sys
spotify = spotipy.Spotify()
client_credentials_manager = SpotifyClientCredentials()
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
if len(sys.argv) > 1:
name = ' '.join(sys.argv[1:])
else:
name = 'Radiohead'
results = spotify.search(q='artist:' + name, type='artist')
results = sp.search(q='artist:' + name, type='artist')
items = results['artists']['items']
if len(items) > 0:
artist = items[0]

View File

@ -60,4 +60,4 @@ if __name__ == '__main__':
import sys
title = ' '.join(sys.argv[1:])
make_chain(sys.argv[1].lower())

View File

@ -1,6 +1,6 @@
# Gets all the public playlists for the given
# user. Uses Client Credentials flow
#
#
import sys
import spotipy

View File

@ -0,0 +1,30 @@
"""
Deletes user saved album
"""
import pprint
import sys
import json
import spotipy
import spotipy.util as util
if len(sys.argv) > 1:
username = sys.argv[1]
else:
print("Usage: %s username" % (sys.argv[0],))
sys.exit()
scope = 'user-library-modify'
token = util.prompt_for_user_token(username, scope)
if token:
sp = spotipy.Spotify(auth=token)
sp.trace = False
uris = input("input a list of album URIs, URLs or IDs: ")
uris = list(map(str, uris.split()))
deleted = sp.current_user_saved_albums_delete(uris)
print("Deletion successful.")
else:
print("Can't get token for", username)

View File

@ -1,2 +1,4 @@
mock==2.0.0
requests==2.3.0
simplejson==3.13.2
six==1.10.0

View File

@ -9,8 +9,10 @@ setup(
author_email="paul@echonest.com",
url='http://spotipy.readthedocs.org/',
install_requires=[
'mock>=2.0.0',
'requests>=2.3.0',
'six>=1.10.0',
],
'simplejson==3.13.2',
],
license='LICENSE.txt',
packages=['spotipy'])

View File

@ -1,2 +1,5 @@
VERSION='2.0.1'
from .client import Spotify, SpotifyException
VERSION='2.4.5'
from .client import *
from .oauth2 import *
from .util import *

View File

@ -1,16 +1,21 @@
# coding: utf-8
# -*- coding: utf-8 -*-
""" A simple and thin Python library for the Spotify Web API """
from __future__ import print_function
import sys
import requests
__all__ = [
'Spotify',
'SpotifyException'
]
import json
import sys
import time
import requests
import six
""" A simple and thin Python library for the Spotify Web API
"""
class SpotifyException(Exception):
@ -55,7 +60,7 @@ class Spotify(object):
def __init__(self, auth=None, requests_session=True,
client_credentials_manager=None, proxies=None, requests_timeout=None):
"""
Create a Spotify API object.
Creates a Spotify API client.
:param auth: An authorization token (optional)
:param requests_session:
@ -382,6 +387,18 @@ class Spotify(object):
plid = self._get_id('playlist', playlist_id)
return self._get("users/%s/playlists/%s" % (user, plid), fields=fields)
def playlist(self, playlist_id, fields=None, market=None):
""" Gets playlist by id
Parameters:
- playlist - the id of the playlist
- fields - which fields to return
- market - An ISO 3166-1 alpha-2 country code or the string from_token.
"""
plid = self._get_id('playlist', playlist_id)
return self._get("playlists/%s" % (plid), fields=fields)
def user_playlist_tracks(self, user, playlist_id=None, fields=None,
limit=100, offset=0, market=None):
""" Get full details of the tracks of a playlist owned by a user.
@ -507,7 +524,7 @@ class Spotify(object):
Parameters:
- user - the id of the user
- playlist_id - the id of the playlist
- tracks - the list of track ids to add to the playlist
- tracks - the list of track ids to remove from the playlist
- snapshot_id - optional id of the playlist snapshot
"""
@ -527,9 +544,11 @@ class Spotify(object):
Parameters:
- user - the id of the user
- playlist_id - the id of the playlist
- tracks - an array of objects containing Spotify URIs of the tracks to remove with their current positions in the playlist. For example:
[ { "uri":"4iV5W9uYEdYUVa79Axb7Rh", "positions":[2] },
{ "uri":"1301WleyT98MSxVHPZCA6M", "positions":[7] } ]
- tracks - an array of objects containing Spotify URIs of the
tracks to remove with their current positions in the
playlist. For example:
[ { "uri":"4iV5W9uYEdYUVa79Axb7Rh", "positions":[2] },
{ "uri":"1301WleyT98MSxVHPZCA6M", "positions":[7] } ]
- snapshot_id - optional id of the playlist snapshot
"""
@ -564,7 +583,8 @@ class Spotify(object):
Parameters:
- playlist_owner_id - the user id of the playlist owner
- playlist_id - the id of the playlist
- user_ids - the ids of the users that you want to check to see if they follow the playlist. Maximum: 5 ids.
- user_ids - the ids of the users that you want to check to see
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)))
@ -586,17 +606,6 @@ class Spotify(object):
'''
return self._get('me/player/currently-playing')
def current_user_saved_albums(self, limit=20, offset=0):
""" Gets a list of the albums saved in the current authorized user's
"Your Music" library
Parameters:
- limit - the number of albums to return
- offset - the index of the first album to return
"""
return self._get('me/albums', limit=limit, offset=offset)
def current_user_saved_tracks(self, limit=20, offset=0):
""" Gets a list of the tracks saved in the current authorized user's
"Your Music" library
@ -612,8 +621,8 @@ class Spotify(object):
""" Gets a list of the artists followed by the current authorized user
Parameters:
- limit - the number of tracks to return
- after - ghe last artist ID retrieved from the previous request
- limit - the number of artists to return
- after - the last artist ID retrieved from the previous request
"""
return self._get('me/following', type='artist', limit=limit,
@ -686,9 +695,30 @@ class Spotify(object):
Parameters:
- limit - the number of entities to return
'''
'''
return self._get('me/player/recently-played', limit=limit)
def current_user_saved_albums(self, limit=20, offset=0):
""" Gets a list of the albums saved in the current authorized user's
"Your Music" library
Parameters:
- limit - the number of albums to return
- offset - the index of the first album to return
"""
return self._get('me/albums', limit=limit, offset=offset)
def current_user_saved_albums_contains(self, albums=[]):
""" Check if one or more albums is already saved in
the current Spotify users Your Music library.
Parameters:
- albums - a list of album URIs, URLs or IDs
"""
alist = [self._get_id('album', a) for a in albums]
return self._get('me/albums/contains?ids=' + ','.join(alist))
def current_user_saved_albums_add(self, albums=[]):
""" Add one or more albums to the current user's
"Your Music" library.
@ -696,8 +726,17 @@ class Spotify(object):
- albums - a list of album URIs, URLs or IDs
"""
alist = [self._get_id('album', a) for a in albums]
r = self._put('me/albums?ids=' + ','.join(alist))
return r
return self._put('me/albums?ids=' + ','.join(alist))
def current_user_saved_albums_delete(self, albums=[]):
""" Remove one or more albums from the current user's
"Your Music" library.
Parameters:
- albums - a list of album URIs, URLs or IDs
"""
alist = [self._get_id('album', a) for a in albums]
return self._delete('me/albums/?ids=' + ','.join(alist))
def user_follow_artists(self, ids=[]):
''' Follow one or more artists
@ -713,6 +752,20 @@ class Spotify(object):
'''
return self._put('me/following?type=user&ids=' + ','.join(ids))
def user_unfollow_artists(self, ids=[]):
''' Unfollow one or more artists
Parameters:
- ids - a list of artist IDs
'''
return self._delete('me/following?type=artist&ids=' + ','.join(ids))
def user_unfollow_users(self, ids=[]):
''' Unfollow one or more users
Parameters:
- ids - a list of user IDs
'''
return self._delete('me/following?type=user&ids=' + ','.join(ids))
def featured_playlists(self, locale=None, country=None, timestamp=None,
limit=20, offset=0):
""" Get a list of Spotify featured playlists
@ -869,14 +922,6 @@ class Spotify(object):
else:
return results
def audio_analysis(self, id):
""" Get audio analysis for a track based upon its Spotify ID
Parameters:
- id - a track URIs, URLs or IDs
"""
id = self._get_id('track', id)
return self._get('audio-analysis/'+id)
def devices(self):
''' Get a list of user's available devices.
'''
@ -1040,15 +1085,15 @@ class Spotify(object):
fields = id.split(':')
if len(fields) >= 3:
if type != fields[-2]:
self._warn('expected id of type %s but found type %s %s',
type, fields[-2], id)
self._warn('expected id of type %s but found type %s %s' %
(type, fields[-2], id))
return fields[-1]
fields = id.split('/')
if len(fields) >= 3:
itype = fields[-2]
if type != itype:
self._warn('expected id of type %s but found type %s %s',
type, itype, id)
self._warn('expected id of type %s but found type %s %s' %
(type, itype, id))
return fields[-1]
return id

View File

@ -1,11 +1,21 @@
# -*- coding: utf-8 -*-
from __future__ import print_function
__all__ = [
'is_token_expired',
'SpotifyClientCredentials',
'SpotifyOAuth',
'SpotifyOauthError'
]
import base64
import requests
import os
import json
import time
import os
import sys
import time
import requests
# Workaround to support both python 2 & 3
import six

View File

@ -1,15 +1,31 @@
# -*- coding: utf-8 -*-
# shows a user's playlists (need to be authenticated via oauth)
""" Shows a user's playlists (need to be authenticated via oauth) """
from __future__ import print_function
__all__ = [
'CLIENT_CREDS_ENV_VARS',
'prompt_for_user_token'
]
import os
from . import oauth2
import spotipy
CLIENT_CREDS_ENV_VARS = {
'client_id': 'SPOTIPY_CLIENT_ID',
'client_secret': 'SPOTIPY_CLIENT_SECRET',
'client_username': 'SPOTIPY_CLIENT_USERNAME',
'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):
''' 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
Parameters:
@ -41,13 +57,13 @@ def prompt_for_user_token(username, scope=None, client_id = None,
export SPOTIPY_CLIENT_SECRET='your-spotify-client-secret'
export SPOTIPY_REDIRECT_URI='your-app-redirect-url'
Get your credentials at
Get your credentials at
https://developer.spotify.com/my-applications
''')
raise spotipy.SpotifyException(550, -1, 'no credentials set')
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)
# try to get a valid token for this user, from the cache,
@ -82,7 +98,7 @@ def prompt_for_user_token(username, scope=None, client_id = None,
response = input("Enter the URL you were redirected to: ")
print()
print()
print()
code = sp_oauth.parse_response_code(response)
token_info = sp_oauth.get_access_token(code)

View File

@ -1,222 +0,0 @@
# -*- coding: latin-1 -*-
import spotipy
from spotipy import util
import unittest
import pprint
import sys
import simplejson as json
'''
Since these tests require authentication they are maintained
separately from the other tests.
These tests try to be benign and leave your collection and
playlists in a relatively stable state.
'''
class AuthTestSpotipy(unittest.TestCase):
'''
These tests require user authentication
'''
playlist = "spotify:user:plamere:playlist:2oCEWyyAPbZp9xhVSxZavx"
four_tracks = ["spotify:track:6RtPijgfPKROxEzTHNRiDp",
"spotify:track:7IHOIqZUUInxjVkko181PB",
"4VrWlk8IQxevMvERoX08iC",
"http://open.spotify.com/track/3cySlItpiPiIAzU3NyHCJf"]
two_tracks = ["spotify:track:6RtPijgfPKROxEzTHNRiDp",
"spotify:track:7IHOIqZUUInxjVkko181PB"]
other_tracks=["spotify:track:2wySlB6vMzCbQrRnNGOYKa",
"spotify:track:29xKs5BAHlmlX1u4gzQAbJ",
"spotify:track:1PB7gRWcvefzu7t3LJLUlf"]
bad_id = 'BAD_ID'
def test_track_bad_id(self):
try:
track = spotify.track(self.bad_id)
self.assertTrue(False)
except spotipy.SpotifyException:
self.assertTrue(True)
def test_basic_user_profile(self):
user = spotify.user(username)
self.assertTrue(user['id'] == username)
def test_current_user(self):
user = spotify.current_user()
self.assertTrue(user['id'] == username)
def test_me(self):
user = spotify.me()
self.assertTrue(user['id'] == username)
def test_user_playlists(self):
playlists = spotify.user_playlists(username, limit=5)
self.assertTrue('items' in playlists)
self.assertTrue(len(playlists['items']) == 5)
def test_user_playlist_tracks(self):
playlists = spotify.user_playlists(username, limit=5)
self.assertTrue('items' in playlists)
for playlist in playlists['items']:
user = playlist['owner']['id']
pid = playlist['id']
results = spotify.user_playlist_tracks(user, pid)
self.assertTrue(len(results['items']) >= 0)
def user_playlist_tracks(self, user, playlist_id = None, fields=None,
limit=100, offset=0):
# known API issue currently causes this test to fail
# the issue is that the API doesn't currently respect the
# limit paramter
self.assertTrue(len(playlists['items']) == 5)
def test_current_user_saved_tracks(self):
tracks = spotify.current_user_saved_tracks()
self.assertTrue(len(tracks['items']) > 0)
def test_current_user_saved_albums(self):
albums = spotify.current_user_saved_albums()
self.assertTrue(len(albums['items']) > 0)
def test_current_user_playlists(self):
playlists = spotify.current_user_playlists(limit=10)
self.assertTrue('items' in playlists)
self.assertTrue(len(playlists['items']) == 10)
def test_user_playlist_follow(self):
spotify.user_playlist_follow_playlist('plamere', '4erXB04MxwRAVqcUEpu30O')
follows = spotify.user_playlist_is_following('plamere', '4erXB04MxwRAVqcUEpu30O', ['plamere'])
self.assertTrue(len(follows) == 1, 'proper follows length')
self.assertTrue(follows[0], 'is following')
spotify.user_playlist_unfollow('plamere', '4erXB04MxwRAVqcUEpu30O')
follows = spotify.user_playlist_is_following('plamere', '4erXB04MxwRAVqcUEpu30O', ['plamere'])
self.assertTrue(len(follows) == 1, 'proper follows length')
self.assertFalse(follows[0], 'is no longer following')
def test_current_user_save_and_unsave_tracks(self):
tracks = spotify.current_user_saved_tracks()
total = tracks['total']
spotify.current_user_saved_tracks_add(self.four_tracks)
tracks = spotify.current_user_saved_tracks()
new_total = tracks['total']
self.assertTrue(new_total - total == len(self.four_tracks))
tracks = spotify.current_user_saved_tracks_delete(self.four_tracks)
tracks = spotify.current_user_saved_tracks()
new_total = tracks['total']
self.assertTrue(new_total == total)
def test_categories(self):
response = spotify.categories()
self.assertTrue(len(response['categories']) > 0)
def test_category_playlists(self):
response = spotify.categories()
for cat in response['categories']['items']:
cat_id = cat['id']
response = spotify.category_playlists(category_id=cat_id)
self.assertTrue(len(response['playlists']["items"]) > 0)
def test_new_releases(self):
response = spotify.new_releases()
self.assertTrue(len(response['albums']) > 0)
def test_featured_releases(self):
response = spotify.featured_playlists()
self.assertTrue(len(response['playlists']) > 0)
def test_current_user_follows(self):
response = spotify.current_user_followed_artists()
artists = response['artists']
self.assertTrue(len(artists['items']) > 0)
def test_current_user_top_tracks(self):
response = spotify.current_user_top_tracks()
items = response['items']
self.assertTrue(len(items) > 0)
def test_current_user_top_artists(self):
response = spotify.current_user_top_artists()
items = response['items']
self.assertTrue(len(items) > 0)
def get_or_create_spotify_playlist(self, username, playlist_name):
playlists = spotify.user_playlists(username)
while playlists:
for item in playlists['items']:
if item['name'] == playlist_name:
return item['id']
playlists = spotify.next(playlists)
playlist = spotify.user_playlist_create(username, playlist_name)
playlist_id = playlist['uri']
return playlist_id
def test_user_playlist_ops(self):
# create empty playlist
playlist_id = self.get_or_create_spotify_playlist(username,
'spotipy-testing-playlist-1')
# remove all tracks from it
spotify.user_playlist_replace_tracks(username, playlist_id,[])
playlist = spotify.user_playlist(username, playlist_id)
self.assertTrue(playlist['tracks']['total'] == 0)
self.assertTrue(len(playlist['tracks']['items']) == 0)
# add tracks to it
spotify.user_playlist_add_tracks(username, playlist_id, self.four_tracks)
playlist = spotify.user_playlist(username, playlist_id)
self.assertTrue(playlist['tracks']['total'] == 4)
self.assertTrue(len(playlist['tracks']['items']) == 4)
# remove two tracks from it
spotify.user_playlist_remove_all_occurrences_of_tracks (username,
playlist_id, self.two_tracks)
playlist = spotify.user_playlist(username, playlist_id)
self.assertTrue(playlist['tracks']['total'] == 2)
self.assertTrue(len(playlist['tracks']['items']) == 2)
# replace with 3 other tracks
spotify.user_playlist_replace_tracks(username,
playlist_id, self.other_tracks)
playlist = spotify.user_playlist(username, playlist_id)
self.assertTrue(playlist['tracks']['total'] == 3)
self.assertTrue(len(playlist['tracks']['items']) == 3)
if __name__ == '__main__':
if len(sys.argv) > 1:
username = sys.argv[1]
del sys.argv[1]
scope = 'playlist-modify-public '
scope += 'user-library-read '
scope += 'user-follow-read '
scope += 'user-library-modify '
scope += 'user-read-private '
scope += 'user-top-read'
token = util.prompt_for_user_token(username, scope)
spotify = spotipy.Spotify(auth=token)
spotify.trace = False
unittest.main()
else:
print("Usage: %s username" % (sys.argv[0],))

View File

@ -1,70 +0,0 @@
# -*- coding: latin-1 -*-
import spotipy
from spotipy import util
import unittest
import pprint
import sys
import simplejson as json
from spotipy.oauth2 import SpotifyClientCredentials
'''
Since these tests require authentication they are maintained
separately from the other tests.
These tests try to be benign and leave your collection and
playlists in a relatively stable state.
'''
class AuthTestSpotipy(unittest.TestCase):
'''
These tests require user authentication
'''
playlist = "spotify:user:plamere:playlist:2oCEWyyAPbZp9xhVSxZavx"
four_tracks = ["spotify:track:6RtPijgfPKROxEzTHNRiDp",
"spotify:track:7IHOIqZUUInxjVkko181PB",
"4VrWlk8IQxevMvERoX08iC",
"http://open.spotify.com/track/3cySlItpiPiIAzU3NyHCJf"]
two_tracks = ["spotify:track:6RtPijgfPKROxEzTHNRiDp",
"spotify:track:7IHOIqZUUInxjVkko181PB"]
other_tracks=["spotify:track:2wySlB6vMzCbQrRnNGOYKa",
"spotify:track:29xKs5BAHlmlX1u4gzQAbJ",
"spotify:track:1PB7gRWcvefzu7t3LJLUlf"]
bad_id = 'BAD_ID'
def test_audio_analysis(self):
result = spotify.audio_analysis(self.four_tracks[0])
assert('beats' in result)
def test_audio_features(self):
results = spotify.audio_features(self.four_tracks)
self.assertTrue(len(results) == len(self.four_tracks))
for track in results:
assert('speechiness' in track)
def test_audio_features_with_bad_track(self):
bad_tracks = []
bad_tracks = ['spotify:track:bad']
input = self.four_tracks + bad_tracks
results = spotify.audio_features(input)
self.assertTrue(len(results) == len(input))
for track in results[:-1]:
if track != None:
assert('speechiness' in track)
self.assertTrue(results[-1] == None)
def test_recommendations(self):
results = spotify.recommendations(seed_tracks=self.four_tracks, min_danceability=0, max_loudness=0, target_popularity=50)
self.assertTrue(len(results['tracks']) == 20)
if __name__ == '__main__':
client_credentials_manager = SpotifyClientCredentials()
spotify = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
spotify.trace = False
unittest.main()

View File

@ -1,27 +0,0 @@
# -*- coding: latin-1 -*-
import spotipy
from spotipy.oauth2 import SpotifyClientCredentials
import unittest
'''
Client Credentials Requests Tests
'''
class ClientCredentialsTestSpotipy(unittest.TestCase):
'''
These tests require user authentication
'''
muse_urn = 'spotify:artist:12Chz98pHFMPJEknJQMWvI'
def test_request_with_token(self):
artist = spotify.artist(self.muse_urn)
self.assertTrue(artist['name'] == 'Muse')
if __name__ == '__main__':
spotify_cc = SpotifyClientCredentials()
spotify = spotipy.Spotify(client_credentials_manager=spotify_cc)
spotify.trace = False
unittest.main()

297
tests/test_auth.py Normal file
View File

@ -0,0 +1,297 @@
# -*- coding: utf-8 -*-
"""
These tests require user authentication - provide client credentials using the
following environment variables
::
'SPOTIPY_CLIENT_USERNAME'
'SPOTIPY_CLIENT_ID'
'SPOTIPY_CLIENT_SECRET'
'SPOTIPY_REDIRECT_URI'
"""
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 (
CLIENT_CREDS_ENV_VARS as CCEV,
prompt_for_user_token,
Spotify,
SpotifyException,
)
class AuthTestSpotipy(unittest.TestCase):
"""
These tests require user authentication - provide client credentials using the
following environment variables
::
'SPOTIPY_CLIENT_USERNAME'
'SPOTIPY_CLIENT_ID'
'SPOTIPY_CLIENT_SECRET'
'SPOTIPY_REDIRECT_URI'
"""
playlist = "spotify:user:plamere:playlist:2oCEWyyAPbZp9xhVSxZavx"
playlist_new_id = "spotify:playlist:7GlxpQjjxRjmbb3RP2rDqI"
four_tracks = ["spotify:track:6RtPijgfPKROxEzTHNRiDp",
"spotify:track:7IHOIqZUUInxjVkko181PB",
"4VrWlk8IQxevMvERoX08iC",
"http://open.spotify.com/track/3cySlItpiPiIAzU3NyHCJf"]
two_tracks = ["spotify:track:6RtPijgfPKROxEzTHNRiDp",
"spotify:track:7IHOIqZUUInxjVkko181PB"]
other_tracks=["spotify:track:2wySlB6vMzCbQrRnNGOYKa",
"spotify:track:29xKs5BAHlmlX1u4gzQAbJ",
"spotify:track:1PB7gRWcvefzu7t3LJLUlf"]
album_ids = ["spotify:album:6kL09DaURb7rAoqqaA51KU",
"spotify:album:6RTzC0rDbvagTSJLlY7AKl"]
bad_id = 'BAD_ID'
@classmethod
def setUpClass(self):
missing = list(filter(lambda var: not os.getenv(CCEV[var]), CCEV))
if missing:
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.scope = (
'playlist-modify-public '
'user-library-read '
'user-follow-read '
'user-library-modify '
'user-read-private '
'user-top-read '
'user-follow-modify'
)
self.token = prompt_for_user_token(self.username, scope=self.scope)
self.spotify = Spotify(auth=self.token)
def test_track_bad_id(self):
try:
self.spotify.track(self.bad_id)
self.assertTrue(False)
except SpotifyException:
self.assertTrue(True)
def test_basic_user_profile(self):
user = self.spotify.user(self.username)
self.assertTrue(user['id'] == self.username.lower())
def test_current_user(self):
user = self.spotify.current_user()
self.assertTrue(user['id'] == self.username.lower())
def test_me(self):
user = self.spotify.me()
self.assertTrue(user['id'] == self.username.lower())
def test_user_playlists(self):
playlists = self.spotify.user_playlists(self.username, limit=5)
self.assertTrue('items' in playlists)
self.assertTrue(len(playlists['items']) == 5)
def test_user_playlist_tracks(self):
playlists = self.spotify.user_playlists(self.username, limit=5)
self.assertTrue('items' in playlists)
for playlist in playlists['items']:
user = playlist['owner']['id']
pid = playlist['id']
results = self.spotify.user_playlist_tracks(user, pid)
self.assertTrue(len(results['items']) >= 0)
def user_playlist_tracks(self, user, playlist_id = None, fields=None,
limit=100, offset=0):
# known API issue currently causes this test to fail
# the issue is that the API doesn't currently respect the
# limit parameter
self.assertTrue(len(playlists['items']) == 5)
def test_current_user_saved_albums(self):
# List
albums = self.spotify.current_user_saved_albums()
self.assertTrue(len(albums['items']) == 1)
# Add
self.spotify.current_user_saved_albums_add(self.album_ids)
# Contains
self.assertTrue(self.spotify.current_user_saved_albums_contains(self.album_ids) == [True, True])
# Remove
self.spotify.current_user_saved_albums_delete(self.album_ids)
albums = self.spotify.current_user_saved_albums()
self.assertTrue(len(albums['items']) == 1)
def test_current_user_playlists(self):
playlists = self.spotify.current_user_playlists(limit=10)
self.assertTrue('items' in playlists)
self.assertTrue(len(playlists['items']) == 10)
def test_user_playlist_follow(self):
self.spotify.user_playlist_follow_playlist('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(follows[0], 'is following')
self.spotify.user_playlist_unfollow('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.assertFalse(follows[0], 'is no longer following')
def test_current_user_saved_tracks(self):
tracks = self.spotify.current_user_saved_tracks()
self.assertTrue(len(tracks['items']) > 0)
def test_current_user_save_and_unsave_tracks(self):
tracks = self.spotify.current_user_saved_tracks()
total = tracks['total']
self.spotify.current_user_saved_tracks_add(self.four_tracks)
tracks = self.spotify.current_user_saved_tracks()
new_total = tracks['total']
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()
new_total = tracks['total']
self.assertTrue(new_total == total)
def test_categories(self):
response = self.spotify.categories()
self.assertTrue(len(response['categories']) > 0)
def test_category_playlists(self):
response = self.spotify.categories()
for cat in response['categories']['items']:
cat_id = cat['id']
response = self.spotify.category_playlists(category_id=cat_id)
if len(response['playlists']["items"]) > 0:
break
self.assertTrue(True)
def test_new_releases(self):
response = self.spotify.new_releases()
self.assertTrue(len(response['albums']) > 0)
def test_featured_releases(self):
response = self.spotify.featured_playlists()
self.assertTrue(len(response['playlists']) > 0)
def test_current_user_follows(self):
response = self.spotify.current_user_followed_artists()
artists = response['artists']
self.assertTrue(len(artists['items']) > 0)
def test_current_user_top_tracks(self):
response = self.spotify.current_user_top_tracks()
items = response['items']
self.assertTrue(len(items) > 0)
def test_current_user_top_artists(self):
response = self.spotify.current_user_top_artists()
items = response['items']
self.assertTrue(len(items) > 0)
def get_or_create_spotify_playlist(self, playlist_name):
playlists = self.spotify.user_playlists(self.username)
while playlists:
for item in playlists['items']:
if item['name'] == playlist_name:
return item['id']
playlists = self.spotify.next(playlists)
playlist = self.spotify.user_playlist_create(self.username, playlist_name)
playlist_id = playlist['uri']
return playlist_id
def test_user_playlist_ops(self):
# create empty playlist
playlist_id = self.get_or_create_spotify_playlist('spotipy-testing-playlist-1')
# remove all tracks from it
self.spotify.user_playlist_replace_tracks(self.username, playlist_id,[])
playlist = self.spotify.user_playlist(self.username, playlist_id)
self.assertTrue(playlist['tracks']['total'] == 0)
self.assertTrue(len(playlist['tracks']['items']) == 0)
# add tracks to it
self.spotify.user_playlist_add_tracks(self.username, playlist_id, self.four_tracks)
playlist = self.spotify.user_playlist(self.username, playlist_id)
self.assertTrue(playlist['tracks']['total'] == 4)
self.assertTrue(len(playlist['tracks']['items']) == 4)
# remove two tracks from it
self.spotify.user_playlist_remove_all_occurrences_of_tracks (self.username,
playlist_id, self.two_tracks)
playlist = self.spotify.user_playlist(self.username, playlist_id)
self.assertTrue(playlist['tracks']['total'] == 2)
self.assertTrue(len(playlist['tracks']['items']) == 2)
# replace with 3 other tracks
self.spotify.user_playlist_replace_tracks(self.username,
playlist_id, self.other_tracks)
playlist = self.spotify.user_playlist(self.username, playlist_id)
self.assertTrue(playlist['tracks']['total'] == 3)
self.assertTrue(len(playlist['tracks']['items']) == 3)
def test_playlist(self):
# New playlist ID
pl = self.spotify.playlist(self.playlist_new_id)
self.assertTrue(pl["tracks"]["total"] > 0)
# Old playlist ID
pl = self.spotify.playlist(self.playlist)
self.assertTrue(pl["tracks"]["total"] > 0)
def test_user_follows_and_unfollows_artist(self):
# Initially follows 1 artist
res = self.spotify.current_user_followed_artists()
self.assertTrue(res['artists']['total'] == 1)
# Follow 2 more artists
artists = ["6DPYiyq5kWVQS4RGwxzPC7", "0NbfKEOTQCcwd6o7wSDOHI"]
self.spotify.user_follow_artists(artists)
res = self.spotify.current_user_followed_artists()
self.assertTrue(res['artists']['total'] == 3)
# Unfollow these 2 artists
self.spotify.user_unfollow_artists(artists)
res = self.spotify.current_user_followed_artists()
self.assertTrue(res['artists']['total'] == 1)
def test_user_follows_and_unfollows_user(self):
# TODO improve after implementing `me/following/contains`
users = ["11111204", "xlqeojt6n7on0j7coh9go8ifd"]
# Follow 2 more users
self.spotify.user_follow_users(users)
# Unfollow these 2 users
self.spotify.user_unfollow_users(users)
if __name__ == '__main__':
unittest.main()

91
tests/test_auth2.py Normal file
View File

@ -0,0 +1,91 @@
# -*- coding: utf-8 -*-
"""
These tests require user authentication - provide client credentials using the
following environment variables
::
'SPOTIPY_CLIENT_USERNAME'
'SPOTIPY_CLIENT_ID'
'SPOTIPY_CLIENT_SECRET'
'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 (
Spotify,
SpotifyClientCredentials,
)
class AuthTestSpotipy(unittest.TestCase):
"""
These tests require user authentication - provide client credentials using the
following environment variables
::
'SPOTIPY_CLIENT_USERNAME'
'SPOTIPY_CLIENT_ID'
'SPOTIPY_CLIENT_SECRET'
'SPOTIPY_REDIRECT_URI'
"""
playlist = "spotify:user:plamere:playlist:2oCEWyyAPbZp9xhVSxZavx"
four_tracks = ["spotify:track:6RtPijgfPKROxEzTHNRiDp",
"spotify:track:7IHOIqZUUInxjVkko181PB",
"4VrWlk8IQxevMvERoX08iC",
"http://open.spotify.com/track/3cySlItpiPiIAzU3NyHCJf"]
two_tracks = ["spotify:track:6RtPijgfPKROxEzTHNRiDp",
"spotify:track:7IHOIqZUUInxjVkko181PB"]
other_tracks=["spotify:track:2wySlB6vMzCbQrRnNGOYKa",
"spotify:track:29xKs5BAHlmlX1u4gzQAbJ",
"spotify:track:1PB7gRWcvefzu7t3LJLUlf"]
bad_id = 'BAD_ID'
@classmethod
def setUpClass(self):
self.spotify = Spotify(client_credentials_manager=SpotifyClientCredentials())
self.spotify.trace = False
def test_audio_analysis(self):
result = self.spotify.audio_analysis(self.four_tracks[0])
assert('beats' in result)
def test_audio_features(self):
results = self.spotify.audio_features(self.four_tracks)
self.assertTrue(len(results) == len(self.four_tracks))
for track in results:
assert('speechiness' in track)
def test_audio_features_with_bad_track(self):
bad_tracks = []
bad_tracks = ['spotify:track:bad']
input = self.four_tracks + bad_tracks
results = self.spotify.audio_features(input)
self.assertTrue(len(results) == len(input))
for track in results[:-1]:
if track != None:
assert('speechiness' in track)
self.assertTrue(results[-1] == None)
def test_recommendations(self):
results = self.spotify.recommendations(seed_tracks=self.four_tracks, min_danceability=0, max_loudness=0, target_popularity=50)
self.assertTrue(len(results['tracks']) == 20)
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1,44 @@
# -*- coding: utf-8 -*-
""" Client Credentials Requests Tests """
import os
import sys
import unittest
sys.path.insert(0, os.path.abspath(os.pardir))
from spotipy import (
Spotify,
SpotifyClientCredentials,
)
class ClientCredentialsTestSpotipy(unittest.TestCase):
"""
These tests require user authentication - provide client credentials using the
following environment variables
::
'SPOTIPY_CLIENT_USERNAME'
'SPOTIPY_CLIENT_ID'
'SPOTIPY_CLIENT_SECRET'
'SPOTIPY_REDIRECT_URI'
"""
@classmethod
def setUpClass(self):
self.spotify = Spotify(client_credentials_manager=SpotifyClientCredentials())
self.spotify.trace = False
muse_urn = 'spotify:artist:12Chz98pHFMPJEknJQMWvI'
def test_request_with_token(self):
artist = self.spotify.artist(self.muse_urn)
self.assertTrue(artist['name'] == 'Muse')
if __name__ == '__main__':
unittest.main()

View File

@ -1,8 +1,15 @@
from spotipy.oauth2 import SpotifyOAuth
import json
# -*- coding: utf-8 -*-
import io
import json
import os
import sys
import unittest
sys.path.insert(0, os.path.abspath(os.pardir))
from spotipy import SpotifyOAuth
try:
import unittest.mock as mock
except ImportError:
@ -166,4 +173,5 @@ class TestSpotifyOAuth(unittest.TestCase):
if __name__ == '__main__':
unittest.main()

View File

@ -1,13 +1,36 @@
# -*- coding: latin-1 -*-
import spotipy
import unittest
# -*- coding: utf-8 -*-
import os
import pprint
import sys
import unittest
import requests
from spotipy.client import SpotifyException
sys.path.insert(0, os.path.abspath(os.pardir))
from spotipy import (
CLIENT_CREDS_ENV_VARS as CCEV,
prompt_for_user_token,
Spotify,
SpotifyException,
)
class TestSpotipy(unittest.TestCase):
"""
These tests require user authentication - provide client credentials using the
following environment variables
::
'SPOTIPY_CLIENT_USERNAME'
'SPOTIPY_CLIENT_ID'
'SPOTIPY_CLIENT_SECRET'
'SPOTIPY_REDIRECT_URI'
"""
creep_urn = 'spotify:track:3HfB5hBU0dmBt8T0iCmH42'
creep_id = '3HfB5hBU0dmBt8T0iCmH42'
creep_url = 'http://open.spotify.com/track/3HfB5hBU0dmBt8T0iCmH42'
@ -22,8 +45,20 @@ class TestSpotipy(unittest.TestCase):
bad_id = 'BAD_ID'
def setUp(self):
self.spotify = spotipy.Spotify()
@classmethod
def setUpClass(self):
missing = list(filter(lambda var: not os.getenv(CCEV[var]), CCEV))
if missing:
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.scope = 'user-library-read'
self.token = prompt_for_user_token(self.username, scope=self.scope)
self.spotify = Spotify(auth=self.token)
def test_artist_urn(self):
artist = self.spotify.artist(self.radiohead_urn)
@ -41,7 +76,7 @@ class TestSpotipy(unittest.TestCase):
def test_album_tracks(self):
results = self.spotify.album_tracks(self.pinkerton_urn)
self.assertTrue(len(results['items']) == 10)
def test_album_tracks_many(self):
results = self.spotify.album_tracks(self.angeles_haydn_urn)
tracks = results['items']
@ -74,7 +109,7 @@ class TestSpotipy(unittest.TestCase):
try:
track = self.spotify.track(self.el_scorcho_bad_urn)
self.assertTrue(False)
except spotipy.SpotifyException:
except SpotifyException:
self.assertTrue(True)
def test_tracks(self):
@ -121,11 +156,11 @@ class TestSpotipy(unittest.TestCase):
self.assertTrue(found)
def test_search_timeout(self):
sp = spotipy.Spotify(requests_timeout=.1)
sp = Spotify(auth=self.token, requests_timeout=.01)
try:
results = sp.search(q='my*', type='track')
self.assertTrue(False, 'unexpected search timeout')
except requests.ReadTimeout:
except requests.Timeout:
self.assertTrue(True, 'expected search timeout')
@ -149,14 +184,14 @@ class TestSpotipy(unittest.TestCase):
try:
track = self.spotify.track(self.bad_id)
self.assertTrue(False)
except spotipy.SpotifyException:
except SpotifyException:
self.assertTrue(True)
def test_track_bad_id(self):
try:
track = self.spotify.track(self.bad_id)
self.assertTrue(False)
except spotipy.SpotifyException:
except SpotifyException:
self.assertTrue(True)
def test_unauthenticated_post_fails(self):
@ -166,20 +201,17 @@ class TestSpotipy(unittest.TestCase):
cm.exception.http_status == 403)
def test_custom_requests_session(self):
from requests import Session
sess = Session()
sess = requests.Session()
sess.headers["user-agent"] = "spotipy-test"
with_custom_session = spotipy.Spotify(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")
def test_force_no_requests_session(self):
from requests import Session
with_no_session = spotipy.Spotify(requests_session=False)
self.assertFalse(isinstance(with_no_session._session, Session))
with_no_session = Spotify(auth=self.token, requests_session=False)
self.assertFalse(isinstance(with_no_session._session, requests.Session))
self.assertTrue(with_no_session.user(user="akx")["uri"] == "spotify:user:akx")
'''
Need tests for:
@ -188,4 +220,5 @@ class TestSpotipy(unittest.TestCase):
'''
if __name__ == '__main__':
unittest.main()

View File

@ -3,6 +3,7 @@ envlist = py27,py34
[testenv]
deps=
requests
simplejson
six
py27: mock
commands=python -m unittest discover tests
commands=python -m unittest discover -v tests