diff --git a/CHANGELOG.md b/CHANGELOG.md index de1c5e4..bbd8107 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [2.6.3] - 2020-01-16 + +### Fixed + + - Fixed broken doc in 2.6.2 + +## [2.6.2] - 2020-01-16 + +### Fixed + + - Fixed broken examples in README, examples and doc + ### Changed - Allow session keepalive diff --git a/README.md b/README.md index 8a52a79..a82dbcf 100644 --- a/README.md +++ b/README.md @@ -29,27 +29,34 @@ or easy_install spotipy ``` - ## Dependencies - [Requests](https://github.com/kennethreitz/requests) - spotipy requires the requests package to be installed ## Quick Start -To get started, simply install spotipy, create a Spotify object and call methods: + +A full set of examples can be found in the [online documentation](http://spotipy.readthedocs.org/) and in the [Spotipy examples directory](https://github.com/plamere/spotipy/tree/master/examples). Here are two basic examples. + +To get started, install spotipy and create an app on https://developers.spotify.com/. +Add your new ID and SECRET to your environment: + + export SPOTIPY_CLIENT_ID='your-spotify-client-id' + export SPOTIPY_CLIENT_SECRET='your-spotify-client-secret' + +Then, create a Spotify object and call methods: ```python import spotipy -sp = spotipy.Spotify() +from spotipy.oauth2 import SpotifyClientCredentials + +sp = spotipy.Spotify(client_credentials_manager=SpotifyClientCredentials()) results = sp.search(q='weezer', limit=20) for i, t in enumerate(results['tracks']['items']): print(' ', i, t['name']) ``` -A full set of examples can be found in the [online documentation](http://spotipy.readthedocs.org/) and in the [Spotipy examples directory](https://github.com/plamere/spotipy/tree/master/examples). - - ## 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. \ No newline at end of file +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. diff --git a/docs/index.rst b/docs/index.rst index efb52cf..f652dd2 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -27,7 +27,6 @@ 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' @@ -44,7 +43,6 @@ for the top 10 tracks for Led Zeppelin:: 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 @@ -71,9 +69,9 @@ API `_ documentation. Installation ============ -Install *Spotipy* with:: +Install or upgrade *Spotipy* with:: - pip install spotipy + pip install spotipy --upgrade Or with:: @@ -84,38 +82,19 @@ Or you can get the source from github at https://github.com/plamere/spotipy Getting Started =============== -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) - -Authorized requests -======================= -Many methods require user authentication. For these requests you will need to -generate an authorization token that indicates that the user has granted -permission for your application to perform the given task. You will need to +All methods require user authorization. You will need to register your app to get the credentials necessary to make authorized calls. Even if your script does not have an accessible URL you will need to specify one when registering your application which the Spotify authentication server will redirect to after successful login. The URL doesn't need to be publicly -accessible, so you can specify "http://localhost/", and after succesfully -authenticating your app, you can simply copy the -"http://localhost/?code=..." URL from your browser and paste it to the -console where your script is running. +accessible, so you can specify "http://localhost/". Register your app at `My Applications `_ and register the redirect URI mentioned in the above paragragh. - *spotipy* supports two authorization flows: - The **Authorization Code flow** This method is suitable for long-running applications @@ -123,11 +102,18 @@ redirect URI mentioned in the above paragragh. - The **Client Credentials flow** The method makes it possible to authenticate your requests to the Spotify Web API and to obtain - a higher rate limit than you would + a higher rate limit than you would with the Authorization Code flow. Authorization Code Flow ======================= + +This flow is suitable for long-running applications in which the user grants +permission only once. It provides an access token that can be refreshed. +Since the token exchange involves sending your secret key, perform this on a +secure location, like a backend service, and not from a client such as a +browser or from a mobile app. + 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:: @@ -144,14 +130,16 @@ you can set environment variables like so:: Call ``util.prompt_for_user_token`` method with the username and the desired scope (see `Using Scopes `_ for information -about scopes) and credentials. This will coordinate the user authorization via +about scopes) and credentials. After succesfully +authenticating your app, you can simply copy the +"http://localhost/?code=..." URL from your browser and paste it to the +console where your script is running. This will coordinate the user authorization via your web browser and callback to the SPOTIPY_REDIRECT_URI you were redirected to with the authorization token appended. The credentials are cached locally and 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 @@ -177,6 +165,11 @@ Here's an example of getting user authorization to read a user's saved tracks:: Client Credentials Flow ======================= +The Client Credentials flow is used in server-to-server authentication. Only +endpoints that do not access user information can be accessed. The advantage here +in comparison with requests to the Web API made without an access token, +is that a higher rate limit is applied. + To support the **Client Credentials Flow** *Spotipy* provides a class SpotifyClientCredentials that can be used to authenticate requests like so:: @@ -196,9 +189,6 @@ class SpotifyClientCredentials that can be used to authenticate requests like so else: 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 IDs URIs and URLs ======================= @@ -223,8 +213,6 @@ Here are a few more examples of using *Spotipy*. Add tracks to a playlist:: - from __future__ import print_function - import pprint import sys import spotipy @@ -254,7 +242,6 @@ 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 @@ -366,6 +353,7 @@ Spotipy authored by Paul Lamere (plamere) with contributions by: - Michael Birtwell // mbirtwell - Harrison Hayes // Harrison97 - Stephane Bruckert // stephanebruckert + - Ritiek Malhotra // ritiek License ======= diff --git a/examples/artist_albums.py b/examples/artist_albums.py index 8cb53db..d426c9a 100644 --- a/examples/artist_albums.py +++ b/examples/artist_albums.py @@ -1,3 +1,4 @@ +from spotipy.oauth2 import SpotifyClientCredentials import sys import spotipy @@ -31,7 +32,7 @@ def show_artist_albums(artist): if __name__ == '__main__': - sp = spotipy.Spotify() + sp = spotipy.Spotify(client_credentials_manager=SpotifyClientCredentials()) if len(sys.argv) < 2: print(('Usage: {0} artist name'.format(sys.argv[0]))) diff --git a/examples/artist_discography.py b/examples/artist_discography.py index 1f9c837..75647f1 100644 --- a/examples/artist_discography.py +++ b/examples/artist_discography.py @@ -1,3 +1,4 @@ +from spotipy.oauth2 import SpotifyClientCredentials import sys import spotipy @@ -52,7 +53,8 @@ def show_artist(artist): if __name__ == '__main__': - sp = spotipy.Spotify() + client_credentials_manager = SpotifyClientCredentials() + sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager) sp.trace = False if len(sys.argv) < 2: diff --git a/examples/client_credentials_flow.py b/examples/client_credentials_flow.py index ab1f315..856bf5e 100644 --- a/examples/client_credentials_flow.py +++ b/examples/client_credentials_flow.py @@ -1,10 +1,10 @@ from spotipy.oauth2 import SpotifyClientCredentials import spotipy -import pprint +from pprint import pprint client_credentials_manager = SpotifyClientCredentials() sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager) search_str = 'Muse' result = sp.search(search_str) -pprint.pprint(result) +pprint(result) diff --git a/examples/deadmau5.gv b/examples/deadmau5.gv deleted file mode 100644 index b5873ca..0000000 --- a/examples/deadmau5.gv +++ /dev/null @@ -1,31 +0,0 @@ -digraph G { - "deadmau5" -> "Billy Newton-Davis" [label="All U Ever Want"]; - "deadmau5" -> "Melleefresh" [label="Afterhours (The Remixes)"]; - "deadmau5" -> "Imogen Heap" [label="Telemiscommunications (Remixes)"]; - "deadmau5" -> "Kaskade" [label="DJ Hero EP"]; - "Billy Newton-Davis" -> "Spekrfreks" [label="Back It Up"]; - "Billy Newton-Davis" -> "Cajjmere Wray" [label="Fuk Chat"]; - "Billy Newton-Davis" -> "Nino Anthony" [label="Everything I Wanna Do Remixes"]; - "Melleefresh" -> "Wutam" [label="Do You Wannit Now"]; - "Melleefresh" -> "Stereo Scum" [label="How Dangerous"]; - "Melleefresh" -> "Tyler Michaud" [label="Kisses Remixes"]; - "Imogen Heap" -> "Ron van den Beuken" [label="Headlock"]; - "Spekrfreks" -> "SpekrFreks Feat. Michelle Ericsson" [label="Tears of Blood"]; - "Spekrfreks" -> "Michelle Ericsson" [label="Voyager EP"]; - "Nino Anthony" -> "Mr. Eyez" [label="Night Muzik"]; - "Tyler Michaud" -> "Interstate" [label="Junkie"]; - "Tyler Michaud" -> "Moonbeam" [label="Openhearted"]; - "Ron van den Beuken" -> "Simon Demillo" [label="Chaos"]; - "Ron van den Beuken" -> "Tatana" [label="United Music"]; - "Ron van den Beuken" -> "Fidde Stiggson" [label="Visions"]; - "Ron van den Beuken" -> "Tom Pulse" [label="Time"]; - "Michelle Ericsson" -> "Alex Torn" [label="Electro Avenue"]; - "Mr. Eyez" -> "John Joshua feat. Mr Eyez" [label="Way of Life"]; - "Mr. Eyez" -> "Doug Smuggler" [label="Sukka MC's"]; - "Mr. Eyez" -> "New Vegas" [label="Hard Funk"]; - "Interstate" -> "Hammer & Bennett" [label="Coldharbour Selections Part 8"]; - "Tom Pulse" -> "Tom Pulse feat. Fit4Funk" [label="Flying Through the Air"]; - "Hammer & Bennett" -> "Lens" [label="Coldharbour Selections Part 10"]; - "Lens" -> "Santiago Nino" [label="Coldharbour Selections Part 6"]; - "Santiago Nino" -> "Hammer" [label="Coldharbour Selections Part 19"]; -} diff --git a/examples/deadmau5.png b/examples/deadmau5.png deleted file mode 100644 index 7343e63..0000000 Binary files a/examples/deadmau5.png and /dev/null differ diff --git a/examples/long_track_test.dat b/examples/long_track_test.dat deleted file mode 100644 index fac3f95..0000000 --- a/examples/long_track_test.dat +++ /dev/null @@ -1,283 +0,0 @@ -spotify:track:0qMujfRhXLalSaDtN0PPMS -spotify:track:0S7Dd8FfW5ZomBAwY3rBg6 -spotify:track:5gCvgOuAxw8YpHCV9m1xue -spotify:track:0eZoEIFWMNTt3BVejJdUH7 -spotify:track:3P6OwCX7Ofiaaqtvujb6i5 -spotify:track:2q3PUwv7bnSFHFn73WyzIv -spotify:track:2sOwqF4Meye7XjSiO2oZk8 -spotify:track:5Hfa4TyZO402MFD10VbRCv -spotify:track:6SJFk7LilJXZwp8rvzGc1T -spotify:track:1dVy8va6CN9sWd8ISPWbmg -spotify:track:2UC9CbjVQSCMHykP0D39lj -spotify:track:02LhttutJp836x9MmTjUXQ -spotify:track:2j5siP7TDM8p8KJYz21f7i -spotify:track:1QzEIizaV0H420lOVRa4dW -spotify:track:7Emg43gSQ281JmC5FKBX5X -spotify:track:6Ly0owXzUn5aNeTNBIOzKH -spotify:track:22WpTfGxNHK5fdBTbFKjvV -spotify:track:4jqMLKRvugl6ya7o9G40NP -spotify:track:5o9L8CttqYj339wDetGdcG -spotify:track:3LNr24GL6u2OdLVH7GqMlm -spotify:track:7exER11O6jaBmUWhOvWRGh -spotify:track:1NqsDKWgqhVVjCvDyArfWn -spotify:track:7AxQN7tWw0aHlS8yYG1mi4 -spotify:track:3aEMkgM7iVXWNqTuP9phSM -spotify:track:37JwzWYOOYz2in4tXNNISx -spotify:track:2jLRbx1FdLauLTpjvKTgII -spotify:track:50BttjUL1U1L3Ngb0DRUWw -spotify:track:2GYyXvlQHvhcP9KEJo7pQs -spotify:track:2x0supcZhd6NEH1nem9DnR -spotify:track:45aBkgJ9UV2XVvWrLMOsyd -spotify:track:4xVEXwEALvLrmW4aef7esn -spotify:track:558w6Ru8SJCNzk0xdmISqX -spotify:track:0JnBXtqagQOFV9w9x7N0K6 -spotify:track:5aUnqiF9Y3W0OITq0UJscm -spotify:track:0jPr0tQreoKXHl460Jhp3P -spotify:track:6loFvY6N6URSVSnTz2RZ7L -spotify:track:3YYdwYqIlz3MKTVQLkXQ9m -spotify:track:77t1U17P4Q6ihd8JOq8ODr -spotify:track:5um9oqJyIRSOxYi1r4X04f -spotify:track:3bEzNqaPcOW6lQrXafl6F6 -spotify:track:5iHVKPDXHF40LaBCrxBsGH -spotify:track:6QybCOHAvZVEierFVIzY6E -spotify:track:7qXqrMSj9gr2GUAdZDjknQ -spotify:track:6I658qHs4LntNGSUUn1JHW -spotify:track:1ODvt9aF7ZuJeUtQ3HHNAF -spotify:track:7iU2b4II1E0saCk9vgsO9h -spotify:track:3h9m1K11aR6MUYPoHI6uQY -spotify:track:5kiHXz2911MbTjORtQ2thG -spotify:track:1qYShm8Jvs8zY9ivWKUhj1 -spotify:track:07HTDHDHxuHwtvS7xMpCsF -spotify:track:0dLeXCoYP3LTzQShO0DWds -spotify:track:7qLEaxMiR8WUsCG1uOBsuO -spotify:track:2veYJl7RAW2lkveifGHYKT -spotify:track:5efdzHjhTXm3P32utkjZsB -spotify:track:6xKDnd8rau33dOcr4eaLGp -spotify:track:67q3zVsJsPRks4k0eomEWy -spotify:track:1zD5Vk9Ay0V8OOI4YKuoAf -spotify:track:2v9IJFdS1O3Xszio2DOq4J -spotify:track:1392JJKNqrtn6ZKQ8bqB6g -spotify:track:3KQuCRQ6J9unCt6fB9OLFw -spotify:track:0M2YiDrjeH9kCTVitG7GIZ -spotify:track:4QIUa0bsk6cmtyl9TsHpyX -spotify:track:6q7zNqL13uQ8cYeLJPAnvM -spotify:track:3Un3OOg3VQnVgzqYFwtSA1 -spotify:track:0xbF056L1Rh3aorkYrnrcw -spotify:track:6LPff9WXf0mo93hWLQDfW4 -spotify:track:6MVim3XIOHTUUJt6ZZ4xiI -spotify:track:4oopnnqYQep1bRRHjWI5NZ -spotify:track:2SylgYRXnwmYe5dVUswwVC -spotify:track:64PbCTNpfIfsYNnbRjrarf -spotify:track:0zvOZPdyqHPEWjvhyURQ5X -spotify:track:0CQpJlD9j8gkpF6vYpPBvE -spotify:track:2xJC5rQTpX9Yv5EhbpETkk -spotify:track:4hpx4xuGn53AH1nWVGRh8v -spotify:track:4xP5U2WqMJK20BO9D918RI -spotify:track:0NZCRmTQbH2CcTXrA1tINk -spotify:track:7CXdkXxOJrOWAwKKrSPlWS -spotify:track:6NmldQ2cNdas2Rv4YwIrfn -spotify:track:0NZCRmTQbH2CcTXrA1tINk -spotify:track:3s6bstAaZbC6uBHPuel3W6 -spotify:track:2hJ7E250KxFXuE0TCCfoI3 -spotify:track:1Sv7P3pIY2Zjzpen78OORc -spotify:track:5VD27c9f7BuDaRVplcnebl -spotify:track:1uyDxNgwyXIJRy87tyewDt -spotify:track:7nV61Rd3q3LwRUt5qQ5rtR -spotify:track:5Lp4xptZSf2khojxC8iehH -spotify:track:0IcFhAtZQqCgdv4ugyjQZx -spotify:track:0vyJfb5merhL1NtmrucJaH -spotify:track:1x95pWB3KeK3evKa1VrW6e -spotify:track:3HM8glYP7qh2VQ2DilsEAi -spotify:track:60TdUFHyUfcBmRuf4AMldq -spotify:track:1uqZw35kbgxuvb5nJJ5y23 -spotify:track:74sz92IUs02Bh2fJzXyGSK -spotify:track:583YTL8Fl6pCWtZAi2GvVZ -spotify:track:1dl7TO9hPWPaUwURKqBGmP -spotify:track:0ph9DIJozeJOEvIev5qVQk -spotify:track:4mai1CggFbdIpK8MEohA0K -spotify:track:6h7Kh7pGFAwB1dyghm0mZZ -spotify:track:7DOZPeLfQqkcskfKUKoAUf -spotify:track:3FPobLmheSF7QWzq4pDLD9 -spotify:track:3PRVwEDVVK5ITqwu0Hy84V -spotify:track:50xlAtqoFecexXj3N4kynJ -spotify:track:5vwudDPhjnuA1KrNsFjAHK -spotify:track:6BhyyrUEbOI7szsjgbzAju -spotify:track:3XfylwQhFCIoDvC0BNjCWt -spotify:track:0iuTv9sYunbo4zW6cykFYk -spotify:track:5y95ucn3laegC0ObJhlufv -spotify:track:0MkD7ugsiBFbK83ZwAvobZ -spotify:track:1UczOJLWGL9VQJVAePRMcI -spotify:track:4Ks83rDIAwNokEG4PYnog4 -spotify:track:2CgAKuEdwtx34U5T2rLyw4 -spotify:track:2H3YWZ3Q1PNtUA8z0mPpGQ -spotify:track:33F1I9sAEUcB7Q05tHh9fp -spotify:track:5vKOOD6x7YMqcvgxaGnt64 -spotify:track:4vnfKsDUJGaHqEnpNKLOL8 -spotify:track:0JbiyOEt6YuDFTZj7Rep8s -spotify:track:4DQTlpLapighigY8paBEd9 -spotify:track:38bq59et0KNcjTMQJAWDJs -spotify:track:2AckvF8zhoMhmZ49jmIf8O -spotify:track:0g0RzAZH3nlKWkl41CLyNT -spotify:track:5Og1ngUAa8N6GRdLJp81Pg -spotify:track:03W5lEf82eVBF8rjDxhbW2 -spotify:track:4VtD7qiPoHYpKAuOmTLyc2 -spotify:track:1Xn6hGSkbjbnOFKQxvk5Qh -spotify:track:7aiL6F8q7D10xQtXchzu2W -spotify:track:6HhZrrj25eb6hAcqa1jmIa -spotify:track:7568pJYdTxmQiyV2Pt3TAK -spotify:track:7sXcHlfKfEwPSGDrLmDbfB -spotify:track:57vgSkXvr4KkaCIJMWSFB2 -spotify:track:2T848jgfBpBt0vhw2LSKhN -spotify:track:1A3HGfeudhMFNd8b6Mswp8 -spotify:track:4DqnhrbWAH3I92TAqtBrGY -spotify:track:6jLrlevctgoeGPXDLEdt6L -spotify:track:2Ntx16XsOz8pMz3ygHodpS -spotify:track:02lTCqFw0RasK7xAqu5fqE -spotify:track:3Jxi6P3Y4bYXEAHhcYho4a -spotify:track:6urjT2UUnX83D8CDOPfux3 -spotify:track:4oobntmhVjfkWkSNAo9ijn -spotify:track:1yCxOSKbSlYAUbjeeH0Yv3 -spotify:track:4AMsQnCRSXL4x0C0b0i7kk -spotify:track:0WKdB7PG53c1QlDbQzqn7s -spotify:track:15zhodeybsv2mz5Yw7hS48 -spotify:track:4CL8fkzCyhM0DDlotIDDpr -spotify:track:7Cb1KVyKSOUauQLTofWKEw -spotify:track:0SfG2rMDw7ZviADcXv1TI0 -spotify:track:2j3PFZXmenUxgjjBUIod7F -spotify:track:0dOg1ySSI7NkpAe89Zo0b9 -spotify:track:6Pgm5NvlnLVqPvPtIMj6Dh -spotify:track:33OzFYIVWZPn0E6RHctiC9 -spotify:track:7yPvz9Z57Vq3DnA1LqTwER -spotify:track:6sWj81TNza7VqfspjWjHDc -spotify:track:2nXSfOUS7BmPhLRV6ehiml -spotify:track:1MqGKtY9L5qjPi8s7gX645 -spotify:track:7a61OH8U2s1OhVPgCuNPMZ -spotify:track:3fzE5vxFTZ2DRiIdKI4l4B -spotify:track:6YxJ9uq7ex1rcFfx6boYDo -spotify:track:3qnf1FH4LHe9bHXEuMUZoG -spotify:track:6Jb4MjZlwDOsKyqXXCw7X6 -spotify:track:35YJCWAB360MTp0AxSZgNB -spotify:track:4f2FDf06hmv5YptohyLQV8 -spotify:track:0pkIyrSYE0BRpw4nNsBlmq -spotify:track:1ek5AmqUXMkx3eQPytV1BN -spotify:track:4jRtPv8a9wcpm8gJEKQSlR -spotify:track:1Fv48qm7W9AR1PwVc3wS9A -spotify:track:1mUpXELX93AvTswzLLY0UT -spotify:track:1qvFHNSBXGOsryKOr3p03m -spotify:track:5pvIVmZJZIc8SE3Gk3sEye -spotify:track:5ynfc3x7H5t8shUZRZpb6N -spotify:track:48Wl0w5LmiqhWwYVK9Win7 -spotify:track:45qDQvSBricT3zn3jzAxnk -spotify:track:0Gh1GsynRMY3cZZY7G0dlY -spotify:track:01nP5PpbvUBcAIMQW5i1vP -spotify:track:26Sm4ymfC0TVUK2RnHlciw -spotify:track:1myBSHHET1Re4UTSGmneeH -spotify:track:2dTRTQXRSCo4zgiXlyYaY3 -spotify:track:5qKmpbegJWROssoQgo0r7O -spotify:track:5IT43uHiMbw4AdI9VcCZxm -spotify:track:2ggBhNH6UexpYnziaW78SG -spotify:track:600wNkX9UT5rB0HRceHxX7 -spotify:track:30dT0S656DlaJrtimk8ItR -spotify:track:1PCftEVEn0PihLine6dIHQ -spotify:track:788Cp8dfA6GWwyEP8qHXTG -spotify:track:4DHKG1Hewrb9fTzVUXRl2D -spotify:track:0RQ3uttlfwETe72tZZQZFw -spotify:track:6kLfEKc7z5trZKWCv8hCYX -spotify:track:4RcRScJt7v5FhaZaCAWQ0T -spotify:track:4aJKkm3GYi8rCYPbhV8r0b -spotify:track:7IU6s1cVja1qWFmXkmR7iA -spotify:track:6vZLotWyNDlzDjoqY0Ec0D -spotify:track:5I6Y18eR8JelTClXNKdL2B -spotify:track:3ZKSCv9AfXOUuFO9j27EOb -spotify:track:0m4RZWh8jsqwIFZFxpNJZI -spotify:track:36NwlLTSsboo9SeQpTE3Mo -spotify:track:0M7mWKqwTIaVjYyxfZmtTa -spotify:track:0gnTF8QD5apHcK86nvCkrp -spotify:track:5MF1TOtDyYMQIyBXSDnzSu -spotify:track:12UzVR0M7asW2MHAZRJk0I -spotify:track:6uJpoNDk8sgJlQ13hKwGWH -spotify:track:50GWfznvmLBhUlHYKMq9G8 -spotify:track:7mIEvNbJxo1aEAGd7DkiC3 -spotify:track:1BY78IlCc8KiZjYLi9tk0l -spotify:track:4oYbwL03t1isZD4cFPtCxM -spotify:track:7lPzpmqhKwMaETmOBVTamL -spotify:track:5RqFC823JhgZjcX2p5pLC2 -spotify:track:6EHBJHPgbFv2uEdljLTYUo -spotify:track:0MCkLZZP1CJXOzBe2XGcdm -spotify:track:42I483ip9VozNoMKfbbnls -spotify:track:0BK3KDnit2B9lGptYsOyNG -spotify:track:0cVwLfU8BXN9zxZ2HKns9h -spotify:track:6mBsRxVAfZ7TdrooLmxexO -spotify:track:6QyJ8AQSoH1zJFyf86E6mx -spotify:track:5Vo4Lu0SF93q8pHFo68UOa -spotify:track:5EyYnQ3F8sPaylsWFTR4Qg -spotify:track:5lTEhTjBY2grPGjLKFSuks -spotify:track:0kcGX9Z9Q5i6EHX1QLNXDp -spotify:track:3t4hsTZCob6hwJU2f5Pz3u -spotify:track:2xHRb4OLnfhQMdJSyMW2dU -spotify:track:21l0IzdoW75sT5TewUT22V -spotify:track:5wllnBkcq1IMlTXnaW6Jv3 -spotify:track:4Uvbm8ijckGf4xDer9SF9s -spotify:track:1zKkQ6gyZQOMw68CUCf8GX -spotify:track:6pi7OwWvCYaOvEqAfBYiM4 -spotify:track:34yStWRRrbosgMs32yMlc1 -spotify:track:7gSbqXLD5glv5w7giXInvf -spotify:track:7EaYzSnP0akAQVfCu4RFBX -spotify:track:4Iduy3277LDiuCztPw9NAS -spotify:track:4UBTrrSotbB1DaRbapsR0R -spotify:track:54fskci17LPbSCmE2qGAD5 -spotify:track:1H84cRYr4wzEwgFM9PGOE5 -spotify:track:5nfQ7FgSfCG5FRK0Xoxy3M -spotify:track:7tSlB26fVA76eCVJQz1ueH -spotify:track:2hftOwcKNudZraI6Edvh8t -spotify:track:6CZEhTgAiPCa4fAD269PlI -spotify:track:2dPKh2wXy4Fc1S9UcmHRNu -spotify:track:4UDWJipAonm3DzOvRIo5N2 -spotify:track:3Goagh1ioAxjfKA5W6eqNN -spotify:track:6tT1EQyFcOZfmZQf1wSjtb -spotify:track:5KNltwC6xlNHIzUrigMISL -spotify:track:1HpTDohERdRdSw195oPKUv -spotify:track:5X5rx4uRMEWwxD1Lwl2NQU -spotify:track:43dgoxSKLWvfeUWZ9uEEWK -spotify:track:3KRGfygdhSiGG9r5JmWFZV -spotify:track:7u3L8sB8NdL5UeARrFN536 -spotify:track:0fZQfEfq9JxUEy1FjqOiCZ -spotify:track:58TxkZIEZWtqPMn1Y4Vd3t -spotify:track:3P4J0WzZSXGpl9z8Suz5jO -spotify:track:37Z1knZBcsUQfc1jM1zrOu -spotify:track:0yHBzIb97dsuxcOkRhKU0v -spotify:track:3emSZCViwDicSLBi6SMIRX -spotify:track:3bL9LUHgTTqPeU7s3bqyMd -spotify:track:6864dMeIjWotTlWlbhUsbr -spotify:track:78bpVL8pZBGhQa6CV9Bvlq -spotify:track:7F3WX3rfpm29WDy8UkfKmg -spotify:track:3uQDfCKlwfK9Yz10JFcsC7 -spotify:track:2ZyTdkTn5h4xPgX48hWGdI -spotify:track:4qb2AKvnaDdvJJnKmxo9ST -spotify:track:1Nruw7r9cwfQVLz7j9Qc1b -spotify:track:5bOG5FKR5eJOhNYCIO4E35 -spotify:track:5ZCjhZABvYc50lt5zRPdgZ -spotify:track:2kSpNkYlQCRCZX0a6tW02a -spotify:track:7HUFClGakCCS6DUHkdey5M -spotify:track:3CbPsxgJB53v51wWqcY6oD -spotify:track:5twEsir35519mNkxfH9Lnv -spotify:track:2HRYa6iG1M5DRefO8pK2I3 -spotify:track:2x0supcZhd6NEH1nem9DnR -spotify:track:5bZI4j4gZQUj0ZkE2wER9O -spotify:track:0yuKuvDJlOf4GjUtf3OPjf -spotify:track:28BFxsobryXuZghzAGBImi -spotify:track:50nv5PDK8zVmdIC7KdBSOz -spotify:track:3kJ6B8jf7G2KRPELgntYOL -spotify:track:3HJ8LpromeQLHrP5XPuBL3 -spotify:track:2KPflscGoyKv5Kc6PG7KNe -spotify:track:6ytJGSzgBunW0VePRAyhNn -spotify:track:1QninLAEEtyzoDTCsGNrQz -spotify:track:7oyKc3RgnMaSRgwNTLCDgE -spotify:track:0PA9HmVnyHknT43go3tFz3 -spotify:track:5cp7armpdpEOfdkD5WiX6q -spotify:track:1qmJbXpVLydNcN6VTR40GU -spotify:track:2bdapwYVEGpGWxlx3iooAB -spotify:track:21YbiQuw6j4k6DOBzE79z2 -spotify:track:31WCZ6zpqXOz3Rljc0Yor8 -spotify:track:3Ozp5uFYtC4Q6X4L4ivBDv - diff --git a/examples/search.py b/examples/search.py index 6955e4f..cf81208 100644 --- a/examples/search.py +++ b/examples/search.py @@ -1,5 +1,6 @@ # shows artist info for a URN or URL +from spotipy.oauth2 import SpotifyClientCredentials import spotipy import sys import pprint @@ -9,6 +10,6 @@ if len(sys.argv) > 1: else: search_str = 'Radiohead' -sp = spotipy.Spotify() +sp = spotipy.Spotify(client_credentials_manager=SpotifyClientCredentials()) result = sp.search(search_str) pprint.pprint(result) diff --git a/examples/show_album.py b/examples/show_album.py index acd310f..248e305 100644 --- a/examples/show_album.py +++ b/examples/show_album.py @@ -1,18 +1,16 @@ # shows album info for a URN or URL -import spotipy from spotipy.oauth2 import SpotifyClientCredentials +import spotipy import sys -import pprint +from pprint import pprint if len(sys.argv) > 1: urn = sys.argv[1] else: urn = 'spotify:album:5yTx83u3qerZF7GRJu7eFk' - -client_credentials_manager = SpotifyClientCredentials() -sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager) +sp = spotipy.Spotify(client_credentials_manager=SpotifyClientCredentials()) album = sp.album(urn) -pprint.pprint(album) +pprint(album) diff --git a/examples/show_artist.py b/examples/show_artist.py index c0a9834..72f18cc 100644 --- a/examples/show_artist.py +++ b/examples/show_artist.py @@ -1,18 +1,16 @@ # shows artist info for a URN or URL -import spotipy from spotipy.oauth2 import SpotifyClientCredentials +import spotipy import sys -import pprint +from pprint import pprint if len(sys.argv) > 1: urn = sys.argv[1] else: urn = 'spotify:artist:3jOstUTkEu2JkjvRdBA5Gu' -client_credentials_manager = SpotifyClientCredentials() -sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager) +sp = spotipy.Spotify(client_credentials_manager=SpotifyClientCredentials()) artist = sp.artist(urn) - -pprint.pprint(artist) +pprint(artist) diff --git a/examples/show_artist_top_tracks.py b/examples/show_artist_top_tracks.py index dbca651..857bfb8 100644 --- a/examples/show_artist_top_tracks.py +++ b/examples/show_artist_top_tracks.py @@ -1,7 +1,7 @@ # shows artist info for a URN or URL -import spotipy from spotipy.oauth2 import SpotifyClientCredentials +import spotipy import sys if len(sys.argv) > 1: @@ -9,8 +9,7 @@ if len(sys.argv) > 1: else: urn = 'spotify:artist:3jOstUTkEu2JkjvRdBA5Gu' -client_credentials_manager = SpotifyClientCredentials() -sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager) +sp = spotipy.Spotify(client_credentials_manager=SpotifyClientCredentials()) response = sp.artist_top_tracks(urn) for track in response['tracks']: diff --git a/examples/show_related.py b/examples/show_related.py index f8e9a65..6fed03f 100644 --- a/examples/show_related.py +++ b/examples/show_related.py @@ -1,8 +1,8 @@ # shows related artists for the given seed artist -import spotipy from spotipy.oauth2 import SpotifyClientCredentials +import spotipy import sys if len(sys.argv) > 1: @@ -10,7 +10,6 @@ if len(sys.argv) > 1: else: artist_name = 'weezer' - client_credentials_manager = SpotifyClientCredentials() sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager) result = sp.search(q='artist:' + artist_name, type='artist') diff --git a/examples/show_track_info.py b/examples/show_track_info.py index def5a9a..353172c 100644 --- a/examples/show_track_info.py +++ b/examples/show_track_info.py @@ -1,16 +1,16 @@ # shows track info for a URN or URL -import spotipy from spotipy.oauth2 import SpotifyClientCredentials +import spotipy import sys -import pprint +from pprint import pprint if len(sys.argv) > 1: urn = sys.argv[1] else: urn = 'spotify:track:0Svkvt5I79wficMFgaqEQJ' -client_credentials_manager = SpotifyClientCredentials() -sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager) +sp = spotipy.Spotify(client_credentials_manager=SpotifyClientCredentials()) + track = sp.track(urn) -pprint.pprint(track) +pprint(track) diff --git a/examples/show_tracks.py b/examples/show_tracks.py index db9c4c5..efee1d2 100644 --- a/examples/show_tracks.py +++ b/examples/show_tracks.py @@ -3,6 +3,7 @@ given a list of track IDs show the artist and track name ''' +from spotipy.oauth2 import SpotifyClientCredentials import sys import spotipy @@ -14,7 +15,8 @@ if __name__ == '__main__': file = sys.stdin tids = file.read().split() - sp = spotipy.Spotify() + client_credentials_manager = SpotifyClientCredentials() + sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager) for start in range(0, len(tids), max_tracks_per_call): results = sp.tracks(tids[start: start + max_tracks_per_call]) for track in results['tracks']: diff --git a/examples/show_user.py b/examples/show_user.py index 8ce6fe9..c6075d4 100644 --- a/examples/show_user.py +++ b/examples/show_user.py @@ -1,6 +1,7 @@ # shows artist info for a URN or URL +from spotipy.oauth2 import SpotifyClientCredentials import spotipy import sys import pprint @@ -10,7 +11,8 @@ if len(sys.argv) > 1: else: username = 'plamere' -sp = spotipy.Spotify() +client_credentials_manager = SpotifyClientCredentials() +sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager) sp.trace = True user = sp.user(username) pprint.pprint(user) diff --git a/examples/simple0.py b/examples/simple0.py index c1ea7d7..a89ca42 100644 --- a/examples/simple0.py +++ b/examples/simple0.py @@ -1,5 +1,5 @@ -import spotipy from spotipy.oauth2 import SpotifyClientCredentials +import spotipy client_credentials_manager = SpotifyClientCredentials() sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager) diff --git a/examples/simple1.py b/examples/simple1.py index 92cf482..c4cc562 100644 --- a/examples/simple1.py +++ b/examples/simple1.py @@ -1,5 +1,5 @@ -import spotipy from spotipy.oauth2 import SpotifyClientCredentials +import spotipy birdy_uri = 'spotify:artist:2WX2uTcsvV5OnS0inACecP' diff --git a/examples/simple2.py b/examples/simple2.py index 79a67e1..1a207b2 100644 --- a/examples/simple2.py +++ b/examples/simple2.py @@ -1,7 +1,6 @@ -import spotipy from spotipy.oauth2 import SpotifyClientCredentials - +import spotipy lz_uri = 'spotify:artist:36QJpDe2go2KgaRleHCDTp' @@ -14,4 +13,3 @@ for track in results['tracks'][:10]: print('track : ' + track['name']) print('audio : ' + track['preview_url']) print('cover art: ' + track['album']['images'][0]['url']) - print() diff --git a/examples/simple3.py b/examples/simple3.py index 08777f2..ef3df9b 100644 --- a/examples/simple3.py +++ b/examples/simple3.py @@ -1,9 +1,9 @@ -import spotipy -from spotipy.oauth2 import SpotifyClientCredentials import sys -client_credentials_manager = SpotifyClientCredentials() -sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager) +from spotipy.oauth2 import SpotifyClientCredentials +import spotipy + +sp = spotipy.Spotify(client_credentials_manager=SpotifyClientCredentials()) if len(sys.argv) > 1: name = ' '.join(sys.argv[1:]) diff --git a/examples/title_chain.py b/examples/title_chain.py index 6251382..f3bc321 100644 --- a/examples/title_chain.py +++ b/examples/title_chain.py @@ -1,12 +1,16 @@ +from spotipy.oauth2 import SpotifyClientCredentials import spotipy import random ''' generates a list of songs where the first word in each subsequent song matches the last word of the previous song. + + usage: python title_chain.py [song name] ''' -sp = spotipy.Spotify() +client_credentials_manager = SpotifyClientCredentials() +sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager) skiplist = set(['dm', 'remix']) diff --git a/examples/tracks.py b/examples/tracks.py index 0e3f8c0..33e943e 100644 --- a/examples/tracks.py +++ b/examples/tracks.py @@ -1,9 +1,13 @@ # shows tracks for the given artist +# usage: python tracks.py [artist name] +from spotipy.oauth2 import SpotifyClientCredentials import spotipy import sys -sp = spotipy.Spotify() + +client_credentials_manager = SpotifyClientCredentials() +sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager) if len(sys.argv) > 1: artist_name = ' '.join(sys.argv[1:]) diff --git a/setup.py b/setup.py index e45c18e..f5d3dd8 100644 --- a/setup.py +++ b/setup.py @@ -1,12 +1,14 @@ from setuptools import setup -desc = """### A light weight Python library for the Spotify Web API""" +with open("README.md", "r") as f: + long_description = f.read() setup( name='spotipy', - version='2.6.1', - long_description=desc, - long_description_content_type='text/markdown', + version='2.6.3', + description='A light weight Python library for the Spotify Web API', + long_description=long_description, + long_description_content_type="text/markdown", author="@plamere", author_email="paul@echonest.com", url='http://spotipy.readthedocs.org/', diff --git a/tests/test_auth.py b/tests/test_auth.py index 327898a..a0b8237 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -129,7 +129,7 @@ class AuthTestSpotipy(unittest.TestCase): def test_current_user_saved_albums(self): # List albums = self.spotify.current_user_saved_albums() - self.assertTrue(len(albums['items']) == 1) + self.assertTrue(len(albums['items']) > 1) # Add self.spotify.current_user_saved_albums_add(self.album_ids) @@ -143,7 +143,7 @@ class AuthTestSpotipy(unittest.TestCase): # Remove self.spotify.current_user_saved_albums_delete(self.album_ids) albums = self.spotify.current_user_saved_albums() - self.assertTrue(len(albums['items']) == 1) + self.assertTrue(len(albums['items']) > 1) def test_current_user_playlists(self): playlists = self.spotify.current_user_playlists(limit=10) diff --git a/tests/tests.py b/tests/tests.py index 1cc119f..cccab6f 100644 --- a/tests/tests.py +++ b/tests/tests.py @@ -1,18 +1,17 @@ # -*- coding: utf-8 -*- +import unittest +import os +import requests + +import spotipy from spotipy import ( CLIENT_CREDS_ENV_VARS as CCEV, prompt_for_user_token, Spotify, SpotifyException, + SpotifyClientCredentials ) -import os -import sys -import unittest - -import requests - -sys.path.insert(0, os.path.abspath(os.pardir)) class TestSpotipy(unittest.TestCase): @@ -45,20 +44,16 @@ class TestSpotipy(unittest.TestCase): @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 ' '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) + self.spotify = Spotify( + client_credentials_manager=SpotifyClientCredentials()) def test_artist_urn(self): artist = self.spotify.artist(self.radiohead_urn) @@ -158,11 +153,15 @@ class TestSpotipy(unittest.TestCase): self.assertTrue(found) def test_search_timeout(self): - sp = Spotify(auth=self.token, requests_timeout=.01) + client_credentials_manager = SpotifyClientCredentials() + sp = spotipy.Spotify( + client_credentials_manager=client_credentials_manager, + requests_timeout=.01) + try: sp.search(q='my*', type='track') self.assertTrue(False, 'unexpected search timeout') - except requests.Timeout: + except requests.exceptions.Timeout: self.assertTrue(True, 'expected search timeout') def test_album_search(self): @@ -199,18 +198,20 @@ class TestSpotipy(unittest.TestCase): def test_custom_requests_session(self): sess = requests.Session() sess.headers["user-agent"] = "spotipy-test" - with_custom_session = Spotify(auth=self.token, requests_session=sess) + with_custom_session = spotipy.Spotify( + client_credentials_manager=SpotifyClientCredentials(), + requests_session=sess) self.assertTrue( with_custom_session.user( user="akx")["uri"] == "spotify:user:akx") sess.close() def test_force_no_requests_session(self): - with_no_session = Spotify(auth=self.token, requests_session=False) - self.assertFalse( - isinstance( - with_no_session._session, - requests.Session)) + from requests import Session + with_no_session = spotipy.Spotify( + client_credentials_manager=SpotifyClientCredentials(), + requests_session=False) + self.assertFalse(isinstance(with_no_session._session, Session)) self.assertTrue(with_no_session.user(user="akx") ["uri"] == "spotify:user:akx")