mirror of
https://github.com/spotipy-dev/spotipy.git
synced 2026-06-19 09:13:53 +00:00
Merge branch 'master' into v3_rebase_rebase
# Conflicts: # setup.py
This commit is contained in:
commit
3b1fd2a8f3
16
CHANGELOG.md
16
CHANGELOG.md
@ -8,6 +8,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
## Unreleased
|
## Unreleased
|
||||||
Add your changes below.
|
Add your changes below.
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
## [2.25.0] - 2025-03-01
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- Added unit tests for queue functions
|
- Added unit tests for queue functions
|
||||||
- Added detailed function docstrings to 'util.py', including descriptions and special sections that lists arguments, returns, and raises.
|
- Added detailed function docstrings to 'util.py', including descriptions and special sections that lists arguments, returns, and raises.
|
||||||
@ -19,6 +27,14 @@ Add your changes below.
|
|||||||
- Added `personalized_playlist.py`, `track_recommendations.py`, and `audio_features_analysis.py` to `/examples`.
|
- Added `personalized_playlist.py`, `track_recommendations.py`, and `audio_features_analysis.py` to `/examples`.
|
||||||
- Discord badge in README
|
- Discord badge in README
|
||||||
- Added `SpotifyBaseException` and moved all exceptions to `exceptions.py`
|
- Added `SpotifyBaseException` and moved all exceptions to `exceptions.py`
|
||||||
|
- Marked the following methods as deprecated:
|
||||||
|
- artist_related_artists
|
||||||
|
- recommendations
|
||||||
|
- audio_features
|
||||||
|
- audio_analysis
|
||||||
|
- featured_playlists
|
||||||
|
- category_playlists
|
||||||
|
- Added FAQ entry for inaccessible playlists
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Audiobook integration tests
|
- Audiobook integration tests
|
||||||
|
|||||||
6
FAQ.md
6
FAQ.md
@ -74,3 +74,9 @@ sp = spotipy.Spotify(
|
|||||||
)
|
)
|
||||||
```
|
```
|
||||||
The error raised is a `spotipy.exceptions.SpotifyException`
|
The error raised is a `spotipy.exceptions.SpotifyException`
|
||||||
|
|
||||||
|
### I get a 404 when trying to access a Spotify-owned playlist
|
||||||
|
|
||||||
|
Spotify has begun restricting access to algorithmic and Spotify-owned editorial playlists.
|
||||||
|
Only applications with an existing extended mode will still have access to these playlists.
|
||||||
|
Read more about this change here: [Introducing some changes to our Web API](https://developer.spotify.com/blog/2024-11-27-changes-to-the-web-api)
|
||||||
|
|||||||
@ -443,6 +443,11 @@ class Spotify:
|
|||||||
Parameters:
|
Parameters:
|
||||||
- artist_id - the artist ID, URI or URL
|
- artist_id - the artist ID, URI or URL
|
||||||
"""
|
"""
|
||||||
|
warnings.warn(
|
||||||
|
"You're using `artist_related_artists(...)`, "
|
||||||
|
"which is marked as deprecated by Spotify.",
|
||||||
|
DeprecationWarning
|
||||||
|
)
|
||||||
trid = self._get_id("artist", artist_id)
|
trid = self._get_id("artist", artist_id)
|
||||||
return self._get("artists/" + trid + "/related-artists")
|
return self._get("artists/" + trid + "/related-artists")
|
||||||
|
|
||||||
@ -1268,6 +1273,11 @@ class Spotify:
|
|||||||
(the first object). Use with limit to get the next set of
|
(the first object). Use with limit to get the next set of
|
||||||
items.
|
items.
|
||||||
"""
|
"""
|
||||||
|
warnings.warn(
|
||||||
|
"You're using `featured_playlists(...)`, "
|
||||||
|
"which is marked as deprecated by Spotify.",
|
||||||
|
DeprecationWarning,
|
||||||
|
)
|
||||||
return self._get(
|
return self._get(
|
||||||
"browse/featured-playlists",
|
"browse/featured-playlists",
|
||||||
locale=locale,
|
locale=locale,
|
||||||
@ -1352,6 +1362,11 @@ class Spotify:
|
|||||||
(the first object). Use with limit to get the next set of
|
(the first object). Use with limit to get the next set of
|
||||||
items.
|
items.
|
||||||
"""
|
"""
|
||||||
|
warnings.warn(
|
||||||
|
"You're using `category_playlists(...)`, "
|
||||||
|
"which is marked as deprecated by Spotify.",
|
||||||
|
DeprecationWarning,
|
||||||
|
)
|
||||||
return self._get(
|
return self._get(
|
||||||
"browse/categories/" + category_id + "/playlists",
|
"browse/categories/" + category_id + "/playlists",
|
||||||
country=country,
|
country=country,
|
||||||
@ -1389,6 +1404,12 @@ class Spotify:
|
|||||||
attributes listed in the documentation, these values
|
attributes listed in the documentation, these values
|
||||||
provide filters and targeting on results.
|
provide filters and targeting on results.
|
||||||
"""
|
"""
|
||||||
|
warnings.warn(
|
||||||
|
"You're using `recommendations(...)`, "
|
||||||
|
"which is marked as deprecated by Spotify.",
|
||||||
|
DeprecationWarning,
|
||||||
|
)
|
||||||
|
|
||||||
params = dict(limit=limit)
|
params = dict(limit=limit)
|
||||||
if seed_artists:
|
if seed_artists:
|
||||||
params["seed_artists"] = ",".join(
|
params["seed_artists"] = ",".join(
|
||||||
@ -1435,6 +1456,11 @@ class Spotify:
|
|||||||
Parameters:
|
Parameters:
|
||||||
- track_id - a track URI, URL or ID
|
- track_id - a track URI, URL or ID
|
||||||
"""
|
"""
|
||||||
|
warnings.warn(
|
||||||
|
"You're using `audio_analysis(...)`, "
|
||||||
|
"which is marked as deprecated by Spotify.",
|
||||||
|
DeprecationWarning,
|
||||||
|
)
|
||||||
trid = self._get_id("track", track_id)
|
trid = self._get_id("track", track_id)
|
||||||
return self._get("audio-analysis/" + trid)
|
return self._get("audio-analysis/" + trid)
|
||||||
|
|
||||||
@ -1443,6 +1469,12 @@ class Spotify:
|
|||||||
Parameters:
|
Parameters:
|
||||||
- tracks - a list of track URIs, URLs or IDs, maximum: 100 ids
|
- tracks - a list of track URIs, URLs or IDs, maximum: 100 ids
|
||||||
"""
|
"""
|
||||||
|
warnings.warn(
|
||||||
|
"You're using `audio_features(...)`, "
|
||||||
|
"which is marked as deprecated by Spotify.",
|
||||||
|
DeprecationWarning,
|
||||||
|
)
|
||||||
|
|
||||||
if isinstance(tracks, str):
|
if isinstance(tracks, str):
|
||||||
trackid = self._get_id("track", tracks)
|
trackid = self._get_id("track", tracks)
|
||||||
results = self._get("audio-features/?ids=" + trackid)
|
results = self._get("audio-features/?ids=" + trackid)
|
||||||
|
|||||||
@ -74,34 +74,6 @@ class AuthTestSpotipy(unittest.TestCase):
|
|||||||
)
|
)
|
||||||
self.spotify.trace = False
|
self.spotify.trace = False
|
||||||
|
|
||||||
def test_audio_analysis(self):
|
|
||||||
result = self.spotify.audio_analysis(self.four_tracks[0])
|
|
||||||
assert ('beats' in result)
|
|
||||||
|
|
||||||
def test_audio_features(self):
|
|
||||||
results = self.spotify.audio_features(self.four_tracks)
|
|
||||||
self.assertTrue(len(results) == len(self.four_tracks))
|
|
||||||
for track in results:
|
|
||||||
assert ('speechiness' in track)
|
|
||||||
|
|
||||||
def test_audio_features_with_bad_track(self):
|
|
||||||
bad_tracks = ['spotify:track:bad']
|
|
||||||
input = self.four_tracks + bad_tracks
|
|
||||||
results = self.spotify.audio_features(input)
|
|
||||||
self.assertTrue(len(results) == len(input))
|
|
||||||
for track in results[:-1]:
|
|
||||||
if track is not None:
|
|
||||||
assert ('speechiness' in track)
|
|
||||||
self.assertTrue(results[-1] is None)
|
|
||||||
|
|
||||||
def test_recommendations(self):
|
|
||||||
results = self.spotify.recommendations(
|
|
||||||
seed_tracks=self.four_tracks,
|
|
||||||
min_danceability=0,
|
|
||||||
max_loudness=0,
|
|
||||||
target_popularity=50)
|
|
||||||
self.assertTrue(len(results['tracks']) == 20)
|
|
||||||
|
|
||||||
def test_artist_urn(self):
|
def test_artist_urn(self):
|
||||||
artist = self.spotify.artist(self.radiohead_urn)
|
artist = self.spotify.artist(self.radiohead_urn)
|
||||||
self.assertTrue(artist['name'] == 'Radiohead')
|
self.assertTrue(artist['name'] == 'Radiohead')
|
||||||
@ -180,17 +152,6 @@ class AuthTestSpotipy(unittest.TestCase):
|
|||||||
self.assertTrue('tracks' in results)
|
self.assertTrue('tracks' in results)
|
||||||
self.assertTrue(len(results['tracks']) == 10)
|
self.assertTrue(len(results['tracks']) == 10)
|
||||||
|
|
||||||
def test_artist_related_artists(self):
|
|
||||||
results = self.spotify.artist_related_artists(self.weezer_urn)
|
|
||||||
self.assertTrue('artists' in results)
|
|
||||||
self.assertTrue(len(results['artists']) == 20)
|
|
||||||
|
|
||||||
found = False
|
|
||||||
for artist in results['artists']:
|
|
||||||
if artist['name'] == 'Jimmy Eat World':
|
|
||||||
found = True
|
|
||||||
self.assertTrue(found)
|
|
||||||
|
|
||||||
def test_artist_search(self):
|
def test_artist_search(self):
|
||||||
results = self.spotify.search(q='weezer', type='artist')
|
results = self.spotify.search(q='weezer', type='artist')
|
||||||
self.assertTrue('artists' in results)
|
self.assertTrue('artists' in results)
|
||||||
|
|||||||
@ -391,33 +391,6 @@ class SpotipyBrowseApiTests(unittest.TestCase):
|
|||||||
response = self.spotify.categories(limit=50)
|
response = self.spotify.categories(limit=50)
|
||||||
self.assertLessEqual(len(response['categories']['items']), 50)
|
self.assertLessEqual(len(response['categories']['items']), 50)
|
||||||
|
|
||||||
def test_category_playlists(self):
|
|
||||||
response = self.spotify.categories()
|
|
||||||
category = 'rock'
|
|
||||||
for cat in response['categories']['items']:
|
|
||||||
cat_id = cat['id']
|
|
||||||
if cat_id == category:
|
|
||||||
response = self.spotify.category_playlists(category_id=cat_id)
|
|
||||||
self.assertGreater(len(response['playlists']["items"]), 0)
|
|
||||||
|
|
||||||
def test_category_playlists_limit_low(self):
|
|
||||||
response = self.spotify.categories()
|
|
||||||
category = 'rock'
|
|
||||||
for cat in response['categories']['items']:
|
|
||||||
cat_id = cat['id']
|
|
||||||
if cat_id == category:
|
|
||||||
response = self.spotify.category_playlists(category_id=cat_id, limit=1)
|
|
||||||
self.assertEqual(len(response['categories']['items']), 1)
|
|
||||||
|
|
||||||
def test_category_playlists_limit_high(self):
|
|
||||||
response = self.spotify.categories()
|
|
||||||
category = 'rock'
|
|
||||||
for cat in response['categories']['items']:
|
|
||||||
cat_id = cat['id']
|
|
||||||
if cat_id == category:
|
|
||||||
response = self.spotify.category_playlists(category_id=cat_id, limit=50)
|
|
||||||
self.assertLessEqual(len(response['categories']['items']), 50)
|
|
||||||
|
|
||||||
def test_new_releases(self):
|
def test_new_releases(self):
|
||||||
response = self.spotify.new_releases()
|
response = self.spotify.new_releases()
|
||||||
self.assertGreater(len(response['albums']['items']), 0)
|
self.assertGreater(len(response['albums']['items']), 0)
|
||||||
@ -430,10 +403,6 @@ class SpotipyBrowseApiTests(unittest.TestCase):
|
|||||||
response = self.spotify.new_releases(limit=50)
|
response = self.spotify.new_releases(limit=50)
|
||||||
self.assertLessEqual(len(response['albums']['items']), 50)
|
self.assertLessEqual(len(response['albums']['items']), 50)
|
||||||
|
|
||||||
def test_featured_releases(self):
|
|
||||||
response = self.spotify.featured_playlists()
|
|
||||||
self.assertGreater(len(response['playlists']), 0)
|
|
||||||
|
|
||||||
|
|
||||||
class SpotipyFollowApiTests(unittest.TestCase):
|
class SpotipyFollowApiTests(unittest.TestCase):
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user