mirror of
https://github.com/spotipy-dev/spotipy.git
synced 2026-06-19 01:03:53 +00:00
Allow the scope to be either a list or comma separated string (#650)
* Allow the scope to be either a list or comma separated string * Move normalize scope to util file and make it a base method Also adjust documentation to reflect the new scope parameter supporting a list * Add change to CHANGELOG.md
This commit is contained in:
parent
d001326cc3
commit
e07dd64925
@ -27,6 +27,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- The query parameters of requests are now logged
|
||||
- Deprecate specifing `cache_path` or `username` directly to `SpotifyOAuth`, `SpotifyPKCE`, and `SpotifyImplicitGrant` constructors, instead directing users to use the `CacheFileHandler` cache handler
|
||||
- Removed requirement for examples/app.py to specify port multiple times (only SPOTIPY_REDIRECT_URI needs to contain the port)
|
||||
- Add support for a list of scopes rather than just a comma separated string of scopes
|
||||
|
||||
### Added
|
||||
|
||||
|
||||
@ -25,7 +25,7 @@ from six.moves.urllib_parse import parse_qsl, urlparse
|
||||
|
||||
from spotipy.cache_handler import CacheFileHandler, CacheHandler
|
||||
from spotipy.exceptions import SpotifyException
|
||||
from spotipy.util import CLIENT_CREDS_ENV_VARS, get_host_port
|
||||
from spotipy.util import CLIENT_CREDS_ENV_VARS, get_host_port, normalize_scope
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -83,6 +83,9 @@ class SpotifyAuthBase(object):
|
||||
from requests import api
|
||||
self._session = api
|
||||
|
||||
def _normalize_scope(self, scope):
|
||||
return normalize_scope(scope)
|
||||
|
||||
@property
|
||||
def client_id(self):
|
||||
return self._client_id
|
||||
@ -254,21 +257,23 @@ class SpotifyOAuth(SpotifyAuthBase):
|
||||
* client_id: Must be supplied or set as environment variable
|
||||
* client_secret: Must be supplied or set as environment variable
|
||||
* redirect_uri: Must be supplied or set as environment variable
|
||||
* state: May be supplied, no verification is performed
|
||||
* scope: May be supplied, intuitively converted to proper format
|
||||
* state: Optional, no verification is performed
|
||||
* scope: Optional, either a list of scopes or comma separated string of scopes.
|
||||
e.g, "playlist-read-private,playlist-read-collaborative"
|
||||
* cache_handler: An instance of the `CacheHandler` class to handle
|
||||
getting and saving cached authorization tokens.
|
||||
May be supplied, will otherwise use `CacheFileHandler`.
|
||||
Optional, will otherwise use `CacheFileHandler`.
|
||||
(takes precedence over `cache_path` and `username`)
|
||||
* cache_path: (deprecated) May be supplied, will otherwise be generated
|
||||
* cache_path: (deprecated) Optional, will otherwise be generated
|
||||
(takes precedence over `username`)
|
||||
* username: (deprecated) May be supplied or set as environment variable
|
||||
* username: (deprecated) Optional or set as environment variable
|
||||
(will set `cache_path` to `.cache-{username}`)
|
||||
* proxies: Proxy for the requests library to route through
|
||||
* show_dialog: Interpreted as boolean
|
||||
* requests_timeout: Tell Requests to stop waiting for a response after a given number
|
||||
of seconds
|
||||
* open_browser: Whether or not the web browser should be opened to authorize a user
|
||||
* show_dialog: Optional, interpreted as boolean
|
||||
* proxies: Optional, proxy for the requests library to route through
|
||||
* requests_timeout: Optional, tell Requests to stop waiting for a response after
|
||||
a given number of seconds
|
||||
* open_browser: Optional, whether or not the web browser should be opened to
|
||||
authorize a user
|
||||
"""
|
||||
|
||||
super(SpotifyOAuth, self).__init__(requests_session)
|
||||
@ -513,13 +518,6 @@ class SpotifyOAuth(SpotifyAuthBase):
|
||||
self.cache_handler.save_token_to_cache(token_info)
|
||||
return token_info if as_dict else token_info["access_token"]
|
||||
|
||||
def _normalize_scope(self, scope):
|
||||
if scope:
|
||||
scopes = sorted(scope.split())
|
||||
return " ".join(scopes)
|
||||
else:
|
||||
return None
|
||||
|
||||
def refresh_access_token(self, refresh_token):
|
||||
payload = {
|
||||
"refresh_token": refresh_token,
|
||||
@ -627,21 +625,23 @@ class SpotifyPKCE(SpotifyAuthBase):
|
||||
* client_id: Must be supplied or set as environment variable
|
||||
* client_secret: Must be supplied or set as environment variable
|
||||
* redirect_uri: Must be supplied or set as environment variable
|
||||
* state: May be supplied, no verification is performed
|
||||
* scope: May be supplied, intuitively converted to proper format
|
||||
* state: Optional, no verification is performed
|
||||
* scope: Optional, either a list of scopes or comma separated string of scopes.
|
||||
e.g, "playlist-read-private,playlist-read-collaborative"
|
||||
* cache_handler: An instance of the `CacheHandler` class to handle
|
||||
getting and saving cached authorization tokens.
|
||||
May be supplied, will otherwise use `CacheFileHandler`.
|
||||
Optional, will otherwise use `CacheFileHandler`.
|
||||
(takes precedence over `cache_path` and `username`)
|
||||
* cache_path: (deprecated) May be supplied, will otherwise be generated
|
||||
* cache_path: (deprecated) Optional, will otherwise be generated
|
||||
(takes precedence over `username`)
|
||||
* username: (deprecated) May be supplied or set as environment variable
|
||||
* username: (deprecated) Optional or set as environment variable
|
||||
(will set `cache_path` to `.cache-{username}`)
|
||||
* show_dialog: Interpreted as boolean
|
||||
* proxies: Proxy for the requests library to route through
|
||||
* requests_timeout: Tell Requests to stop waiting for a response after a given number
|
||||
of seconds
|
||||
* open_browser: Whether or not the web browser should be opened to authorize a user
|
||||
* show_dialog: Optional, interpreted as boolean
|
||||
* proxies: Optional, proxy for the requests library to route through
|
||||
* requests_timeout: Optional, tell Requests to stop waiting for a response after
|
||||
a given number of seconds
|
||||
* open_browser: Optional, thether or not the web browser should be opened to
|
||||
authorize a user
|
||||
"""
|
||||
|
||||
super(SpotifyPKCE, self).__init__(requests_session)
|
||||
@ -683,13 +683,6 @@ class SpotifyPKCE(SpotifyAuthBase):
|
||||
self.authorization_code = None
|
||||
self.open_browser = open_browser
|
||||
|
||||
def _normalize_scope(self, scope):
|
||||
if scope:
|
||||
scopes = sorted(scope.split())
|
||||
return " ".join(scopes)
|
||||
else:
|
||||
return None
|
||||
|
||||
def _get_code_verifier(self):
|
||||
""" Spotify PCKE code verifier - See step 1 of the reference guide below
|
||||
Reference:
|
||||
@ -1040,7 +1033,8 @@ class SpotifyImplicitGrant(SpotifyAuthBase):
|
||||
* client_id: Must be supplied or set as environment variable
|
||||
* redirect_uri: Must be supplied or set as environment variable
|
||||
* state: May be supplied, no verification is performed
|
||||
* scope: May be supplied, intuitively converted to proper format
|
||||
* scope: Optional, either a list of scopes or comma separated string of scopes.
|
||||
e.g, "playlist-read-private,playlist-read-collaborative"
|
||||
* cache_handler: An instance of the `CacheHandler` class to handle
|
||||
getting and saving cached authorization tokens.
|
||||
May be supplied, will otherwise use `CacheFileHandler`.
|
||||
@ -1131,13 +1125,6 @@ class SpotifyImplicitGrant(SpotifyAuthBase):
|
||||
|
||||
return token_info["access_token"]
|
||||
|
||||
def _normalize_scope(self, scope):
|
||||
if scope:
|
||||
scopes = sorted(scope.split())
|
||||
return " ".join(scopes)
|
||||
else:
|
||||
return None
|
||||
|
||||
def get_authorize_url(self, state=None):
|
||||
""" Gets the URL to use to authorize this app """
|
||||
payload = {
|
||||
|
||||
@ -117,3 +117,19 @@ def get_host_port(netloc):
|
||||
port = None
|
||||
|
||||
return host, port
|
||||
|
||||
|
||||
def normalize_scope(scope):
|
||||
if scope:
|
||||
if isinstance(scope, str):
|
||||
scopes = scope.split(',')
|
||||
elif isinstance(scope, list) or isinstance(scope, tuple):
|
||||
scopes = scope
|
||||
else:
|
||||
raise Exception(
|
||||
"Unsupported scope value, please either provide a list of scopes, "
|
||||
"or a string of scopes separated by commas"
|
||||
)
|
||||
return " ".join(sorted(scopes))
|
||||
else:
|
||||
return None
|
||||
|
||||
Loading…
Reference in New Issue
Block a user