Compare commits

...

6 Commits

Author SHA1 Message Date
Fabian Wunsch
351d4223d0
Reduce artist_album limit (#1232)
Reduces the limit so that a query called without explicit limit is valid
with the new changes to the spotify API.
2026-03-11 22:07:45 +01:00
Niko
6787aabe0f
Merge pull request #1230 from spotipy-dev/pr/1228
* #1227 - Updated methods related to API changes

- Updated /tracks endpoints to /items
- Switching IDs to URIs for /me/library endpoint
- Fixed playlist limit to 50 (according to API)
- Added warnings for deprecated methods

* #1227 - Formatted code and updated changelog

* #1227 - Improved HTTP URLs computation with kwargs

* bump version to 2.26.0

---------
2026-03-03 17:34:10 +01:00
Cédric Tonarelli
fa7049ea1d
Fix: Web API Changes of February 2026 (#1228)
* #1227 - Updated methods related to API changes

- Updated /tracks endpoints to /items
- Switching IDs to URIs for /me/library endpoint
- Fixed playlist limit to 50 (according to API)
- Added warnings for deprecated methods

* #1227 - Formatted code and updated changelog

* #1227 - Improved HTTP URLs computation with kwargs

* bump version to 2.26.0

---------

Co-authored-by: Niko <github@dieserniko.link>
2026-03-03 17:30:58 +01:00
dependabot[bot]
c52a29f6d2
Update sphinx-rtd-theme requirement from ~=3.0.2 to ~=3.1.0 (#1226)
Updates the requirements on [sphinx-rtd-theme](https://github.com/readthedocs/sphinx_rtd_theme) to permit the latest version.
- [Changelog](https://github.com/readthedocs/sphinx_rtd_theme/blob/master/docs/changelog.rst)
- [Commits](https://github.com/readthedocs/sphinx_rtd_theme/compare/3.0.2...3.1.0)

---
updated-dependencies:
- dependency-name: sphinx-rtd-theme
  dependency-version: 3.1.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-16 20:28:54 +01:00
Niko
179d3e486c
Update skipLabel to skipLabels in workflow 2025-12-23 18:43:11 +01:00
Stephane Bruckert
9119b6a070 Fix lint workflow 2025-11-27 07:33:35 +00:00
7 changed files with 154 additions and 67 deletions

View File

@ -12,4 +12,4 @@ jobs:
- uses: dangoslen/changelog-enforcer@v3.6.1 - uses: dangoslen/changelog-enforcer@v3.6.1
with: with:
changeLogPath: 'CHANGELOG.md' changeLogPath: 'CHANGELOG.md'
skipLabel: 'skip-changelog' skipLabels: 'skip-changelog'

View File

@ -6,7 +6,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## Unreleased ## Unreleased
Add your changes below. Add your changes below.
### Added ### Added
@ -15,6 +14,19 @@ Add your changes below.
### Removed ### 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 ## [2.25.2] - 2025-11-26
### Added ### Added

View File

@ -39,8 +39,7 @@ To give you a flavour of what we mean, here are some examples of what PRs go whe
Just choose v3 if you are unsure which branch to work on. 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 ```bash
$ virtualenv --python=python3 env $ virtualenv --python=python3 env
@ -51,7 +50,7 @@ $ source env/bin/activate
### Lint ### Lint
pip install .[test] pip install ".[test]"
To automatically fix some of the code style: To automatically fix some of the code style:
@ -75,9 +74,9 @@ Don't forget to add a short description of your change in the [CHANGELOG](CHANGE
### Publishing (by maintainer) ### Publishing (by maintainer)
- Bump version in setup.py - Bump version in setup.py
- Bump and date changelog - Bump and date changelog
- Add to changelog: - Add to changelog:
## Unreleased ## Unreleased
Add your changes below. Add your changes below.
@ -88,9 +87,8 @@ Don't forget to add a short description of your change in the [CHANGELOG](CHANGE
### Removed ### Removed
- Commit changes - Commit changes
- Push tag to trigger PyPI build & release workflow - Push tag to trigger PyPI build & release workflow
- Create github release https://github.com/plamere/spotipy/releases with the changelog content - 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 for the version and a short name that describes the main addition
- Verify doc uses latest https://readthedocs.org/projects/spotipy/ - Verify doc uses latest <https://readthedocs.org/projects/spotipy/>

View File

@ -1,3 +1,3 @@
Sphinx~=8.1.3 Sphinx~=8.1.3
sphinx-rtd-theme~=3.0.2 sphinx-rtd-theme~=3.1.0
redis>=3.5.3 redis>=3.5.3

View File

@ -13,15 +13,15 @@ extra_reqs = {
], ],
'test': [ 'test': [
'autopep8>=2.3.2', 'autopep8>=2.3.2',
'flake8>=7.1.1', 'flake8>=7.3.0',
'flake8-string-format>=0.3.0', 'flake8-use-fstring>=1.4',
'isort>=5.13.2' 'isort>=7.0.0'
] ]
} }
setup( setup(
name='spotipy', name='spotipy',
version='2.25.2', version='2.26.0',
description='A light weight Python library for the Spotify Web API', description='A light weight Python library for the Spotify Web API',
long_description=long_description, long_description=long_description,
long_description_content_type="text/markdown", long_description_content_type="text/markdown",

View File

@ -400,7 +400,7 @@ class Spotify:
return self._get("artists/?ids=" + ",".join(tlist)) return self._get("artists/?ids=" + ",".join(tlist))
def artist_albums( def artist_albums(
self, artist_id, album_type=None, include_groups=None, country=None, limit=20, offset=0 self, artist_id, album_type=None, include_groups=None, country=None, limit=10, offset=0
): ):
""" Get Spotify catalog information about an artist's albums """ Get Spotify catalog information about an artist's albums
@ -445,6 +445,11 @@ class Spotify:
- country - limit the response to one particular country. - 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) trid = self._get_id("artist", artist_id)
return self._get("artists/" + trid + "/top-tracks", country=country) return self._get("artists/" + trid + "/top-tracks", country=country)
@ -647,6 +652,11 @@ class Spotify:
Parameters: Parameters:
- user - the id of the usr - 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) return self._get("users/" + user)
def current_user_playlists(self, limit=50, offset=0): def current_user_playlists(self, limit=50, offset=0):
@ -680,7 +690,7 @@ class Spotify:
self, self,
playlist_id, playlist_id,
fields=None, fields=None,
limit=100, limit=50,
offset=0, offset=0,
market=None, market=None,
additional_types=("track",) additional_types=("track",)
@ -712,7 +722,7 @@ class Spotify:
self, self,
playlist_id, playlist_id,
fields=None, fields=None,
limit=100, limit=50,
offset=0, offset=0,
market=None, market=None,
additional_types=("track", "episode") additional_types=("track", "episode")
@ -730,7 +740,7 @@ class Spotify:
""" """
plid = self._get_id("playlist", playlist_id) plid = self._get_id("playlist", playlist_id)
return self._get( return self._get(
f"playlists/{plid}/tracks", f"playlists/{plid}/items",
limit=limit, limit=limit,
offset=offset, offset=offset,
fields=fields, fields=fields,
@ -826,6 +836,12 @@ class Spotify:
- limit - the number of items to return - limit - the number of items to return
- offset - the index of the first item 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( return self._get(
f"users/{user}/playlists", limit=limit, offset=offset f"users/{user}/playlists", limit=limit, offset=offset
) )
@ -840,6 +856,12 @@ class Spotify:
- collaborative - is the created playlist collaborative - collaborative - is the created playlist collaborative
- description - the description of the playlist - 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 = { data = {
"name": name, "name": name,
"public": public, "public": public,
@ -849,6 +871,24 @@ class Spotify:
return self._post(f"users/{user}/playlists", payload=data) 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( def user_playlist_change_details(
self, self,
user, user,
@ -1171,7 +1211,7 @@ class Spotify:
plid = self._get_id("playlist", playlist_id) plid = self._get_id("playlist", playlist_id)
ftracks = [self._get_uri("track", tid) for tid in items] ftracks = [self._get_uri("track", tid) for tid in items]
return self._post( return self._post(
f"playlists/{plid}/tracks", f"playlists/{plid}/items",
payload=ftracks, payload=ftracks,
position=position, position=position,
) )
@ -1187,7 +1227,7 @@ class Spotify:
ftracks = [self._get_uri("track", tid) for tid in items] ftracks = [self._get_uri("track", tid) for tid in items]
payload = {"uris": ftracks} payload = {"uris": ftracks}
return self._put( return self._put(
f"playlists/{plid}/tracks", payload=payload f"playlists/{plid}/items", payload=payload
) )
def playlist_reorder_items( def playlist_reorder_items(
@ -1218,7 +1258,7 @@ class Spotify:
if snapshot_id: if snapshot_id:
payload["snapshot_id"] = snapshot_id payload["snapshot_id"] = snapshot_id
return self._put( return self._put(
f"playlists/{plid}/tracks", payload=payload f"playlists/{plid}/items", payload=payload
) )
def playlist_remove_all_occurrences_of_items( def playlist_remove_all_occurrences_of_items(
@ -1235,11 +1275,11 @@ class Spotify:
plid = self._get_id("playlist", playlist_id) plid = self._get_id("playlist", playlist_id)
ftracks = [self._get_uri("track", tid) for tid in items] 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: if snapshot_id:
payload["snapshot_id"] = snapshot_id payload["snapshot_id"] = snapshot_id
return self._delete( return self._delete(
f"playlists/{plid}/tracks", payload=payload f"playlists/{plid}/items", payload=payload
) )
def playlist_remove_specific_occurrences_of_items( def playlist_remove_specific_occurrences_of_items(
@ -1266,14 +1306,14 @@ class Spotify:
"positions": tr["positions"], "positions": tr["positions"],
} }
) )
payload = {"tracks": ftracks} payload = {"items": ftracks}
if snapshot_id: if snapshot_id:
payload["snapshot_id"] = snapshot_id payload["snapshot_id"] = snapshot_id
return self._delete( 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. Add the current authenticated user as a follower of a playlist.
@ -1281,10 +1321,7 @@ class Spotify:
- playlist_id - the id of the playlist - playlist_id - the id of the playlist
""" """
return self._put( return self._put("me/library", uris=self._get_uri("playlist", playlist_id))
f"playlists/{playlist_id}/followers",
payload={"public": public}
)
def playlist_is_following( def playlist_is_following(
self, playlist_id, user_ids self, playlist_id, user_ids
@ -1298,9 +1335,27 @@ class Spotify:
if they follow the playlist. Maximum: 5 ids. 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)}" endpoint = f"playlists/{playlist_id}/followers/contains?ids={','.join(user_ids)}"
return self._get(endpoint) 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): def me(self):
""" Get detailed profile information about the current user. """ Get detailed profile information about the current user.
An alias for the 'current_user' method. An alias for the 'current_user' method.
@ -1347,8 +1402,8 @@ class Spotify:
- albums - a list of album URIs, URLs or IDs - albums - a list of album URIs, URLs or IDs
""" """
alist = [self._get_id("album", a) for a in albums] alist = [self._get_uri("album", a) for a in albums]
return self._put("me/albums?ids=" + ",".join(alist)) return self._put("me/library", uris=",".join(alist))
def current_user_saved_albums_delete(self, albums=[]): def current_user_saved_albums_delete(self, albums=[]):
""" Remove one or more albums from the current user's """ Remove one or more albums from the current user's
@ -1357,8 +1412,8 @@ class Spotify:
Parameters: Parameters:
- albums - a list of album URIs, URLs or IDs - albums - a list of album URIs, URLs or IDs
""" """
alist = [self._get_id("album", a) for a in albums] alist = [self._get_uri("album", a) for a in albums]
return self._delete("me/albums/?ids=" + ",".join(alist)) return self._delete("me/library", uris=",".join(alist))
def current_user_saved_albums_contains(self, albums=[]): def current_user_saved_albums_contains(self, albums=[]):
""" Check if one or more albums is already saved in """ Check if one or more albums is already saved in
@ -1367,8 +1422,8 @@ class Spotify:
Parameters: Parameters:
- albums - a list of album URIs, URLs or IDs - albums - a list of album URIs, URLs or IDs
""" """
alist = [self._get_id("album", a) for a in albums] alist = [self._get_uri("album", a) for a in albums]
return self._get("me/albums/contains?ids=" + ",".join(alist)) return self._get("me/library/contains", uris=",".join(alist))
def current_user_saved_tracks(self, limit=20, offset=0, market=None): 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 """ Gets a list of the tracks saved in the current authorized user's
@ -1391,8 +1446,8 @@ class Spotify:
""" """
tlist = [] tlist = []
if tracks is not None: if tracks is not None:
tlist = [self._get_id("track", t) for t in tracks] tlist = [self._get_uri("track", t) for t in tracks]
return self._put("me/tracks/?ids=" + ",".join(tlist)) return self._put("me/library", uris=",".join(tlist))
def current_user_saved_tracks_delete(self, tracks=None): def current_user_saved_tracks_delete(self, tracks=None):
""" Remove one or more tracks from the current user's """ Remove one or more tracks from the current user's
@ -1403,8 +1458,8 @@ class Spotify:
""" """
tlist = [] tlist = []
if tracks is not None: if tracks is not None:
tlist = [self._get_id("track", t) for t in tracks] tlist = [self._get_uri("track", t) for t in tracks]
return self._delete("me/tracks/?ids=" + ",".join(tlist)) return self._delete("me/library", uris=",".join(tlist))
def current_user_saved_tracks_contains(self, tracks=None): def current_user_saved_tracks_contains(self, tracks=None):
""" Check if one or more tracks is already saved in """ Check if one or more tracks is already saved in
@ -1415,8 +1470,8 @@ class Spotify:
""" """
tlist = [] tlist = []
if tracks is not None: if tracks is not None:
tlist = [self._get_id("track", t) for t in tracks] tlist = [self._get_uri("track", t) for t in tracks]
return self._get("me/tracks/contains?ids=" + ",".join(tlist)) return self._get("me/library/contains", uris=",".join(tlist))
def current_user_saved_episodes(self, limit=20, offset=0, market=None): 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 """ Gets a list of the episodes saved in the current authorized user's
@ -1439,8 +1494,8 @@ class Spotify:
""" """
elist = [] elist = []
if episodes is not None: if episodes is not None:
elist = [self._get_id("episode", e) for e in episodes] elist = [self._get_uri("episode", e) for e in episodes]
return self._put("me/episodes/?ids=" + ",".join(elist)) return self._put("me/library", uris=",".join(elist))
def current_user_saved_episodes_delete(self, episodes=None): def current_user_saved_episodes_delete(self, episodes=None):
""" Remove one or more episodes from the current user's """ Remove one or more episodes from the current user's
@ -1451,8 +1506,8 @@ class Spotify:
""" """
elist = [] elist = []
if episodes is not None: if episodes is not None:
elist = [self._get_id("episode", e) for e in episodes] elist = [self._get_uri("episode", e) for e in episodes]
return self._delete("me/episodes/?ids=" + ",".join(elist)) return self._delete("me/library", uris=",".join(elist))
def current_user_saved_episodes_contains(self, episodes=None): def current_user_saved_episodes_contains(self, episodes=None):
""" Check if one or more episodes is already saved in """ Check if one or more episodes is already saved in
@ -1484,8 +1539,8 @@ class Spotify:
Parameters: Parameters:
- shows - a list of show URIs, URLs or IDs - shows - a list of show URIs, URLs or IDs
""" """
slist = [self._get_id("show", s) for s in shows] slist = [self._get_uri("show", s) for s in shows]
return self._put("me/shows?ids=" + ",".join(slist)) return self._put("me/library", uris=",".join(slist))
def current_user_saved_shows_delete(self, shows=[]): def current_user_saved_shows_delete(self, shows=[]):
""" Remove one or more shows from the current user's """ Remove one or more shows from the current user's
@ -1494,8 +1549,8 @@ class Spotify:
Parameters: Parameters:
- shows - a list of show URIs, URLs or IDs - shows - a list of show URIs, URLs or IDs
""" """
slist = [self._get_id("show", s) for s in shows] slist = [self._get_uri("show", s) for s in shows]
return self._delete("me/shows/?ids=" + ",".join(slist)) return self._delete("me/library", uris=",".join(slist))
def current_user_saved_shows_contains(self, shows=[]): def current_user_saved_shows_contains(self, shows=[]):
""" Check if one or more shows is already saved in """ Check if one or more shows is already saved in
@ -1504,8 +1559,8 @@ class Spotify:
Parameters: Parameters:
- shows - a list of show URIs, URLs or IDs - shows - a list of show URIs, URLs or IDs
""" """
slist = [self._get_id("show", s) for s in shows] slist = [self._get_uri("show", s) for s in shows]
return self._get("me/shows/contains?ids=" + ",".join(slist)) return self._get("me/library/contains", uris=",".join(slist))
def current_user_followed_artists(self, limit=20, after=None): def current_user_followed_artists(self, limit=20, after=None):
""" Gets a list of the artists followed by the current authorized user """ Gets a list of the artists followed by the current authorized user
@ -1528,11 +1583,11 @@ class Spotify:
Parameters: Parameters:
- ids - a list of artist URIs, URLs or IDs - ids - a list of artist URIs, URLs or IDs
""" """
idlist = [] ulist = []
if ids is not None: 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( 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): def current_user_following_users(self, ids=None):
@ -1543,11 +1598,11 @@ class Spotify:
Parameters: Parameters:
- ids - a list of user URIs, URLs or IDs - ids - a list of user URIs, URLs or IDs
""" """
idlist = [] ulist = []
if ids is not None: 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( return self._get(
"me/following/contains", ids=",".join(idlist), type="user" "me/library/contains", uris=",".join(ulist)
) )
def current_user_top_artists( def current_user_top_artists(
@ -1604,28 +1659,32 @@ class Spotify:
Parameters: Parameters:
- ids - a list of artist IDs - 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=[]): def user_follow_users(self, ids=[]):
""" Follow one or more users """ Follow one or more users
Parameters: Parameters:
- ids - a list of user IDs - 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=[]): def user_unfollow_artists(self, ids=[]):
""" Unfollow one or more artists """ Unfollow one or more artists
Parameters: Parameters:
- ids - a list of artist IDs - 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=[]): def user_unfollow_users(self, ids=[]):
""" Unfollow one or more users """ Unfollow one or more users
Parameters: Parameters:
- ids - a list of user IDs - 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( def featured_playlists(
self, locale=None, country=None, timestamp=None, limit=20, offset=0 self, locale=None, country=None, timestamp=None, limit=20, offset=0
@ -1681,6 +1740,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 `new_release(...)`, "
"which is marked as deprecated by Spotify.",
DeprecationWarning,
)
return self._get( return self._get(
"browse/new-releases", country=country, limit=limit, offset=offset "browse/new-releases", country=country, limit=limit, offset=offset
) )
@ -1696,6 +1760,11 @@ class Spotify:
language code and an ISO 3166-1 alpha-2 country code, joined language code and an ISO 3166-1 alpha-2 country code, joined
by an underscore. by an underscore.
""" """
warnings.warn(
"You're using `category(...)`, "
"which is marked as deprecated by Spotify.",
DeprecationWarning,
)
return self._get( return self._get(
"browse/categories/" + category_id, "browse/categories/" + category_id,
country=country, country=country,
@ -1718,6 +1787,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 `categories(...)`, "
"which is marked as deprecated by Spotify.",
DeprecationWarning,
)
return self._get( return self._get(
"browse/categories", "browse/categories",
country=country, country=country,

View File

@ -8,6 +8,9 @@ commands=python -m unittest discover -v tests/unit
max-line-length = 99 max-line-length = 99
exclude= exclude=
.git, .git,
.venv,
build,
dist, dist,
docs, docs,
examples examples,
spotipy.egg-info