mirror of
https://github.com/spotipy-dev/spotipy.git
synced 2026-06-19 01:03:53 +00:00
* test_improvements - Add __init__.py files to tests dirs so you can run all tests * test_improvements - added helpers file, restructured tests to work without previous data and to be grouped with api type * http_retries - Implement Retry for all requests * Readme - Update README with contributing info * PR Feedback - Added CONTRIBUTING.md, fixed README, fixed test
This commit is contained in:
parent
8b84300597
commit
024a6c96d4
18
CONTRIBUTING.md
Normal file
18
CONTRIBUTING.md
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
## Contributing
|
||||||
|
If you would like to contribute to spotipy follow these steps:
|
||||||
|
|
||||||
|
### Export the needed environment variables
|
||||||
|
```bash
|
||||||
|
export SPOTIPY_CLIENT_ID=client_id_here
|
||||||
|
export SPOTIPY_CLIENT_SECRET=client_secret_here
|
||||||
|
export SPOTIPY_CLIENT_USERNAME=client_username_here # This is actually an id not spotify display name
|
||||||
|
export SPOTIPY_REDIRECT_URI=http://localhost/ # Make url is set in app you created to get your ID and SECRET
|
||||||
|
```
|
||||||
|
|
||||||
|
### Create virtual enevironment, install dependencies, run tests:
|
||||||
|
```bash
|
||||||
|
$ virtualenv --python=python3.7 env
|
||||||
|
(env) $ pip install requirements.txt
|
||||||
|
(env) $ python -m unittest discover -v tests
|
||||||
|
```
|
||||||
|
|
||||||
@ -1,3 +1,3 @@
|
|||||||
mock==2.0.0
|
mock==2.0.0
|
||||||
requests==2.20.0
|
requests==2.20.0
|
||||||
six==1.10.0
|
six==1.10.0
|
||||||
|
|||||||
@ -8,10 +8,10 @@ __all__ = ["Spotify", "SpotifyException"]
|
|||||||
|
|
||||||
import json
|
import json
|
||||||
import sys
|
import sys
|
||||||
import time
|
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
import urllib3
|
||||||
import six
|
import six
|
||||||
|
|
||||||
|
|
||||||
@ -53,7 +53,8 @@ class Spotify(object):
|
|||||||
|
|
||||||
trace = False # Enable tracing?
|
trace = False # Enable tracing?
|
||||||
trace_out = False
|
trace_out = False
|
||||||
max_get_retries = 10
|
max_retries = 3
|
||||||
|
default_retry_codes = (429, 500, 502, 503, 504)
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
@ -63,7 +64,11 @@ class Spotify(object):
|
|||||||
oauth_manager=None,
|
oauth_manager=None,
|
||||||
auth_manager=None,
|
auth_manager=None,
|
||||||
proxies=None,
|
proxies=None,
|
||||||
requests_timeout=None,
|
requests_timeout=5,
|
||||||
|
status_forcelist=None,
|
||||||
|
retries=max_retries,
|
||||||
|
status_retries=max_retries,
|
||||||
|
backoff_factor=0.3,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Creates a Spotify API client.
|
Creates a Spotify API client.
|
||||||
@ -86,6 +91,15 @@ class Spotify(object):
|
|||||||
:param requests_timeout:
|
:param requests_timeout:
|
||||||
Tell Requests to stop waiting for a response after a given
|
Tell Requests to stop waiting for a response after a given
|
||||||
number of seconds
|
number of seconds
|
||||||
|
:param status_forcelist:
|
||||||
|
Tell requests what type of status codes retries should occur on
|
||||||
|
:param retries:
|
||||||
|
Total number of retries to allow
|
||||||
|
:param status_retries:
|
||||||
|
Number of times to retry on bad status codes
|
||||||
|
:param backoff_factor:
|
||||||
|
A backoff factor to apply between attempts after the second try
|
||||||
|
See urllib3 https://urllib3.readthedocs.io/en/latest/reference/urllib3.util.html
|
||||||
"""
|
"""
|
||||||
self.prefix = "https://api.spotify.com/v1/"
|
self.prefix = "https://api.spotify.com/v1/"
|
||||||
self._auth = auth
|
self._auth = auth
|
||||||
@ -94,16 +108,18 @@ class Spotify(object):
|
|||||||
self.auth_manager = auth_manager
|
self.auth_manager = auth_manager
|
||||||
self.proxies = proxies
|
self.proxies = proxies
|
||||||
self.requests_timeout = requests_timeout
|
self.requests_timeout = requests_timeout
|
||||||
|
self.status_forcelist = status_forcelist or self.default_retry_codes
|
||||||
|
self.backoff_factor = backoff_factor
|
||||||
|
self.retries = retries
|
||||||
|
self.status_retries = status_retries
|
||||||
|
|
||||||
if isinstance(requests_session, requests.Session):
|
if isinstance(requests_session, requests.Session):
|
||||||
self._session = requests_session
|
self._session = requests_session
|
||||||
else:
|
else:
|
||||||
if requests_session: # Build a new session.
|
if requests_session: # Build a new session.
|
||||||
self._session = requests.Session()
|
self._build_session()
|
||||||
else: # Use the Requests API module as a "session".
|
else: # Use the Requests API module as a "session".
|
||||||
from requests import api
|
self._session = requests.api
|
||||||
|
|
||||||
self._session = api
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def auth_manager(self):
|
def auth_manager(self):
|
||||||
@ -118,6 +134,20 @@ class Spotify(object):
|
|||||||
self.client_credentials_manager or self.oauth_manager
|
self.client_credentials_manager or self.oauth_manager
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def _build_session(self):
|
||||||
|
self._session = requests.Session()
|
||||||
|
retry = urllib3.Retry(
|
||||||
|
total=self.retries,
|
||||||
|
connect=None,
|
||||||
|
read=False,
|
||||||
|
status=self.status_retries,
|
||||||
|
backoff_factor=self.backoff_factor,
|
||||||
|
status_forcelist=self.status_forcelist)
|
||||||
|
|
||||||
|
adapter = requests.adapters.HTTPAdapter(max_retries=retry)
|
||||||
|
self._session.mount('http://', adapter)
|
||||||
|
self._session.mount('https://', adapter)
|
||||||
|
|
||||||
def _auth_headers(self):
|
def _auth_headers(self):
|
||||||
if self._auth:
|
if self._auth:
|
||||||
return {"Authorization": "Bearer {0}".format(self._auth)}
|
return {"Authorization": "Bearer {0}".format(self._auth)}
|
||||||
@ -129,7 +159,6 @@ class Spotify(object):
|
|||||||
|
|
||||||
def _internal_call(self, method, url, payload, params):
|
def _internal_call(self, method, url, payload, params):
|
||||||
args = dict(params=params)
|
args = dict(params=params)
|
||||||
args["timeout"] = self.requests_timeout
|
|
||||||
if not url.startswith("http"):
|
if not url.startswith("http"):
|
||||||
url = self.prefix + url
|
url = self.prefix + url
|
||||||
headers = self._auth_headers()
|
headers = self._auth_headers()
|
||||||
@ -147,37 +176,44 @@ class Spotify(object):
|
|||||||
if self.trace_out:
|
if self.trace_out:
|
||||||
print(url)
|
print(url)
|
||||||
|
|
||||||
with self._session.request(
|
try:
|
||||||
method, url, headers=headers, proxies=self.proxies, **args
|
response = self._session.request(
|
||||||
) as r:
|
method, url, headers=headers, proxies=self.proxies,
|
||||||
|
timeout=self.requests_timeout, **args
|
||||||
|
)
|
||||||
|
|
||||||
if self.trace: # pragma: no cover
|
if self.trace: # pragma: no cover
|
||||||
print()
|
print()
|
||||||
print("Request headers:", headers)
|
print("Request headers:", headers)
|
||||||
print("Response headers:", r.headers)
|
print("Response headers:", response.headers)
|
||||||
print("HTTP status", r.status_code)
|
print("HTTP status", response.status_code)
|
||||||
print(method, r.url)
|
print(method, response.url)
|
||||||
if payload:
|
if payload:
|
||||||
print("Data", json.dumps(payload))
|
print("Data", json.dumps(payload))
|
||||||
|
|
||||||
|
response.raise_for_status()
|
||||||
|
results = response.json()
|
||||||
|
except requests.exceptions.HTTPError:
|
||||||
try:
|
try:
|
||||||
r.raise_for_status()
|
msg = response.json()["error"]["message"]
|
||||||
except BaseException:
|
except (ValueError, KeyError):
|
||||||
try:
|
msg = "error"
|
||||||
msg = r.json()["error"]["message"]
|
|
||||||
except BaseException:
|
|
||||||
msg = "error"
|
|
||||||
raise SpotifyException(
|
|
||||||
r.status_code,
|
|
||||||
-1,
|
|
||||||
"%s:\n %s" % (r.url, msg),
|
|
||||||
headers=r.headers,
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
raise SpotifyException(
|
||||||
results = r.json()
|
response.status_code,
|
||||||
except BaseException:
|
-1,
|
||||||
results = None
|
"%s:\n %s" % (response.url, msg),
|
||||||
|
headers=response.headers,
|
||||||
|
)
|
||||||
|
except requests.exceptions.RetryError:
|
||||||
|
raise SpotifyException(
|
||||||
|
599,
|
||||||
|
-1,
|
||||||
|
"%s:\n %s" % (response.url, "Max Retries"),
|
||||||
|
headers=response.headers,
|
||||||
|
)
|
||||||
|
except ValueError:
|
||||||
|
results = None
|
||||||
|
|
||||||
if self.trace: # pragma: no cover
|
if self.trace: # pragma: no cover
|
||||||
print("Response:", results)
|
print("Response:", results)
|
||||||
@ -187,23 +223,8 @@ class Spotify(object):
|
|||||||
def _get(self, url, args=None, payload=None, **kwargs):
|
def _get(self, url, args=None, payload=None, **kwargs):
|
||||||
if args:
|
if args:
|
||||||
kwargs.update(args)
|
kwargs.update(args)
|
||||||
retries = self.max_get_retries
|
|
||||||
delay = 0
|
return self._internal_call("GET", url, payload, kwargs)
|
||||||
while retries > 0:
|
|
||||||
try:
|
|
||||||
return self._internal_call("GET", url, payload, kwargs)
|
|
||||||
except SpotifyException as e:
|
|
||||||
retries -= 1
|
|
||||||
delay += 1
|
|
||||||
status = e.http_status
|
|
||||||
# 429 means we hit a rate limit, back-off
|
|
||||||
if not (status == 429 or status >= 500 and status < 600):
|
|
||||||
raise
|
|
||||||
sleep_seconds = int(
|
|
||||||
e.headers.get("Retry-After", delay)
|
|
||||||
)
|
|
||||||
print("retrying after..." + str(sleep_seconds) + "secs")
|
|
||||||
time.sleep(sleep_seconds + 1)
|
|
||||||
|
|
||||||
def _post(self, url, args=None, payload=None, **kwargs):
|
def _post(self, url, args=None, payload=None, **kwargs):
|
||||||
if args:
|
if args:
|
||||||
|
|||||||
0
tests/__init__.py
Normal file
0
tests/__init__.py
Normal file
19
tests/helpers.py
Normal file
19
tests/helpers.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import base64
|
||||||
|
import requests
|
||||||
|
|
||||||
|
|
||||||
|
def get_spotify_playlist(spotify_object, playlist_name, username):
|
||||||
|
playlists = spotify_object.user_playlists(username)
|
||||||
|
while playlists:
|
||||||
|
for item in playlists['items']:
|
||||||
|
if item['name'] == playlist_name:
|
||||||
|
return item
|
||||||
|
playlists = spotify_object.next(playlists)
|
||||||
|
|
||||||
|
|
||||||
|
def create_spotify_playlist(spotify_object, playlist_name, username):
|
||||||
|
return spotify_object.user_playlist_create(username, playlist_name)
|
||||||
|
|
||||||
|
|
||||||
|
def get_as_base64(url):
|
||||||
|
return base64.b64encode(requests.get(url).content).decode("utf-8")
|
||||||
0
tests/integration/__init__.py
Normal file
0
tests/integration/__init__.py
Normal file
@ -189,15 +189,11 @@ class AuthTestSpotipy(unittest.TestCase):
|
|||||||
|
|
||||||
def test_search_timeout(self):
|
def test_search_timeout(self):
|
||||||
client_credentials_manager = SpotifyClientCredentials()
|
client_credentials_manager = SpotifyClientCredentials()
|
||||||
sp = spotipy.Spotify(
|
sp = spotipy.Spotify(requests_timeout=0.01,
|
||||||
client_credentials_manager=client_credentials_manager,
|
client_credentials_manager=client_credentials_manager)
|
||||||
requests_timeout=.01)
|
|
||||||
|
|
||||||
try:
|
with self.assertRaises(requests.exceptions.Timeout):
|
||||||
sp.search(q='my*', type='track')
|
sp.search(q='my*', type='track')
|
||||||
self.assertTrue(False, 'unexpected search timeout')
|
|
||||||
except requests.exceptions.Timeout:
|
|
||||||
self.assertTrue(True, 'expected search timeout')
|
|
||||||
|
|
||||||
def test_album_search(self):
|
def test_album_search(self):
|
||||||
results = self.spotify.search(q='weezer pinkerton', type='album')
|
results = self.spotify.search(q='weezer pinkerton', type='album')
|
||||||
@ -302,10 +298,9 @@ class AuthTestSpotipy(unittest.TestCase):
|
|||||||
sess.close()
|
sess.close()
|
||||||
|
|
||||||
def test_force_no_requests_session(self):
|
def test_force_no_requests_session(self):
|
||||||
from requests import Session
|
|
||||||
with_no_session = spotipy.Spotify(
|
with_no_session = spotipy.Spotify(
|
||||||
client_credentials_manager=SpotifyClientCredentials(),
|
client_credentials_manager=SpotifyClientCredentials(),
|
||||||
requests_session=False)
|
requests_session=False)
|
||||||
self.assertFalse(isinstance(with_no_session._session, Session))
|
self.assertNotIsInstance(with_no_session._session, requests.Session)
|
||||||
self.assertTrue(with_no_session.user(user="akx")
|
user = with_no_session.user(user="akx")
|
||||||
["uri"] == "spotify:user:akx")
|
self.assertEqual(user["uri"], "spotify:user:akx")
|
||||||
|
|||||||
@ -1,20 +1,4 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""
|
|
||||||
These tests require user authentication - provide client credentials using the
|
|
||||||
following environment variables
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
'SPOTIPY_CLIENT_USERNAME'
|
|
||||||
'SPOTIPY_CLIENT_ID'
|
|
||||||
'SPOTIPY_CLIENT_SECRET'
|
|
||||||
'SPOTIPY_REDIRECT_URI'
|
|
||||||
"""
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
|
||||||
|
|
||||||
from spotipy import (
|
from spotipy import (
|
||||||
CLIENT_CREDS_ENV_VARS as CCEV,
|
CLIENT_CREDS_ENV_VARS as CCEV,
|
||||||
@ -23,63 +7,23 @@ from spotipy import (
|
|||||||
SpotifyException,
|
SpotifyException,
|
||||||
)
|
)
|
||||||
import unittest
|
import unittest
|
||||||
import warnings
|
|
||||||
import requests
|
import requests
|
||||||
from pprint import pprint # noqa
|
from tests import helpers
|
||||||
|
|
||||||
|
|
||||||
class AuthTestSpotipy(unittest.TestCase):
|
class SpotipyPlaylistApiTest(unittest.TestCase):
|
||||||
"""
|
|
||||||
These tests require user authentication - provide client credentials using
|
|
||||||
the following environment variables
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
'SPOTIPY_CLIENT_USERNAME'
|
|
||||||
'SPOTIPY_CLIENT_ID'
|
|
||||||
'SPOTIPY_CLIENT_SECRET'
|
|
||||||
'SPOTIPY_REDIRECT_URI'
|
|
||||||
"""
|
|
||||||
|
|
||||||
playlist = "spotify:user:plamere:playlist:2oCEWyyAPbZp9xhVSxZavx"
|
|
||||||
playlist_new_id = "spotify:playlist:7GlxpQjjxRjmbb3RP2rDqI"
|
|
||||||
four_tracks = ["spotify:track:6RtPijgfPKROxEzTHNRiDp",
|
|
||||||
"spotify:track:7IHOIqZUUInxjVkko181PB",
|
|
||||||
"4VrWlk8IQxevMvERoX08iC",
|
|
||||||
"http://open.spotify.com/track/3cySlItpiPiIAzU3NyHCJf"]
|
|
||||||
|
|
||||||
two_tracks = ["spotify:track:6RtPijgfPKROxEzTHNRiDp",
|
|
||||||
"spotify:track:7IHOIqZUUInxjVkko181PB"]
|
|
||||||
|
|
||||||
other_tracks = ["spotify:track:2wySlB6vMzCbQrRnNGOYKa",
|
|
||||||
"spotify:track:29xKs5BAHlmlX1u4gzQAbJ",
|
|
||||||
"spotify:track:1PB7gRWcvefzu7t3LJLUlf"]
|
|
||||||
|
|
||||||
album_ids = ["spotify:album:6kL09DaURb7rAoqqaA51KU",
|
|
||||||
"spotify:album:6RTzC0rDbvagTSJLlY7AKl"]
|
|
||||||
|
|
||||||
bad_id = 'BAD_ID'
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpClass(self):
|
def setUpClass(cls):
|
||||||
if sys.version_info >= (3, 2):
|
cls.four_tracks = ["spotify:track:6RtPijgfPKROxEzTHNRiDp",
|
||||||
# >= Python3.2 only
|
"spotify:track:7IHOIqZUUInxjVkko181PB",
|
||||||
warnings.filterwarnings(
|
"4VrWlk8IQxevMvERoX08iC",
|
||||||
"ignore",
|
"http://open.spotify.com/track/3cySlItpiPiIAzU3NyHCJf"]
|
||||||
category=ResourceWarning, # noqa
|
cls.other_tracks = ["spotify:track:2wySlB6vMzCbQrRnNGOYKa",
|
||||||
message="unclosed.*<ssl.SSLSocket.*>")
|
"spotify:track:29xKs5BAHlmlX1u4gzQAbJ",
|
||||||
|
"spotify:track:1PB7gRWcvefzu7t3LJLUlf"]
|
||||||
|
cls.username = os.getenv(CCEV['client_username'])
|
||||||
|
|
||||||
missing = list(filter(lambda var: not os.getenv(CCEV[var]), CCEV))
|
scope = (
|
||||||
|
|
||||||
if missing:
|
|
||||||
raise Exception(
|
|
||||||
('Please set the client credentials for the test application'
|
|
||||||
' using the following environment variables: {}').format(
|
|
||||||
CCEV.values()))
|
|
||||||
|
|
||||||
self.username = os.getenv(CCEV['client_username'])
|
|
||||||
|
|
||||||
self.scope = (
|
|
||||||
'playlist-modify-public '
|
'playlist-modify-public '
|
||||||
'user-library-read '
|
'user-library-read '
|
||||||
'user-follow-read '
|
'user-follow-read '
|
||||||
@ -88,52 +32,25 @@ class AuthTestSpotipy(unittest.TestCase):
|
|||||||
'user-top-read '
|
'user-top-read '
|
||||||
'user-follow-modify '
|
'user-follow-modify '
|
||||||
'user-read-recently-played '
|
'user-read-recently-played '
|
||||||
'ugc-image-upload'
|
'ugc-image-upload '
|
||||||
|
'user-read-playback-state'
|
||||||
)
|
)
|
||||||
|
|
||||||
self.token = prompt_for_user_token(self.username, scope=self.scope)
|
token = prompt_for_user_token(cls.username, scope=scope)
|
||||||
|
|
||||||
self.spotify = Spotify(auth=self.token)
|
cls.spotify = Spotify(auth=token)
|
||||||
|
|
||||||
# Helper
|
cls.new_playlist_name = 'spotipy-playlist-test'
|
||||||
def get_or_create_spotify_playlist(self, playlist_name):
|
cls.new_playlist = helpers.get_spotify_playlist(
|
||||||
playlists = self.spotify.user_playlists(self.username)
|
cls.spotify, cls.new_playlist_name, cls.username) or \
|
||||||
while playlists:
|
helpers.create_spotify_playlist(
|
||||||
for item in playlists['items']:
|
cls.spotify, cls.new_playlist_name, cls.username)
|
||||||
if item['name'] == playlist_name:
|
cls.new_playlist_uri = cls.new_playlist['uri']
|
||||||
return item
|
|
||||||
playlists = self.spotify.next(playlists)
|
|
||||||
return self.spotify.user_playlist_create(
|
|
||||||
self.username, playlist_name)
|
|
||||||
|
|
||||||
# Helper
|
|
||||||
def get_as_base64(self, url):
|
|
||||||
import base64
|
|
||||||
return base64.b64encode(requests.get(url).content).decode("utf-8")
|
|
||||||
|
|
||||||
def test_track_bad_id(self):
|
|
||||||
try:
|
|
||||||
self.spotify.track(self.bad_id)
|
|
||||||
self.assertTrue(False)
|
|
||||||
except SpotifyException:
|
|
||||||
self.assertTrue(True)
|
|
||||||
|
|
||||||
def test_basic_user_profile(self):
|
|
||||||
user = self.spotify.user(self.username)
|
|
||||||
self.assertTrue(user['id'] == self.username.lower())
|
|
||||||
|
|
||||||
def test_current_user(self):
|
|
||||||
user = self.spotify.current_user()
|
|
||||||
self.assertTrue(user['id'] == self.username.lower())
|
|
||||||
|
|
||||||
def test_me(self):
|
|
||||||
user = self.spotify.me()
|
|
||||||
self.assertTrue(user['id'] == self.username.lower())
|
|
||||||
|
|
||||||
def test_user_playlists(self):
|
def test_user_playlists(self):
|
||||||
playlists = self.spotify.user_playlists(self.username, limit=5)
|
playlists = self.spotify.user_playlists(self.username, limit=5)
|
||||||
self.assertTrue('items' in playlists)
|
self.assertTrue('items' in playlists)
|
||||||
self.assertTrue(len(playlists['items']) == 5)
|
self.assertGreaterEqual(len(playlists['items']), 1)
|
||||||
|
|
||||||
def test_user_playlist_tracks(self):
|
def test_user_playlist_tracks(self):
|
||||||
playlists = self.spotify.user_playlists(self.username, limit=5)
|
playlists = self.spotify.user_playlists(self.username, limit=5)
|
||||||
@ -142,53 +59,135 @@ class AuthTestSpotipy(unittest.TestCase):
|
|||||||
user = playlist['owner']['id']
|
user = playlist['owner']['id']
|
||||||
pid = playlist['id']
|
pid = playlist['id']
|
||||||
results = self.spotify.user_playlist_tracks(user, pid)
|
results = self.spotify.user_playlist_tracks(user, pid)
|
||||||
self.assertTrue(len(results['items']) >= 0)
|
self.assertEquals(len(results['items']), 0)
|
||||||
|
|
||||||
def test_current_user_saved_albums(self):
|
|
||||||
# List
|
|
||||||
albums = self.spotify.current_user_saved_albums()
|
|
||||||
self.assertTrue(len(albums['items']) > 1)
|
|
||||||
|
|
||||||
# Add
|
|
||||||
self.spotify.current_user_saved_albums_add(self.album_ids)
|
|
||||||
|
|
||||||
# Contains
|
|
||||||
self.assertTrue(
|
|
||||||
self.spotify.current_user_saved_albums_contains(
|
|
||||||
self.album_ids) == [
|
|
||||||
True, True])
|
|
||||||
|
|
||||||
# Remove
|
|
||||||
self.spotify.current_user_saved_albums_delete(self.album_ids)
|
|
||||||
albums = self.spotify.current_user_saved_albums()
|
|
||||||
self.assertTrue(len(albums['items']) > 1)
|
|
||||||
|
|
||||||
def test_current_user_playlists(self):
|
def test_current_user_playlists(self):
|
||||||
playlists = self.spotify.current_user_playlists(limit=10)
|
playlists = self.spotify.current_user_playlists(limit=10)
|
||||||
self.assertTrue('items' in playlists)
|
self.assertTrue('items' in playlists)
|
||||||
self.assertTrue(len(playlists['items']) == 10)
|
self.assertGreaterEqual(len(playlists['items']), 1)
|
||||||
|
self.assertLessEqual(len(playlists['items']), 10)
|
||||||
|
|
||||||
def test_user_playlist_follow(self):
|
def test_user_playlist_follow(self):
|
||||||
|
user_to_follow = 'plamere'
|
||||||
|
user_to_follow_id = '4erXB04MxwRAVqcUEpu30O'
|
||||||
self.spotify.user_playlist_follow_playlist(
|
self.spotify.user_playlist_follow_playlist(
|
||||||
'plamere', '4erXB04MxwRAVqcUEpu30O')
|
user_to_follow, user_to_follow_id)
|
||||||
follows = self.spotify.user_playlist_is_following(
|
follows = self.spotify.user_playlist_is_following(
|
||||||
'plamere', '4erXB04MxwRAVqcUEpu30O', [
|
user_to_follow, user_to_follow_id, [self.username])
|
||||||
self.spotify.current_user()['id']])
|
|
||||||
|
|
||||||
self.assertTrue(len(follows) == 1, 'proper follows length')
|
self.assertTrue(len(follows) == 1, 'proper follows length')
|
||||||
self.assertTrue(follows[0], 'is following')
|
self.assertTrue(follows[0], 'is following')
|
||||||
self.spotify.user_playlist_unfollow(
|
self.spotify.user_playlist_unfollow(
|
||||||
'plamere', '4erXB04MxwRAVqcUEpu30O')
|
user_to_follow, user_to_follow_id)
|
||||||
|
|
||||||
follows = self.spotify.user_playlist_is_following(
|
follows = self.spotify.user_playlist_is_following(
|
||||||
'plamere', '4erXB04MxwRAVqcUEpu30O', [
|
user_to_follow, user_to_follow_id, [self.username])
|
||||||
self.spotify.current_user()['id']])
|
|
||||||
self.assertTrue(len(follows) == 1, 'proper follows length')
|
self.assertTrue(len(follows) == 1, 'proper follows length')
|
||||||
self.assertFalse(follows[0], 'is no longer following')
|
self.assertFalse(follows[0], 'is no longer following')
|
||||||
|
|
||||||
|
def test_user_playlist_replace_tracks(self):
|
||||||
|
# add tracks to playlist
|
||||||
|
self.spotify.user_playlist_add_tracks(
|
||||||
|
self.username, self.new_playlist['id'], self.four_tracks)
|
||||||
|
playlist = self.spotify.user_playlist(self.username, self.new_playlist['id'])
|
||||||
|
self.assertEqual(playlist['tracks']['total'], 4)
|
||||||
|
self.assertEqual(len(playlist['tracks']['items']), 4)
|
||||||
|
|
||||||
|
# replace with 3 other tracks
|
||||||
|
self.spotify.user_playlist_replace_tracks(self.username,
|
||||||
|
self.new_playlist['id'],
|
||||||
|
self.other_tracks)
|
||||||
|
playlist = self.spotify.user_playlist(self.username,
|
||||||
|
self.new_playlist['id'])
|
||||||
|
self.assertEqual(playlist['tracks']['total'], 3)
|
||||||
|
self.assertEqual(len(playlist['tracks']['items']), 3)
|
||||||
|
|
||||||
|
self.spotify.user_playlist_remove_all_occurrences_of_tracks(
|
||||||
|
self.username, playlist['id'], self.other_tracks)
|
||||||
|
playlist = self.spotify.user_playlist(self.username, self.new_playlist['id'])
|
||||||
|
self.assertEqual(playlist["tracks"]["total"], 0)
|
||||||
|
|
||||||
|
def test_get_playlist_by_id(self):
|
||||||
|
pl = self.spotify.playlist(self.new_playlist['id'])
|
||||||
|
self.assertEqual(pl["tracks"]["total"], 0)
|
||||||
|
|
||||||
|
def test_playlist_add_tracks(self):
|
||||||
|
# add tracks to playlist
|
||||||
|
self.spotify.user_playlist_add_tracks(
|
||||||
|
self.username, self.new_playlist['id'], self.other_tracks)
|
||||||
|
playlist = self.spotify.user_playlist(self.username, self.new_playlist['id'])
|
||||||
|
self.assertEqual(playlist['tracks']['total'], 3)
|
||||||
|
self.assertEqual(len(playlist['tracks']['items']), 3)
|
||||||
|
|
||||||
|
pl = self.spotify.playlist_tracks(self.new_playlist['id'], limit=2)
|
||||||
|
self.assertEqual(len(pl["items"]), 2)
|
||||||
|
|
||||||
|
self.spotify.user_playlist_remove_all_occurrences_of_tracks(
|
||||||
|
self.username, playlist['id'], self.other_tracks)
|
||||||
|
playlist = self.spotify.user_playlist(self.username, self.new_playlist['id'])
|
||||||
|
self.assertEqual(playlist["tracks"]["total"], 0)
|
||||||
|
|
||||||
|
def test_playlist_cover_image(self):
|
||||||
|
# Upload random dog image
|
||||||
|
r = requests.get('https://dog.ceo/api/breeds/image/random')
|
||||||
|
dog_base64 = helpers.get_as_base64(r.json()['message'])
|
||||||
|
self.spotify.playlist_upload_cover_image(self.new_playlist_uri, dog_base64)
|
||||||
|
|
||||||
|
res = self.spotify.playlist_cover_image(self.new_playlist_uri)
|
||||||
|
self.assertEquals(len(res), 1)
|
||||||
|
first_image = res[0]
|
||||||
|
self.assertIn('width', first_image)
|
||||||
|
self.assertIn('height', first_image)
|
||||||
|
self.assertIn('url', first_image)
|
||||||
|
|
||||||
|
def test_deprecated_starred(self):
|
||||||
|
pl = self.spotify.user_playlist(self.username)
|
||||||
|
self.assertTrue(pl["tracks"] is None)
|
||||||
|
self.assertTrue(pl["owner"] is None)
|
||||||
|
|
||||||
|
def test_deprecated_user_playlist(self):
|
||||||
|
# Test without user due to change from
|
||||||
|
# https://developer.spotify.com/community/news/2018/06/12/changes-to-playlist-uris/
|
||||||
|
pl = self.spotify.user_playlist(None, self.new_playlist['id'])
|
||||||
|
self.assertEqual(pl["tracks"]["total"], 0)
|
||||||
|
|
||||||
|
|
||||||
|
class SpotipyLibraryApiTests(unittest.TestCase):
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
cls.four_tracks = ["spotify:track:6RtPijgfPKROxEzTHNRiDp",
|
||||||
|
"spotify:track:7IHOIqZUUInxjVkko181PB",
|
||||||
|
"4VrWlk8IQxevMvERoX08iC",
|
||||||
|
"http://open.spotify.com/track/3cySlItpiPiIAzU3NyHCJf"]
|
||||||
|
cls.album_ids = ["spotify:album:6kL09DaURb7rAoqqaA51KU",
|
||||||
|
"spotify:album:6RTzC0rDbvagTSJLlY7AKl"]
|
||||||
|
cls.username = os.getenv(CCEV['client_username'])
|
||||||
|
|
||||||
|
scope = (
|
||||||
|
'playlist-modify-public '
|
||||||
|
'user-library-read '
|
||||||
|
'user-follow-read '
|
||||||
|
'user-library-modify '
|
||||||
|
'user-read-private '
|
||||||
|
'user-top-read '
|
||||||
|
'user-follow-modify '
|
||||||
|
'user-read-recently-played '
|
||||||
|
'ugc-image-upload '
|
||||||
|
'user-read-playback-state'
|
||||||
|
)
|
||||||
|
|
||||||
|
token = prompt_for_user_token(cls.username, scope=scope)
|
||||||
|
|
||||||
|
cls.spotify = Spotify(auth=token)
|
||||||
|
|
||||||
|
def test_track_bad_id(self):
|
||||||
|
with self.assertRaises(SpotifyException):
|
||||||
|
self.spotify.track('BadID123')
|
||||||
|
|
||||||
def test_current_user_saved_tracks(self):
|
def test_current_user_saved_tracks(self):
|
||||||
|
# TODO make this not fail if someone doesnthave saved tracks
|
||||||
tracks = self.spotify.current_user_saved_tracks()
|
tracks = self.spotify.current_user_saved_tracks()
|
||||||
self.assertTrue(len(tracks['items']) > 0)
|
self.assertGreater(len(tracks['items']), 0)
|
||||||
|
|
||||||
def test_current_user_save_and_unsave_tracks(self):
|
def test_current_user_save_and_unsave_tracks(self):
|
||||||
tracks = self.spotify.current_user_saved_tracks()
|
tracks = self.spotify.current_user_saved_tracks()
|
||||||
@ -197,168 +196,146 @@ class AuthTestSpotipy(unittest.TestCase):
|
|||||||
|
|
||||||
tracks = self.spotify.current_user_saved_tracks()
|
tracks = self.spotify.current_user_saved_tracks()
|
||||||
new_total = tracks['total']
|
new_total = tracks['total']
|
||||||
self.assertTrue(new_total - total == len(self.four_tracks))
|
self.assertEquals(new_total - total, len(self.four_tracks))
|
||||||
|
|
||||||
tracks = self.spotify.current_user_saved_tracks_delete(
|
tracks = self.spotify.current_user_saved_tracks_delete(
|
||||||
self.four_tracks)
|
self.four_tracks)
|
||||||
tracks = self.spotify.current_user_saved_tracks()
|
tracks = self.spotify.current_user_saved_tracks()
|
||||||
new_total = tracks['total']
|
new_total = tracks['total']
|
||||||
self.assertTrue(new_total == total)
|
self.assertEquals(new_total, total)
|
||||||
|
|
||||||
def test_categories(self):
|
def test_current_user_saved_albums(self):
|
||||||
response = self.spotify.categories()
|
# Add
|
||||||
self.assertTrue(len(response['categories']) > 0)
|
self.spotify.current_user_saved_albums_add(self.album_ids)
|
||||||
|
albums = self.spotify.current_user_saved_albums()
|
||||||
|
self.assertGreaterEqual(len(albums['items']), 2)
|
||||||
|
|
||||||
def test_category_playlists(self):
|
# Contains
|
||||||
response = self.spotify.categories()
|
resp = self.spotify.current_user_saved_albums_contains(self.album_ids)
|
||||||
for cat in response['categories']['items']:
|
self.assertEquals(resp, [True, True])
|
||||||
cat_id = cat['id']
|
|
||||||
response = self.spotify.category_playlists(category_id=cat_id)
|
|
||||||
if len(response['playlists']["items"]) > 0:
|
|
||||||
break
|
|
||||||
self.assertTrue(True)
|
|
||||||
|
|
||||||
def test_new_releases(self):
|
# Remove
|
||||||
response = self.spotify.new_releases()
|
self.spotify.current_user_saved_albums_delete(self.album_ids)
|
||||||
self.assertTrue(len(response['albums']) > 0)
|
resp = self.spotify.current_user_saved_albums_contains(self.album_ids)
|
||||||
|
self.assertEquals(resp, [False, False])
|
||||||
|
|
||||||
def test_featured_releases(self):
|
|
||||||
response = self.spotify.featured_playlists()
|
|
||||||
self.assertTrue(len(response['playlists']) > 0)
|
|
||||||
|
|
||||||
def test_current_user_follows(self):
|
class SpotipyUserApiTests(unittest.TestCase):
|
||||||
response = self.spotify.current_user_followed_artists()
|
@classmethod
|
||||||
artists = response['artists']
|
def setUpClass(cls):
|
||||||
self.assertTrue(len(artists['items']) > 0)
|
cls.username = os.getenv(CCEV['client_username'])
|
||||||
|
|
||||||
|
scope = (
|
||||||
|
'playlist-modify-public '
|
||||||
|
'user-library-read '
|
||||||
|
'user-follow-read '
|
||||||
|
'user-library-modify '
|
||||||
|
'user-read-private '
|
||||||
|
'user-top-read '
|
||||||
|
'user-follow-modify '
|
||||||
|
'user-read-recently-played '
|
||||||
|
'ugc-image-upload '
|
||||||
|
'user-read-playback-state'
|
||||||
|
)
|
||||||
|
|
||||||
|
token = prompt_for_user_token(cls.username, scope=scope)
|
||||||
|
|
||||||
|
cls.spotify = Spotify(auth=token)
|
||||||
|
|
||||||
|
def test_basic_user_profile(self):
|
||||||
|
user = self.spotify.user(self.username)
|
||||||
|
self.assertEquals(user['id'], self.username.lower())
|
||||||
|
|
||||||
|
def test_current_user(self):
|
||||||
|
user = self.spotify.current_user()
|
||||||
|
self.assertEquals(user['id'], self.username.lower())
|
||||||
|
|
||||||
|
def test_me(self):
|
||||||
|
user = self.spotify.me()
|
||||||
|
self.assertTrue(user['id'] == self.username.lower())
|
||||||
|
|
||||||
def test_current_user_top_tracks(self):
|
def test_current_user_top_tracks(self):
|
||||||
response = self.spotify.current_user_top_tracks()
|
response = self.spotify.current_user_top_tracks()
|
||||||
items = response['items']
|
items = response['items']
|
||||||
self.assertTrue(len(items) > 0)
|
self.assertGreater(len(items), 0)
|
||||||
|
|
||||||
def test_current_user_top_artists(self):
|
def test_current_user_top_artists(self):
|
||||||
response = self.spotify.current_user_top_artists()
|
response = self.spotify.current_user_top_artists()
|
||||||
items = response['items']
|
items = response['items']
|
||||||
self.assertTrue(len(items) > 0)
|
self.assertGreater(len(items), 0)
|
||||||
|
|
||||||
def test_current_user_recently_played(self):
|
|
||||||
# No cursor
|
|
||||||
res = self.spotify.current_user_recently_played()
|
|
||||||
self.assertTrue(len(res['items']) <= 50)
|
|
||||||
played_at = res['items'][0]['played_at']
|
|
||||||
|
|
||||||
# Using `before` gives tracks played before
|
class SpotipyBrowseApiTests(unittest.TestCase):
|
||||||
res = self.spotify.current_user_recently_played(
|
@classmethod
|
||||||
before=res['cursors']['after'])
|
def setUpClass(cls):
|
||||||
self.assertTrue(len(res['items']) <= 50)
|
username = os.getenv(CCEV['client_username'])
|
||||||
self.assertTrue(res['items'][0]['played_at'] < played_at)
|
token = prompt_for_user_token(username)
|
||||||
played_at = res['items'][0]['played_at']
|
cls.spotify = Spotify(auth=token)
|
||||||
|
|
||||||
# Using `after` gives tracks played after
|
def test_categories(self):
|
||||||
res = self.spotify.current_user_recently_played(
|
response = self.spotify.categories()
|
||||||
after=res['cursors']['before'])
|
self.assertGreater(len(response['categories']), 0)
|
||||||
self.assertTrue(len(res['items']) <= 50)
|
|
||||||
self.assertTrue(res['items'][0]['played_at'] > played_at)
|
|
||||||
|
|
||||||
def test_user_playlist_ops(self):
|
def test_category_playlists(self):
|
||||||
sp = self.spotify
|
response = self.spotify.categories()
|
||||||
# create empty playlist
|
category = 'rock'
|
||||||
playlist = self.get_or_create_spotify_playlist(
|
for cat in response['categories']['items']:
|
||||||
'spotipy-testing-playlist-1')
|
cat_id = cat['id']
|
||||||
playlist_id = playlist['id']
|
if cat_id == category:
|
||||||
|
response = self.spotify.category_playlists(category_id=cat_id)
|
||||||
|
self.assertGreater(len(response['playlists']["items"]), 0)
|
||||||
|
|
||||||
# remove all tracks from it
|
def test_new_releases(self):
|
||||||
sp.user_playlist_replace_tracks(
|
response = self.spotify.new_releases()
|
||||||
self.username, playlist_id, [])
|
self.assertGreater(len(response['albums']), 0)
|
||||||
playlist = sp.user_playlist(self.username, playlist_id)
|
|
||||||
self.assertTrue(playlist['tracks']['total'] == 0)
|
|
||||||
self.assertTrue(len(playlist['tracks']['items']) == 0)
|
|
||||||
|
|
||||||
# add tracks to it
|
def test_featured_releases(self):
|
||||||
sp.user_playlist_add_tracks(
|
response = self.spotify.featured_playlists()
|
||||||
self.username, playlist_id, self.four_tracks)
|
self.assertGreater(len(response['playlists']), 0)
|
||||||
playlist = sp.user_playlist(self.username, playlist_id)
|
|
||||||
self.assertTrue(playlist['tracks']['total'] == 4)
|
|
||||||
self.assertTrue(len(playlist['tracks']['items']) == 4)
|
|
||||||
|
|
||||||
# remove two tracks from it
|
|
||||||
|
|
||||||
sp.user_playlist_remove_all_occurrences_of_tracks(self.username,
|
class SpotipyFollowApiTests(unittest.TestCase):
|
||||||
playlist_id,
|
@classmethod
|
||||||
self.two_tracks)
|
def setUpClass(cls):
|
||||||
playlist = sp.user_playlist(self.username, playlist_id)
|
cls.username = os.getenv(CCEV['client_username'])
|
||||||
self.assertTrue(playlist['tracks']['total'] == 2)
|
|
||||||
self.assertTrue(len(playlist['tracks']['items']) == 2)
|
|
||||||
|
|
||||||
# replace with 3 other tracks
|
scope = (
|
||||||
sp.user_playlist_replace_tracks(self.username,
|
'playlist-modify-public '
|
||||||
playlist_id,
|
'user-library-read '
|
||||||
self.other_tracks)
|
'user-follow-read '
|
||||||
playlist = sp.user_playlist(self.username, playlist_id)
|
'user-library-modify '
|
||||||
self.assertTrue(playlist['tracks']['total'] == 3)
|
'user-read-private '
|
||||||
self.assertTrue(len(playlist['tracks']['items']) == 3)
|
'user-top-read '
|
||||||
|
'user-follow-modify '
|
||||||
|
'user-read-recently-played '
|
||||||
|
'ugc-image-upload '
|
||||||
|
'user-read-playback-state'
|
||||||
|
)
|
||||||
|
|
||||||
def test_playlist(self):
|
token = prompt_for_user_token(cls.username, scope=scope)
|
||||||
# New playlist ID
|
|
||||||
pl = self.spotify.playlist(self.playlist_new_id)
|
|
||||||
self.assertTrue(pl["tracks"]["total"] > 0)
|
|
||||||
|
|
||||||
# Old playlist ID
|
cls.spotify = Spotify(auth=token)
|
||||||
pl = self.spotify.playlist(self.playlist)
|
|
||||||
self.assertTrue(pl["tracks"]["total"] > 0)
|
|
||||||
|
|
||||||
def test_playlist_tracks(self):
|
def test_current_user_follows(self):
|
||||||
# New playlist ID
|
response = self.spotify.current_user_followed_artists()
|
||||||
pl = self.spotify.playlist_tracks(self.playlist_new_id, limit=2)
|
artists = response['artists']
|
||||||
self.assertTrue(len(pl["items"]) == 2)
|
self.assertGreater(len(artists['items']), 0)
|
||||||
self.assertTrue(pl["total"] > 0)
|
|
||||||
|
|
||||||
# Old playlist ID
|
|
||||||
pl = self.spotify.playlist_tracks(self.playlist, limit=2)
|
|
||||||
self.assertTrue(len(pl["items"]) == 2)
|
|
||||||
self.assertTrue(pl["total"] > 0)
|
|
||||||
|
|
||||||
def test_playlist_upload_cover_image(self):
|
|
||||||
pl1 = self.get_or_create_spotify_playlist('spotipy-testing-playlist-1')
|
|
||||||
plid = pl1['uri']
|
|
||||||
old_b64 = pl1['images'][0]['url']
|
|
||||||
|
|
||||||
# Upload random dog image
|
|
||||||
r = requests.get('https://dog.ceo/api/breeds/image/random')
|
|
||||||
dog_base64 = self.get_as_base64(r.json()['message'])
|
|
||||||
self.spotify.playlist_upload_cover_image(plid, dog_base64)
|
|
||||||
|
|
||||||
# Image must be different
|
|
||||||
pl1 = self.spotify.playlist(plid)
|
|
||||||
new_b64 = self.get_as_base64(pl1['images'][0]['url'])
|
|
||||||
self.assertTrue(old_b64 != new_b64)
|
|
||||||
|
|
||||||
def test_playlist_cover_image(self):
|
|
||||||
pl = self.get_or_create_spotify_playlist('spotipy-testing-playlist-1')
|
|
||||||
plid = pl['uri']
|
|
||||||
res = self.spotify.playlist_cover_image(plid)
|
|
||||||
|
|
||||||
self.assertTrue(len(res) > 0)
|
|
||||||
first_image = res[0]
|
|
||||||
self.assertTrue('width' in first_image)
|
|
||||||
self.assertTrue('height' in first_image)
|
|
||||||
self.assertTrue('url' in first_image)
|
|
||||||
|
|
||||||
def test_user_follows_and_unfollows_artist(self):
|
def test_user_follows_and_unfollows_artist(self):
|
||||||
# Initially follows 1 artist
|
# Initially follows 1 artist
|
||||||
res = self.spotify.current_user_followed_artists()
|
res = self.spotify.current_user_followed_artists()
|
||||||
self.assertTrue(res['artists']['total'] == 1)
|
self.assertEqual(res['artists']['total'], 1)
|
||||||
|
|
||||||
# Follow 2 more artists
|
# Follow 2 more artists
|
||||||
artists = ["6DPYiyq5kWVQS4RGwxzPC7", "0NbfKEOTQCcwd6o7wSDOHI"]
|
artists = ["6DPYiyq5kWVQS4RGwxzPC7", "0NbfKEOTQCcwd6o7wSDOHI"]
|
||||||
self.spotify.user_follow_artists(artists)
|
self.spotify.user_follow_artists(artists)
|
||||||
res = self.spotify.current_user_followed_artists()
|
res = self.spotify.current_user_followed_artists()
|
||||||
self.assertTrue(res['artists']['total'] == 3)
|
self.assertEqual(res['artists']['total'], 3)
|
||||||
|
|
||||||
# Unfollow these 2 artists
|
# Unfollow these 2 artists
|
||||||
self.spotify.user_unfollow_artists(artists)
|
self.spotify.user_unfollow_artists(artists)
|
||||||
res = self.spotify.current_user_followed_artists()
|
res = self.spotify.current_user_followed_artists()
|
||||||
self.assertTrue(res['artists']['total'] == 1)
|
self.assertEqual(res['artists']['total'], 1)
|
||||||
|
|
||||||
def test_user_follows_and_unfollows_user(self):
|
def test_user_follows_and_unfollows_user(self):
|
||||||
# TODO improve after implementing `me/following/contains`
|
# TODO improve after implementing `me/following/contains`
|
||||||
@ -370,25 +347,49 @@ class AuthTestSpotipy(unittest.TestCase):
|
|||||||
# Unfollow these 2 users
|
# Unfollow these 2 users
|
||||||
self.spotify.user_unfollow_users(users)
|
self.spotify.user_unfollow_users(users)
|
||||||
|
|
||||||
def test_deprecated_starred(self):
|
|
||||||
pl = self.spotify.user_playlist(self.username)
|
|
||||||
self.assertTrue(pl["tracks"] is None)
|
|
||||||
self.assertTrue(pl["owner"] is None)
|
|
||||||
|
|
||||||
def test_deprecated_user_playlist(self):
|
class SpotipyPlayerApiTests(unittest.TestCase):
|
||||||
# Test without user due to change from
|
@classmethod
|
||||||
# https://developer.spotify.com/community/news/2018/06/12/changes-to-playlist-uris/
|
def setUpClass(cls):
|
||||||
pl = self.spotify.user_playlist(None, self.playlist)
|
cls.username = os.getenv(CCEV['client_username'])
|
||||||
self.assertTrue(pl["tracks"]["total"] > 0)
|
|
||||||
|
|
||||||
def test_deprecated_user_playlis(self):
|
scope = (
|
||||||
# Test without user due to change from
|
'playlist-modify-public '
|
||||||
# https://developer.spotify.com/community/news/2018/06/12/changes-to-playlist-uris/
|
'user-library-read '
|
||||||
pl = self.spotify.user_playlist_tracks(None, self.playlist, limit=2)
|
'user-follow-read '
|
||||||
self.assertTrue(len(pl["items"]) == 2)
|
'user-library-modify '
|
||||||
self.assertTrue(pl["total"] > 0)
|
'user-read-private '
|
||||||
|
'user-top-read '
|
||||||
|
'user-follow-modify '
|
||||||
|
'user-read-recently-played '
|
||||||
|
'ugc-image-upload '
|
||||||
|
'user-read-playback-state'
|
||||||
|
)
|
||||||
|
|
||||||
|
token = prompt_for_user_token(cls.username, scope=scope)
|
||||||
|
|
||||||
|
cls.spotify = Spotify(auth=token)
|
||||||
|
|
||||||
def test_devices(self):
|
def test_devices(self):
|
||||||
# No devices playing by default
|
# No devices playing by default
|
||||||
res = self.spotify.devices()
|
res = self.spotify.devices()
|
||||||
self.assertEqual(len(res["devices"]), 0)
|
self.assertEquals(len(res["devices"]), 0)
|
||||||
|
|
||||||
|
def test_current_user_recently_played(self):
|
||||||
|
# No cursor
|
||||||
|
res = self.spotify.current_user_recently_played()
|
||||||
|
self.assertLessEqual(len(res['items']), 50)
|
||||||
|
played_at = res['items'][0]['played_at']
|
||||||
|
|
||||||
|
# Using `before` gives tracks played before
|
||||||
|
res = self.spotify.current_user_recently_played(
|
||||||
|
before=res['cursors']['after'])
|
||||||
|
self.assertLessEqual(len(res['items']), 50)
|
||||||
|
self.assertTrue(res['items'][0]['played_at'] < played_at)
|
||||||
|
played_at = res['items'][0]['played_at']
|
||||||
|
|
||||||
|
# Using `after` gives tracks played after
|
||||||
|
res = self.spotify.current_user_recently_played(
|
||||||
|
after=res['cursors']['before'])
|
||||||
|
self.assertLessEqual(len(res['items']), 50)
|
||||||
|
self.assertGreater(res['items'][0]['played_at'], played_at)
|
||||||
|
|||||||
0
tests/unit/__init__.py
Normal file
0
tests/unit/__init__.py
Normal file
Loading…
Reference in New Issue
Block a user