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"""
{dl_link}
""" st.markdown(div_dl_link, unsafe_allow_html=True) return dl_link