diff --git a/src/spotifyaio/__init__.py b/src/spotifyaio/__init__.py index c64c2a62..b094faf8 100644 --- a/src/spotifyaio/__init__.py +++ b/src/spotifyaio/__init__.py @@ -5,6 +5,7 @@ SpotifyConnectionError, SpotifyError, SpotifyNotFoundError, + SpotifyRateLimitError, ) from .models import ( Album, @@ -68,6 +69,7 @@ "SpotifyConnectionError", "SpotifyError", "SpotifyNotFoundError", + "SpotifyRateLimitError", "Track", "UserProfile", ] diff --git a/src/spotifyaio/exceptions.py b/src/spotifyaio/exceptions.py index 676b9e75..6809255f 100644 --- a/src/spotifyaio/exceptions.py +++ b/src/spotifyaio/exceptions.py @@ -15,3 +15,7 @@ class SpotifyAuthenticationFailedError(SpotifyError): class SpotifyNotFoundError(SpotifyError): """Spotify not found exception.""" + + +class SpotifyRateLimitError(SpotifyError): + """Spotify rate limit exception.""" diff --git a/src/spotifyaio/spotify.py b/src/spotifyaio/spotify.py index 6039418e..4585d157 100644 --- a/src/spotifyaio/spotify.py +++ b/src/spotifyaio/spotify.py @@ -12,7 +12,11 @@ import orjson from yarl import URL -from spotifyaio.exceptions import SpotifyConnectionError, SpotifyNotFoundError +from spotifyaio.exceptions import ( + SpotifyConnectionError, + SpotifyNotFoundError, + SpotifyRateLimitError, +) from spotifyaio.models import ( Album, AlbumsResponse, @@ -132,6 +136,10 @@ async def _request( msg = f"Resource not found: {uri}" raise SpotifyNotFoundError(msg) + if '"status": 429' in text: + msg = "Ratelimit exceeded" + raise SpotifyRateLimitError(msg) + return text async def _get(self, uri: str, params: dict[str, Any] | None = None) -> str: diff --git a/tests/fixtures/rate_limit.json b/tests/fixtures/rate_limit.json new file mode 100644 index 00000000..1f0648d2 --- /dev/null +++ b/tests/fixtures/rate_limit.json @@ -0,0 +1,6 @@ +{ + "error": { + "status": 429, + "message": "API rate limit exceeded" + } +} diff --git a/tests/test_spotify.py b/tests/test_spotify.py index 9b37780c..f66a6a2e 100644 --- a/tests/test_spotify.py +++ b/tests/test_spotify.py @@ -16,6 +16,7 @@ SpotifyClient, SpotifyConnectionError, SpotifyNotFoundError, + SpotifyRateLimitError, ) from . import load_fixture @@ -884,6 +885,23 @@ async def test_get_not_found_playlist( await authenticated_client.get_playlist("37i9dQZF1DXcBWIGoYBM5M") +async def test_rate_limit( + responses: aioresponses, + authenticated_client: SpotifyClient, +) -> None: + """Test raising rate limit exception.""" + responses.get( + f"{SPOTIFY_URL}/v1/playlists/37i9dQZF1DXcBWIGoYBM5M?additional_types=track,episode", + status=200, + body=load_fixture("rate_limit.json"), + ) + with pytest.raises( + SpotifyRateLimitError, + match="Ratelimit exceeded", + ): + await authenticated_client.get_playlist("37i9dQZF1DXcBWIGoYBM5M") + + @pytest.mark.parametrize( "fixture", [