mirror of
https://github.com/spotipy-dev/spotipy.git
synced 2026-06-19 01:03:53 +00:00
style: use pipe notation, change minimum version to 3.10
This commit is contained in:
parent
c99eea0cb0
commit
94b6305919
2
.github/workflows/integration_tests.yml
vendored
2
.github/workflows/integration_tests.yml
vendored
@ -10,7 +10,7 @@ jobs:
|
|||||||
SPOTIPY_CLIENT_SECRET: ${{ secrets.SPOTIPY_CLIENT_SECRET }}
|
SPOTIPY_CLIENT_SECRET: ${{ secrets.SPOTIPY_CLIENT_SECRET }}
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
|
python-version: ["3.10", "3.11", "3.12"]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Set up Python ${{ matrix.python-version }}
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
|
|||||||
2
.github/workflows/unit_tests.yml
vendored
2
.github/workflows/unit_tests.yml
vendored
@ -7,7 +7,7 @@ jobs:
|
|||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
|
python-version: ["3.10", "3.11", "3.12"]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Set up Python ${{ matrix.python-version }}
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
|
|||||||
2
setup.py
2
setup.py
@ -31,7 +31,7 @@ setup(
|
|||||||
project_urls={
|
project_urls={
|
||||||
'Source': 'https://github.com/plamere/spotipy',
|
'Source': 'https://github.com/plamere/spotipy',
|
||||||
},
|
},
|
||||||
python_requires='>3.8',
|
python_requires='>=3.10',
|
||||||
install_requires=[
|
install_requires=[
|
||||||
"redis>=3.5.3", # TODO: Move to extras_require in v3
|
"redis>=3.5.3", # TODO: Move to extras_require in v3
|
||||||
"requests>=2.25.0",
|
"requests>=2.25.0",
|
||||||
|
|||||||
@ -12,7 +12,7 @@ import json
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
from json import JSONEncoder
|
from json import JSONEncoder
|
||||||
from typing import Dict, Optional
|
from typing import Dict
|
||||||
|
|
||||||
from redis import RedisError
|
from redis import RedisError
|
||||||
|
|
||||||
@ -53,9 +53,9 @@ class CacheFileHandler(CacheHandler):
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
cache_path: Optional[str] = None,
|
cache_path: str | None = None,
|
||||||
username: Optional[str] = None,
|
username: str | None = None,
|
||||||
encoder_cls: Optional[JSONEncoder] = None,
|
encoder_cls: JSONEncoder | None = None,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Parameters:
|
Parameters:
|
||||||
@ -113,7 +113,7 @@ class MemoryCacheHandler(CacheHandler):
|
|||||||
instance is freed.
|
instance is freed.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, token_info: Optional[Dict] = None):
|
def __init__(self, token_info: Dict | None = None):
|
||||||
"""
|
"""
|
||||||
Parameters:
|
Parameters:
|
||||||
* token_info: The token info to store in memory. Can be None.
|
* token_info: The token info to store in memory. Can be None.
|
||||||
@ -189,7 +189,7 @@ class RedisCacheHandler(CacheHandler):
|
|||||||
A cache handler that stores the token info in the Redis.
|
A cache handler that stores the token info in the Redis.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, redis, key: Optional[str] = None):
|
def __init__(self, redis, key: str | None = None):
|
||||||
"""
|
"""
|
||||||
Parameters:
|
Parameters:
|
||||||
* redis: Redis object provided by redis-py library
|
* redis: Redis object provided by redis-py library
|
||||||
@ -222,7 +222,7 @@ class MemcacheCacheHandler(CacheHandler):
|
|||||||
"""A Cache handler that stores the token info in Memcache using the pymemcache client
|
"""A Cache handler that stores the token info in Memcache using the pymemcache client
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, memcache, key: Optional[str] = None):
|
def __init__(self, memcache, key: str | None = None):
|
||||||
"""
|
"""
|
||||||
Parameters:
|
Parameters:
|
||||||
* memcache: memcache client object provided by pymemcache
|
* memcache: memcache client object provided by pymemcache
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import logging
|
|||||||
import re
|
import re
|
||||||
import warnings
|
import warnings
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from typing import Dict, List, Optional, TypedDict, Union
|
from typing import Dict, List, TypedDict, Union
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
@ -138,7 +138,7 @@ class Spotify:
|
|||||||
retries: int = max_retries,
|
retries: int = max_retries,
|
||||||
status_retries: int = max_retries,
|
status_retries: int = max_retries,
|
||||||
backoff_factor: float = 0.3,
|
backoff_factor: float = 0.3,
|
||||||
language: Optional[str] = None,
|
language: str | None = None,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Creates a Spotify API client.
|
Creates a Spotify API client.
|
||||||
@ -360,7 +360,7 @@ class Spotify:
|
|||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def track(self, track_id: str, market: Optional[str] = None):
|
def track(self, track_id: str, market: str | None = None):
|
||||||
""" returns a single track given the track's ID, URI or URL
|
""" returns a single track given the track's ID, URI or URL
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
@ -371,7 +371,7 @@ class Spotify:
|
|||||||
trid = self._get_id("track", track_id)
|
trid = self._get_id("track", track_id)
|
||||||
return self._get("tracks/" + trid, market=market)
|
return self._get("tracks/" + trid, market=market)
|
||||||
|
|
||||||
def tracks(self, tracks: StrListOrTuple, market: Optional[str] = None):
|
def tracks(self, tracks: StrListOrTuple, market: str | None = None):
|
||||||
""" returns a list of tracks given a list of track IDs, URIs, or URLs
|
""" returns a list of tracks given a list of track IDs, URIs, or URLs
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
@ -405,9 +405,9 @@ class Spotify:
|
|||||||
def artist_albums(
|
def artist_albums(
|
||||||
self,
|
self,
|
||||||
artist_id: str,
|
artist_id: str,
|
||||||
album_type: Optional[str] = None,
|
album_type: str | None = None,
|
||||||
include_groups: Optional[str] = None,
|
include_groups: str | None = None,
|
||||||
country: Optional[str] = None,
|
country: str | None = None,
|
||||||
limit: int = 20,
|
limit: int = 20,
|
||||||
offset: int = 0,
|
offset: int = 0,
|
||||||
):
|
):
|
||||||
@ -476,7 +476,7 @@ class Spotify:
|
|||||||
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")
|
||||||
|
|
||||||
def album(self, album_id: str, market: Optional[str] = None):
|
def album(self, album_id: str, market: str | None = None):
|
||||||
""" returns a single album given the album's ID, URIs or URL
|
""" returns a single album given the album's ID, URIs or URL
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
@ -495,7 +495,7 @@ class Spotify:
|
|||||||
album_id: str,
|
album_id: str,
|
||||||
limit: int = 50,
|
limit: int = 50,
|
||||||
offset: int = 0,
|
offset: int = 0,
|
||||||
market: Optional[str] = None,
|
market: str | None = None,
|
||||||
):
|
):
|
||||||
""" Get Spotify catalog information about an album's tracks
|
""" Get Spotify catalog information about an album's tracks
|
||||||
|
|
||||||
@ -512,7 +512,7 @@ class Spotify:
|
|||||||
"albums/" + trid + "/tracks/", limit=limit, offset=offset, market=market
|
"albums/" + trid + "/tracks/", limit=limit, offset=offset, market=market
|
||||||
)
|
)
|
||||||
|
|
||||||
def albums(self, albums: StrListOrTuple, market: Optional[str] = None):
|
def albums(self, albums: StrListOrTuple, market: str | None = None):
|
||||||
""" returns a list of albums given the album IDs, URIs, or URLs
|
""" returns a list of albums given the album IDs, URIs, or URLs
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
@ -526,7 +526,7 @@ class Spotify:
|
|||||||
else:
|
else:
|
||||||
return self._get("albums/?ids=" + ",".join(tlist))
|
return self._get("albums/?ids=" + ",".join(tlist))
|
||||||
|
|
||||||
def show(self, show_id: str, market: Optional[str] = None):
|
def show(self, show_id: str, market: str | None = None):
|
||||||
""" returns a single show given the show's ID, URIs or URL
|
""" returns a single show given the show's ID, URIs or URL
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
@ -541,7 +541,7 @@ class Spotify:
|
|||||||
trid = self._get_id("show", show_id)
|
trid = self._get_id("show", show_id)
|
||||||
return self._get("shows/" + trid, market=market)
|
return self._get("shows/" + trid, market=market)
|
||||||
|
|
||||||
def shows(self, shows: StrListOrTuple, market: Optional[str] = None):
|
def shows(self, shows: StrListOrTuple, market: str | None = None):
|
||||||
""" returns a list of shows given the show IDs, URIs, or URLs
|
""" returns a list of shows given the show IDs, URIs, or URLs
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
@ -561,7 +561,7 @@ class Spotify:
|
|||||||
show_id: str,
|
show_id: str,
|
||||||
limit: int = 50,
|
limit: int = 50,
|
||||||
offset: int = 0,
|
offset: int = 0,
|
||||||
market: Optional[str] = None,
|
market: str | None = None,
|
||||||
):
|
):
|
||||||
""" Get Spotify catalog information about a show's episodes
|
""" Get Spotify catalog information about a show's episodes
|
||||||
|
|
||||||
@ -581,7 +581,7 @@ class Spotify:
|
|||||||
"shows/" + trid + "/episodes/", limit=limit, offset=offset, market=market
|
"shows/" + trid + "/episodes/", limit=limit, offset=offset, market=market
|
||||||
)
|
)
|
||||||
|
|
||||||
def episode(self, episode_id: str, market: Optional[str] = None):
|
def episode(self, episode_id: str, market: str | None = None):
|
||||||
""" returns a single episode given the episode's ID, URIs or URL
|
""" returns a single episode given the episode's ID, URIs or URL
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
@ -596,7 +596,7 @@ class Spotify:
|
|||||||
trid = self._get_id("episode", episode_id)
|
trid = self._get_id("episode", episode_id)
|
||||||
return self._get("episodes/" + trid, market=market)
|
return self._get("episodes/" + trid, market=market)
|
||||||
|
|
||||||
def episodes(self, episodes: StrListOrTuple, market: Optional[str] = None):
|
def episodes(self, episodes: StrListOrTuple, market: str | None = None):
|
||||||
""" returns a list of episodes given the episode IDs, URIs, or URLs
|
""" returns a list of episodes given the episode IDs, URIs, or URLs
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
@ -617,7 +617,7 @@ class Spotify:
|
|||||||
limit: int = 10,
|
limit: int = 10,
|
||||||
offset: int = 0,
|
offset: int = 0,
|
||||||
type: str = "track",
|
type: str = "track",
|
||||||
market: Optional[str] = None,
|
market: str | None = None,
|
||||||
):
|
):
|
||||||
""" searches for an item
|
""" searches for an item
|
||||||
|
|
||||||
@ -643,8 +643,8 @@ class Spotify:
|
|||||||
limit: int = 10,
|
limit: int = 10,
|
||||||
offset: int = 0,
|
offset: int = 0,
|
||||||
type: str = "track",
|
type: str = "track",
|
||||||
markets: Optional[StrListOrTuple] = None,
|
markets: StrListOrTuple | None = None,
|
||||||
total: Optional[int] = None,
|
total: int | None = None,
|
||||||
):
|
):
|
||||||
""" (experimental) Searches multiple markets for an item
|
""" (experimental) Searches multiple markets for an item
|
||||||
|
|
||||||
@ -696,8 +696,8 @@ class Spotify:
|
|||||||
def playlist(
|
def playlist(
|
||||||
self,
|
self,
|
||||||
playlist_id: str,
|
playlist_id: str,
|
||||||
fields: Optional[str] = None,
|
fields: str | None = None,
|
||||||
market: Optional[str] = None,
|
market: str | None = None,
|
||||||
additional_types: StrListOrTuple = ("track",),
|
additional_types: StrListOrTuple = ("track",),
|
||||||
):
|
):
|
||||||
""" Gets playlist by id.
|
""" Gets playlist by id.
|
||||||
@ -721,10 +721,10 @@ class Spotify:
|
|||||||
def playlist_tracks(
|
def playlist_tracks(
|
||||||
self,
|
self,
|
||||||
playlist_id: str,
|
playlist_id: str,
|
||||||
fields: Optional[str] = None,
|
fields: str | None = None,
|
||||||
limit: int = 100,
|
limit: int = 100,
|
||||||
offset: int = 0,
|
offset: int = 0,
|
||||||
market: Optional[str] = None,
|
market: str | None = None,
|
||||||
additional_types: StrListOrTuple = ("track",)
|
additional_types: StrListOrTuple = ("track",)
|
||||||
):
|
):
|
||||||
""" Get full details of the tracks of a playlist.
|
""" Get full details of the tracks of a playlist.
|
||||||
@ -753,10 +753,10 @@ class Spotify:
|
|||||||
def playlist_items(
|
def playlist_items(
|
||||||
self,
|
self,
|
||||||
playlist_id: str,
|
playlist_id: str,
|
||||||
fields: Optional[str] = None,
|
fields: str | None = None,
|
||||||
limit: int = 100,
|
limit: int = 100,
|
||||||
offset: int = 0,
|
offset: int = 0,
|
||||||
market: Optional[str] = None,
|
market: str | None = None,
|
||||||
additional_types: StrListOrTuple = ("track", "episode")
|
additional_types: StrListOrTuple = ("track", "episode")
|
||||||
):
|
):
|
||||||
""" Get full details of the tracks and episodes of a playlist.
|
""" Get full details of the tracks and episodes of a playlist.
|
||||||
@ -807,9 +807,9 @@ class Spotify:
|
|||||||
def user_playlist(
|
def user_playlist(
|
||||||
self,
|
self,
|
||||||
user: str,
|
user: str,
|
||||||
playlist_id: Optional[str] = None,
|
playlist_id: str | None = None,
|
||||||
fields: Optional[str] = None,
|
fields: str | None = None,
|
||||||
market: Optional[str] = None,
|
market: str | None = None,
|
||||||
):
|
):
|
||||||
""" Gets a single playlist of a user
|
""" Gets a single playlist of a user
|
||||||
|
|
||||||
@ -833,12 +833,12 @@ class Spotify:
|
|||||||
|
|
||||||
def user_playlist_tracks(
|
def user_playlist_tracks(
|
||||||
self,
|
self,
|
||||||
user: Optional[str] = None,
|
user: str | None = None,
|
||||||
playlist_id: Optional[str] = None,
|
playlist_id: str | None = None,
|
||||||
fields: Optional[str] = None,
|
fields: str | None = None,
|
||||||
limit: int = 100,
|
limit: int = 100,
|
||||||
offset: int = 0,
|
offset: int = 0,
|
||||||
market: Optional[str] = None,
|
market: str | None = None,
|
||||||
):
|
):
|
||||||
""" Get full details of the tracks of a playlist owned by a user.
|
""" Get full details of the tracks of a playlist owned by a user.
|
||||||
|
|
||||||
@ -908,10 +908,10 @@ class Spotify:
|
|||||||
self,
|
self,
|
||||||
user: str,
|
user: str,
|
||||||
playlist_id: str,
|
playlist_id: str,
|
||||||
name: Optional[str] = None,
|
name: str | None = None,
|
||||||
public: Optional[bool] = None,
|
public: bool | None = None,
|
||||||
collaborative: Optional[bool] = None,
|
collaborative: bool | None = None,
|
||||||
description: Optional[str] = None,
|
description: str | None = None,
|
||||||
):
|
):
|
||||||
""" This function is no longer in use, please use the recommended function in the warning!
|
""" This function is no longer in use, please use the recommended function in the warning!
|
||||||
|
|
||||||
@ -961,7 +961,7 @@ class Spotify:
|
|||||||
user: str,
|
user: str,
|
||||||
playlist_id: str,
|
playlist_id: str,
|
||||||
tracks: StrListOrTuple,
|
tracks: StrListOrTuple,
|
||||||
position: Optional[int] = None,
|
position: int | None = None,
|
||||||
):
|
):
|
||||||
""" This function is no longer in use, please use the recommended function in the warning!
|
""" This function is no longer in use, please use the recommended function in the warning!
|
||||||
|
|
||||||
@ -990,7 +990,7 @@ class Spotify:
|
|||||||
user: str,
|
user: str,
|
||||||
playlist_id: str,
|
playlist_id: str,
|
||||||
episodes: StrListOrTuple,
|
episodes: StrListOrTuple,
|
||||||
position: Optional[int] = None,
|
position: int | None = None,
|
||||||
):
|
):
|
||||||
""" This function is no longer in use, please use the recommended function in the warning!
|
""" This function is no longer in use, please use the recommended function in the warning!
|
||||||
|
|
||||||
@ -1043,7 +1043,7 @@ class Spotify:
|
|||||||
range_start: int,
|
range_start: int,
|
||||||
insert_before: int,
|
insert_before: int,
|
||||||
range_length: int = 1,
|
range_length: int = 1,
|
||||||
snapshot_id: Optional[str] = None,
|
snapshot_id: str | None = None,
|
||||||
):
|
):
|
||||||
""" This function is no longer in use, please use the recommended function in the warning!
|
""" This function is no longer in use, please use the recommended function in the warning!
|
||||||
|
|
||||||
@ -1076,7 +1076,7 @@ class Spotify:
|
|||||||
user: str,
|
user: str,
|
||||||
playlist_id: str,
|
playlist_id: str,
|
||||||
tracks: StrListOrTuple,
|
tracks: StrListOrTuple,
|
||||||
snapshot_id: Optional[str] = None,
|
snapshot_id: str | None = None,
|
||||||
):
|
):
|
||||||
""" This function is no longer in use, please use the recommended function in the warning!
|
""" This function is no longer in use, please use the recommended function in the warning!
|
||||||
|
|
||||||
@ -1106,7 +1106,7 @@ class Spotify:
|
|||||||
user: str,
|
user: str,
|
||||||
playlist_id: str,
|
playlist_id: str,
|
||||||
tracks: List[TrackOccurances],
|
tracks: List[TrackOccurances],
|
||||||
snapshot_id: Optional[str] = None,
|
snapshot_id: str | None = None,
|
||||||
):
|
):
|
||||||
""" This function is no longer in use, please use the recommended function in the warning!
|
""" This function is no longer in use, please use the recommended function in the warning!
|
||||||
|
|
||||||
@ -1191,10 +1191,10 @@ class Spotify:
|
|||||||
def playlist_change_details(
|
def playlist_change_details(
|
||||||
self,
|
self,
|
||||||
playlist_id: str,
|
playlist_id: str,
|
||||||
name: Optional[str] = None,
|
name: str | None = None,
|
||||||
public: Optional[bool] = None,
|
public: bool | None = None,
|
||||||
collaborative: Optional[bool] = None,
|
collaborative: bool | None = None,
|
||||||
description: Optional[str] = None,
|
description: str | None = 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
|
collaborative state, and/or description
|
||||||
@ -1232,7 +1232,7 @@ class Spotify:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def playlist_add_items(
|
def playlist_add_items(
|
||||||
self, playlist_id: str, items: StrListOrTuple, position: Optional[int] = None
|
self, playlist_id: str, items: StrListOrTuple, position: int | None = None
|
||||||
):
|
):
|
||||||
""" Adds tracks/episodes to a playlist
|
""" Adds tracks/episodes to a playlist
|
||||||
|
|
||||||
@ -1269,7 +1269,7 @@ class Spotify:
|
|||||||
range_start: int,
|
range_start: int,
|
||||||
insert_before: int,
|
insert_before: int,
|
||||||
range_length: int = 1,
|
range_length: int = 1,
|
||||||
snapshot_id: Optional[str] = None,
|
snapshot_id: str | None = None,
|
||||||
):
|
):
|
||||||
""" Reorder tracks in a playlist
|
""" Reorder tracks in a playlist
|
||||||
|
|
||||||
@ -1295,7 +1295,7 @@ class Spotify:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def playlist_remove_all_occurrences_of_items(
|
def playlist_remove_all_occurrences_of_items(
|
||||||
self, playlist_id: str, items: StrListOrTuple, snapshot_id: Optional[str] = None
|
self, playlist_id: str, items: StrListOrTuple, snapshot_id: str | None = None
|
||||||
):
|
):
|
||||||
""" Removes all occurrences of the given tracks/episodes from the given playlist
|
""" Removes all occurrences of the given tracks/episodes from the given playlist
|
||||||
|
|
||||||
@ -1319,7 +1319,7 @@ class Spotify:
|
|||||||
self,
|
self,
|
||||||
playlist_id: str,
|
playlist_id: str,
|
||||||
items: List[TrackOccurances],
|
items: List[TrackOccurances],
|
||||||
snapshot_id: Optional[str] = None,
|
snapshot_id: str | None = None,
|
||||||
):
|
):
|
||||||
""" Removes all occurrences of the given tracks from the given playlist
|
""" Removes all occurrences of the given tracks from the given playlist
|
||||||
|
|
||||||
@ -1391,7 +1391,7 @@ class Spotify:
|
|||||||
|
|
||||||
def current_user_playing_track(
|
def current_user_playing_track(
|
||||||
self,
|
self,
|
||||||
market: Optional[str] = None,
|
market: str | None = None,
|
||||||
additional_types: StrListOrTuple = ("track",)
|
additional_types: StrListOrTuple = ("track",)
|
||||||
):
|
):
|
||||||
""" Get information about the current users currently playing track.
|
""" Get information about the current users currently playing track.
|
||||||
@ -1409,7 +1409,7 @@ class Spotify:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def current_user_saved_albums(
|
def current_user_saved_albums(
|
||||||
self, limit: int = 20, offset: int = 0, market: Optional[str] = None
|
self, limit: int = 20, offset: int = 0, market: str | None = None
|
||||||
):
|
):
|
||||||
""" Gets a list of the albums saved in the current authorized user's
|
""" Gets a list of the albums saved in the current authorized user's
|
||||||
"Your Music" library
|
"Your Music" library
|
||||||
@ -1453,7 +1453,7 @@ class Spotify:
|
|||||||
return self._get("me/albums/contains?ids=" + ",".join(alist))
|
return self._get("me/albums/contains?ids=" + ",".join(alist))
|
||||||
|
|
||||||
def current_user_saved_tracks(
|
def current_user_saved_tracks(
|
||||||
self, limit: int = 20, offset: int = 0, market: Optional[str] = None
|
self, limit: int = 20, offset: int = 0, market: str | None = 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
|
||||||
"Your Music" library
|
"Your Music" library
|
||||||
@ -1497,7 +1497,7 @@ class Spotify:
|
|||||||
return self._get("me/tracks/contains?ids=" + ",".join(tlist))
|
return self._get("me/tracks/contains?ids=" + ",".join(tlist))
|
||||||
|
|
||||||
def current_user_saved_episodes(
|
def current_user_saved_episodes(
|
||||||
self, limit: int = 20, offset: int = 0, market: Optional[str] = None
|
self, limit: int = 20, offset: int = 0, market: str | None = 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
|
||||||
"Your Music" library
|
"Your Music" library
|
||||||
@ -1541,7 +1541,7 @@ class Spotify:
|
|||||||
return self._get("me/episodes/contains?ids=" + ",".join(elist))
|
return self._get("me/episodes/contains?ids=" + ",".join(elist))
|
||||||
|
|
||||||
def current_user_saved_shows(
|
def current_user_saved_shows(
|
||||||
self, limit: int = 20, offset: int = 0, market: Optional[str] = None
|
self, limit: int = 20, offset: int = 0, market: str | None = None
|
||||||
):
|
):
|
||||||
""" Gets a list of the shows saved in the current authorized user's
|
""" Gets a list of the shows saved in the current authorized user's
|
||||||
"Your Music" library
|
"Your Music" library
|
||||||
@ -1584,7 +1584,7 @@ class Spotify:
|
|||||||
return self._get("me/shows/contains?ids=" + ",".join(slist))
|
return self._get("me/shows/contains?ids=" + ",".join(slist))
|
||||||
|
|
||||||
def current_user_followed_artists(
|
def current_user_followed_artists(
|
||||||
self, limit: int = 20, after: Optional[str] = None
|
self, limit: int = 20, after: str | None = 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
|
||||||
|
|
||||||
@ -1655,7 +1655,7 @@ class Spotify:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def current_user_recently_played(
|
def current_user_recently_played(
|
||||||
self, limit: int = 50, after: Optional[int] = None, before: Optional[int] = None
|
self, limit: int = 50, after: int | None = None, before: int | None = None
|
||||||
):
|
):
|
||||||
""" Get the current user's recently played tracks
|
""" Get the current user's recently played tracks
|
||||||
|
|
||||||
@ -1705,9 +1705,9 @@ class Spotify:
|
|||||||
|
|
||||||
def featured_playlists(
|
def featured_playlists(
|
||||||
self,
|
self,
|
||||||
locale: Optional[str] = None,
|
locale: str | None = None,
|
||||||
country: Optional[str] = None,
|
country: str | None = None,
|
||||||
timestamp: Optional[str] = None,
|
timestamp: str | None = None,
|
||||||
limit: int = 20,
|
limit: int = 20,
|
||||||
offset: int = 0,
|
offset: int = 0,
|
||||||
):
|
):
|
||||||
@ -1750,7 +1750,7 @@ class Spotify:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def new_releases(
|
def new_releases(
|
||||||
self, country: Optional[str] = None, limit: int = 20, offset: int = 0
|
self, country: str | None = None, limit: int = 20, offset: int = 0
|
||||||
):
|
):
|
||||||
""" Get a list of new album releases featured in Spotify
|
""" Get a list of new album releases featured in Spotify
|
||||||
|
|
||||||
@ -1771,8 +1771,8 @@ class Spotify:
|
|||||||
def category(
|
def category(
|
||||||
self,
|
self,
|
||||||
category_id: str,
|
category_id: str,
|
||||||
country: Optional[str] = None,
|
country: str | None = None,
|
||||||
locale: Optional[str] = None,
|
locale: str | None = None,
|
||||||
):
|
):
|
||||||
""" Get info about a category
|
""" Get info about a category
|
||||||
|
|
||||||
@ -1792,8 +1792,8 @@ class Spotify:
|
|||||||
|
|
||||||
def categories(
|
def categories(
|
||||||
self,
|
self,
|
||||||
country: Optional[str] = None,
|
country: str | None = None,
|
||||||
locale: Optional[str] = None,
|
locale: str | None = None,
|
||||||
limit: int = 20,
|
limit: int = 20,
|
||||||
offset: int = 0,
|
offset: int = 0,
|
||||||
):
|
):
|
||||||
@ -1822,8 +1822,8 @@ class Spotify:
|
|||||||
|
|
||||||
def category_playlists(
|
def category_playlists(
|
||||||
self,
|
self,
|
||||||
category_id: Optional[str] = None,
|
category_id: str | None = None,
|
||||||
country: Optional[str] = None,
|
country: str | None = None,
|
||||||
limit: int = 20,
|
limit: int = 20,
|
||||||
offset: int = 0,
|
offset: int = 0,
|
||||||
):
|
):
|
||||||
@ -1858,11 +1858,11 @@ class Spotify:
|
|||||||
|
|
||||||
def recommendations(
|
def recommendations(
|
||||||
self,
|
self,
|
||||||
seed_artists: Optional[StrListOrTuple] = None,
|
seed_artists: StrListOrTuple | None = None,
|
||||||
seed_genres: Optional[StrListOrTuple] = None,
|
seed_genres: StrListOrTuple | None = None,
|
||||||
seed_tracks: Optional[StrListOrTuple] = None,
|
seed_tracks: StrListOrTuple | None = None,
|
||||||
limit: int = 20,
|
limit: int = 20,
|
||||||
country: Optional[str] = None,
|
country: str | None = None,
|
||||||
**kwargs
|
**kwargs
|
||||||
):
|
):
|
||||||
""" Get a list of recommended tracks for one to five seeds.
|
""" Get a list of recommended tracks for one to five seeds.
|
||||||
@ -1995,7 +1995,7 @@ class Spotify:
|
|||||||
return self._get("me/player/devices")
|
return self._get("me/player/devices")
|
||||||
|
|
||||||
def current_playback(
|
def current_playback(
|
||||||
self, market: Optional[str] = None, additional_types: Optional[str] = None
|
self, market: str = None, additional_types: str | None = None
|
||||||
):
|
):
|
||||||
""" Get information about user's current playback.
|
""" Get information about user's current playback.
|
||||||
|
|
||||||
@ -2006,7 +2006,7 @@ class Spotify:
|
|||||||
return self._get("me/player", market=market, additional_types=additional_types)
|
return self._get("me/player", market=market, additional_types=additional_types)
|
||||||
|
|
||||||
def currently_playing(
|
def currently_playing(
|
||||||
self, market: Optional[str] = None, additional_types: Optional[str] = None
|
self, market: str | None = None, additional_types: str | None = None
|
||||||
):
|
):
|
||||||
""" Get user's currently playing track.
|
""" Get user's currently playing track.
|
||||||
|
|
||||||
@ -2037,11 +2037,11 @@ class Spotify:
|
|||||||
|
|
||||||
def start_playback(
|
def start_playback(
|
||||||
self,
|
self,
|
||||||
device_id: Optional[str] = None,
|
device_id: str | None = None,
|
||||||
context_uri: Optional[str] = None,
|
context_uri: str | None = None,
|
||||||
uris: Optional[List[str]] = None,
|
uris: List[str] | None = None,
|
||||||
offset: Optional[PlaybackOffset] = None,
|
offset: PlaybackOffset | None = None,
|
||||||
position_ms: Optional[Union[int, float]] = None,
|
position_ms: Union[int, float] | None = None,
|
||||||
):
|
):
|
||||||
""" Start or resume user's playback.
|
""" Start or resume user's playback.
|
||||||
|
|
||||||
@ -2083,7 +2083,7 @@ class Spotify:
|
|||||||
self._append_device_id("me/player/play", device_id), payload=data
|
self._append_device_id("me/player/play", device_id), payload=data
|
||||||
)
|
)
|
||||||
|
|
||||||
def pause_playback(self, device_id: Optional[str] = None):
|
def pause_playback(self, device_id: str | None = None):
|
||||||
""" Pause user's playback.
|
""" Pause user's playback.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
@ -2091,7 +2091,7 @@ class Spotify:
|
|||||||
"""
|
"""
|
||||||
return self._put(self._append_device_id("me/player/pause", device_id))
|
return self._put(self._append_device_id("me/player/pause", device_id))
|
||||||
|
|
||||||
def next_track(self, device_id: Optional[str] = None):
|
def next_track(self, device_id: str | None = None):
|
||||||
""" Skip user's playback to next track.
|
""" Skip user's playback to next track.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
@ -2099,7 +2099,7 @@ class Spotify:
|
|||||||
"""
|
"""
|
||||||
return self._post(self._append_device_id("me/player/next", device_id))
|
return self._post(self._append_device_id("me/player/next", device_id))
|
||||||
|
|
||||||
def previous_track(self, device_id: Optional[str] = None):
|
def previous_track(self, device_id: str | None = None):
|
||||||
""" Skip user's playback to previous track.
|
""" Skip user's playback to previous track.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
@ -2110,7 +2110,7 @@ class Spotify:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def seek_track(
|
def seek_track(
|
||||||
self, position_ms: Union[int, float], device_id: Optional[str] = None
|
self, position_ms: Union[int, float], device_id: str | None = None
|
||||||
):
|
):
|
||||||
""" Seek to position in current track.
|
""" Seek to position in current track.
|
||||||
|
|
||||||
@ -2127,7 +2127,7 @@ class Spotify:
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
def repeat(self, state: str, device_id: Optional[str] = None):
|
def repeat(self, state: str, device_id: str | None = None):
|
||||||
""" Set repeat mode for playback.
|
""" Set repeat mode for playback.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
@ -2143,7 +2143,7 @@ class Spotify:
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
def volume(self, volume_percent: int, device_id: Optional[str] = None):
|
def volume(self, volume_percent: int, device_id: str | None = None):
|
||||||
""" Set playback volume.
|
""" Set playback volume.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
@ -2163,7 +2163,7 @@ class Spotify:
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
def shuffle(self, state: bool, device_id: Optional[str] = None):
|
def shuffle(self, state: bool, device_id: str | None = None):
|
||||||
""" Toggle playback shuffling.
|
""" Toggle playback shuffling.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
@ -2184,7 +2184,7 @@ class Spotify:
|
|||||||
""" Gets the current user's queue """
|
""" Gets the current user's queue """
|
||||||
return self._get("me/player/queue")
|
return self._get("me/player/queue")
|
||||||
|
|
||||||
def add_to_queue(self, uri: str, device_id: Optional[str] = None):
|
def add_to_queue(self, uri: str, device_id: str | None = None):
|
||||||
""" Adds a song to the end of a user's queue
|
""" Adds a song to the end of a user's queue
|
||||||
|
|
||||||
If device A is currently playing music, and you try to add to the queue
|
If device A is currently playing music, and you try to add to the queue
|
||||||
@ -2215,7 +2215,7 @@ class Spotify:
|
|||||||
"""
|
"""
|
||||||
return self._get("markets")
|
return self._get("markets")
|
||||||
|
|
||||||
def _append_device_id(self, path: str, device_id: Optional[str]) -> str:
|
def _append_device_id(self, path: str, device_id: str | None) -> str:
|
||||||
""" Append device ID to API path.
|
""" Append device ID to API path.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
@ -2271,7 +2271,7 @@ class Spotify:
|
|||||||
offset: int,
|
offset: int,
|
||||||
type: str,
|
type: str,
|
||||||
markets: StrListOrTuple,
|
markets: StrListOrTuple,
|
||||||
total: Optional[int],
|
total: int | None,
|
||||||
):
|
):
|
||||||
if total and limit > total:
|
if total and limit > total:
|
||||||
limit = total
|
limit = total
|
||||||
@ -2306,7 +2306,7 @@ class Spotify:
|
|||||||
|
|
||||||
return results
|
return results
|
||||||
|
|
||||||
def get_audiobook(self, id: str, market: Optional[str] = None):
|
def get_audiobook(self, id: str, market: str | None = None):
|
||||||
""" Get Spotify catalog information for a single audiobook identified by its unique
|
""" Get Spotify catalog information for a single audiobook identified by its unique
|
||||||
Spotify ID.
|
Spotify ID.
|
||||||
|
|
||||||
@ -2322,7 +2322,7 @@ class Spotify:
|
|||||||
|
|
||||||
return self._get(endpoint)
|
return self._get(endpoint)
|
||||||
|
|
||||||
def get_audiobooks(self, ids: StrListOrTuple, market: Optional[str] = None):
|
def get_audiobooks(self, ids: StrListOrTuple, market: str | None = None):
|
||||||
""" Get Spotify catalog information for multiple audiobooks based on their Spotify IDs.
|
""" Get Spotify catalog information for multiple audiobooks based on their Spotify IDs.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
@ -2338,7 +2338,7 @@ class Spotify:
|
|||||||
return self._get(endpoint)
|
return self._get(endpoint)
|
||||||
|
|
||||||
def get_audiobook_chapters(
|
def get_audiobook_chapters(
|
||||||
self, id: str, market: Optional[str] = None, limit: int = 20, offset: int = 0
|
self, id: str, market: str | None = None, limit: int = 20, offset: int = 0
|
||||||
):
|
):
|
||||||
""" Get Spotify catalog information about an audiobook’s chapters.
|
""" Get Spotify catalog information about an audiobook’s chapters.
|
||||||
|
|
||||||
|
|||||||
@ -16,7 +16,7 @@ import urllib.parse as urllibparse
|
|||||||
import warnings
|
import warnings
|
||||||
import webbrowser
|
import webbrowser
|
||||||
from http.server import BaseHTTPRequestHandler, HTTPServer
|
from http.server import BaseHTTPRequestHandler, HTTPServer
|
||||||
from typing import Any, Dict, Optional, Union
|
from typing import Any, Dict, Union
|
||||||
from urllib.parse import parse_qsl, urlparse
|
from urllib.parse import parse_qsl, urlparse
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
@ -38,7 +38,7 @@ def _make_authorization_headers(client_id: str, client_secret: str):
|
|||||||
return {"Authorization": f"Basic {auth_header.decode('ascii')}"}
|
return {"Authorization": f"Basic {auth_header.decode('ascii')}"}
|
||||||
|
|
||||||
|
|
||||||
def _ensure_value(value: Optional[str], env_key: str) -> str:
|
def _ensure_value(value: str | None, env_key: str) -> str:
|
||||||
env_val = CLIENT_CREDS_ENV_VARS[env_key]
|
env_val = CLIENT_CREDS_ENV_VARS[env_key]
|
||||||
_val = value or os.getenv(env_val)
|
_val = value or os.getenv(env_val)
|
||||||
if _val is None:
|
if _val is None:
|
||||||
@ -48,7 +48,7 @@ def _ensure_value(value: Optional[str], env_key: str) -> str:
|
|||||||
|
|
||||||
|
|
||||||
class SpotifyAuthBase:
|
class SpotifyAuthBase:
|
||||||
def __init__(self, requests_session: Optional[Union[requests.Session, bool]] = None):
|
def __init__(self, requests_session: Union[requests.Session, bool] | None = None):
|
||||||
if isinstance(requests_session, requests.Session):
|
if isinstance(requests_session, requests.Session):
|
||||||
self._session = requests_session
|
self._session = requests_session
|
||||||
else:
|
else:
|
||||||
@ -58,7 +58,7 @@ class SpotifyAuthBase:
|
|||||||
from requests import api
|
from requests import api
|
||||||
self._session = api
|
self._session = api
|
||||||
|
|
||||||
def _normalize_scope(self, scope: Optional[ScopeArgType]):
|
def _normalize_scope(self, scope: ScopeArgType | None):
|
||||||
return normalize_scope(scope)
|
return normalize_scope(scope)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -66,7 +66,7 @@ class SpotifyAuthBase:
|
|||||||
return self._client_id
|
return self._client_id
|
||||||
|
|
||||||
@client_id.setter
|
@client_id.setter
|
||||||
def client_id(self, val: Optional[str]):
|
def client_id(self, val: str | None):
|
||||||
self._client_id = _ensure_value(val, "client_id")
|
self._client_id = _ensure_value(val, "client_id")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -74,7 +74,7 @@ class SpotifyAuthBase:
|
|||||||
return self._client_secret
|
return self._client_secret
|
||||||
|
|
||||||
@client_secret.setter
|
@client_secret.setter
|
||||||
def client_secret(self, val: Optional[str]):
|
def client_secret(self, val: str | None):
|
||||||
self._client_secret = _ensure_value(val, "client_secret")
|
self._client_secret = _ensure_value(val, "client_secret")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -82,7 +82,7 @@ class SpotifyAuthBase:
|
|||||||
return self._redirect_uri
|
return self._redirect_uri
|
||||||
|
|
||||||
@redirect_uri.setter
|
@redirect_uri.setter
|
||||||
def redirect_uri(self, val: Optional[str]):
|
def redirect_uri(self, val: str | None):
|
||||||
self._redirect_uri = _ensure_value(val, "redirect_uri")
|
self._redirect_uri = _ensure_value(val, "redirect_uri")
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -99,7 +99,7 @@ class SpotifyAuthBase:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _is_scope_subset(
|
def _is_scope_subset(
|
||||||
needle_scope: Optional[str], haystack_scope: Optional[str]
|
needle_scope: str | None, haystack_scope: str | None
|
||||||
) -> bool:
|
) -> bool:
|
||||||
needle_scope = set(needle_scope.split()) if needle_scope else set()
|
needle_scope = set(needle_scope.split()) if needle_scope else set()
|
||||||
haystack_scope = set(haystack_scope.split()) if haystack_scope else set()
|
haystack_scope = set(haystack_scope.split()) if haystack_scope else set()
|
||||||
@ -136,12 +136,12 @@ class SpotifyClientCredentials(SpotifyAuthBase):
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
client_id: Optional[str] = None,
|
client_id: str | None = None,
|
||||||
client_secret: Optional[str] = None,
|
client_secret: str | None = None,
|
||||||
proxies: Optional[Any] = None,
|
proxies: Any | None = None,
|
||||||
requests_session: Union[requests.Session, bool] = True,
|
requests_session: Union[requests.Session, bool] = True,
|
||||||
requests_timeout: Optional[int] = None,
|
requests_timeout: int | None = None,
|
||||||
cache_handler: Optional[CacheHandler] = None,
|
cache_handler: CacheHandler | None = None,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Creates a Client Credentials Flow Manager.
|
Creates a Client Credentials Flow Manager.
|
||||||
@ -259,19 +259,19 @@ class SpotifyOAuth(SpotifyAuthBase):
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
client_id: Optional[str] = None,
|
client_id: str | None = None,
|
||||||
client_secret: Optional[str] = None,
|
client_secret: str | None = None,
|
||||||
redirect_uri: Optional[str] = None,
|
redirect_uri: str | None = None,
|
||||||
state: Optional[Any] = None,
|
state: Any | None = None,
|
||||||
scope: Optional[ScopeArgType] = None,
|
scope: ScopeArgType | None = None,
|
||||||
cache_path: Optional[str] = None,
|
cache_path: str | None = None,
|
||||||
username: Optional[str] = None,
|
username: str | None = None,
|
||||||
proxies: Optional[Any] = None,
|
proxies: Any | None = None,
|
||||||
show_dialog: bool = False,
|
show_dialog: bool = False,
|
||||||
requests_session: Union[requests.Session, bool] = True,
|
requests_session: Union[requests.Session, bool] = True,
|
||||||
requests_timeout: Optional[int] = None,
|
requests_timeout: int | None = None,
|
||||||
open_browser: bool = True,
|
open_browser: bool = True,
|
||||||
cache_handler: Optional[CacheHandler] = None,
|
cache_handler: CacheHandler | None = None,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Creates a SpotifyOAuth object
|
Creates a SpotifyOAuth object
|
||||||
@ -339,7 +339,7 @@ class SpotifyOAuth(SpotifyAuthBase):
|
|||||||
self.show_dialog = show_dialog
|
self.show_dialog = show_dialog
|
||||||
self.open_browser = open_browser
|
self.open_browser = open_browser
|
||||||
|
|
||||||
def validate_token(self, token_info: Optional[Dict]):
|
def validate_token(self, token_info: Dict | None):
|
||||||
if token_info is None:
|
if token_info is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@ -356,7 +356,7 @@ class SpotifyOAuth(SpotifyAuthBase):
|
|||||||
|
|
||||||
return token_info
|
return token_info
|
||||||
|
|
||||||
def get_authorize_url(self, state: Optional[Any] = None) -> str:
|
def get_authorize_url(self, state: Any | None = None) -> str:
|
||||||
""" Gets the URL to use to authorize this app
|
""" Gets the URL to use to authorize this app
|
||||||
"""
|
"""
|
||||||
payload = {
|
payload = {
|
||||||
@ -439,7 +439,7 @@ class SpotifyOAuth(SpotifyAuthBase):
|
|||||||
else:
|
else:
|
||||||
raise SpotifyOauthError("Server listening on localhost has not been accessed")
|
raise SpotifyOauthError("Server listening on localhost has not been accessed")
|
||||||
|
|
||||||
def get_auth_response(self, open_browser: Optional[bool] = None):
|
def get_auth_response(self, open_browser: bool | None = None):
|
||||||
logger.info('User authentication requires interaction with your '
|
logger.info('User authentication requires interaction with your '
|
||||||
'web browser. Once you enter your credentials and '
|
'web browser. Once you enter your credentials and '
|
||||||
'give authorization, you will be redirected to '
|
'give authorization, you will be redirected to '
|
||||||
@ -480,13 +480,13 @@ class SpotifyOAuth(SpotifyAuthBase):
|
|||||||
|
|
||||||
return self._get_auth_response_interactive(open_browser=open_browser)
|
return self._get_auth_response_interactive(open_browser=open_browser)
|
||||||
|
|
||||||
def get_authorization_code(self, response: Optional[Any] = None):
|
def get_authorization_code(self, response: Any | None = None):
|
||||||
if response:
|
if response:
|
||||||
return self.parse_response_code(response)
|
return self.parse_response_code(response)
|
||||||
return self.get_auth_response()
|
return self.get_auth_response()
|
||||||
|
|
||||||
def get_access_token(
|
def get_access_token(
|
||||||
self, code: Optional[str] = None, as_dict: bool = True, check_cache: bool = True
|
self, code: str | None = None, as_dict: bool = True, check_cache: bool = True
|
||||||
):
|
):
|
||||||
""" Gets the access token for the app given the code
|
""" Gets the access token for the app given the code
|
||||||
|
|
||||||
@ -627,17 +627,17 @@ class SpotifyPKCE(SpotifyAuthBase):
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
client_id: Optional[str] = None,
|
client_id: str | None = None,
|
||||||
redirect_uri: Optional[str] = None,
|
redirect_uri: str | None = None,
|
||||||
state: Optional[Any] = None,
|
state: Any | None = None,
|
||||||
scope: Optional[ScopeArgType] = None,
|
scope: ScopeArgType | None = None,
|
||||||
cache_path: Optional[str] = None,
|
cache_path: str | None = None,
|
||||||
username: Optional[str] = None,
|
username: str | None = None,
|
||||||
proxies: Optional[Any] = None,
|
proxies: Any | None = None,
|
||||||
requests_timeout: Optional[int] = None,
|
requests_timeout: int | None = None,
|
||||||
requests_session: Union[requests.Session, bool] = True,
|
requests_session: Union[requests.Session, bool] = True,
|
||||||
open_browser: bool = True,
|
open_browser: bool = True,
|
||||||
cache_handler: Optional[CacheHandler] = None,
|
cache_handler: CacheHandler | None = None,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Creates Auth Manager with the PKCE Auth flow.
|
Creates Auth Manager with the PKCE Auth flow.
|
||||||
@ -728,7 +728,7 @@ class SpotifyPKCE(SpotifyAuthBase):
|
|||||||
code_challenge = base64.urlsafe_b64encode(code_challenge_digest).decode('utf-8')
|
code_challenge = base64.urlsafe_b64encode(code_challenge_digest).decode('utf-8')
|
||||||
return code_challenge.replace('=', '')
|
return code_challenge.replace('=', '')
|
||||||
|
|
||||||
def get_authorize_url(self, state: Optional[Any] = None) -> str:
|
def get_authorize_url(self, state: Any | None = None) -> str:
|
||||||
""" Gets the URL to use to authorize this app """
|
""" Gets the URL to use to authorize this app """
|
||||||
if not self.code_challenge:
|
if not self.code_challenge:
|
||||||
self.get_pkce_handshake_parameters()
|
self.get_pkce_handshake_parameters()
|
||||||
@ -748,7 +748,7 @@ class SpotifyPKCE(SpotifyAuthBase):
|
|||||||
urlparams = urllibparse.urlencode(payload)
|
urlparams = urllibparse.urlencode(payload)
|
||||||
return f"{self.OAUTH_AUTHORIZE_URL}?{urlparams}"
|
return f"{self.OAUTH_AUTHORIZE_URL}?{urlparams}"
|
||||||
|
|
||||||
def _open_auth_url(self, state: Optional[Any] = None):
|
def _open_auth_url(self, state: Any | None = None):
|
||||||
auth_url = self.get_authorize_url(state)
|
auth_url = self.get_authorize_url(state)
|
||||||
try:
|
try:
|
||||||
webbrowser.open(auth_url)
|
webbrowser.open(auth_url)
|
||||||
@ -756,7 +756,7 @@ class SpotifyPKCE(SpotifyAuthBase):
|
|||||||
except webbrowser.Error:
|
except webbrowser.Error:
|
||||||
logger.error(f"Please navigate here: {auth_url}")
|
logger.error(f"Please navigate here: {auth_url}")
|
||||||
|
|
||||||
def _get_auth_response(self, open_browser: Optional[bool] = None):
|
def _get_auth_response(self, open_browser: bool | None = None):
|
||||||
logger.info('User authentication requires interaction with your '
|
logger.info('User authentication requires interaction with your '
|
||||||
'web browser. Once you enter your credentials and '
|
'web browser. Once you enter your credentials and '
|
||||||
'give authorization, you will be redirected to '
|
'give authorization, you will be redirected to '
|
||||||
@ -825,7 +825,7 @@ class SpotifyPKCE(SpotifyAuthBase):
|
|||||||
raise SpotifyStateError(self.state, state)
|
raise SpotifyStateError(self.state, state)
|
||||||
return code
|
return code
|
||||||
|
|
||||||
def get_authorization_code(self, response: Optional[Any] = None):
|
def get_authorization_code(self, response: Any | None = None):
|
||||||
if response:
|
if response:
|
||||||
return self.parse_response_code(response)
|
return self.parse_response_code(response)
|
||||||
return self._get_auth_response()
|
return self._get_auth_response()
|
||||||
@ -859,7 +859,7 @@ class SpotifyPKCE(SpotifyAuthBase):
|
|||||||
self.code_verifier = self._get_code_verifier()
|
self.code_verifier = self._get_code_verifier()
|
||||||
self.code_challenge = self._get_code_challenge()
|
self.code_challenge = self._get_code_challenge()
|
||||||
|
|
||||||
def get_access_token(self, code: Optional[Any] = None, check_cache: bool = True):
|
def get_access_token(self, code: Any | None = None, check_cache: bool = True):
|
||||||
""" Gets the access token for the app
|
""" Gets the access token for the app
|
||||||
|
|
||||||
If the code is not given and no cached token is used, an
|
If the code is not given and no cached token is used, an
|
||||||
@ -1018,14 +1018,14 @@ class SpotifyImplicitGrant(SpotifyAuthBase):
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
client_id: Optional[str] = None,
|
client_id: str | None = None,
|
||||||
redirect_uri: Optional[str] = None,
|
redirect_uri: str | None = None,
|
||||||
state: Optional[Any] = None,
|
state: Any | None = None,
|
||||||
scope: Optional[ScopeArgType] = None,
|
scope: ScopeArgType | None = None,
|
||||||
cache_path: Optional[str] = None,
|
cache_path: str | None = None,
|
||||||
username: Optional[str] = None,
|
username: str | None = None,
|
||||||
show_dialog: bool = False,
|
show_dialog: bool = False,
|
||||||
cache_handler: Optional[CacheHandler] = None,
|
cache_handler: CacheHandler | None = None,
|
||||||
):
|
):
|
||||||
""" Creates Auth Manager using the Implicit Grant flow
|
""" Creates Auth Manager using the Implicit Grant flow
|
||||||
|
|
||||||
@ -1087,7 +1087,7 @@ class SpotifyImplicitGrant(SpotifyAuthBase):
|
|||||||
self.show_dialog = show_dialog
|
self.show_dialog = show_dialog
|
||||||
self._session = None # As to not break inherited __del__
|
self._session = None # As to not break inherited __del__
|
||||||
|
|
||||||
def validate_token(self, token_info: Optional[Dict]):
|
def validate_token(self, token_info: Dict | None):
|
||||||
if token_info is None:
|
if token_info is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@ -1104,8 +1104,8 @@ class SpotifyImplicitGrant(SpotifyAuthBase):
|
|||||||
|
|
||||||
def get_access_token(
|
def get_access_token(
|
||||||
self,
|
self,
|
||||||
state: Optional[Any] = None,
|
state: Any | None = None,
|
||||||
response: Optional[Any] = None,
|
response: Any | None = None,
|
||||||
check_cache: bool = True,
|
check_cache: bool = True,
|
||||||
):
|
):
|
||||||
""" Gets Auth Token from cache (preferred) or user interaction
|
""" Gets Auth Token from cache (preferred) or user interaction
|
||||||
@ -1130,7 +1130,7 @@ class SpotifyImplicitGrant(SpotifyAuthBase):
|
|||||||
|
|
||||||
return token_info["access_token"]
|
return token_info["access_token"]
|
||||||
|
|
||||||
def get_authorize_url(self, state: Optional[Any] = None) -> str:
|
def get_authorize_url(self, state: Any | None = None) -> str:
|
||||||
""" Gets the URL to use to authorize this app """
|
""" Gets the URL to use to authorize this app """
|
||||||
payload = {
|
payload = {
|
||||||
"client_id": self.client_id,
|
"client_id": self.client_id,
|
||||||
@ -1150,7 +1150,7 @@ class SpotifyImplicitGrant(SpotifyAuthBase):
|
|||||||
|
|
||||||
return f"{self.OAUTH_AUTHORIZE_URL}?{urlparams}"
|
return f"{self.OAUTH_AUTHORIZE_URL}?{urlparams}"
|
||||||
|
|
||||||
def parse_response_token(self, url, state: Optional[Any] = None):
|
def parse_response_token(self, url, state: Any | None = None):
|
||||||
""" Parse the response code in the given response url """
|
""" Parse the response code in the given response url """
|
||||||
remote_state, token, t_type, exp_in = self.parse_auth_response_url(url)
|
remote_state, token, t_type, exp_in = self.parse_auth_response_url(url)
|
||||||
if state is None:
|
if state is None:
|
||||||
@ -1175,7 +1175,7 @@ class SpotifyImplicitGrant(SpotifyAuthBase):
|
|||||||
return tuple(form.get(param) for param in ["state", "access_token",
|
return tuple(form.get(param) for param in ["state", "access_token",
|
||||||
"token_type", "expires_in"])
|
"token_type", "expires_in"])
|
||||||
|
|
||||||
def _open_auth_url(self, state: Optional[Any] = None):
|
def _open_auth_url(self, state: Any | None = None):
|
||||||
auth_url = self.get_authorize_url(state)
|
auth_url = self.get_authorize_url(state)
|
||||||
try:
|
try:
|
||||||
webbrowser.open(auth_url)
|
webbrowser.open(auth_url)
|
||||||
@ -1183,7 +1183,7 @@ class SpotifyImplicitGrant(SpotifyAuthBase):
|
|||||||
except webbrowser.Error:
|
except webbrowser.Error:
|
||||||
logger.error(f"Please navigate here: {auth_url}")
|
logger.error(f"Please navigate here: {auth_url}")
|
||||||
|
|
||||||
def get_auth_response(self, state: Optional[Any] = None):
|
def get_auth_response(self, state: Any | None = None):
|
||||||
""" Gets a new auth **token** with user interaction """
|
""" Gets a new auth **token** with user interaction """
|
||||||
logger.info('User authentication requires interaction with your '
|
logger.info('User authentication requires interaction with your '
|
||||||
'web browser. Once you enter your credentials and '
|
'web browser. Once you enter your credentials and '
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import logging
|
|||||||
import os
|
import os
|
||||||
import warnings
|
import warnings
|
||||||
from types import TracebackType
|
from types import TracebackType
|
||||||
from typing import List, Optional, Tuple, Union
|
from typing import List, Tuple, Union
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
import urllib3
|
import urllib3
|
||||||
@ -31,15 +31,15 @@ StrListOrTuple = Union[List[str], Tuple[str, ...]]
|
|||||||
|
|
||||||
|
|
||||||
def prompt_for_user_token(
|
def prompt_for_user_token(
|
||||||
username: Optional[str] = None,
|
username: str | None = None,
|
||||||
scope: Optional[str] = None,
|
scope: str | None = None,
|
||||||
client_id: Optional[str] = None,
|
client_id: str | None = None,
|
||||||
client_secret: Optional[str] = None,
|
client_secret: str | None = None,
|
||||||
redirect_uri: Optional[str] = None,
|
redirect_uri: str | None = None,
|
||||||
cache_path: Optional[str] = None,
|
cache_path: str | None = None,
|
||||||
oauth_manager: Optional[spotipy.SpotifyOAuth] = None,
|
oauth_manager: spotipy.SpotifyOAuth | None = None,
|
||||||
show_dialog: bool = False,
|
show_dialog: bool = False,
|
||||||
) -> Union[str, None]:
|
) -> str | None:
|
||||||
""" Prompt the user to login if necessary and returns a user token
|
""" Prompt the user to login if necessary and returns a user token
|
||||||
suitable for use with the spotipy.Spotify constructor.
|
suitable for use with the spotipy.Spotify constructor.
|
||||||
|
|
||||||
@ -139,7 +139,7 @@ def get_host_port(netloc: str):
|
|||||||
ScopeArgType = Union[str, StrListOrTuple]
|
ScopeArgType = Union[str, StrListOrTuple]
|
||||||
|
|
||||||
|
|
||||||
def normalize_scope(scope: Optional[ScopeArgType]) -> Union[str, None]:
|
def normalize_scope(scope: ScopeArgType | None) -> str | None:
|
||||||
"""Normalize the scope to verify that it is a list or tuple. A string
|
"""Normalize the scope to verify that it is a list or tuple. A string
|
||||||
input will split the string by commas to create a list of scopes.
|
input will split the string by commas to create a list of scopes.
|
||||||
A list or tuple input is used directly.
|
A list or tuple input is used directly.
|
||||||
@ -170,12 +170,12 @@ class Retry(urllib3.Retry):
|
|||||||
|
|
||||||
def increment(
|
def increment(
|
||||||
self,
|
self,
|
||||||
method: Optional[str] = None,
|
method: str | None = None,
|
||||||
url: Optional[str] = None,
|
url: str | None = None,
|
||||||
response: Optional[urllib3.BaseHTTPResponse] = None,
|
response: urllib3.BaseHTTPResponse | None = None,
|
||||||
error: Optional[Exception] = None,
|
error: Exception | None = None,
|
||||||
_pool: Optional[urllib3.connectionpool.ConnectionPool] = None,
|
_pool: urllib3.connectionpool.ConnectionPool | None = None,
|
||||||
_stacktrace: Optional[TracebackType] = None,
|
_stacktrace: TracebackType | None = None,
|
||||||
) -> urllib3.Retry:
|
) -> urllib3.Retry:
|
||||||
if response:
|
if response:
|
||||||
retry_header = response.headers.get("Retry-After")
|
retry_header = response.headers.get("Retry-After")
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user