Both SpotifyClient and AsyncSpotifyClient support Python’s context manager protocol, allowing you to use with and async with statements for automatic resource cleanup.
Context managers ensure that resources are properly cleaned up when you’re done with them, even if an exception occurs. This is especially important for:
from spotify_sdk import SpotifyClientwith SpotifyClient(access_token="your-access-token") as client: album = client.albums.get("4aawyAB9vmqN3uQ7FjRGTy") print(f"{album.name} by {album.artists[0].name}")# Client automatically closed when exiting the with block
import asynciofrom spotify_sdk import AsyncSpotifyClientasync def main(): async with AsyncSpotifyClient(access_token="your-access-token") as client: album = await client.albums.get("4Uv86qWpGTxf7fU7lG5X6F") print(f"{album.name} by {album.artists[0].name}") # Client automatically closed when exiting the async with blockasyncio.run(main())
The async close() method (src/spotify_sdk/_async/_client.py:86-88) properly closes the async HTTP client:
async def close(self) -> None: """Close the client and release resources.""" await self._base_client.close()
The AsyncBaseClient.close() method (src/spotify_sdk/_async/_base_client.py:230-236) handles cleanup:
async def close(self) -> None: """Close the HTTP client.""" if self._client is not None: await self._client.aclose() self._client = None if self._auth_provider and hasattr(self._auth_provider, "close"): await self._auth_provider.close()
from spotify_sdk import SpotifyClient# Resources automatically cleaned upwith SpotifyClient(access_token="your-access-token") as client: album = client.albums.get("5K79FLRUCSysQnVESLcTdb") print(album.name)# close() called automatically, even if an exception occurs
Always use context managers (with or async with) unless you have a specific reason to manage the lifecycle manually.
Context managers ensure cleanup even when exceptions occur:
from spotify_sdk import SpotifyClient, NotFoundErrortry: with SpotifyClient(access_token="your-access-token") as client: album = client.albums.get("invalid_id") print(album.name)except NotFoundError as e: print(f"Album not found: {e.message}")# Client is still properly closed despite the exception
You can perform multiple operations within a single context:
1
Sync Client Example
2
from spotify_sdk import SpotifyClientwith SpotifyClient(access_token="your-access-token") as client: # Fetch an album album = client.albums.get("5K79FLRUCSysQnVESLcTdb") print(f"Album: {album.name}") # Fetch album tracks tracks = client.albums.get_tracks(album.id, limit=10) for track in tracks.items: print(f"{track.track_number}. {track.name}") # Search for artists results = client.search.search( q="Bad Bunny", types=["artist"], limit=5, )# All resources cleaned up after this block
3
Async Client Example
4
import asynciofrom spotify_sdk import AsyncSpotifyClientasync def main(): async with AsyncSpotifyClient(access_token="your-access-token") as client: # Fetch an album album = await client.albums.get("4Uv86qWpGTxf7fU7lG5X6F") print(f"Album: {album.name}") # Fetch album tracks tracks = await client.albums.get_tracks(album.id, limit=10) for track in tracks.items: print(f"{track.track_number}. {track.name}") # Fetch artist artist = await client.artists.get(album.artists[0].id) print(f"Artist: {artist.name}") # All resources cleaned up after this blockasyncio.run(main())
You can use multiple clients simultaneously with nested context managers:
from spotify_sdk import SpotifyClient# Two different clients with different tokenswith SpotifyClient(access_token="token-1") as client1: with SpotifyClient(access_token="token-2") as client2: album1 = client1.albums.get("5K79FLRUCSysQnVESLcTdb") album2 = client2.albums.get("4Uv86qWpGTxf7fU7lG5X6F") print(f"Album 1: {album1.name}") print(f"Album 2: {album2.name}")# Both clients are properly closed
Or use a more compact syntax:
from spotify_sdk import SpotifyClientwith ( SpotifyClient(access_token="token-1") as client1, SpotifyClient(access_token="token-2") as client2,): album1 = client1.albums.get("5K79FLRUCSysQnVESLcTdb") album2 = client2.albums.get("4Uv86qWpGTxf7fU7lG5X6F")
Context managers guarantee that resources are released, even if exceptions occur:
# Goodwith SpotifyClient(access_token="token") as client: album = client.albums.get("id")# Badclient = SpotifyClient(access_token="token")album = client.albums.get("id")# Forgot to close!
Reuse client instances within a context
Creating a new client for every request is inefficient:
# Good: One client, multiple operationswith SpotifyClient(access_token="token") as client: album1 = client.albums.get("id1") album2 = client.albums.get("id2") album3 = client.albums.get("id3")# Bad: Multiple clientswith SpotifyClient(access_token="token") as client: album1 = client.albums.get("id1")with SpotifyClient(access_token="token") as client: album2 = client.albums.get("id2")
Use async context managers with AsyncSpotifyClient
Always use async with for async clients:
# Goodasync with AsyncSpotifyClient(access_token="token") as client: album = await client.albums.get("id")# Bad: Missing asyncwith AsyncSpotifyClient(access_token="token") as client: album = await client.albums.get("id") # Won't work!
For web applications, manage lifecycle at app level
In web frameworks, create the client at startup and close at shutdown:
Even with context managers, be explicit about error handling:
from spotify_sdk import SpotifyClient, SpotifyErrortry: with SpotifyClient(access_token="token") as client: album = client.albums.get("id")except SpotifyError as e: # Handle the error print(f"Error: {e.message}")# Client is still closed properly