Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-spotipy for openSUSE:Factory checked in at 2026-03-14 22:22:29 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-spotipy (Old) and /work/SRC/openSUSE:Factory/.python-spotipy.new.8177 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-spotipy" Sat Mar 14 22:22:29 2026 rev:17 rq:1338814 version:2.26.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-spotipy/python-spotipy.changes 2025-11-27 15:23:30.917924342 +0100 +++ /work/SRC/openSUSE:Factory/.python-spotipy.new.8177/python-spotipy.changes 2026-03-14 22:23:40.120295820 +0100 @@ -1,0 +2,10 @@ +Fri Mar 13 20:43:57 UTC 2026 - Dirk Müller <[email protected]> + +- update to 2.26.0: + * Created generic methods to get user saved items + * Updated `/tracks` endpoints to `/items` + * Switching IDs to URIs to use `/me/library` endpoint + * Fixed playlist limit to 50 (according to API) + * Added warnings for deprecated methods + +------------------------------------------------------------------- Old: ---- 2.25.2.tar.gz New: ---- 2.26.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-spotipy.spec ++++++ --- /var/tmp/diff_new_pack.5YbEa8/_old 2026-03-14 22:23:40.664318356 +0100 +++ /var/tmp/diff_new_pack.5YbEa8/_new 2026-03-14 22:23:40.668318522 +0100 @@ -1,7 +1,7 @@ # # spec file for package python-spotipy # -# Copyright (c) 2025 SUSE LLC and contributors +# Copyright (c) 2026 SUSE LLC and contributors # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -18,7 +18,7 @@ %{?sle15_python_module_pythons} Name: python-spotipy -Version: 2.25.2 +Version: 2.26.0 Release: 0 Summary: Client for the Spotify Web API License: MIT ++++++ 2.25.2.tar.gz -> 2.26.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spotipy-2.25.2/.github/workflows/pull_request.yml new/spotipy-2.26.0/.github/workflows/pull_request.yml --- old/spotipy-2.25.2/.github/workflows/pull_request.yml 2025-11-26 21:16:13.000000000 +0100 +++ new/spotipy-2.26.0/.github/workflows/pull_request.yml 2026-03-03 17:34:10.000000000 +0100 @@ -12,4 +12,4 @@ - uses: dangoslen/[email protected] with: changeLogPath: 'CHANGELOG.md' - skipLabel: 'skip-changelog' + skipLabels: 'skip-changelog' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spotipy-2.25.2/CHANGELOG.md new/spotipy-2.26.0/CHANGELOG.md --- old/spotipy-2.25.2/CHANGELOG.md 2025-11-26 21:16:13.000000000 +0100 +++ new/spotipy-2.26.0/CHANGELOG.md 2026-03-03 17:34:10.000000000 +0100 @@ -6,7 +6,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## Unreleased - Add your changes below. ### Added @@ -15,6 +14,19 @@ ### Removed +## [2.26.0] - 2026-03-03 + +### Added +- Created generic methods to get user saved items + +### Fixed +- Updated `/tracks` endpoints to `/items` +- Switching IDs to URIs to use `/me/library` endpoint +- Fixed playlist limit to 50 (according to API) +- Added warnings for deprecated methods + +### Removed + ## [2.25.2] - 2025-11-26 ### Added diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spotipy-2.25.2/CONTRIBUTING.md new/spotipy-2.26.0/CONTRIBUTING.md --- old/spotipy-2.25.2/CONTRIBUTING.md 2025-11-26 21:16:13.000000000 +0100 +++ new/spotipy-2.26.0/CONTRIBUTING.md 2026-03-03 17:34:10.000000000 +0100 @@ -39,8 +39,7 @@ Just choose v3 if you are unsure which branch to work on. - -### Create virtual environment, install dependencies, run tests: +### Create virtual environment, install dependencies, run tests ```bash $ virtualenv --python=python3 env @@ -51,7 +50,7 @@ ### Lint - pip install .[test] + pip install ".[test]" To automatically fix some of the code style: @@ -75,9 +74,9 @@ ### Publishing (by maintainer) - - Bump version in setup.py - - Bump and date changelog - - Add to changelog: +- Bump version in setup.py +- Bump and date changelog +- Add to changelog: ## Unreleased Add your changes below. @@ -88,9 +87,8 @@ ### Removed - - Commit changes - - Push tag to trigger PyPI build & release workflow - - Create github release https://github.com/plamere/spotipy/releases with the changelog content +- Commit changes +- Push tag to trigger PyPI build & release workflow +- Create github release <https://github.com/plamere/spotipy/releases> with the changelog content for the version and a short name that describes the main addition - - Verify doc uses latest https://readthedocs.org/projects/spotipy/ - \ No newline at end of file +- Verify doc uses latest <https://readthedocs.org/projects/spotipy/> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spotipy-2.25.2/docs/requirements.txt new/spotipy-2.26.0/docs/requirements.txt --- old/spotipy-2.25.2/docs/requirements.txt 2025-11-26 21:16:13.000000000 +0100 +++ new/spotipy-2.26.0/docs/requirements.txt 2026-03-03 17:34:10.000000000 +0100 @@ -1,3 +1,3 @@ Sphinx~=8.1.3 -sphinx-rtd-theme~=3.0.2 +sphinx-rtd-theme~=3.1.0 redis>=3.5.3 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spotipy-2.25.2/setup.py new/spotipy-2.26.0/setup.py --- old/spotipy-2.25.2/setup.py 2025-11-26 21:16:13.000000000 +0100 +++ new/spotipy-2.26.0/setup.py 2026-03-03 17:34:10.000000000 +0100 @@ -13,15 +13,15 @@ ], 'test': [ 'autopep8>=2.3.2', - 'flake8>=7.1.1', - 'flake8-string-format>=0.3.0', - 'isort>=5.13.2' + 'flake8>=7.3.0', + 'flake8-use-fstring>=1.4', + 'isort>=7.0.0' ] } setup( name='spotipy', - version='2.25.2', + version='2.26.0', description='A light weight Python library for the Spotify Web API', long_description=long_description, long_description_content_type="text/markdown", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spotipy-2.25.2/spotipy/client.py new/spotipy-2.26.0/spotipy/client.py --- old/spotipy-2.25.2/spotipy/client.py 2025-11-26 21:16:13.000000000 +0100 +++ new/spotipy-2.26.0/spotipy/client.py 2026-03-03 17:34:10.000000000 +0100 @@ -445,6 +445,11 @@ - country - limit the response to one particular country. """ + warnings.warn( + "You're using `artist_top_tracks(...)`, " + "which is marked as deprecated by Spotify.", + DeprecationWarning, + ) trid = self._get_id("artist", artist_id) return self._get("artists/" + trid + "/top-tracks", country=country) @@ -647,6 +652,11 @@ Parameters: - user - the id of the usr """ + warnings.warn( + "You're using `user(...)`, " + "which is marked as deprecated by Spotify.", + DeprecationWarning, + ) return self._get("users/" + user) def current_user_playlists(self, limit=50, offset=0): @@ -680,7 +690,7 @@ self, playlist_id, fields=None, - limit=100, + limit=50, offset=0, market=None, additional_types=("track",) @@ -712,7 +722,7 @@ self, playlist_id, fields=None, - limit=100, + limit=50, offset=0, market=None, additional_types=("track", "episode") @@ -730,7 +740,7 @@ """ plid = self._get_id("playlist", playlist_id) return self._get( - f"playlists/{plid}/tracks", + f"playlists/{plid}/items", limit=limit, offset=offset, fields=fields, @@ -826,6 +836,12 @@ - limit - the number of items to return - offset - the index of the first item to return """ + warnings.warn( + "You're using `user_playlists(...)`, " + "which is marked as deprecated by Spotify. Use " + "current_user_playlists(...) instead.", + DeprecationWarning, + ) return self._get( f"users/{user}/playlists", limit=limit, offset=offset ) @@ -840,6 +856,12 @@ - collaborative - is the created playlist collaborative - description - the description of the playlist """ + warnings.warn( + "You're using `user_playlist_create(...)`, " + "which is marked as deprecated by Spotify. Use " + "current_user_playlist_create(...) instead.", + DeprecationWarning, + ) data = { "name": name, "public": public, @@ -849,6 +871,24 @@ return self._post(f"users/{user}/playlists", payload=data) + def current_user_playlist_create(self, name, public=True, collaborative=False, description=""): + """ Creates a playlist for the current user + + Parameters: + - name - the name of the playlist + - public - is the created playlist public + - collaborative - is the created playlist collaborative + - description - the description of the playlist + """ + data = { + "name": name, + "public": public, + "collaborative": collaborative, + "description": description + } + + return self._post("me/playlists", payload=data) + def user_playlist_change_details( self, user, @@ -1171,7 +1211,7 @@ plid = self._get_id("playlist", playlist_id) ftracks = [self._get_uri("track", tid) for tid in items] return self._post( - f"playlists/{plid}/tracks", + f"playlists/{plid}/items", payload=ftracks, position=position, ) @@ -1187,7 +1227,7 @@ ftracks = [self._get_uri("track", tid) for tid in items] payload = {"uris": ftracks} return self._put( - f"playlists/{plid}/tracks", payload=payload + f"playlists/{plid}/items", payload=payload ) def playlist_reorder_items( @@ -1218,7 +1258,7 @@ if snapshot_id: payload["snapshot_id"] = snapshot_id return self._put( - f"playlists/{plid}/tracks", payload=payload + f"playlists/{plid}/items", payload=payload ) def playlist_remove_all_occurrences_of_items( @@ -1235,11 +1275,11 @@ plid = self._get_id("playlist", playlist_id) ftracks = [self._get_uri("track", tid) for tid in items] - payload = {"tracks": [{"uri": track} for track in ftracks]} + payload = {"items": [{"uri": track} for track in ftracks]} if snapshot_id: payload["snapshot_id"] = snapshot_id return self._delete( - f"playlists/{plid}/tracks", payload=payload + f"playlists/{plid}/items", payload=payload ) def playlist_remove_specific_occurrences_of_items( @@ -1266,14 +1306,14 @@ "positions": tr["positions"], } ) - payload = {"tracks": ftracks} + payload = {"items": ftracks} if snapshot_id: payload["snapshot_id"] = snapshot_id return self._delete( - f"playlists/{plid}/tracks", payload=payload + f"playlists/{plid}/items", payload=payload ) - def current_user_follow_playlist(self, playlist_id, public=True): + def current_user_follow_playlist(self, playlist_id): """ Add the current authenticated user as a follower of a playlist. @@ -1281,10 +1321,7 @@ - playlist_id - the id of the playlist """ - return self._put( - f"playlists/{playlist_id}/followers", - payload={"public": public} - ) + return self._put("me/library", uris=self._get_uri("playlist", playlist_id)) def playlist_is_following( self, playlist_id, user_ids @@ -1298,9 +1335,27 @@ if they follow the playlist. Maximum: 5 ids. """ + warnings.warn( + "You're using `playlist_is_following(..., user_ids=...)`, " + "which is marked as deprecated by Spotify. Use ", + "current_user_follow_playlist(...) instead.", + DeprecationWarning, + ) + endpoint = f"playlists/{playlist_id}/followers/contains?ids={','.join(user_ids)}" return self._get(endpoint) + def current_user_saved_items(self, uris): + """ + Check if the current user is following the given artists, users, or playlists + + Parameters: + - uris - a list of URIs to check for following status. Maximum: 40 ids. + + """ + valid_uris = [uri for uri in uris if self._is_uri(uri)] + return self._get("me/library/contains", uris=",".join(valid_uris)) + def me(self): """ Get detailed profile information about the current user. An alias for the 'current_user' method. @@ -1347,8 +1402,8 @@ - albums - a list of album URIs, URLs or IDs """ - alist = [self._get_id("album", a) for a in albums] - return self._put("me/albums?ids=" + ",".join(alist)) + alist = [self._get_uri("album", a) for a in albums] + return self._put("me/library", uris=",".join(alist)) def current_user_saved_albums_delete(self, albums=[]): """ Remove one or more albums from the current user's @@ -1357,8 +1412,8 @@ Parameters: - albums - a list of album URIs, URLs or IDs """ - alist = [self._get_id("album", a) for a in albums] - return self._delete("me/albums/?ids=" + ",".join(alist)) + alist = [self._get_uri("album", a) for a in albums] + return self._delete("me/library", uris=",".join(alist)) def current_user_saved_albums_contains(self, albums=[]): """ Check if one or more albums is already saved in @@ -1367,8 +1422,8 @@ Parameters: - albums - a list of album URIs, URLs or IDs """ - alist = [self._get_id("album", a) for a in albums] - return self._get("me/albums/contains?ids=" + ",".join(alist)) + alist = [self._get_uri("album", a) for a in albums] + return self._get("me/library/contains", uris=",".join(alist)) def current_user_saved_tracks(self, limit=20, offset=0, market=None): """ Gets a list of the tracks saved in the current authorized user's @@ -1391,8 +1446,8 @@ """ tlist = [] if tracks is not None: - tlist = [self._get_id("track", t) for t in tracks] - return self._put("me/tracks/?ids=" + ",".join(tlist)) + tlist = [self._get_uri("track", t) for t in tracks] + return self._put("me/library", uris=",".join(tlist)) def current_user_saved_tracks_delete(self, tracks=None): """ Remove one or more tracks from the current user's @@ -1403,8 +1458,8 @@ """ tlist = [] if tracks is not None: - tlist = [self._get_id("track", t) for t in tracks] - return self._delete("me/tracks/?ids=" + ",".join(tlist)) + tlist = [self._get_uri("track", t) for t in tracks] + return self._delete("me/library", uris=",".join(tlist)) def current_user_saved_tracks_contains(self, tracks=None): """ Check if one or more tracks is already saved in @@ -1415,8 +1470,8 @@ """ tlist = [] if tracks is not None: - tlist = [self._get_id("track", t) for t in tracks] - return self._get("me/tracks/contains?ids=" + ",".join(tlist)) + tlist = [self._get_uri("track", t) for t in tracks] + return self._get("me/library/contains", uris=",".join(tlist)) def current_user_saved_episodes(self, limit=20, offset=0, market=None): """ Gets a list of the episodes saved in the current authorized user's @@ -1439,8 +1494,8 @@ """ elist = [] if episodes is not None: - elist = [self._get_id("episode", e) for e in episodes] - return self._put("me/episodes/?ids=" + ",".join(elist)) + elist = [self._get_uri("episode", e) for e in episodes] + return self._put("me/library", uris=",".join(elist)) def current_user_saved_episodes_delete(self, episodes=None): """ Remove one or more episodes from the current user's @@ -1451,8 +1506,8 @@ """ elist = [] if episodes is not None: - elist = [self._get_id("episode", e) for e in episodes] - return self._delete("me/episodes/?ids=" + ",".join(elist)) + elist = [self._get_uri("episode", e) for e in episodes] + return self._delete("me/library", uris=",".join(elist)) def current_user_saved_episodes_contains(self, episodes=None): """ Check if one or more episodes is already saved in @@ -1484,8 +1539,8 @@ Parameters: - shows - a list of show URIs, URLs or IDs """ - slist = [self._get_id("show", s) for s in shows] - return self._put("me/shows?ids=" + ",".join(slist)) + slist = [self._get_uri("show", s) for s in shows] + return self._put("me/library", uris=",".join(slist)) def current_user_saved_shows_delete(self, shows=[]): """ Remove one or more shows from the current user's @@ -1494,8 +1549,8 @@ Parameters: - shows - a list of show URIs, URLs or IDs """ - slist = [self._get_id("show", s) for s in shows] - return self._delete("me/shows/?ids=" + ",".join(slist)) + slist = [self._get_uri("show", s) for s in shows] + return self._delete("me/library", uris=",".join(slist)) def current_user_saved_shows_contains(self, shows=[]): """ Check if one or more shows is already saved in @@ -1504,8 +1559,8 @@ Parameters: - shows - a list of show URIs, URLs or IDs """ - slist = [self._get_id("show", s) for s in shows] - return self._get("me/shows/contains?ids=" + ",".join(slist)) + slist = [self._get_uri("show", s) for s in shows] + return self._get("me/library/contains", uris=",".join(slist)) def current_user_followed_artists(self, limit=20, after=None): """ Gets a list of the artists followed by the current authorized user @@ -1528,11 +1583,11 @@ Parameters: - ids - a list of artist URIs, URLs or IDs """ - idlist = [] + ulist = [] if ids is not None: - idlist = [self._get_id("artist", i) for i in ids] + ulist = [self._get_uri("artist", i) for i in ids] return self._get( - "me/following/contains", ids=",".join(idlist), type="artist" + "me/library/contains", uris=",".join(ulist) ) def current_user_following_users(self, ids=None): @@ -1543,11 +1598,11 @@ Parameters: - ids - a list of user URIs, URLs or IDs """ - idlist = [] + ulist = [] if ids is not None: - idlist = [self._get_id("user", i) for i in ids] + ulist = [self._get_uri("user", i) for i in ids] return self._get( - "me/following/contains", ids=",".join(idlist), type="user" + "me/library/contains", uris=",".join(ulist) ) def current_user_top_artists( @@ -1604,28 +1659,32 @@ Parameters: - ids - a list of artist IDs """ - return self._put("me/following?type=artist&ids=" + ",".join(ids)) + alist = [self._get_uri("artist", a) for a in ids] + return self._put("me/library", uris=",".join(alist)) def user_follow_users(self, ids=[]): """ Follow one or more users Parameters: - ids - a list of user IDs """ - return self._put("me/following?type=user&ids=" + ",".join(ids)) + ulist = [self._get_uri("user", a) for a in ids] + return self._put("me/library", uris=",".join(ulist)) def user_unfollow_artists(self, ids=[]): """ Unfollow one or more artists Parameters: - ids - a list of artist IDs """ - return self._delete("me/following?type=artist&ids=" + ",".join(ids)) + alist = [self._get_uri("artist", a) for a in ids] + return self._delete("me/library", uris=",".join(alist)) def user_unfollow_users(self, ids=[]): """ Unfollow one or more users Parameters: - ids - a list of user IDs """ - return self._delete("me/following?type=user&ids=" + ",".join(ids)) + ulist = [self._get_uri("user", a) for a in ids] + return self._delete("me/library", uris=",".join(ulist)) def featured_playlists( self, locale=None, country=None, timestamp=None, limit=20, offset=0 @@ -1681,6 +1740,11 @@ (the first object). Use with limit to get the next set of items. """ + warnings.warn( + "You're using `new_release(...)`, " + "which is marked as deprecated by Spotify.", + DeprecationWarning, + ) return self._get( "browse/new-releases", country=country, limit=limit, offset=offset ) @@ -1696,6 +1760,11 @@ language code and an ISO 3166-1 alpha-2 country code, joined by an underscore. """ + warnings.warn( + "You're using `category(...)`, " + "which is marked as deprecated by Spotify.", + DeprecationWarning, + ) return self._get( "browse/categories/" + category_id, country=country, @@ -1718,6 +1787,11 @@ (the first object). Use with limit to get the next set of items. """ + warnings.warn( + "You're using `categories(...)`, " + "which is marked as deprecated by Spotify.", + DeprecationWarning, + ) return self._get( "browse/categories", country=country, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spotipy-2.25.2/tox.ini new/spotipy-2.26.0/tox.ini --- old/spotipy-2.25.2/tox.ini 2025-11-26 21:16:13.000000000 +0100 +++ new/spotipy-2.26.0/tox.ini 2026-03-03 17:34:10.000000000 +0100 @@ -8,6 +8,9 @@ max-line-length = 99 exclude= .git, + .venv, + build, dist, docs, - examples \ No newline at end of file + examples, + spotipy.egg-info \ No newline at end of file
