import io
import re
import uuid
import base64
import streamlit as st
from typing import Optional, Union
from streamlit.elements.widgets.button import DownloadButtonDataType
DownloadButtonDataType = Union[DownloadButtonDataType, "pd.DataFrame", "Styler"]
HAS_PD = True
def download_button(label: str,
data: DownloadButtonDataType,
file_name: Optional[str] = None) -> str:
"""Generates a link to download the given data, support file-like object and pd.DataFrame.
Params
Args:
label: text show on page.
data: file-like object or pd.DataFrame.
file_name: filename and extension of file. e.g. mydata.csv,
Raises:
RuntimeError: when data type is not supported
Returns:
the anchor tag to download object_to_download
Examples:
download_button('Click to download data!', your_df, 'YOUR_DF.xlsx'),
download_button('Click to download text!', your_str.encode(), 'YOUR_STRING.txt')
"""
# inspired by https://gist.github.com/chad-m/6be98ed6cf1c4f17d09b7f6e5ca2978f
data_as_bytes: bytes
if isinstance(data, str):
data_as_bytes = data.encode()
elif isinstance(data, io.TextIOWrapper):
string_data = data.read()
data_as_bytes = string_data.encode()
# mimetype = mimetype or "text/plain"
# Assume bytes; try methods until we run out.
elif isinstance(data, bytes):
data_as_bytes = data
elif isinstance(data, io.BytesIO):
data.seek(0)
data_as_bytes = data.getvalue()
elif isinstance(data, io.BufferedReader):
data.seek(0)
data_as_bytes = data.read()
elif isinstance(data, io.RawIOBase):
data.seek(0)
data_as_bytes = data.read() or b""
elif HAS_PD and hasattr(data, "to_excel"):
bio = io.BytesIO()
data.to_excel(bio)
bio.seek(0)
data_as_bytes = bio.read()
else:
raise RuntimeError("Invalid binary data format: %s" % type(data))
b64 = base64.b64encode(data_as_bytes).decode()
button_uuid = str(uuid.uuid4()).replace("-", "")
button_id = re.sub(r"\d+", "", button_uuid)
custom_css = f"""
"""
dl_link = (
custom_css
+ f'{label}
'
)
div_dl_link = f"""