spotifywebapiPython 1.0.179__py3-none-any.whl → 1.0.181__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of spotifywebapiPython might be problematic. Click here for more details.

Files changed (23) hide show
  1. {spotifywebapiPython-1.0.179.dist-info → spotifywebapiPython-1.0.181.dist-info}/METADATA +1 -1
  2. {spotifywebapiPython-1.0.179.dist-info → spotifywebapiPython-1.0.181.dist-info}/RECORD +23 -23
  3. spotifywebapipython/const.py +1 -1
  4. spotifywebapipython/docs/__init__.html +15 -2
  5. spotifywebapipython/docs/index.html +2 -2
  6. spotifywebapipython/docs/search.js +1 -1
  7. spotifywebapipython/docs/spotifywebapipython/const.html +3 -3
  8. spotifywebapipython/docs/spotifywebapipython/saappmessages.html +54 -2
  9. spotifywebapipython/docs/spotifywebapipython/sautils.html +2 -2
  10. spotifywebapipython/docs/spotifywebapipython/spotifyapierror.html +2 -2
  11. spotifywebapipython/docs/spotifywebapipython/spotifyapimessage.html +2 -2
  12. spotifywebapipython/docs/spotifywebapipython/spotifyauthtoken.html +2 -2
  13. spotifywebapipython/docs/spotifywebapipython/spotifyclient.html +4 -3
  14. spotifywebapipython/docs/spotifywebapipython/spotifydiscovery.html +2 -2
  15. spotifywebapipython/docs/spotifywebapipython/spotifywebapiauthenticationerror.html +2 -2
  16. spotifywebapipython/docs/spotifywebapipython/spotifywebapierror.html +2 -2
  17. spotifywebapipython/docs/spotifywebapipython/spotifywebplayertoken.html +2 -2
  18. spotifywebapipython/saappmessages.py +15 -0
  19. spotifywebapipython/spotifyclient.py +81 -47
  20. spotifywebapipython/spotifywebplayertoken.py +59 -42
  21. {spotifywebapiPython-1.0.179.dist-info → spotifywebapiPython-1.0.181.dist-info}/LICENSE +0 -0
  22. {spotifywebapiPython-1.0.179.dist-info → spotifywebapiPython-1.0.181.dist-info}/WHEEL +0 -0
  23. {spotifywebapiPython-1.0.179.dist-info → spotifywebapiPython-1.0.181.dist-info}/top_level.txt +0 -0
@@ -1164,6 +1164,7 @@ class SpotifyClient:
1164
1164
  - 500 Internal Server Error. You should never receive this error because our clever coders catch them all ... but if you are unlucky enough to get one, please report it to us through a comment at the bottom of this page.
1165
1165
  - 502 Bad Gateway - The server was acting as a gateway or proxy and received an invalid response from the upstream server.
1166
1166
  - 503 Service Unavailable - The server is currently unable to handle the request due to a temporary condition which will be alleviated after some delay. You can choose to resend the request again.
1167
+ - 504 Gateway Timeout - The server is currently unable to handle the request due to a temporary condition which will be alleviated after some delay. You can choose to resend the request again.
1167
1168
  """
1168
1169
  apiMethodName:str = 'MakeRequest'
1169
1170
  apiMethodParms:SIMethodParmListContext = None
@@ -1228,49 +1229,86 @@ class SpotifyClient:
1228
1229
  # in the logic below, ensure that ALL urllib3.request method calls conform to version 1.26.18.
1229
1230
  # urllib3 version 2.0 is not supported! see internal developer notes for more details.
1230
1231
 
1231
- # call the appropriate poolmanager request method.
1232
- if msg.HasUrlParameters:
1232
+ # request retry loop for failed requests that are temporary in nature (504 Gateway Timeout, etc).
1233
+ loopTotalDelay:float = 0
1234
+ LOOP_DELAY:float = 0.200
1235
+ LOOP_TIMEOUT:float = 1.000
1236
+ while True:
1237
+
1238
+ # call the appropriate poolmanager request method.
1239
+ if msg.HasUrlParameters:
1233
1240
 
1234
- # add querystring parameters to url; if url already has a partial parm
1235
- # string (e.g. has a '?xxx=...') then use the append separator (e.g. '...&xxx=...').
1236
- urlQS:str = urlencode(msg.UrlParameters)
1237
- urlParmSep:str = '?'
1238
- if (url.find('?') > 0):
1239
- urlParmSep = '&'
1240
- url = url + urlParmSep + urlQS
1241
+ # add querystring parameters to url; if url already has a partial parm
1242
+ # string (e.g. has a '?xxx=...') then use the append separator (e.g. '...&xxx=...').
1243
+ urlQS:str = urlencode(msg.UrlParameters)
1244
+ urlParmSep:str = '?'
1245
+ if (url.find('?') > 0):
1246
+ urlParmSep = '&'
1247
+ url = url + urlParmSep + urlQS
1241
1248
 
1242
- _logsi.LogDictionary(SILevel.Verbose, "SpotifyClient http request: '%s' (with urlparms)" % (url), msg.UrlParameters, prettyPrint=True)
1243
- response = self._Manager.request_encode_url(method, url, headers=msg.RequestHeaders)
1249
+ _logsi.LogDictionary(SILevel.Verbose, "SpotifyClient http request: '%s' (with urlparms)" % (url), msg.UrlParameters, prettyPrint=True)
1250
+ response = self._Manager.request_encode_url(method, url, headers=msg.RequestHeaders)
1244
1251
 
1245
- elif msg.HasRequestData:
1252
+ elif msg.HasRequestData:
1246
1253
 
1247
- if msg.IsRequestDataEncoded:
1254
+ if msg.IsRequestDataEncoded:
1248
1255
 
1249
- _logsi.LogText(SILevel.Verbose, "SpotifyClient http request: '%s' (with body encoded)" % (url), msg.RequestData)
1250
- response = self._Manager.request(method, url, body=msg.RequestData, headers=msg.RequestHeaders)
1256
+ _logsi.LogText(SILevel.Verbose, "SpotifyClient http request: '%s' (with body encoded)" % (url), msg.RequestData)
1257
+ response = self._Manager.request(method, url, body=msg.RequestData, headers=msg.RequestHeaders)
1251
1258
 
1252
- else:
1259
+ else:
1253
1260
 
1254
- _logsi.LogDictionary(SILevel.Verbose, "SpotifyClient http request: '%s' (with body)" % (url), msg.RequestData, prettyPrint=True)
1255
- response = self._Manager.request_encode_body(method, url, fields=msg.RequestData, headers=msg.RequestHeaders, encode_multipart=False)
1261
+ _logsi.LogDictionary(SILevel.Verbose, "SpotifyClient http request: '%s' (with body)" % (url), msg.RequestData, prettyPrint=True)
1262
+ response = self._Manager.request_encode_body(method, url, fields=msg.RequestData, headers=msg.RequestHeaders, encode_multipart=False)
1256
1263
 
1257
- elif msg.HasRequestJson:
1264
+ elif msg.HasRequestJson:
1258
1265
 
1259
- _logsi.LogDictionary(SILevel.Verbose, "SpotifyClient http request: '%s' (with json body)" % (url), msg.RequestJson, prettyPrint=True)
1266
+ _logsi.LogDictionary(SILevel.Verbose, "SpotifyClient http request: '%s' (with json body)" % (url), msg.RequestJson, prettyPrint=True)
1260
1267
 
1261
- # add content-type=json header and convert the dictionary to json format.
1262
- if not ("content-type" in map(str.lower, msg.RequestHeaders.keys())):
1263
- #headers = HTTPHeaderDict(headers)
1264
- msg.RequestHeaders["Content-Type"] = "application/json"
1265
- reqBody:str = json.dumps(msg.RequestJson, separators=(",", ":"), ensure_ascii=False).encode("utf-8")
1266
- _logsi.LogBinary(SILevel.Debug, "SpotifyClient http request JSON body", reqBody)
1267
- response = self._Manager.request(method, url, body=reqBody, headers=msg.RequestHeaders)
1268
+ # add content-type=json header and convert the dictionary to json format.
1269
+ if not ("content-type" in map(str.lower, msg.RequestHeaders.keys())):
1270
+ #headers = HTTPHeaderDict(headers)
1271
+ msg.RequestHeaders["Content-Type"] = "application/json"
1272
+ reqBody:str = json.dumps(msg.RequestJson, separators=(",", ":"), ensure_ascii=False).encode("utf-8")
1273
+ _logsi.LogBinary(SILevel.Debug, "SpotifyClient http request JSON body", reqBody)
1274
+ response = self._Manager.request(method, url, body=reqBody, headers=msg.RequestHeaders)
1268
1275
 
1269
- else:
1276
+ else:
1277
+
1278
+ _logsi.LogDictionary(SILevel.Verbose, "SpotifyClient http request: '%s' (no body)" % (url), msg.RequestData, prettyPrint=True)
1279
+ response = self._Manager.request(method, url, headers=msg.RequestHeaders)
1280
+
1281
+ # TEST TODO - for testing retry logic.
1282
+ # if (response.status_code == 200) and (loopTotalDelay <= 0.200):
1283
+ # _logsi.LogWarning("TEST TODO - Testing Spotify Web API 504 status (Gateway timeout) condition ...", colorValue=SIColors.Red)
1284
+ # response.status_code = 404
1285
+ # response.reason = "URL Not Found"
1286
+ # if (response.status_code == 200) and (loopTotalDelay <= 0.200):
1287
+ # _logsi.LogWarning("TEST TODO - Testing Spotify Web API 504 status (Gateway timeout) condition ...", colorValue=SIColors.Red)
1288
+ # response.status_code = 504
1289
+ # response.reason = "Gateway Timeout"
1290
+
1291
+ # check for errors that are temporary in nature; for these errors, we will retry the
1292
+ # request for a specified number of tries with a small wait period in between.
1293
+ if (response.status == 504):
1294
+
1295
+ # only retry so many times before we give up;
1296
+ if (loopTotalDelay >= LOOP_TIMEOUT):
1297
+ raise SpotifyApiError(SAAppMessages.MSG_SPOTIFY_WEB_API_RETRY_TIMEOUT % (loopTotalDelay), None, logsi=_logsi)
1298
+
1299
+ # trace.
1300
+ _logsi.LogVerbose(SAAppMessages.MSG_SPOTIFY_WEB_API_RETRY_RESPONSE_STATUS % (response.status, response.reason), colorValue=SIColors.Red)
1301
+
1302
+ # wait just a bit between requests.
1303
+ _logsi.LogVerbose(SAAppMessages.MSG_SPOTIFY_WEB_API_RETRY_REQUEST_DELAY % (LOOP_DELAY))
1304
+ time.sleep(LOOP_DELAY)
1305
+ loopTotalDelay = loopTotalDelay + LOOP_DELAY
1306
+
1307
+ else:
1308
+
1309
+ # otherwise, break out of retry loop and process response.
1310
+ break
1270
1311
 
1271
- _logsi.LogDictionary(SILevel.Verbose, "SpotifyClient http request: '%s' (no body)" % (url), msg.RequestData, prettyPrint=True)
1272
- response = self._Manager.request(method, url, headers=msg.RequestHeaders)
1273
-
1274
1312
  # process based upon response status code; some requests will not return response data.
1275
1313
  # I know this could have been simplified, but I broke it down into possible return code ranges.
1276
1314
  if response.status >= 200 and response.status <= 299:
@@ -16613,6 +16651,9 @@ class SpotifyClient:
16613
16651
  # trace.
16614
16652
  _logsi.LogObject(SILevel.Verbose, TRACE_MSG_USERPROFILE % (self._UserProfile.DisplayName, self._UserProfile.EMail), self._UserProfile, excludeNonPublic=True)
16615
16653
 
16654
+ # start / restart Zeroconf Directory task.
16655
+ self._RestartSpotifyConnectDirectoryTask()
16656
+
16616
16657
  except SpotifyApiError: raise # pass handled exceptions on thru
16617
16658
  except Exception as ex:
16618
16659
 
@@ -16625,10 +16666,6 @@ class SpotifyClient:
16625
16666
  # trace.
16626
16667
  _logsi.LeaveMethod(SILevel.Debug, apiMethodName)
16627
16668
 
16628
- # we do this in the finalizer, so trace messages log correctly (due to multi-threading).
16629
- # start / restart Zeroconf Directory task.
16630
- self._RestartSpotifyConnectDirectoryTask()
16631
-
16632
16669
 
16633
16670
  def SetAuthTokenAuthorizationCodePKCE(
16634
16671
  self,
@@ -16803,6 +16840,9 @@ class SpotifyClient:
16803
16840
  # trace.
16804
16841
  _logsi.LogObject(SILevel.Verbose, TRACE_MSG_USERPROFILE % (self._UserProfile.DisplayName, self._UserProfile.EMail), self._UserProfile, excludeNonPublic=True)
16805
16842
 
16843
+ # start / restart Zeroconf Directory task.
16844
+ self._RestartSpotifyConnectDirectoryTask()
16845
+
16806
16846
  except SpotifyApiError: raise # pass handled exceptions on thru
16807
16847
  except Exception as ex:
16808
16848
 
@@ -16815,10 +16855,6 @@ class SpotifyClient:
16815
16855
  # trace.
16816
16856
  _logsi.LeaveMethod(SILevel.Debug, apiMethodName)
16817
16857
 
16818
- # we do this in the finalizer, so trace messages log correctly (due to multi-threading).
16819
- # start / restart Zeroconf Directory task.
16820
- self._RestartSpotifyConnectDirectoryTask()
16821
-
16822
16858
 
16823
16859
  def SetAuthTokenClientCredentials(
16824
16860
  self,
@@ -16898,6 +16934,9 @@ class SpotifyClient:
16898
16934
  # trace.
16899
16935
  _logsi.LogObject(SILevel.Verbose, TRACE_MSG_USERPROFILE % (self._UserProfile.DisplayName, self._UserProfile.EMail), self._UserProfile, excludeNonPublic=True)
16900
16936
 
16937
+ # start / restart Zeroconf Directory task.
16938
+ self._RestartSpotifyConnectDirectoryTask()
16939
+
16901
16940
  except SpotifyApiError: raise # pass handled exceptions on thru
16902
16941
  except SpotifyWebApiError: raise # pass handled exceptions on thru
16903
16942
  except SpotifyWebApiAuthenticationError: raise # pass handled exceptions on thru
@@ -16912,10 +16951,6 @@ class SpotifyClient:
16912
16951
  # trace.
16913
16952
  _logsi.LeaveMethod(SILevel.Debug, apiMethodName)
16914
16953
 
16915
- # we do this in the finalizer, so trace messages log correctly (due to multi-threading).
16916
- # start / restart Zeroconf Directory task.
16917
- self._RestartSpotifyConnectDirectoryTask()
16918
-
16919
16954
 
16920
16955
  def SetAuthTokenFromToken(
16921
16956
  self,
@@ -17012,6 +17047,9 @@ class SpotifyClient:
17012
17047
  # trace.
17013
17048
  _logsi.LogObject(SILevel.Verbose, TRACE_MSG_USERPROFILE % (self._UserProfile.DisplayName, self._UserProfile.EMail), self._UserProfile, excludeNonPublic=True)
17014
17049
 
17050
+ # start / restart Zeroconf Directory task, if there was no exception.
17051
+ self._RestartSpotifyConnectDirectoryTask()
17052
+
17015
17053
  except SpotifyApiError: raise # pass handled exceptions on thru
17016
17054
  except Exception as ex:
17017
17055
 
@@ -17024,10 +17062,6 @@ class SpotifyClient:
17024
17062
  # trace.
17025
17063
  _logsi.LeaveMethod(SILevel.Debug, apiMethodName)
17026
17064
 
17027
- # we do this in the finalizer, so trace messages log correctly (due to multi-threading).
17028
- # start / restart Zeroconf Directory task.
17029
- self._RestartSpotifyConnectDirectoryTask()
17030
-
17031
17065
 
17032
17066
  def ToString(self) -> str:
17033
17067
  """
@@ -7,6 +7,7 @@ import requests
7
7
  import time
8
8
 
9
9
  # our package imports.
10
+ from .saappmessages import SAAppMessages
10
11
  from .spotifyapierror import SpotifyApiError
11
12
  from .const import (
12
13
  SPOTIFY_WEBUI_URL_BASE,
@@ -14,7 +15,7 @@ from .const import (
14
15
  )
15
16
 
16
17
  # get smartinspect logger reference; create a new session for this module name.
17
- from smartinspectpython.siauto import SIAuto, SILevel, SISession, SIMethodParmListContext
18
+ from smartinspectpython.siauto import SIAuto, SILevel, SISession, SIMethodParmListContext, SIColors
18
19
  import logging
19
20
  _logsi:SISession = SIAuto.Si.GetSession(__name__)
20
21
  if (_logsi == None):
@@ -276,17 +277,17 @@ class SpotifyWebPlayerToken:
276
277
  "productType": "web_player",
277
278
  }
278
279
 
279
- # retry if gateway timeout error is returned.
280
+ # trace.
281
+ _logsi.LogVerbose("Exchanging Spotify Web Player cookie credentials for OAuth2 authorization access token")
282
+ _logsi.LogDictionary(SILevel.Verbose, "%s http request: \"%s\" (cookies)" % (tracePrefix, SPOTIFY_WEBUI_URL_GET_ACCESS_TOKEN), reqCookies)
283
+ _logsi.LogDictionary(SILevel.Debug, "%s http request: \"%s\" (headers)" % (tracePrefix, SPOTIFY_WEBUI_URL_GET_ACCESS_TOKEN), reqHeaders)
284
+ _logsi.LogDictionary(SILevel.Verbose, "%s http request: \"%s\" (parms)" % (tracePrefix, SPOTIFY_WEBUI_URL_GET_ACCESS_TOKEN), reqParms)
285
+
286
+ # request retry loop for failed requests that are temporary in nature (504 Gateway Timeout, etc).
280
287
  loopTotalDelay:float = 0
281
- LOOP_DELAY:float = 0.100
282
- LOOP_TIMEOUT:float = 0.500
288
+ LOOP_DELAY:float = 0.200
289
+ LOOP_TIMEOUT:float = 1.000
283
290
  while True:
284
-
285
- # trace.
286
- _logsi.LogVerbose("Exchanging Spotify Web Player cookie credentials for OAuth2 authorization access token")
287
- _logsi.LogDictionary(SILevel.Verbose, "%s http request: \"%s\" (cookies)" % (tracePrefix, SPOTIFY_WEBUI_URL_GET_ACCESS_TOKEN), reqCookies)
288
- _logsi.LogDictionary(SILevel.Debug, "%s http request: \"%s\" (headers)" % (tracePrefix, SPOTIFY_WEBUI_URL_GET_ACCESS_TOKEN), reqHeaders)
289
- _logsi.LogDictionary(SILevel.Verbose, "%s http request: \"%s\" (parms)" % (tracePrefix, SPOTIFY_WEBUI_URL_GET_ACCESS_TOKEN), reqParms)
290
291
 
291
292
  # convert the spotify web player cookie credentials to an access token.
292
293
  response = session.get(
@@ -297,42 +298,58 @@ class SpotifyWebPlayerToken:
297
298
  allow_redirects=False,
298
299
  )
299
300
 
300
- # trace.
301
- if _logsi.IsOn(SILevel.Debug):
302
- _logsi.LogObject(SILevel.Debug, "%s http response object - type=\"%s\", module=\"%s\"" % (tracePrefix, type(response).__name__, type(response).__module__), response)
303
-
304
- # trace.
305
- if _logsi.IsOn(SILevel.Debug):
306
- _logsi.LogObject(SILevel.Debug, "%s http response [%s-%s] (response)" % (tracePrefix, response.status_code, response.reason), response)
307
- if (response.headers):
308
- _logsi.LogCollection(SILevel.Debug, "%s http response [%s-%s] (headers)" % (tracePrefix, response.status_code, response.reason), response.headers.items())
309
-
310
- # raise exception if we could not get the access token, or if a redirect occured.
311
- # the redirect usually indicates the sp_dc and sp_key are expired, and it's redirecting to a login page.
312
- respHdrLocation:str = response.headers.get("Location", None)
313
- if (response.status_code == 302 and respHdrLocation == "/get_access_token?reason=transport&productType=web_player&_authfailed=1"):
314
- raise SpotifyApiError("Unsuccessful token request, received status 302 and Location header \"%s\". sp_dc and sp_key could be expired. Please update values in token storage file." % (respHdrLocation), None, logsi=_logsi)
315
-
316
- # if successful request, then break out of the retry loop.
317
- if response.status_code == 200:
318
- _logsi.LogVerbose("Token exchange request was successful within %f seconds from initial request; processing results" % (loopTotalDelay))
319
- break
301
+ # TEST TODO - for testing retry logic.
302
+ # if (response.status_code == 200) and (loopTotalDelay <= 0.200):
303
+ # _logsi.LogWarning("TEST TODO - Testing Spotify Web API 504 status (Gateway timeout) condition ...", colorValue=SIColors.Red)
304
+ # response.status_code = 404
305
+ # response.reason = "URL Not Found"
306
+ # if (response.status_code == 200) and (loopTotalDelay <= 0.200):
307
+ # _logsi.LogWarning("TEST TODO - Testing Spotify Web API 504 status (Gateway timeout) condition ...", colorValue=SIColors.Red)
308
+ # response.status_code = 504
309
+ # response.reason = "Gateway Timeout"
310
+
311
+ # check for errors that are temporary in nature; for these errors, we will retry the
312
+ # request for a specified number of tries with a small wait period in between.
313
+ if (response.status_code == 504):
314
+
315
+ # only retry so many times before we give up.
316
+ if (loopTotalDelay >= LOOP_TIMEOUT):
317
+ raise SpotifyApiError(SAAppMessages.MSG_SPOTIFY_WEB_API_RETRY_TIMEOUT % (loopTotalDelay), None, logsi=_logsi)
320
318
 
321
- # any other status code besides 504 (gateway timeout) is an exception event!
322
- if response.status_code != 504:
323
- raise SpotifyApiError("Token exchange request failed: %s - %s" % (response.status_code, response.reason), None, logsi=_logsi)
319
+ # trace.
320
+ _logsi.LogVerbose(SAAppMessages.MSG_SPOTIFY_WEB_API_RETRY_RESPONSE_STATUS % (response.status_code, response.reason), colorValue=SIColors.Red)
324
321
 
325
- # only retry so many times before we give up;
326
- if (loopTotalDelay > LOOP_TIMEOUT):
327
- raise SpotifyApiError("Timed out waiting for Spotify Gateway to become available; gave up after %f seconds from initial request" % (loopTotalDelay), None, logsi=_logsi)
322
+ # wait just a bit between requests.
323
+ _logsi.LogVerbose(SAAppMessages.MSG_SPOTIFY_WEB_API_RETRY_REQUEST_DELAY % (LOOP_DELAY))
324
+ time.sleep(LOOP_DELAY)
325
+ loopTotalDelay = loopTotalDelay + LOOP_DELAY
328
326
 
329
- # trace.
330
- _logsi.LogVerbose("Spotify Web Player cookie credentials token exchange request returned with a 504 status (Gateway timeout); request will be retried")
327
+ else:
328
+
329
+ # otherwise, break out of retry loop and process response.
330
+ break
331
331
 
332
- # wait just a bit between requests.
333
- _logsi.LogVerbose("Delaying for %s seconds to allow Spotify Gateway to become available" % (LOOP_DELAY))
334
- time.sleep(LOOP_DELAY)
335
- loopTotalDelay = loopTotalDelay + LOOP_DELAY
332
+ # trace.
333
+ if _logsi.IsOn(SILevel.Debug):
334
+ _logsi.LogObject(SILevel.Debug, "%s http response object - type=\"%s\", module=\"%s\"" % (tracePrefix, type(response).__name__, type(response).__module__), response)
335
+
336
+ # trace.
337
+ if _logsi.IsOn(SILevel.Debug):
338
+ _logsi.LogObject(SILevel.Debug, "%s http response [%s-%s] (response)" % (tracePrefix, response.status_code, response.reason), response)
339
+ if (response.headers):
340
+ _logsi.LogCollection(SILevel.Debug, "%s http response [%s-%s] (headers)" % (tracePrefix, response.status_code, response.reason), response.headers.items())
341
+
342
+ # raise exception if we could not get the access token, or if a redirect occured.
343
+ # the redirect usually indicates the sp_dc and sp_key are expired, and it's redirecting to a login page.
344
+ respHdrLocation:str = response.headers.get("Location", None)
345
+ if (response.status_code == 302 and respHdrLocation == "/get_access_token?reason=transport&productType=web_player&_authfailed=1"):
346
+ raise SpotifyApiError("Unsuccessful token request, received status 302 and Location header \"%s\". sp_dc and sp_key could be expired. Please update values in token storage file." % (respHdrLocation), None, logsi=_logsi)
347
+
348
+ # if successful request, then break out of the retry loop.
349
+ if (response.status_code == 200):
350
+ _logsi.LogVerbose("Token exchange request was successful within %f seconds from initial request; processing results" % (loopTotalDelay))
351
+ else:
352
+ raise SpotifyApiError("Token exchange request failed: %s - %s" % (response.status_code, response.reason), None, logsi=_logsi)
336
353
 
337
354
  # load request response.
338
355
  data = response.content.decode('utf-8')