API
Extract a file from a Project
All files within a project can be extracted using a link in the following format:
https://py.cafe/files/{owner}/{project}/{file_path}
This is mostly used in combination with the requirements.txt
file to install a wheel that is uploaded to a project, e.g.:
See Howto build for an example.
Extract wheel from a GitHub action artifact
Based on Artifact ID
This API endpoint allows you to extract wheels from GitHub actions artifacts. This makes it possible to install a wheel from the latest successful run of your GitHub action by including a link in your requirements.txt
.
The link URL is structured as follows:
https://py.cafe/gh/artifact/{owner}/{repo}/{artifact_id}/{full_path_to_wheel}
An example requirement file that could be used for Panel:
# requirements.txt
# The normal requirement for panel is just panel:
# panel
# based on the run of this action https://github.com/holoviz/panel/actions/runs/11204446095
# we have a link to the artifact
# https://github.com/holoviz/panel/actions/runs/11204446095/artifacts/2021154790
# which contains the file pip/panel-1.5.2-py3-none-any.whl
https://py.cafe/gh/artifact/holoviz/panel/2021154790/panel-1.5.2-py3-none-any.whl
Note that the Artifact ID cannot be obtained from within a running GitHub Action, and therefore it is not possible to generate messages or links from a GitHub Action itself.
Note: the runId is not used, only the artifactId is used to extract the wheel.
Based on Run ID
You can also extract a wheel from a artifact based on the runId. In this case the URL is structured as follows:
https://py.cafe/gh/artifact/{owner}/{repo}/actions/runs/{run_id}/{artifact_name}/{wheel_filename}
For example:
# requirements.txt
# The normal requirement for panel is just panel:
# panel
# based on the run of this action https://github.com/holoviz/panel/actions/runs/11204446095
# which contains an artifact with the name pip and a file
# panel-1.5.2-py3-none-any.whl (you do not need to enter the full path for this endpoint)
https://py.cafe/gh/artifact/holoviz/panel/actions/runs/11204446095/pip/panel-1.5.2-py3-none-any.whl
The artifact name can be a regular expression if ?regex
is appended to the url. So in the above case, p.*p
would also work:
https://py.cafe/gh/artifact/holoviz/panel/actions/runs/11204446095/p.p/panel-1.5.2-py3-none-any.whl?regex
wheel_filename
does not have to be the full pathname, as long as the full path in the zipfile matches wheel_filename
The advantage of this endpoint is that we can generate links to the artifact from within the GitHub Action
because each GitHub action has access to a Run ID via the {{ github.run_id }}
variable.
Note that the artifact_name
is a name given to the artifact in the GitHub Action workflow file.
Based on a PR
If you are only interested in extracting a wheel from the last run that was triggered in a PR, you can use the following endpoint:
https://py.cafe/gh/artifact/{owner}/{repo}/pull/{pr_number}/{workflow_name}/{artifact_name}/{wheel_filename}
An example url is:
https://py.cafe/gh/artifact/mckinsey/vizro/pull/766/PyCafe.*/pip/vizro-0.1.26.dev0-py3-none-any.whl?regex
Note that the workflow_name
is in the GitHub Action workflow files. Here we use a regular expression (PyCafe.*
) to match it and therefore
pass the ?regex
parameter.
Snippet links
Snippet links are self-contained links that include everything needed by an app hosted on PyCafe. These links can be created without interacting with the PyCafe website, and can be shared in GitHub issues, Discord, or in other places where you want to share code.
Snippet links with only code
The simplest form of a snippet link is a link that only includes the code. This can be done by adding the code to the URL as a query parameter or hash parameter. The code should be quoted to make sure spaces and special characters are correctly encoded.
from urllib.parse import quote
code = quote("""import streamlit as st
if st.button("PyCafe is great"):
st.balloons()
""")
# Note: you can also use a link as a source for code
# code = quote("https://raw.githubusercontent.com/streamlit/streamlit/refs/heads/develop/lib/tests/streamlit/test_data/widgets_script.py")
url = f"https://py.cafe/snippet/streamlit/v1#code={code}"
print(url)
This should result in a the following link:
You can play with this example code using the following PyCafe project:
Note that the code argument can also be an URL.
Snippet links with code and requirements
from urllib.parse import quote
code = quote("""import streamlit as st
import pandas as pd
chart_data = pd.DataFrame(np.random.randn(20, 3), columns=["a", "b", "c"])
st.area_chart(chart_data)
""")
requirements = quote("""streamlit==1.27.2 # currently pinned to this version
altair
pandas
""")
url = f"https://py.cafe/snippet/streamlit/v1#code={code}&requirements={requirements}"
print(url)
Use this project to play with this example code.
Snippet links with code, requirements, and extra files
There are three ways to add a file to a snippet link:
- Provide a URL to a file that will be downloaded on the fly
- Provide the content of the file directly (text only)
- Provide the content of the file directly, but encoded in base64
Once you start adding files, the URL will get longer, so it’s recommended to compress the JSON object using gzip, and then encode it in base64. This will make the URL much shorter.
The following example shows how to create a snippet link with code, requirements, and extra files.
from urllib.parse import quote, urlencode
import base64
import json
import gzip
code = """import streamlit as st
import pandas as pd
chart_data = pd.DataFrame(np.random.randn(20, 3), columns=["a", "b", "c"])
st.area_chart(chart_data)
"""
requirements = """streamlit==1.27.2 # currently pinned to this version
altair
pandas
"""
files = [
{
"name": "some_file_loaded_from_a_url.py",
# this file will be downloaded on the fly, this will keep the generated url short, and the content always up to date
"url": "https://github.com/projectmesa/mesa-examples/raw/main/examples/virus_on_network/virus_on_network/model.py",
},
{
"name": "other_file_from_data.py",
# if content is provided, it's assumed to be text (utf8 encoded)
"content": "plain text",
},
{
"name": "binary_data.dat",
# encode binary data in base64, but make sure to include the encoding
"content": base64.b64encode(b"binary data").decode("utf8"),
"encoding": "base64"
}
]
json_object = {
"code": code,
"requirements": requirements,
"files": files
}
json_text = json.dumps(json_object)
# compress using gzip to make the url shorter
compressed_json_text = gzip.compress(json_text.encode("utf8"))
# but encode in base64
base64_text = base64.b64encode(compressed_json_text).decode("utf8")
c = quote(base64_text)
# use the c= argument, c stands for compressed
url = f"https://py.cafe/snippet/streamlit/v1#c={c}"
print(url)