style: use pipe notation, change minimum version to 3.10

This commit is contained in:
bvandercar-vt 2026-01-23 11:06:52 -07:00
parent c99eea0cb0
commit 94b6305919
7 changed files with 171 additions and 171 deletions

View File

@ -10,7 +10,7 @@ jobs:
SPOTIPY_CLIENT_SECRET: ${{ secrets.SPOTIPY_CLIENT_SECRET }}
strategy:
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
python-version: ["3.10", "3.11", "3.12"]
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}

View File

@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-22.04
strategy:
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
python-version: ["3.10", "3.11", "3.12"]
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}

View File

@ -31,7 +31,7 @@ setup(
project_urls={
'Source': 'https://github.com/plamere/spotipy',
},
python_requires='>3.8',
python_requires='>=3.10',
install_requires=[
"redis>=3.5.3", # TODO: Move to extras_require in v3
"requests>=2.25.0",

View File

@ -12,7 +12,7 @@ import json
import logging
import os
from json import JSONEncoder
from typing import Dict, Optional
from typing import Dict
from redis import RedisError
@ -53,9 +53,9 @@ class CacheFileHandler(CacheHandler):
def __init__(
self,
cache_path: Optional[str] = None,
username: Optional[str] = None,
encoder_cls: Optional[JSONEncoder] = None,
cache_path: str | None = None,
username: str | None = None,
encoder_cls: JSONEncoder | None = None,
):
"""
Parameters:
@ -113,7 +113,7 @@ class MemoryCacheHandler(CacheHandler):
instance is freed.
"""
def __init__(self, token_info: Optional[Dict] = None):
def __init__(self, token_info: Dict | None = None):
"""
Parameters:
* 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.
"""
def __init__(self, redis, key: Optional[str] = None):
def __init__(self, redis, key: str | None = None):
"""
Parameters:
* 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
"""
def __init__(self, memcache, key: Optional[str] = None):
def __init__(self, memcache, key: str | None = None):
"""
Parameters:
* memcache: memcache client object provided by pymemcache

View File

@ -7,7 +7,7 @@ import logging
import re
import warnings
from collections import defaultdict
from typing import Dict, List, Optional, TypedDict, Union
from typing import Dict, List, TypedDict, Union
import requests
@ -138,7 +138,7 @@ class Spotify:
retries: int = max_retries,
status_retries: int = max_retries,
backoff_factor: float = 0.3,
language: Optional[str] = None,
language: str | None = None,
):
"""
Creates a Spotify API client.
@ -360,7 +360,7 @@ class Spotify:
else:
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
Parameters:
@ -371,7 +371,7 @@ class Spotify:
trid = self._get_id("track", track_id)
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
Parameters:
@ -405,9 +405,9 @@ class Spotify:
def artist_albums(
self,
artist_id: str,
album_type: Optional[str] = None,
include_groups: Optional[str] = None,
country: Optional[str] = None,
album_type: str | None = None,
include_groups: str | None = None,
country: str | None = None,
limit: int = 20,
offset: int = 0,
):
@ -476,7 +476,7 @@ class Spotify:
trid = self._get_id("artist", artist_id)
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
Parameters:
@ -495,7 +495,7 @@ class Spotify:
album_id: str,
limit: int = 50,
offset: int = 0,
market: Optional[str] = None,
market: str | None = None,
):
""" Get Spotify catalog information about an album's tracks
@ -512,7 +512,7 @@ class Spotify:
"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
Parameters:
@ -526,7 +526,7 @@ class Spotify:
else:
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
Parameters:
@ -541,7 +541,7 @@ class Spotify:
trid = self._get_id("show", show_id)
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
Parameters:
@ -561,7 +561,7 @@ class Spotify:
show_id: str,
limit: int = 50,
offset: int = 0,
market: Optional[str] = None,
market: str | None = None,
):
""" Get Spotify catalog information about a show's episodes
@ -581,7 +581,7 @@ class Spotify:
"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
Parameters:
@ -596,7 +596,7 @@ class Spotify:
trid = self._get_id("episode", episode_id)
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
Parameters:
@ -617,7 +617,7 @@ class Spotify:
limit: int = 10,
offset: int = 0,
type: str = "track",
market: Optional[str] = None,
market: str | None = None,
):
""" searches for an item
@ -643,8 +643,8 @@ class Spotify:
limit: int = 10,
offset: int = 0,
type: str = "track",
markets: Optional[StrListOrTuple] = None,
total: Optional[int] = None,
markets: StrListOrTuple | None = None,
total: int | None = None,
):
""" (experimental) Searches multiple markets for an item
@ -696,8 +696,8 @@ class Spotify:
def playlist(
self,
playlist_id: str,
fields: Optional[str] = None,
market: Optional[str] = None,
fields: str | None = None,
market: str | None = None,
additional_types: StrListOrTuple = ("track",),
):
""" Gets playlist by id.
@ -721,10 +721,10 @@ class Spotify:
def playlist_tracks(
self,
playlist_id: str,
fields: Optional[str] = None,
fields: str | None = None,
limit: int = 100,
offset: int = 0,
market: Optional[str] = None,
market: str | None = None,
additional_types: StrListOrTuple = ("track",)
):
""" Get full details of the tracks of a playlist.
@ -753,10 +753,10 @@ class Spotify:
def playlist_items(
self,
playlist_id: str,
fields: Optional[str] = None,
fields: str | None = None,
limit: int = 100,
offset: int = 0,
market: Optional[str] = None,
market: str | None = None,
additional_types: StrListOrTuple = ("track", "episode")
):
""" Get full details of the tracks and episodes of a playlist.
@ -807,9 +807,9 @@ class Spotify:
def user_playlist(
self,
user: str,
playlist_id: Optional[str] = None,
fields: Optional[str] = None,
market: Optional[str] = None,
playlist_id: str | None = None,
fields: str | None = None,
market: str | None = None,
):
""" Gets a single playlist of a user
@ -833,12 +833,12 @@ class Spotify:
def user_playlist_tracks(
self,
user: Optional[str] = None,
playlist_id: Optional[str] = None,
fields: Optional[str] = None,
user: str | None = None,
playlist_id: str | None = None,
fields: str | None = None,
limit: int = 100,
offset: int = 0,
market: Optional[str] = None,
market: str | None = None,
):
""" Get full details of the tracks of a playlist owned by a user.
@ -908,10 +908,10 @@ class Spotify:
self,
user: str,
playlist_id: str,
name: Optional[str] = None,
public: Optional[bool] = None,
collaborative: Optional[bool] = None,
description: Optional[str] = None,
name: str | None = None,
public: bool | None = None,
collaborative: bool | None = None,
description: str | None = None,
):
""" This function is no longer in use, please use the recommended function in the warning!
@ -961,7 +961,7 @@ class Spotify:
user: str,
playlist_id: str,
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!
@ -990,7 +990,7 @@ class Spotify:
user: str,
playlist_id: str,
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!
@ -1043,7 +1043,7 @@ class Spotify:
range_start: int,
insert_before: int,
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!
@ -1076,7 +1076,7 @@ class Spotify:
user: str,
playlist_id: str,
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!
@ -1106,7 +1106,7 @@ class Spotify:
user: str,
playlist_id: str,
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!
@ -1191,10 +1191,10 @@ class Spotify:
def playlist_change_details(
self,
playlist_id: str,
name: Optional[str] = None,
public: Optional[bool] = None,
collaborative: Optional[bool] = None,
description: Optional[str] = None,
name: str | None = None,
public: bool | None = None,
collaborative: bool | None = None,
description: str | None = None,
):
""" Changes a playlist's name and/or public/private state,
collaborative state, and/or description
@ -1232,7 +1232,7 @@ class Spotify:
)
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
@ -1269,7 +1269,7 @@ class Spotify:
range_start: int,
insert_before: int,
range_length: int = 1,
snapshot_id: Optional[str] = None,
snapshot_id: str | None = None,
):
""" Reorder tracks in a playlist
@ -1295,7 +1295,7 @@ class Spotify:
)
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
@ -1319,7 +1319,7 @@ class Spotify:
self,
playlist_id: str,
items: List[TrackOccurances],
snapshot_id: Optional[str] = None,
snapshot_id: str | None = None,
):
""" Removes all occurrences of the given tracks from the given playlist
@ -1391,7 +1391,7 @@ class Spotify:
def current_user_playing_track(
self,
market: Optional[str] = None,
market: str | None = None,
additional_types: StrListOrTuple = ("track",)
):
""" Get information about the current users currently playing track.
@ -1409,7 +1409,7 @@ class Spotify:
)
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
"Your Music" library
@ -1453,7 +1453,7 @@ class Spotify:
return self._get("me/albums/contains?ids=" + ",".join(alist))
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
"Your Music" library
@ -1497,7 +1497,7 @@ class Spotify:
return self._get("me/tracks/contains?ids=" + ",".join(tlist))
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
"Your Music" library
@ -1541,7 +1541,7 @@ class Spotify:
return self._get("me/episodes/contains?ids=" + ",".join(elist))
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
"Your Music" library
@ -1584,7 +1584,7 @@ class Spotify:
return self._get("me/shows/contains?ids=" + ",".join(slist))
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
@ -1655,7 +1655,7 @@ class Spotify:
)
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
@ -1705,9 +1705,9 @@ class Spotify:
def featured_playlists(
self,
locale: Optional[str] = None,
country: Optional[str] = None,
timestamp: Optional[str] = None,
locale: str | None = None,
country: str | None = None,
timestamp: str | None = None,
limit: int = 20,
offset: int = 0,
):
@ -1750,7 +1750,7 @@ class Spotify:
)
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
@ -1771,8 +1771,8 @@ class Spotify:
def category(
self,
category_id: str,
country: Optional[str] = None,
locale: Optional[str] = None,
country: str | None = None,
locale: str | None = None,
):
""" Get info about a category
@ -1792,8 +1792,8 @@ class Spotify:
def categories(
self,
country: Optional[str] = None,
locale: Optional[str] = None,
country: str | None = None,
locale: str | None = None,
limit: int = 20,
offset: int = 0,
):
@ -1822,8 +1822,8 @@ class Spotify:
def category_playlists(
self,
category_id: Optional[str] = None,
country: Optional[str] = None,
category_id: str | None = None,
country: str | None = None,
limit: int = 20,
offset: int = 0,
):
@ -1858,11 +1858,11 @@ class Spotify:
def recommendations(
self,
seed_artists: Optional[StrListOrTuple] = None,
seed_genres: Optional[StrListOrTuple] = None,
seed_tracks: Optional[StrListOrTuple] = None,
seed_artists: StrListOrTuple | None = None,
seed_genres: StrListOrTuple | None = None,
seed_tracks: StrListOrTuple | None = None,
limit: int = 20,
country: Optional[str] = None,
country: str | None = None,
**kwargs
):
""" Get a list of recommended tracks for one to five seeds.
@ -1995,7 +1995,7 @@ class Spotify:
return self._get("me/player/devices")
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.
@ -2006,7 +2006,7 @@ class Spotify:
return self._get("me/player", market=market, additional_types=additional_types)
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.
@ -2037,11 +2037,11 @@ class Spotify:
def start_playback(
self,
device_id: Optional[str] = None,
context_uri: Optional[str] = None,
uris: Optional[List[str]] = None,
offset: Optional[PlaybackOffset] = None,
position_ms: Optional[Union[int, float]] = None,
device_id: str | None = None,
context_uri: str | None = None,
uris: List[str] | None = None,
offset: PlaybackOffset | None = None,
position_ms: Union[int, float] | None = None,
):
""" Start or resume user's playback.
@ -2083,7 +2083,7 @@ class Spotify:
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.
Parameters:
@ -2091,7 +2091,7 @@ class Spotify:
"""
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.
Parameters:
@ -2099,7 +2099,7 @@ class Spotify:
"""
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.
Parameters:
@ -2110,7 +2110,7 @@ class Spotify:
)
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.
@ -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.
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.
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.
Parameters:
@ -2184,7 +2184,7 @@ class Spotify:
""" Gets the current user's 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
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")
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.
Parameters:
@ -2271,7 +2271,7 @@ class Spotify:
offset: int,
type: str,
markets: StrListOrTuple,
total: Optional[int],
total: int | None,
):
if total and limit > total:
limit = total
@ -2306,7 +2306,7 @@ class Spotify:
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
Spotify ID.
@ -2322,7 +2322,7 @@ class Spotify:
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.
Parameters:
@ -2338,7 +2338,7 @@ class Spotify:
return self._get(endpoint)
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 audiobooks chapters.

View File

@ -16,7 +16,7 @@ import urllib.parse as urllibparse
import warnings
import webbrowser
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
import requests
@ -38,7 +38,7 @@ def _make_authorization_headers(client_id: str, client_secret: str):
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]
_val = value or os.getenv(env_val)
if _val is None:
@ -48,7 +48,7 @@ def _ensure_value(value: Optional[str], env_key: str) -> str:
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):
self._session = requests_session
else:
@ -58,7 +58,7 @@ class SpotifyAuthBase:
from requests import api
self._session = api
def _normalize_scope(self, scope: Optional[ScopeArgType]):
def _normalize_scope(self, scope: ScopeArgType | None):
return normalize_scope(scope)
@property
@ -66,7 +66,7 @@ class SpotifyAuthBase:
return self._client_id
@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")
@property
@ -74,7 +74,7 @@ class SpotifyAuthBase:
return self._client_secret
@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")
@property
@ -82,7 +82,7 @@ class SpotifyAuthBase:
return self._redirect_uri
@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")
@staticmethod
@ -99,7 +99,7 @@ class SpotifyAuthBase:
@staticmethod
def _is_scope_subset(
needle_scope: Optional[str], haystack_scope: Optional[str]
needle_scope: str | None, haystack_scope: str | None
) -> bool:
needle_scope = set(needle_scope.split()) if needle_scope else set()
haystack_scope = set(haystack_scope.split()) if haystack_scope else set()
@ -136,12 +136,12 @@ class SpotifyClientCredentials(SpotifyAuthBase):
def __init__(
self,
client_id: Optional[str] = None,
client_secret: Optional[str] = None,
proxies: Optional[Any] = None,
client_id: str | None = None,
client_secret: str | None = None,
proxies: Any | None = None,
requests_session: Union[requests.Session, bool] = True,
requests_timeout: Optional[int] = None,
cache_handler: Optional[CacheHandler] = None,
requests_timeout: int | None = None,
cache_handler: CacheHandler | None = None,
):
"""
Creates a Client Credentials Flow Manager.
@ -259,19 +259,19 @@ class SpotifyOAuth(SpotifyAuthBase):
def __init__(
self,
client_id: Optional[str] = None,
client_secret: Optional[str] = None,
redirect_uri: Optional[str] = None,
state: Optional[Any] = None,
scope: Optional[ScopeArgType] = None,
cache_path: Optional[str] = None,
username: Optional[str] = None,
proxies: Optional[Any] = None,
client_id: str | None = None,
client_secret: str | None = None,
redirect_uri: str | None = None,
state: Any | None = None,
scope: ScopeArgType | None = None,
cache_path: str | None = None,
username: str | None = None,
proxies: Any | None = None,
show_dialog: bool = False,
requests_session: Union[requests.Session, bool] = True,
requests_timeout: Optional[int] = None,
requests_timeout: int | None = None,
open_browser: bool = True,
cache_handler: Optional[CacheHandler] = None,
cache_handler: CacheHandler | None = None,
):
"""
Creates a SpotifyOAuth object
@ -339,7 +339,7 @@ class SpotifyOAuth(SpotifyAuthBase):
self.show_dialog = show_dialog
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:
return None
@ -356,7 +356,7 @@ class SpotifyOAuth(SpotifyAuthBase):
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
"""
payload = {
@ -439,7 +439,7 @@ class SpotifyOAuth(SpotifyAuthBase):
else:
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 '
'web browser. Once you enter your credentials and '
'give authorization, you will be redirected to '
@ -480,13 +480,13 @@ class SpotifyOAuth(SpotifyAuthBase):
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:
return self.parse_response_code(response)
return self.get_auth_response()
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
@ -627,17 +627,17 @@ class SpotifyPKCE(SpotifyAuthBase):
def __init__(
self,
client_id: Optional[str] = None,
redirect_uri: Optional[str] = None,
state: Optional[Any] = None,
scope: Optional[ScopeArgType] = None,
cache_path: Optional[str] = None,
username: Optional[str] = None,
proxies: Optional[Any] = None,
requests_timeout: Optional[int] = None,
client_id: str | None = None,
redirect_uri: str | None = None,
state: Any | None = None,
scope: ScopeArgType | None = None,
cache_path: str | None = None,
username: str | None = None,
proxies: Any | None = None,
requests_timeout: int | None = None,
requests_session: Union[requests.Session, bool] = True,
open_browser: bool = True,
cache_handler: Optional[CacheHandler] = None,
cache_handler: CacheHandler | None = None,
):
"""
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')
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 """
if not self.code_challenge:
self.get_pkce_handshake_parameters()
@ -748,7 +748,7 @@ class SpotifyPKCE(SpotifyAuthBase):
urlparams = urllibparse.urlencode(payload)
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)
try:
webbrowser.open(auth_url)
@ -756,7 +756,7 @@ class SpotifyPKCE(SpotifyAuthBase):
except webbrowser.Error:
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 '
'web browser. Once you enter your credentials and '
'give authorization, you will be redirected to '
@ -825,7 +825,7 @@ class SpotifyPKCE(SpotifyAuthBase):
raise SpotifyStateError(self.state, state)
return code
def get_authorization_code(self, response: Optional[Any] = None):
def get_authorization_code(self, response: Any | None = None):
if response:
return self.parse_response_code(response)
return self._get_auth_response()
@ -859,7 +859,7 @@ class SpotifyPKCE(SpotifyAuthBase):
self.code_verifier = self._get_code_verifier()
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
If the code is not given and no cached token is used, an
@ -1018,14 +1018,14 @@ class SpotifyImplicitGrant(SpotifyAuthBase):
def __init__(
self,
client_id: Optional[str] = None,
redirect_uri: Optional[str] = None,
state: Optional[Any] = None,
scope: Optional[ScopeArgType] = None,
cache_path: Optional[str] = None,
username: Optional[str] = None,
client_id: str | None = None,
redirect_uri: str | None = None,
state: Any | None = None,
scope: ScopeArgType | None = None,
cache_path: str | None = None,
username: str | None = None,
show_dialog: bool = False,
cache_handler: Optional[CacheHandler] = None,
cache_handler: CacheHandler | None = None,
):
""" Creates Auth Manager using the Implicit Grant flow
@ -1087,7 +1087,7 @@ class SpotifyImplicitGrant(SpotifyAuthBase):
self.show_dialog = show_dialog
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:
return None
@ -1104,8 +1104,8 @@ class SpotifyImplicitGrant(SpotifyAuthBase):
def get_access_token(
self,
state: Optional[Any] = None,
response: Optional[Any] = None,
state: Any | None = None,
response: Any | None = None,
check_cache: bool = True,
):
""" Gets Auth Token from cache (preferred) or user interaction
@ -1130,7 +1130,7 @@ class SpotifyImplicitGrant(SpotifyAuthBase):
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 """
payload = {
"client_id": self.client_id,
@ -1150,7 +1150,7 @@ class SpotifyImplicitGrant(SpotifyAuthBase):
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 """
remote_state, token, t_type, exp_in = self.parse_auth_response_url(url)
if state is None:
@ -1175,7 +1175,7 @@ class SpotifyImplicitGrant(SpotifyAuthBase):
return tuple(form.get(param) for param in ["state", "access_token",
"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)
try:
webbrowser.open(auth_url)
@ -1183,7 +1183,7 @@ class SpotifyImplicitGrant(SpotifyAuthBase):
except webbrowser.Error:
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 """
logger.info('User authentication requires interaction with your '
'web browser. Once you enter your credentials and '

View File

@ -8,7 +8,7 @@ import logging
import os
import warnings
from types import TracebackType
from typing import List, Optional, Tuple, Union
from typing import List, Tuple, Union
import requests
import urllib3
@ -31,15 +31,15 @@ StrListOrTuple = Union[List[str], Tuple[str, ...]]
def prompt_for_user_token(
username: Optional[str] = None,
scope: Optional[str] = None,
client_id: Optional[str] = None,
client_secret: Optional[str] = None,
redirect_uri: Optional[str] = None,
cache_path: Optional[str] = None,
oauth_manager: Optional[spotipy.SpotifyOAuth] = None,
username: str | None = None,
scope: str | None = None,
client_id: str | None = None,
client_secret: str | None = None,
redirect_uri: str | None = None,
cache_path: str | None = None,
oauth_manager: spotipy.SpotifyOAuth | None = None,
show_dialog: bool = False,
) -> Union[str, None]:
) -> str | None:
""" Prompt the user to login if necessary and returns a user token
suitable for use with the spotipy.Spotify constructor.
@ -139,7 +139,7 @@ def get_host_port(netloc: str):
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
input will split the string by commas to create a list of scopes.
A list or tuple input is used directly.
@ -170,12 +170,12 @@ class Retry(urllib3.Retry):
def increment(
self,
method: Optional[str] = None,
url: Optional[str] = None,
response: Optional[urllib3.BaseHTTPResponse] = None,
error: Optional[Exception] = None,
_pool: Optional[urllib3.connectionpool.ConnectionPool] = None,
_stacktrace: Optional[TracebackType] = None,
method: str | None = None,
url: str | None = None,
response: urllib3.BaseHTTPResponse | None = None,
error: Exception | None = None,
_pool: urllib3.connectionpool.ConnectionPool | None = None,
_stacktrace: TracebackType | None = None,
) -> urllib3.Retry:
if response:
retry_header = response.headers.get("Retry-After")