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 2022-11-12 17:41:04 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-spotipy (Old) and /work/SRC/openSUSE:Factory/.python-spotipy.new.1597 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-spotipy" Sat Nov 12 17:41:04 2022 rev:9 rq:1035256 version:2.21.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-spotipy/python-spotipy.changes 2022-09-30 17:58:18.237313960 +0200 +++ /work/SRC/openSUSE:Factory/.python-spotipy.new.1597/python-spotipy.changes 2022-11-12 17:41:21.338234602 +0100 @@ -1,0 +2,15 @@ +Wed Nov 9 19:13:31 UTC 2022 - Yogalakshmi Arunachalam <yarunacha...@suse.com> + +- Update to version 2.21.0 + Added + * Added market parameter to album and albums to address #753 + * Added 'show_featured_artists.py' to 'examples'. + * Expanded contribution and license sections of the documentation. + * Added FlaskSessionCacheHandler, a cache handler that stores the token info in a flask session. + * Added Python 3.10 in GitHub Actions + Fixed + * Updated the documentation to specify ISO-639-1 language codes. + * Fix AttributeError for text attribute of the Response object + * Require redis v3 if python2.7 (fixes readthedocs) + +------------------------------------------------------------------- Old: ---- 2.20.0.tar.gz New: ---- 2.21.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-spotipy.spec ++++++ --- /var/tmp/diff_new_pack.E9yW22/_old 2022-11-12 17:41:21.718236864 +0100 +++ /var/tmp/diff_new_pack.E9yW22/_new 2022-11-12 17:41:21.726236911 +0100 @@ -18,7 +18,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-spotipy -Version: 2.20.0 +Version: 2.21.0 Release: 0 Summary: Client for the Spotify Web API License: MIT ++++++ 2.20.0.tar.gz -> 2.21.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spotipy-2.20.0/.github/workflows/pythonapp.yml new/spotipy-2.21.0/.github/workflows/pythonapp.yml --- old/spotipy-2.20.0/.github/workflows/pythonapp.yml 2022-06-18 23:59:37.000000000 +0200 +++ new/spotipy-2.21.0/.github/workflows/pythonapp.yml 2022-10-27 00:03:42.000000000 +0200 @@ -8,7 +8,7 @@ runs-on: ubuntu-latest strategy: matrix: - python-version: [2.7, 3.6, 3.7, 3.8, 3.9] + python-version: ["2.7", "3.6", "3.7", "3.8", "3.9", "3.10"] steps: - uses: actions/checkout@v2 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spotipy-2.20.0/CHANGELOG.md new/spotipy-2.21.0/CHANGELOG.md --- old/spotipy-2.20.0/CHANGELOG.md 2022-06-18 23:59:37.000000000 +0200 +++ new/spotipy-2.21.0/CHANGELOG.md 2022-10-27 00:03:42.000000000 +0200 @@ -9,6 +9,22 @@ // Add your changes here and then delete this line +## [2.21.0] - 2022-09-26 + +### Added + +* Added `market` parameter to `album` and `albums` to address ([#753](https://github.com/plamere/spotipy/issues/753) +* Added 'show_featured_artists.py' to 'examples'. +* Expanded contribution and license sections of the documentation. +* Added `FlaskSessionCacheHandler`, a cache handler that stores the token info in a flask session. +* Added Python 3.10 in GitHub Actions + +### Fixed + +* Updated the documentation to specify ISO-639-1 language codes. +* Fix `AttributeError` for `text` attribute of the `Response` object +* Require redis v3 if python2.7 (fixes readthedocs) + ## [2.20.0] - 2022-06-18 ### Added diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spotipy-2.20.0/CONTRIBUTING.md new/spotipy-2.21.0/CONTRIBUTING.md --- old/spotipy-2.20.0/CONTRIBUTING.md 2022-06-18 23:59:37.000000000 +0200 +++ new/spotipy-2.21.0/CONTRIBUTING.md 2022-10-27 00:03:42.000000000 +0200 @@ -5,16 +5,24 @@ ### Export the needed environment variables ```bash +# Linux or Mac 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:8080 # Make url is set in app you created to get your ID and SECRET + +# Windows +$env:SPOTIPY_CLIENT_ID="client_id_here" +$env:SPOTIPY_CLIENT_SECRET="client_secret_here" +$env:SPOTIPY_CLIENT_USERNAME="client_username_here" +$env:SPOTIPY_REDIRECT_URI="http://localhost:8080" ``` ### Create virtual environment, install dependencies, run tests: ```bash $ virtualenv --python=python3.7 env +$ source env/bin/activate (env) $ pip install --user -e . (env) $ python -m unittest discover -v tests ``` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spotipy-2.20.0/docs/index.rst new/spotipy-2.21.0/docs/index.rst --- old/spotipy-2.20.0/docs/index.rst 2022-06-18 23:59:37.000000000 +0200 +++ new/spotipy-2.21.0/docs/index.rst 2022-10-27 00:03:42.000000000 +0200 @@ -9,7 +9,7 @@ you get full access to all of the music data provided by the Spotify platform. Assuming you set the ``SPOTIPY_CLIENT_ID`` and ``SPOTIPY_CLIENT_SECRET`` -environment variables, here's a quick example of using *Spotipy* to list the +environment variables (here is a `video <https://youtu.be/3RGm4jALukM>`_ explaining how to do so), here's a quick example of using *Spotipy* to list the names of all the albums released by the artist 'Birdy':: import spotipy @@ -132,7 +132,7 @@ print(idx, track['artists'][0]['name'], " â ", track['name']) or if you are reluctant to immortalize your app credentials in your source code, -you can set environment variables like so (use ``SET`` instead of ``export`` +you can set environment variables like so (use ``$env:"credentials"`` instead of ``export`` on Windows):: export SPOTIPY_CLIENT_ID='your-spotify-client-id' @@ -235,6 +235,7 @@ - ``CacheFileHandler`` - ``MemoryCacheHandler`` - ``DjangoSessionCacheHandler`` + - ``FlaskSessionCacheHandler`` - ``RedisCacheHandler`` Feel free to contribute new cache handlers to the repo. @@ -292,31 +293,96 @@ Spotipy authored by Paul Lamere (plamere) with contributions by: - - Daniel Beaudry // danbeaudry - - Faruk Emre Sahin // fsahin - - George // rogueleaderr - - Henry Greville // sethaurus - - Hugo // hugovk - - José Manuel Pérez // JMPerez - - Lucas Nunno // lnunno - - Lynn Root // econchick - - Matt Dennewitz // mattdennewitz - - Matthew Duck // mattduck - - Michael Thelin // thelinmichael - - Ryan Choi // ryankicks - - Simon Metson // drsm79 - - Steve Winton // swinton - - Tim Balzer // timbalzer - - corycorycory // corycorycory - - Nathan Coleman // nathancoleman - - Michael Birtwell // mbirtwell - - Harrison Hayes // Harrison97 - - Stephane Bruckert // stephanebruckert - - Ritiek Malhotra // ritiek + - Daniel Beaudry (`danbeaudry on Github <https://github.com/danbeaudry>`_) + - Faruk Emre Sahin (`fsahin on Github <https://github.com/fsahin>`_) + - George (`rogueleaderr on Github <https://github.com/rogueleaderr>`_) + - Henry Greville (`sethaurus on Github <https://github.com/sethaurus>`_) + - Hugo van Kemanade (`hugovk on Github <https://github.com/hugovk>`_) + - José Manuel Pérez (`JMPerez on Github <https://github.com/JMPerez>`_) + - Lucas Nunno (`lnunno on Github <https://github.com/lnunno>`_) + - Lynn Root (`econchick on Github <https://github.com/econchick>`_) + - Matt Dennewitz (`mattdennewitz on Github <https://github.com/mattdennewitz>`_) + - Matthew Duck (`mattduck on Github <https://github.com/mattduck>`_) + - Michael Thelin (`thelinmichael on Github <https://github.com/thelinmichael>`_) + - Ryan Choi (`ryankicks on Github <https://github.com/ryankicks>`_) + - Simon Metson (`drsm79 on Github <https://github.com/drsm79>`_) + - Steve Winton (`swinton on Github <https://github.com/swinton>`_) + - Tim Balzer (`timbalzer on Github <https://github.com/timbalzer>`_) + - `corycorycory on Github <https://github.com/corycorycory>`_ + - Nathan Coleman (`nathancoleman on Github <https://github.com/nathancoleman>`_) + - Michael Birtwell (`mbirtwell on Github <https://github.com/mbirtwell>`_) + - Harrison Hayes (`Harrison97 on Github <https://github.com/Harrison97>`_) + - Stephane Bruckert (`stephanebruckert on Github <https://github.com/stephanebruckert>`_) + - Ritiek Malhotra (`ritiek on Github <https://github.com/ritiek>`_) + +If you are a developer with Python experience, and you would like to contribute to Spotipy, please +be sure to follow the guidelines listed below: + +Export the needed Environment variables::: + 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:8080 # Make url is set in app you created to get your ID and SECRET + +Create virtual environment, install dependencies, run tests::: + $ virtualenv --python=python3.7 env + (env) $ pip install --user -e . + (env) $ python -m unittest discover -v tests + +**Lint** + +To automatically fix the code style::: + pip install autopep8 + autopep8 --in-place --aggressive --recursive . + +To verify the code style::: + pip install flake8 + flake8 . + +To make sure if the import lists are stored correctly::: + pip install isort + isort . -c -v + +**Publishing (by maintainer)** + +- Bump version in setup.py +- Bump and date changelog +- Add to changelog: +:: + ## Unreleased + + // Add your changes here and then delete this line +- Commit changes +- Package to pypi: +:: + python setup.py sdist bdist_wheel + python3 setup.py sdist bdist_wheel + twine check dist/* + twine upload --repository-url https://upload.pypi.org/legacy/ --skip-existing dist/*.(whl|gz|zip)~dist/*linux*.whl +- 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 +- Build the documentation again to ensure it's on the latest version + +**Changelog** + +Don't forget to add a short description of your change in the `CHANGELOG <https://github.com/plamere/spotipy/blob/master/CHANGELOG.md>`_! + + License ======= -https://github.com/plamere/spotipy/blob/master/LICENSE.md +(Taken from https://github.com/plamere/spotipy/blob/master/LICENSE.md):: + + MIT License + Copyright (c) 2021 Paul Lamere + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do + so, subject to the following conditions: + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Indices and tables diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spotipy-2.20.0/examples/app.py new/spotipy-2.21.0/examples/app.py --- old/spotipy-2.20.0/examples/app.py 2022-06-18 23:59:37.000000000 +0200 +++ new/spotipy-2.21.0/examples/app.py 2022-10-27 00:03:42.000000000 +0200 @@ -27,7 +27,6 @@ from flask import Flask, session, request, redirect from flask_session import Session import spotipy -import uuid app = Flask(__name__) app.config['SECRET_KEY'] = os.urandom(64) @@ -35,57 +34,44 @@ app.config['SESSION_FILE_DIR'] = './.flask_session/' Session(app) -caches_folder = './.spotify_caches/' -if not os.path.exists(caches_folder): - os.makedirs(caches_folder) - -def session_cache_path(): - return caches_folder + session.get('uuid') @app.route('/') def index(): - if not session.get('uuid'): - # Step 1. Visitor is unknown, give random ID - session['uuid'] = str(uuid.uuid4()) - cache_handler = spotipy.cache_handler.CacheFileHandler(cache_path=session_cache_path()) + cache_handler = spotipy.cache_handler.FlaskSessionCacheHandler(session) auth_manager = spotipy.oauth2.SpotifyOAuth(scope='user-read-currently-playing playlist-modify-private', - cache_handler=cache_handler, - show_dialog=True) + cache_handler=cache_handler, + show_dialog=True) if request.args.get("code"): - # Step 3. Being redirected from Spotify auth page + # Step 2. Being redirected from Spotify auth page auth_manager.get_access_token(request.args.get("code")) return redirect('/') if not auth_manager.validate_token(cache_handler.get_cached_token()): - # Step 2. Display sign in link when no token + # Step 1. Display sign in link when no token auth_url = auth_manager.get_authorize_url() return f'<h2><a href="{auth_url}">Sign in</a></h2>' - # Step 4. Signed in, display data + # Step 3. Signed in, display data spotify = spotipy.Spotify(auth_manager=auth_manager) return f'<h2>Hi {spotify.me()["display_name"]}, ' \ f'<small><a href="/sign_out">[sign out]<a/></small></h2>' \ f'<a href="/playlists">my playlists</a> | ' \ f'<a href="/currently_playing">currently playing</a> | ' \ - f'<a href="/current_user">me</a>' \ + f'<a href="/current_user">me</a>' \ + @app.route('/sign_out') def sign_out(): - try: - # Remove the CACHE file (.cache-test) so that a new user can authorize. - os.remove(session_cache_path()) - session.clear() - except OSError as e: - print ("Error: %s - %s." % (e.filename, e.strerror)) + session.pop("token_info", None) return redirect('/') @app.route('/playlists') def playlists(): - cache_handler = spotipy.cache_handler.CacheFileHandler(cache_path=session_cache_path()) + cache_handler = spotipy.cache_handler.FlaskSessionCacheHandler(session) auth_manager = spotipy.oauth2.SpotifyOAuth(cache_handler=cache_handler) if not auth_manager.validate_token(cache_handler.get_cached_token()): return redirect('/') @@ -96,7 +82,7 @@ @app.route('/currently_playing') def currently_playing(): - cache_handler = spotipy.cache_handler.CacheFileHandler(cache_path=session_cache_path()) + cache_handler = spotipy.cache_handler.FlaskSessionCacheHandler(session) auth_manager = spotipy.oauth2.SpotifyOAuth(cache_handler=cache_handler) if not auth_manager.validate_token(cache_handler.get_cached_token()): return redirect('/') @@ -109,7 +95,7 @@ @app.route('/current_user') def current_user(): - cache_handler = spotipy.cache_handler.CacheFileHandler(cache_path=session_cache_path()) + cache_handler = spotipy.cache_handler.FlaskSessionCacheHandler(session) auth_manager = spotipy.oauth2.SpotifyOAuth(cache_handler=cache_handler) if not auth_manager.validate_token(cache_handler.get_cached_token()): return redirect('/') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spotipy-2.20.0/examples/follow_playlist.py new/spotipy-2.21.0/examples/follow_playlist.py --- old/spotipy-2.20.0/examples/follow_playlist.py 1970-01-01 01:00:00.000000000 +0100 +++ new/spotipy-2.21.0/examples/follow_playlist.py 2022-10-27 00:03:42.000000000 +0200 @@ -0,0 +1,23 @@ +import argparse + +import spotipy +from spotipy.oauth2 import SpotifyOAuth + +def get_args(): + parser = argparse.ArgumentParser(description='Follows a playlist based on playlist ID') + parser.add_argument('-p', '--playlist', required=True, help='Playlist ID') + + return parser.parse_args() + +def main(): + args = get_args() + + if args.playlist is None: + # Uses the Spotify Global Top 50 playlist + spotipy.Spotify(auth_manager=SpotifyOAuth()).current_user_follow_playlist('37i9dQZEVXbMDoHDwVN2tF') + + else: + spotipy.Spotify(auth_manager=SpotifyOAuth()).current_user_follow_playlist(args.playlist) + +if __name__ == '__main__': + main() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spotipy-2.20.0/examples/show_featured_artists.py new/spotipy-2.21.0/examples/show_featured_artists.py --- old/spotipy-2.20.0/examples/show_featured_artists.py 1970-01-01 01:00:00.000000000 +0100 +++ new/spotipy-2.21.0/examples/show_featured_artists.py 2022-10-27 00:03:42.000000000 +0200 @@ -0,0 +1,27 @@ +# Shows all artists featured on an album + +# usage: featured_artists.py spotify:album:[album urn] + +from spotipy.oauth2 import SpotifyClientCredentials +import sys +import spotipy +from pprint import pprint + +if len(sys.argv) > 1: + urn = sys.argv[1] +else: + urn = 'spotify:album:5yTx83u3qerZF7GRJu7eFk' + +sp = spotipy.Spotify(client_credentials_manager=SpotifyClientCredentials()) +album = sp.album(urn) + +featured_artists = set() + +items = album['tracks']['items'] + +for item in items: + for ele in item['artists']: + if 'name' in ele: + featured_artists.add(ele['name']) + +pprint(featured_artists) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spotipy-2.20.0/setup.py new/spotipy-2.21.0/setup.py --- old/spotipy-2.20.0/setup.py 2022-06-18 23:59:37.000000000 +0200 +++ new/spotipy-2.21.0/setup.py 2022-10-27 00:03:42.000000000 +0200 @@ -18,18 +18,22 @@ setup( name='spotipy', - version='2.20.0', + version='2.21.0', description='A light weight Python library for the Spotify Web API', long_description=long_description, long_description_content_type="text/markdown", author="@plamere", author_email="p...@echonest.com", url='https://spotipy.readthedocs.org/', + project_urls={ + 'Source': 'https://github.com/plamere/spotipy', + }, install_requires=[ - 'redis>=3.5.3', - 'requests>=2.25.0', - 'six>=1.15.0', - 'urllib3>=1.26.0' + "redis>=3.5.3", + "redis<4.0.0;python_version<'3.4'", + "requests>=2.25.0", + "six>=1.15.0", + "urllib3>=1.26.0" ], tests_require=test_reqs, extras_require=extra_reqs, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spotipy-2.20.0/spotipy/cache_handler.py new/spotipy-2.21.0/spotipy/cache_handler.py --- old/spotipy-2.20.0/spotipy/cache_handler.py 2022-06-18 23:59:37.000000000 +0200 +++ new/spotipy-2.21.0/spotipy/cache_handler.py 2022-10-27 00:03:42.000000000 +0200 @@ -2,6 +2,7 @@ 'CacheHandler', 'CacheFileHandler', 'DjangoSessionCacheHandler', + 'FlaskSessionCacheHandler', 'MemoryCacheHandler', 'RedisCacheHandler'] @@ -146,6 +147,31 @@ except Exception as e: logger.warning("Error saving token to cache: " + str(e)) + +class FlaskSessionCacheHandler(CacheHandler): + """ + A cache handler that stores the token info in the session framework + provided by flask. + """ + + def __init__(self, session): + self.session = session + + def get_cached_token(self): + token_info = None + try: + token_info = self.session["token_info"] + except KeyError: + logger.debug("Token not found in the session") + + return token_info + + def save_token_to_cache(self, token_info): + try: + self.session["token_info"] = token_info + except Exception as e: + logger.warning("Error saving token to cache: " + str(e)) + class RedisCacheHandler(CacheHandler): """ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spotipy-2.20.0/spotipy/client.py new/spotipy-2.21.0/spotipy/client.py --- old/spotipy-2.20.0/spotipy/client.py 2022-06-18 23:59:37.000000000 +0200 +++ new/spotipy-2.21.0/spotipy/client.py 2022-10-27 00:03:42.000000000 +0200 @@ -144,7 +144,7 @@ See urllib3 https://urllib3.readthedocs.io/en/latest/reference/urllib3.util.html :param language: The language parameter advertises what language the user prefers to see. - See ISO-639 language code: https://www.loc.gov/standards/iso639-2/php/code_list.php + See ISO-639-1 language code: https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes """ self.prefix = "https://api.spotify.com/v1/" self._auth = auth @@ -420,15 +420,19 @@ trid = self._get_id("artist", artist_id) return self._get("artists/" + trid + "/related-artists") - def album(self, album_id): + def album(self, album_id, market=None): """ returns a single album given the album's ID, URIs or URL Parameters: - album_id - the album ID, URI or URL + - market - an ISO 3166-1 alpha-2 country code """ trid = self._get_id("album", album_id) - return self._get("albums/" + trid) + if market is not None: + return self._get("albums/" + trid + '?market=' + market) + else: + return self._get("albums/" + trid) def album_tracks(self, album_id, limit=50, offset=0, market=None): """ Get Spotify catalog information about an album's tracks @@ -446,15 +450,19 @@ "albums/" + trid + "/tracks/", limit=limit, offset=offset, market=market ) - def albums(self, albums): + def albums(self, albums, market=None): """ returns a list of albums given the album IDs, URIs, or URLs Parameters: - albums - a list of album IDs, URIs or URLs + - market - an ISO 3166-1 alpha-2 country code """ tlist = [self._get_id("album", a) for a in albums] - return self._get("albums/?ids=" + ",".join(tlist)) + if market is not None: + return self._get("albums/?ids=" + ",".join(tlist) + '&market=' + market) + else: + return self._get("albums/?ids=" + ",".join(tlist)) def show(self, show_id, market=None): """ returns a single show given the show's ID, URIs or URL @@ -680,7 +688,7 @@ ) def playlist_cover_image(self, playlist_id): - """ Get cover of a playlist. + """ Get cover image of a playlist. Parameters: - playlist_id - the playlist ID, URI or URL @@ -709,7 +717,7 @@ DeprecationWarning, ) - """ Gets playlist of a user + """ Gets a single playlist of a user Parameters: - user - the id of the user @@ -841,7 +849,7 @@ return self.playlist_add_items(playlist_id, tracks, position) def user_playlist_replace_tracks(self, user, playlist_id, tracks): - """ Replace all tracks in a playlist + """ Replace all tracks in a playlist for a user Parameters: - user - the id of the user @@ -863,7 +871,7 @@ range_length=1, snapshot_id=None, ): - """ Reorder tracks in a playlist + """ Reorder tracks in a playlist from a user Parameters: - user - the id of the user @@ -982,7 +990,8 @@ collaborative=None, description=None, ): - """ Changes a playlist's name and/or public/private state + """ Changes a playlist's name and/or public/private state, + collaborative state, and/or description Parameters: - playlist_id - the id of the playlist @@ -1082,7 +1091,7 @@ def playlist_remove_all_occurrences_of_items( self, playlist_id, items, snapshot_id=None ): - """ Removes all occurrences of the given tracks from the given playlist + """ Removes all occurrences of the given tracks/episodes from the given playlist Parameters: - playlist_id - the id of the playlist @@ -1385,7 +1394,7 @@ ) def current_user_following_users(self, ids=None): - """ Check if the current user is following certain artists + """ Check if the current user is following certain users Returns list of booleans respective to ids @@ -1483,8 +1492,8 @@ Parameters: - locale - The desired language, consisting of a lowercase ISO - 639 language code and an uppercase ISO 3166-1 alpha-2 country - code, joined by an underscore. + 639-1 alpha-2 language code and an uppercase ISO 3166-1 alpha-2 + country code, joined by an underscore. - country - An ISO 3166-1 alpha-2 country code. @@ -1533,7 +1542,7 @@ - category_id - The Spotify category ID for the category. - country - An ISO 3166-1 alpha-2 country code. - - locale - The desired language, consisting of an ISO 639 + - locale - The desired language, consisting of an ISO 639-1 alpha-2 language code and an ISO 3166-1 alpha-2 country code, joined by an underscore. """ @@ -1548,7 +1557,7 @@ Parameters: - country - An ISO 3166-1 alpha-2 country code. - - locale - The desired language, consisting of an ISO 639 + - locale - The desired language, consisting of an ISO 639-1 alpha-2 language code and an ISO 3166-1 alpha-2 country code, joined by an underscore. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spotipy-2.20.0/spotipy/oauth2.py new/spotipy-2.21.0/spotipy/oauth2.py --- old/spotipy-2.20.0/spotipy/oauth2.py 2022-06-18 23:59:37.000000000 +0200 +++ new/spotipy-2.21.0/spotipy/oauth2.py 2022-10-27 00:03:42.000000000 +0200 @@ -140,7 +140,7 @@ # then try do decode it into text # if we receive an empty string (which is falsy), then replace it with `None` - error = response.txt or None + error = response.text or None error_description = None raise SpotifyOauthError( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spotipy-2.20.0/tests/integration/test_non_user_endpoints.py new/spotipy-2.21.0/tests/integration/test_non_user_endpoints.py --- old/spotipy-2.20.0/tests/integration/test_non_user_endpoints.py 2022-06-18 23:59:37.000000000 +0200 +++ new/spotipy-2.21.0/tests/integration/test_non_user_endpoints.py 2022-10-27 00:03:42.000000000 +0200 @@ -63,13 +63,13 @@ def test_audio_analysis(self): result = self.spotify.audio_analysis(self.four_tracks[0]) - assert('beats' in result) + 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) + assert ('speechiness' in track) def test_audio_features_with_bad_track(self): bad_tracks = ['spotify:track:bad'] @@ -78,7 +78,7 @@ self.assertTrue(len(results) == len(input)) for track in results[:-1]: if track is not None: - assert('speechiness' in track) + assert ('speechiness' in track) self.assertTrue(results[-1] is None) def test_recommendations(self): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spotipy-2.20.0/tests/integration/test_user_endpoints.py new/spotipy-2.21.0/tests/integration/test_user_endpoints.py --- old/spotipy-2.20.0/tests/integration/test_user_endpoints.py 2022-06-18 23:59:37.000000000 +0200 +++ new/spotipy-2.21.0/tests/integration/test_user_endpoints.py 2022-10-27 00:03:42.000000000 +0200 @@ -359,6 +359,22 @@ response = self.spotify.categories() self.assertGreater(len(response['categories']), 0) + def test_categories_country(self): + response = self.spotify.categories(country='US') + self.assertGreater(len(response['categories']), 0) + + def test_categories_locale(self): + response = self.spotify.categories(locale='en_US') + self.assertGreater(len(response['categories']), 0) + + def test_categories_limit_low(self): + response = self.spotify.categories(limit=1) + self.assertEqual(len(response['categories']), 1) + + def test_categories_limit_high(self): + response = self.spotify.categories(limit=50) + self.assertLessEqual(len(response['categories']), 50) + def test_category_playlists(self): response = self.spotify.categories() category = 'rock' @@ -368,6 +384,24 @@ 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): response = self.spotify.new_releases() self.assertGreater(len(response['albums']), 0)