No project description provided
Project description
Spotipyio
A FREE async Python wrapper to the Spotify API
⚙️ Before Start
In case you haven't already registered a Spotify API app, please go first to the Spotify developers page and create one. You must possess the following credentials before start:
- Client ID
- Client secret
- Redirect URI
Do you have your credentials? Great, let's start cooking 👨🍳
💾 Installation
Pip
pip install spotipyio
Pipenv
pipenv install spotipyio
Poetry
poetry add spotipyio
🚀 Getting Started
🐣 Sending your first request
Here is a simple function that fetches tracks information and prints it
import asyncio
from spotipyio import SpotifyClient
from typing import List
async def fetch_tracks_info(tracks_ids: List[str]):
async with SpotifyClient() as client: # Assuming you set your credentials as env variables
tracks = await client.tracks.info.run(tracks_ids)
print(tracks)
if __name__ == "__main__":
ids = ["0ntQJM78wzOLVeCUAW7Y45", "5FVd6KXrgO9B3JPmC8OPst"] # Sex On Fire, Do I Wanna Know?
loop = asyncio.get_event_loop()
loop.run_until_complete(fetch_tracks_info(ids))
🦶 Walkthrough
Let's walk through this example one line by another.
Env Setup
First, we must ensure our client credentials are accessible to our code. The easiest way to do so is by simply configuring them as environment variables:
| Credential | Env Variable |
|---|---|
| Client ID | SPOTIPY_CLIENT_ID |
| Client secret | SPOTIPY_CLIENT_SECRET |
| Redirect URI | SPOTIPY_REDIRECT_URI |
SpotifyClient
Once our environment is configured, we can create our SpotifyClient. The SpotifyClient object is the single object
you need to use to execute your business logic. Once created, you will not have to use any other object to send requests.
In the above example, we are using it to fetch tracks information. The easiest way to instantiate it
(but not the only) is as an async context manager, as done here.
Run
Our request is then sent using the run method. All objects within the SpotifyClient send requests using this method,
ensuring a standardized way to execute each object's main functionality. Pay attention we are feeding the run method
not a single track id but a list of ids. This is one of the greatest benefits the package is offering to the user.
If you're familiar with the Spotify API you might already know it doesn't offer this kind of functionality, but only
a single track endpoint or several_tracks endpoint limited to maximum 50 tracks ids. The tracks.info.run method - as
well as other similar methods for other types of data - can receive any number of tracks ids. It automatically takes
care of optimizing your requests by splitting it to 50 ids chunks and parallelizing them.
🔐 Sending your second (authorized) request
In our first request, we didn't configure which OAuth flow to use. In this case, the Client Credentials flow is chosen by default, which is suitable for endpoints that don't hold private information, such as tracks' and artists' information. But how can we send authorized requests to engage with endpoint that require such authorization, such as current user's profile? Let's see an example:
import asyncio
from spotipyio import SpotifySession, SpotifyClient
from spotipyio.auth import ClientCredentials, SpotifyGrantType
async def get_current_user_profile(access_code: str):
credentials = ClientCredentials(
grant_type=SpotifyGrantType.AUTHORIZATION_CODE,
access_code=access_code
)
async with SpotifySession(credentials=credentials) as session:
async with SpotifyClient(session=session) as client:
profile = await client.current_user.profile.run()
print(profile)
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(get_current_user_profile("<your-access-code>"))
Let's drill into the differences between this example and the previous:
- First, our method now expects an
access_codeargument. An access code is mandatory - you will not be able to proceed without creating one first. Read more about authorization codes and how to get them in the official documentation, or simply fetch one to start with using the access code fetcher tool this package provides. - Secondly, We can no longer use the default
SpotifyClientconfiguration, so we have to create one ourselves. Initially, we have to create a customClientCredentialsobject and provide it with the relevant grant type (authorization code) and with the access_code we fetched. - Then, we create a new
SpotifySessionusing the credentials we just created. Pay attention that similar to theSpotifyClientclass, aSpotifySessionis also created using an async context manager. - Finally, we instantiate our
SpotifyClientusing the session. Now, we're good to use it on any endpoint, authorized or not.
🥽 Deep Dive
SpotifyClient
💿 Albums
ℹ️ Info
Description
Get Spotify catalog information for multiple albums identified by their Spotify IDs.
Example
from spotipyio import SpotifyClient
import asyncio
async def fetch_albums_info():
async with SpotifyClient() as client:
albums_ids = ["4LH4d3cOWNNsVw41Gqt2kv", "0E4xv5gPjykrwBgBZzI8XG"] # The Dark Side of the Moon, Back to Black
albums_info = await client.albums.info.run(albums_ids)
print(albums_info)
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(fetch_albums_info())
👨🎤 Artists
ℹ️ Info
Description
Get Spotify catalog information for several artists based on their Spotify IDs.
Example
from spotipyio import SpotifyClient
import asyncio
async def fetch_artists_info(spotify_client: SpotifyClient):
artists_ids = ["6l3HvQ5sa6mXTsMTB19rO5", "1vyhD5VmyZ7KMfW5gqLgo5"] # J Cole, J Balvin
artists_info = await spotify_client.artists.info.run(artists_ids)
print(artists_info)
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(fetch_artists_info())
🔝 Top Tracks
Description
Get Spotify catalog information about an artist's top tracks.
Example
from spotipyio import SpotifyClient
import asyncio
async def fetch_artists_top_tracks():
async with SpotifyClient() as client:
artists_ids = ["6ra4GIOgCZQZMOaUECftGN", "1Mxqyy3pSjf8kZZL4QVxS0"] # Frank Zappa, Frank Sinatra
artists_top_tracks = await client.artists.top_tracks.run(artists_ids)
print(artists_top_tracks)
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(fetch_artists_top_tracks())
👨💻 Current User
🔝️ Top Items
Description
Get the current user's top artists or tracks based on calculated affinity.
Example
from spotipyio import SpotifySession, SpotifyClient
from spotipyio.auth import ClientCredentials, SpotifyGrantType
from spotipyio.models import ItemsType, TimeRange
import asyncio
async def fetch_current_user_top_artists(access_code: str):
credentials = ClientCredentials(
grant_type=SpotifyGrantType.AUTHORIZATION_CODE,
access_code=access_code
)
async with SpotifySession(credentials=credentials) as session:
async with SpotifyClient(session=session) as client:
top_items = await client.current_user.top_items.run(
items_type=ItemsType.ARTISTS,
time_range=TimeRange.SHORT_TERM
)
print(top_items)
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(fetch_current_user_top_artists("<your-access-code>"))
👤️ Profile
Description
Get detailed profile information about the current user.
Example
import asyncio
from spotipyio import SpotifySession, SpotifyClient
from spotipyio.auth import ClientCredentials, SpotifyGrantType
async def fetch_current_user_profile(access_code: str):
credentials = ClientCredentials(
grant_type=SpotifyGrantType.AUTHORIZATION_CODE,
access_code=access_code
)
async with SpotifySession(credentials=credentials) as session:
async with SpotifyClient(session=session) as client:
profile = await client.current_user.profile.run()
print(profile)
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(fetch_current_user_profile("<your-access-code>"))
📻 Playlists
➕ Add Items
Description
Add one or more items to a user's playlist.
Example
import asyncio
from spotipyio import SpotifySession, SpotifyClient
from spotipyio.auth import ClientCredentials, SpotifyGrantType
async def add_playlist_items(access_code: str, playlist_id: str):
credentials = ClientCredentials(
grant_type=SpotifyGrantType.AUTHORIZATION_CODE,
access_code=access_code
)
uris = [
"spotify:track:3Um9toULmYFGCpvaIPFw7l", # What's Going On
"spotify:track:7tqhbajSfrz2F7E1Z75ASX" # Ain't No Mountain High Enough
]
async with SpotifySession(credentials=credentials) as session:
async with SpotifyClient(session=session) as client:
response = await client.playlists.add_items.run(
playlist_id=playlist_id,
uris=uris
)
print(response)
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(add_playlist_items("<your-access-code>", "<your-playlist-id>"))
✨ Create Playlist
Description
Create a playlist for a Spotify user.
Example
import asyncio
from spotipyio import SpotifySession, SpotifyClient
from spotipyio.auth import ClientCredentials, SpotifyGrantType
from spotipyio.models import PlaylistCreationRequest
async def create_marvin_gay_hits_playlist(access_code: str, user_id: str):
credentials = ClientCredentials(
grant_type=SpotifyGrantType.AUTHORIZATION_CODE,
access_code=access_code
)
playlist_request = PlaylistCreationRequest(
user_id=user_id,
name="Marvin’s Magic",
description="A soulful mix of Marvin Gaye’s timeless tracks",
public=True
)
async with SpotifySession(credentials=credentials) as session:
async with SpotifyClient(session=session) as client:
response = await client.playlists.create.run(playlist_request)
print(response)
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(create_marvin_gay_hits_playlist("<your-access-code>", "<your-user-id>"))
ℹ️ Info
Description
Get playlists owned by Spotify users.
Example
from spotipyio import SpotifyClient
import asyncio
async def fetch_playlists_info():
async with SpotifyClient() as client:
playlists_ids = [
"37i9dQZF1DX70TzPK5buVf", # Funk Outta Here
"37i9dQZF1EFGVVd09MO7iM", # Written by Pharrell Williams
]
playlists_info = await client.playlists.info.run(playlists_ids)
print(playlists_info)
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(fetch_playlists_info())
➖ Remove Items
Description
Remove one or more items from a user's playlist.
Example
import asyncio
from spotipyio import SpotifySession, SpotifyClient
from spotipyio.auth import ClientCredentials, SpotifyGrantType
async def remove_playlist_items(access_code: str, playlist_id: str, snapshot_id: str):
credentials = ClientCredentials(
grant_type=SpotifyGrantType.AUTHORIZATION_CODE,
access_code=access_code
)
uris = [
"spotify:track:1z6WtY7X4HQJvzxC4UgkSf", # Love on Top
"spotify:track:6dOtVTDdiauQNBQEDOtlAB" # Birds of a Feather
]
async with SpotifySession(credentials=credentials) as session:
async with SpotifyClient(session=session) as client:
response = await client.playlists.remove_items.run(
playlist_id=playlist_id,
uris=uris,
snapshot_id=snapshot_id
)
print(response)
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(
remove_playlist_items(
access_code="<your-access-code>",
playlist_id="<your-playlist-id>",
snapshot_id="<playlist-snapshot-id>" # Not sure what's the snapshot id?, fetch it using the info method
)
)
↕️ Reorder Items
Description
Reorder one or more items from a user's playlist.
Example
import asyncio
from spotipyio import SpotifySession, SpotifyClient
from spotipyio.auth import ClientCredentials, SpotifyGrantType
from spotipyio.models import PlaylistReorderRequest
async def reorder_first_item_to_last(access_code: str, playlist_id: str, snapshot_id: str):
credentials = ClientCredentials(
grant_type=SpotifyGrantType.AUTHORIZATION_CODE,
access_code=access_code
)
request = PlaylistReorderRequest(
playlist_id=playlist_id,
range_start=0,
insert_before=10, # Assuming the playlist consists of 10 items
snapshot_id=snapshot_id,
range_length=1
)
async with SpotifySession(credentials=credentials) as session:
async with SpotifyClient(session=session) as client:
response = await client.playlists.reorder_items.run(request)
print(response)
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(
reorder_first_item_to_last(
access_code="<your-access-code>",
playlist_id="<your-playlist-id>",
snapshot_id="<playlist-snapshot-id>" # Not sure what's the snapshot id?, fetch it using the info method
)
)
🔄️ Replace Items
Description
Replace one or more items from a user's playlist with other provided items.
Example
import asyncio
from spotipyio import SpotifySession, SpotifyClient
from spotipyio.auth import ClientCredentials, SpotifyGrantType
async def replace_all_playlist_items_by_uptown_funk(access_code: str, playlist_id: str):
credentials = ClientCredentials(
grant_type=SpotifyGrantType.AUTHORIZATION_CODE,
access_code=access_code
)
async with SpotifySession(credentials=credentials) as session:
async with SpotifyClient(session=session) as client:
response = await client.playlists.replace_items.run(
playlist_id=playlist_id,
uris=["spotify:track:32OlwWuMpZ6b0aN2RZOeMS"] # Uptown Funk
)
print(response)
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(
replace_all_playlist_items_by_uptown_funk(
access_code="<your-access-code>",
playlist_id="<your-playlist-id>",
)
)
🖼️️ Update Cover
Description
Replace the image used to represent a specific playlist.
Example
import asyncio
from spotipyio import SpotifySession, SpotifyClient
from spotipyio.auth import ClientCredentials, SpotifyGrantType
async def update_playlist_cover(access_code: str, playlist_id: str, image_path: str):
credentials = ClientCredentials(
grant_type=SpotifyGrantType.AUTHORIZATION_CODE,
access_code=access_code
)
with open(image_path, "rb") as f:
image = f.read()
async with SpotifySession(credentials=credentials) as session:
async with SpotifyClient(session=session) as client:
response = await client.playlists.update_cover.run(
playlist_id=playlist_id,
image=image
)
print(response)
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(
update_playlist_cover(
access_code="<your-access-code>",
playlist_id="<your-playlist-id>",
image_path="<path/to/your/image.jpeg>" # Should be a JPEG image
)
)
🔎 Search
Description
Get Spotify catalog information about albums, artists, playlists, tracks, shows, episodes or audiobooks that match a keyword string.
Example
import asyncio
from spotipyio import SpotifyClient
from spotipyio.models import SearchItem, SearchItemMetadata, SearchItemFilters, SpotifySearchType
async def search_bob_dylan_bootlegs():
search_item = SearchItem(
text="Bootleg",
filters=SearchItemFilters(
artist="Bob Dylan"
),
metadata=SearchItemMetadata(
search_types=[SpotifySearchType.ALBUM]
)
)
async with SpotifyClient() as client:
search_results = await client.search.search_item.run([search_item])
print(search_results)
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(search_bob_dylan_bootlegs())
🎷 Tracks
ℹ️ Info
Description
Get Spotify catalog information for multiple tracks based on their Spotify IDs.
Example
import asyncio
from spotipyio import SpotifyClient
from typing import List
async def fetch_tracks_info(tracks_ids: List[str]):
async with SpotifyClient() as client:
tracks = await client.tracks.info.run(tracks_ids)
print(tracks)
if __name__ == "__main__":
ids = ["2MuWTIM3b0YEAskbeeFE1i", "7xVpkVkd1klTzLJEysIR7z"] # Master Of Puppets, Masters Of War
loop = asyncio.get_event_loop()
loop.run_until_complete(fetch_tracks_info(ids))
🔊️ Audio Features
Description
Get Spotify catalog information for multiple tracks based on their Spotify IDs.
Example
import asyncio
from spotipyio import SpotifyClient
async def fetch_tracks_audio_features():
tracks_ids = ["5W3cjX2J3tjhG8zb6u0qHn", "6Sy9BUbgFse0n0LPA5lwy5"] # Harder Better Faster Stronger, Sandstorm
async with SpotifyClient() as client:
tracks = await client.tracks.audio_features.run(tracks_ids)
print(tracks)
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(fetch_tracks_audio_features())
👥 Users
🔀 Users' Playlists
**Description**Get a list of the playlists owned or followed by Spotify users.
Example
import asyncio
from spotipyio import SpotifyClient
async def fetch_users_playlists():
users = ["billboard.com", "pitchfork"]
async with SpotifyClient() as client:
users_playlists = await client.users.playlists.run(users)
print(users_playlists)
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(fetch_users_playlists())
🧪 Testing
Testing is central to software development, but when it comes to external APIs like Spotify's it can be tricky
to test our code without sending any actual request. To this end, spotipy introduces SpotifyTestClient. This object
is designed to help you test components that use the SpotifyClient seamlessly, without having to mock or patch
anything, or familiarize yourself with the internals of SpotifyClient.
Installation
To avoid adding dev dependencies to our production code, the test client sits under a dedicated testing module, which
requirements' are optional. To install these extra requirements, execute the relevant command.
Pip
pip install spotipyio[testing]
Pipenv
pipenv install spotipyio[testing]
Poetry
poetry add spotipyio[testing]
A notice about versions management
As the test client it is designed only for testing, you should include it in only in your dev dependencies.
On a poetry based project, for example, your pyproject.toml file should look somewhat like this:
[tool.poetry.dependencies]
spotipyio = { version = ">=1,<2" }
[tool.poetry.group.dev.dependencies]
spotipyio = { version = "*", extras = ["testing"] }
Pay attention: the version is pinned only in the dependencies section. The dev dependencies section should not pin a version, to avoid conflicts between two sections.
Testing your first component
Imagine having a simple function that should fetch a playlist from Spotify and return a list of the playlist's tracks names. This function should look something like this:
from typing import List
from spotipyio import SpotifyClient
async def get_playlist_tracks(spotify_client: SpotifyClient, playlist_id: str) -> List[str]:
playlist = await spotify_client.playlists.info.run_single(playlist_id)
items = playlist["tracks"]["items"]
return [item["track"]["name"] for item in items]
Now, Let's test it:
import pytest
from spotipyio.testing import SpotifyTestClient
@pytest.fixture
async def test_client() -> SpotifyTestClient:
async with SpotifyTestClient() as client:
yield client
async def test_get_playlist_tracks(test_client: SpotifyTestClient):
# Arrange
spotify_client = test_client.create_client()
playlist_id = "readme-example"
test_client.playlists.info.expect_success(playlist_id)
# Act
actual = await get_playlist_tracks(spotify_client, playlist_id)
# Assert
assert isinstance(actual, list)
What do we have here? Let's break it down step by step
- First, we import
SpotifyTestClientfrom the previously mentionedspotipyio.testingmodule. Notice that if you didn't install the package including thetestingextra you will encounter anImportErrorat this stage. - We create a fixture of
SpotifyTestClient. Notice we use ayieldstatement instead ofreturn, to keep the fixture context alive until teardown - We use the test client to instantiate a
SpotifyClientinstance. This is done using a simplecreate_clientmethod, which sets up a client that shares the exact same settings as the test client. - Finally, we make sure our playlist request will be successful by calling
test_client.playlists.info.expect_success. This makes sure our request to the specific playlist id we're providing will be answered with a 200 status code.
Testing Deep Dive
🐾 SpotifyTestClient blueprint
In case you've noticed, the test client has the exact same blueprint as `SpotifyClient`. In our example, the tested function calls `spotify_client.playlists.info.run`, and our test calls `test_client.playlists.info.expect_success`. This identity is not an accident but lies in the core of the `SpotifyTestClient` blueprint. Every module in `SpotifyClient` has an equivalent in `SpotifyTestClient`. This makes testing easier then ever. All you have to do is check which methods are used by your production code, and call them during test setup with your test client.The only difference between the two blueprints is in the
methods they implement. Whereas SpotifyClient methods implements the run method, SpotifyTestClient methods
implement the expect_success and expect_failure methods.
📥 Setting the response json
This test, of course, is not very good. Mainly, it only validates the return value is a list, but it doesn't **really** check the actual value returned by the `get_platlist_tracks` function. To check this functionality, let's provide it an actual response json we expect. Here's a revised version:async def test_get_playlist_tracks_successful_response(test_client: SpotifyTestClient):
# Arrange
expected = ["Bohemian Raphsody", "The Blacker The Berry", "Take Five", "Jhonny B. Goode"]
response_items = [{"track": {"name": name}} for name in expected]
response_json = {"tracks": {"items": response_items}}
spotify_client = test_client.create_client()
playlist_id = "readme-example"
test_client.playlists.info.expect_success(playlist_id, [response_json])
# Act
actual = await get_playlist_tracks(spotify_client, playlist_id)
# Assert
assert actual == expected
We've added our arrange block three lines where we define our expected value, than use it to create a mock playlist
json that will be returned from the API. Than, we provide the test client with this response json, making sure that
when a request to fetch the readme-example playlist will be received, this will be the exact json that will be
returned. Notice that now our assertion is much stronger - we expect the actual value to be equal to our expectation.
⚠️ Testing failures
Up until now we've been focusing only on testing successful scenarios. But what about exception handling? Handling exceptions is absolutely a must when it comes to work with external APIs like Spotify's. How should we test it? Let's start by wrapping our function with a simple `try-except` blockfrom typing import List
from aiohttp import ClientResponseError
from spotipyio import SpotifyClient
async def get_playlist_tracks(spotify_client: SpotifyClient, playlist_id: str) -> List[str]:
try:
playlist = await spotify_client.playlists.info.run_single(playlist_id)
items = playlist["tracks"]["items"]
return [item["track"]["name"] for item in items]
except ClientResponseError:
print("Failed to fetch playlist. Retuning empty list instead")
return []
Now, our function will simply print and return an empty list in cases it fails to fetch the API, instead of raising an exception that will fail our entire application. But how will we test it? Let's add another test to our suite.
async def test_get_playlist_tracks_failed_response(test_client: SpotifyTestClient):
# Arrange
spotify_client = test_client.create_client()
playlist_id = "readme-example"
test_client.playlists.info.expect_failure(playlist_id)
# Act
actual = await get_playlist_tracks(spotify_client, playlist_id)
# Assert
assert actual == []
The only difference here is the usage of test_client.playlists.info.expect_failure instead of expect_success. This
method instructs the test client to response with a failed status code.
Here again, we may also provide it with a specific response. Let's complicate our example by adding different behavior to different exceptions. A typical use case would be to backoff in case we receive a 429 (too many requests) status code. Here is a naive implementation:
from typing import List
from aiohttp import ClientResponseError
from spotipyio import SpotifyClient
from asyncio import sleep
async def get_playlist_tracks(spotify_client: SpotifyClient, playlist_id: str, retries_left: int = 1) -> List[str]:
try:
playlist = await spotify_client.playlists.info.run_single(playlist_id)
items = playlist["tracks"]["items"]
return [item["track"]["name"] for item in items]
except ClientResponseError as e:
if e.status == 429 and retries_left > 0:
await sleep(1)
return await get_playlist_tracks(spotify_client, playlist_id, retries_left - 1)
print("Failed to fetch playlist. Retuning empty list instead")
return []
How might we test this? By providing our test client a specific status code. This final example will incorporate all use cases we saw by now. We will have to call the test client twice: first to set it to return a custom 429 response, then to return a successful response. This test will now look like this:
async def test_get_playlist_tracks_first_fail_than_success(test_client: SpotifyTestClient):
# Arrange
spotify_client = test_client.create_client()
playlist_id = "readme-example"
test_client.playlists.info.expect_failure(playlist_id, status=429)
expected = ["The Fool on the Hill", "Relax (Take It Easy)", "The Real Slim Shady"]
response_items = [{"track": {"name": name}} for name in expected]
response_json = {"tracks": {"items": response_items}}
playlist_id = "readme-example"
test_client.playlists.info.expect_success(playlist_id, [response_json])
# Act
actual = await get_playlist_tracks(spotify_client, playlist_id)
# Assert
assert actual == expected
Please notice: The test client expects ordered expectations. Here we first set a failed response
expectation, then only a successful response. If we will first call the expect_success method, our code will simply
not reach the except block.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file spotipyio-1.0.0.tar.gz.
File metadata
- Download URL: spotipyio-1.0.0.tar.gz
- Upload date:
- Size: 50.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/5.1.1 CPython/3.12.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
583ee637c7e7366d800e58cf21cde446553ed20c940665ab317fff98c638caf3
|
|
| MD5 |
3e8f501c129ddafaebc8467e3fd0001b
|
|
| BLAKE2b-256 |
63090d9e2108e89b5a7436a8ba7b221a0723758ec3ab68b53eeecea33d804b11
|
Provenance
The following attestation bundles were made for spotipyio-1.0.0.tar.gz:
Publisher:
release.yaml on nirgodin/spotipyio
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
spotipyio-1.0.0.tar.gz -
Subject digest:
583ee637c7e7366d800e58cf21cde446553ed20c940665ab317fff98c638caf3 - Sigstore transparency entry: 150794115
- Sigstore integration time:
-
Permalink:
nirgodin/spotipyio@92b4b39cbcd48bef4bcac1c0e0c7739abb296328 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/nirgodin
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yaml@92b4b39cbcd48bef4bcac1c0e0c7739abb296328 -
Trigger Event:
pull_request
-
Statement type:
File details
Details for the file spotipyio-1.0.0-py3-none-any.whl.
File metadata
- Download URL: spotipyio-1.0.0-py3-none-any.whl
- Upload date:
- Size: 92.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/5.1.1 CPython/3.12.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3b837d161cf73aa6effff358b18e0fe106f20ed956e337b46692807d1a554cb5
|
|
| MD5 |
6607b9f48f802e50c61c501c95afab6c
|
|
| BLAKE2b-256 |
efc5a5c04f883d68d9131569ad52372ec03db8bde887660a6f159eade2cc6e4f
|
Provenance
The following attestation bundles were made for spotipyio-1.0.0-py3-none-any.whl:
Publisher:
release.yaml on nirgodin/spotipyio
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
spotipyio-1.0.0-py3-none-any.whl -
Subject digest:
3b837d161cf73aa6effff358b18e0fe106f20ed956e337b46692807d1a554cb5 - Sigstore transparency entry: 150794116
- Sigstore integration time:
-
Permalink:
nirgodin/spotipyio@92b4b39cbcd48bef4bcac1c0e0c7739abb296328 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/nirgodin
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yaml@92b4b39cbcd48bef4bcac1c0e0c7739abb296328 -
Trigger Event:
pull_request
-
Statement type: