Allow open_browser to be set on creation of auth_manager (SpotifyOAuth/SpotifyPKCE) (#574)

* Fix plamere/spotipy#560

* Adhere to code style

* Update CHANGELOG.md for changes in 939f869bbc

* open_browser passed to get_auth_response should take precedence over the same argument in the constructor

* Update FAQ

* Add information about headless auth

* Add headless auth example
This commit is contained in:
Nick 2020-09-12 12:14:08 +01:00 committed by GitHub
parent a42f2ccd0f
commit 87fe473672
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 59 additions and 30 deletions

View File

@ -7,7 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased
// Add your changes here and then delete this line
### Added
- `open_browser` can be passed to the constructors of `SpotifyOAuth` and `SpotifyPKCE` to make it easier to authorize in browserless environments
## [2.15.0] - 2020-09-08

9
FAQ.md
View File

@ -40,4 +40,11 @@ Problem: you can see a track on the Spotify app but searching for it using the A
Solution: by default `search("abba")` works in the US market.
To search for in your current country, the [country indicator](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2)
must be specified: `search("abba", market="DE")`.
must be specified: `search("abba", market="DE")`.
### How do I obtain authorization in a headless/browserless environment?
If you cannot open a browser, set `open_browser=False` when instantiating SpotifyOAuth or SpotifyPKCE. You will be
prompted to open the authorization URI manually.
See the [headless auth example](examples/headless.py).

8
examples/headless.py Normal file
View File

@ -0,0 +1,8 @@
import spotipy
from spotipy.oauth2 import SpotifyOAuth
# set open_browser=False to prevent Spotipy from attempting to open the default browser
spotify = spotipy.Spotify(auth_manager=SpotifyOAuth(open_browser=False))
print(spotify.me())

View File

@ -234,18 +234,19 @@ class SpotifyOAuth(SpotifyAuthBase):
OAUTH_TOKEN_URL = "https://accounts.spotify.com/api/token"
def __init__(
self,
client_id=None,
client_secret=None,
redirect_uri=None,
state=None,
scope=None,
cache_path=None,
username=None,
proxies=None,
show_dialog=False,
requests_session=True,
requests_timeout=None
self,
client_id=None,
client_secret=None,
redirect_uri=None,
state=None,
scope=None,
cache_path=None,
username=None,
proxies=None,
show_dialog=False,
requests_session=True,
requests_timeout=None,
open_browser=True
):
"""
Creates a SpotifyOAuth object
@ -264,6 +265,7 @@ class SpotifyOAuth(SpotifyAuthBase):
* 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
"""
super(SpotifyOAuth, self).__init__(requests_session)
@ -280,6 +282,7 @@ class SpotifyOAuth(SpotifyAuthBase):
self.proxies = proxies
self.requests_timeout = requests_timeout
self.show_dialog = show_dialog
self.open_browser = open_browser
def get_cached_token(self):
""" Gets a cached auth token
@ -294,7 +297,7 @@ class SpotifyOAuth(SpotifyAuthBase):
# if scopes don't match, then bail
if "scope" not in token_info or not self._is_scope_subset(
self.scope, token_info["scope"]
self.scope, token_info["scope"]
):
return None
@ -382,7 +385,7 @@ class SpotifyOAuth(SpotifyAuthBase):
except webbrowser.Error:
logger.error("Please navigate here: %s", auth_url)
def _get_auth_response_interactive(self, open_browser=True):
def _get_auth_response_interactive(self, open_browser=False):
if open_browser:
self._open_auth_url()
prompt = "Enter the URL you were redirected to: "
@ -413,7 +416,7 @@ class SpotifyOAuth(SpotifyAuthBase):
else:
raise SpotifyOauthError("Server listening on localhost has not been accessed")
def get_auth_response(self, open_browser=True):
def get_auth_response(self, open_browser=None):
logger.info('User authentication requires interaction with your '
'web browser. Once you enter your credentials and '
'give authorization, you will be redirected to '
@ -423,10 +426,13 @@ class SpotifyOAuth(SpotifyAuthBase):
redirect_info = urlparse(self.redirect_uri)
redirect_host, redirect_port = get_host_port(redirect_info.netloc)
if open_browser is None:
open_browser = self.open_browser
if (
open_browser
and redirect_host in ("127.0.0.1", "localhost")
and redirect_info.scheme == "http"
(open_browser or self.open_browser)
and redirect_host in ("127.0.0.1", "localhost")
and redirect_info.scheme == "http"
):
# Only start a local http server if a port is specified
if redirect_port:
@ -584,7 +590,8 @@ class SpotifyPKCE(SpotifyAuthBase):
username=None,
proxies=None,
requests_timeout=None,
requests_session=True,):
requests_session=True,
open_browser=True):
"""
Creates Auth Manager with the PKCE Auth flow.
@ -602,6 +609,7 @@ class SpotifyPKCE(SpotifyAuthBase):
* 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
"""
super(SpotifyPKCE, self).__init__(requests_session)
@ -620,6 +628,7 @@ class SpotifyPKCE(SpotifyAuthBase):
self.code_verifier = None
self.code_challenge = None
self.authorization_code = None
self.open_browser = open_browser
def _normalize_scope(self, scope):
if scope:
@ -642,7 +651,7 @@ class SpotifyPKCE(SpotifyAuthBase):
try:
import secrets
verifier = secrets.token_urlsafe(length)
except ImportError: # For python 3.5 support
except ImportError: # For python 3.5 support
import os
import base64
rand_bytes = os.urandom(length)
@ -688,7 +697,7 @@ class SpotifyPKCE(SpotifyAuthBase):
except webbrowser.Error:
logger.error("Please navigate here: %s", auth_url)
def _get_auth_response(self, open_browser=True):
def _get_auth_response(self, open_browser=None):
logger.info('User authentication requires interaction with your '
'web browser. Once you enter your credentials and '
'give authorization, you will be redirected to '
@ -698,10 +707,13 @@ class SpotifyPKCE(SpotifyAuthBase):
redirect_info = urlparse(self.redirect_uri)
redirect_host, redirect_port = get_host_port(redirect_info.netloc)
if open_browser is None:
open_browser = self.open_browser
if (
open_browser
and redirect_host in ("127.0.0.1", "localhost")
and redirect_info.scheme == "http"
open_browser
and redirect_host in ("127.0.0.1", "localhost")
and redirect_info.scheme == "http"
):
# Only start a local http server if a port is specified
if redirect_port:
@ -730,8 +742,8 @@ class SpotifyPKCE(SpotifyAuthBase):
else:
raise SpotifyOauthError("Server listening on localhost has not been accessed")
def _get_auth_response_interactive(self, open_browser=True):
if open_browser:
def _get_auth_response_interactive(self, open_browser=False):
if open_browser or self.open_browser:
self._open_auth_url()
prompt = "Enter the URL you were redirected to: "
else:
@ -764,7 +776,7 @@ class SpotifyPKCE(SpotifyAuthBase):
# if scopes don't match, then bail
if "scope" not in token_info or not self._is_scope_subset(
self.scope, token_info["scope"]
self.scope, token_info["scope"]
):
return None
@ -1011,7 +1023,7 @@ class SpotifyImplicitGrant(SpotifyAuthBase):
# if scopes don't match, then bail
if "scope" not in token_info or not self._is_scope_subset(
self.scope, token_info["scope"]
self.scope, token_info["scope"]
):
return None