mirror of
https://github.com/spotipy-dev/spotipy.git
synced 2026-10-11 17:10:45 +00:00
* Add SpotifyImplicitGrant with get_access_token and get_cached_token (and minimum related functions) * Add some overlooked necessary methods/values in SpotifyImplicitGrant * Remove unsuppported functionality and make SpotifyImplicitGrant public * Allow/Expose integration of SpotifyImplicitGrant in client * Add Implicit Grant tests and decrease abilities of prompt_for_user_token Remove Implicit Grant and state support from prompt_for_user_token * Add documentation and changelog entry * Touch up PEP8 compliance * Ignore long line with link for flake8 * Correct changelog * Restore compatibility with Python 2.7 * Correct help(SpotifyImplicitGrant.get_access_token) * Remove as_dict from SpotifyImplicitGrant.get_access_token * Combine status check functionality with implicit grant support In oauth2.py: * Add state checking to SpotifyImplicitGrant * Add dedicated SpotifyStateError as subclass of SpotifyOauthError * Moved `_get_user_input` from SpotifyOAuth to superclass SpotifyAuthBase * Renamed `parse_oauth_response_url` to `parse_auth_response_url` * Moved error handling into `parse_auth_response_url` Made minor changes in tests and client.py accordingly * Update changelog * Trim down tests for SpotifyImplicitGrant * Fix trailing whitespace
This commit is contained in:
1 parent
ed136d15df
commit
38515689bc
6 files changed
+451
-29
No files matched your search
+125
-5
@@ -5,8 +5,9 @@ import unittest
|
||||
|
||||
import six.moves.urllib.parse as urllibparse
|
||||
|
||||
from spotipy import SpotifyOAuth
|
||||
from spotipy import SpotifyOAuth, SpotifyImplicitGrant
|
||||
from spotipy.oauth2 import SpotifyClientCredentials, SpotifyOauthError
|
||||
from spotipy.oauth2 import SpotifyStateError
|
||||
|
||||
try:
|
||||
import unittest.mock as mock
|
||||
@@ -41,6 +42,10 @@ def _make_oauth(*args, **kwargs):
|
||||
return SpotifyOAuth("CLID", "CLISEC", "REDIR", "STATE", *args, **kwargs)
|
||||
|
||||
|
||||
def _make_implicitgrantauth(*args, **kwargs):
|
||||
return SpotifyImplicitGrant("CLID", "REDIR", "STATE", *args, **kwargs)
|
||||
|
||||
|
||||
class OAuthCacheTest(unittest.TestCase):
|
||||
|
||||
@patch.multiple(SpotifyOAuth,
|
||||
@@ -199,10 +204,7 @@ class TestSpotifyOAuthGetAuthResponseInteractive(unittest.TestCase):
|
||||
def test_get_auth_response_with_inconsistent_state(self, webbrowser_mock, get_user_input_mock):
|
||||
oauth = SpotifyOAuth("CLID", "CLISEC", "redir.io", state='wxyz')
|
||||
|
||||
with self.assertRaisesRegexp(
|
||||
SpotifyOauthError,
|
||||
"Received inconsistent state from OAuth server."
|
||||
):
|
||||
with self.assertRaises(SpotifyStateError):
|
||||
oauth.get_auth_response()
|
||||
|
||||
|
||||
@@ -213,3 +215,121 @@ class TestSpotifyClientCredentials(unittest.TestCase):
|
||||
with self.assertRaises(SpotifyOauthError) as error:
|
||||
oauth.get_access_token()
|
||||
self.assertEqual(error.exception.error, 'invalid_client')
|
||||
|
||||
|
||||
class ImplicitGrantCacheTest(unittest.TestCase):
|
||||
|
||||
@patch.object(SpotifyImplicitGrant, "is_token_expired", DEFAULT)
|
||||
@patch('spotipy.oauth2.open', create=True)
|
||||
def test_gets_from_cache_path(self, opener, is_token_expired):
|
||||
scope = "playlist-modify-private"
|
||||
path = ".cache-username"
|
||||
tok = _make_fake_token(1, 1, scope)
|
||||
|
||||
opener.return_value = _token_file(json.dumps(tok, ensure_ascii=False))
|
||||
is_token_expired.return_value = False
|
||||
|
||||
spot = _make_implicitgrantauth(scope, path)
|
||||
cached_tok = spot.get_cached_token()
|
||||
|
||||
opener.assert_called_with(path)
|
||||
self.assertIsNotNone(cached_tok)
|
||||
|
||||
@patch.object(SpotifyImplicitGrant, "is_token_expired", DEFAULT)
|
||||
@patch('spotipy.oauth2.open', create=True)
|
||||
def test_expired_token_returns_none(self, opener, is_token_expired):
|
||||
scope = "playlist-modify-private"
|
||||
path = ".cache-username"
|
||||
expired_tok = _make_fake_token(0, None, scope)
|
||||
|
||||
token_file = _token_file(json.dumps(expired_tok, ensure_ascii=False))
|
||||
opener.return_value = token_file
|
||||
|
||||
spot = _make_implicitgrantauth(scope, path)
|
||||
cached_tok = spot.get_cached_token()
|
||||
|
||||
is_token_expired.assert_called_with(expired_tok)
|
||||
opener.assert_any_call(path)
|
||||
self.assertIsNone(cached_tok)
|
||||
|
||||
@patch.object(SpotifyImplicitGrant, "is_token_expired", DEFAULT)
|
||||
@patch('spotipy.oauth2.open', create=True)
|
||||
def test_badly_scoped_token_bails(self, opener, is_token_expired):
|
||||
token_scope = "playlist-modify-public"
|
||||
requested_scope = "playlist-modify-private"
|
||||
path = ".cache-username"
|
||||
tok = _make_fake_token(1, 1, token_scope)
|
||||
|
||||
opener.return_value = _token_file(json.dumps(tok, ensure_ascii=False))
|
||||
is_token_expired.return_value = False
|
||||
|
||||
spot = _make_implicitgrantauth(requested_scope, path)
|
||||
cached_tok = spot.get_cached_token()
|
||||
|
||||
opener.assert_called_with(path)
|
||||
self.assertIsNone(cached_tok)
|
||||
|
||||
@patch('spotipy.oauth2.open', create=True)
|
||||
def test_saves_to_cache_path(self, opener):
|
||||
scope = "playlist-modify-private"
|
||||
path = ".cache-username"
|
||||
tok = _make_fake_token(1, 1, scope)
|
||||
|
||||
fi = _fake_file()
|
||||
opener.return_value = fi
|
||||
|
||||
spot = SpotifyImplicitGrant("CLID", "REDIR", "STATE", scope, path)
|
||||
spot._save_token_info(tok)
|
||||
|
||||
opener.assert_called_with(path, 'w')
|
||||
self.assertTrue(fi.write.called)
|
||||
|
||||
|
||||
class TestSpotifyImplicitGrant(unittest.TestCase):
|
||||
|
||||
def test_get_authorize_url_doesnt_pass_state_by_default(self):
|
||||
auth = SpotifyImplicitGrant("CLID", "REDIR")
|
||||
|
||||
url = auth.get_authorize_url()
|
||||
|
||||
parsed_url = urllibparse.urlparse(url)
|
||||
parsed_qs = urllibparse.parse_qs(parsed_url.query)
|
||||
self.assertNotIn('state', parsed_qs)
|
||||
|
||||
def test_get_authorize_url_passes_state_from_constructor(self):
|
||||
state = "STATE"
|
||||
auth = SpotifyImplicitGrant("CLID", "REDIR", state)
|
||||
|
||||
url = auth.get_authorize_url()
|
||||
|
||||
parsed_url = urllibparse.urlparse(url)
|
||||
parsed_qs = urllibparse.parse_qs(parsed_url.query)
|
||||
self.assertEqual(parsed_qs['state'][0], state)
|
||||
|
||||
def test_get_authorize_url_passes_state_from_func_call(self):
|
||||
state = "STATE"
|
||||
auth = SpotifyImplicitGrant("CLID", "REDIR", "NOT STATE")
|
||||
|
||||
url = auth.get_authorize_url(state=state)
|
||||
|
||||
parsed_url = urllibparse.urlparse(url)
|
||||
parsed_qs = urllibparse.parse_qs(parsed_url.query)
|
||||
self.assertEqual(parsed_qs['state'][0], state)
|
||||
|
||||
def test_get_authorize_url_does_not_show_dialog_by_default(self):
|
||||
auth = SpotifyImplicitGrant("CLID", "REDIR")
|
||||
|
||||
url = auth.get_authorize_url()
|
||||
|
||||
parsed_url = urllibparse.urlparse(url)
|
||||
parsed_qs = urllibparse.parse_qs(parsed_url.query)
|
||||
self.assertNotIn('show_dialog', parsed_qs)
|
||||
|
||||
def test_get_authorize_url_shows_dialog_when_requested(self):
|
||||
auth = SpotifyImplicitGrant("CLID", "REDIR", show_dialog=True)
|
||||
|
||||
url = auth.get_authorize_url()
|
||||
|
||||
parsed_url = urllibparse.urlparse(url)
|
||||
parsed_qs = urllibparse.parse_qs(parsed_url.query)
|
||||
self.assertTrue(parsed_qs['show_dialog'])
|
||||
Reference in new issue
Block a user