question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Create a Download Button API to download files

See original GitHub issue

Problem

I’m hoping to be able to provide a Streamlit function that allows for the downloading of files. There are a few solutions in the wild at the moment that I know of, each with its own downsides:

Solution

API Details

streamlit.download_button(label, data, file_name='file', mime=None, key=None)

Display a button to download data to the user’s machine.

Parameters

  • label (str) – A short label explaining to the user what this button is for.
  • data (str or bytes or file) – The contents of the file to be downloaded.
  • file_name (str) - An optional string to use as the name of the file to be downloaded, eg. ‘my_file.csv’. If not file name is specified, then we provide a generic name for the download.
  • mime (str or None) – The MIME type of the data. If None, defaults to “text/plain” or “application/octet-stream” depending on the data type.
  • key (str) – An optional string to use as the unique key for the widget. If this is omitted, a key will be generated for the widget based on its content. Multiple widgets of the same type may not share the same key.

Returns

True if the button was clicked on the last run of the app. False otherwise.

Return type

bool

Example Usage

# Text files

text_contents = '''
Foo, Bar
123, 456
789, 000
'''

# Different ways to use the API

st.download_button('Download CSV', text_contents, 'text/csv')
st.download_button('Download CSV', text_contents)  # Defaults to 'text/plain'

with open('myfile.csv', 't') as f:
	st.download_button('Download CSV', f)  # Defaults to 'text/plain'


# ---
# Binary files

binary_contents = b'whatever'

# Different ways to use the API

st.download_button('Download file', binary_contents)  # Defaults to 'application/octet-stream'

with open('myfile.zip', 'b') as f:
	st.download_button('Download Zip', f)  # Defaults to 'application/octet-stream'


# You can also grab the return value of the button,
# just like with any other button.

if st.download_button(...):
	st.write('Thanks for downloading!')

Implementation

TLDR

  • Extend the Button Widget with download capabilities
  • Use the MediaFileManager to store the file for downloading.

Plan

Implementation of the download button requires two parts:

  • Implement the Proto/Frontend Button Widget to accept a download URL and file name and download the URL specified.
  • Implementing the API on the Python side to create a button. Essentially, this will be very similar code to st.button, but it must do a few things differently:
    • Store the file information somewhere on the server
    • Instruct the frontend that it’s a download button as well as a URL to download the button from.
    • Proper clean up of the file information on rerun.

Tasks

Can be done in the following order to be done in the mainline develop branch with no issues. Overall, I see 2-3 tasks:

  • Implement the proto/frontend to test for a download button.
    • Extend the proto with a download_url and download_filename default the Python button to set that equal to None
    • Extend the same Button Widget to include the added feature for download url. If it exists, download the url by creating a shadow link. See The VideoRecordedDialog event handler.
    • Unit Tests for the button with the new functionality.
    • Verification of e2e tests that standard buttons are unchanged.
  • Implement the Python API
    • API meets spec.
    • Properly documented and approved by documentation.
    • Add file bytes to a location theMediaFileManager
      • This begins to break the paradigm of the MediaFileManager (focus on media), but routes are provided and there’s no real reason why it focuses on media. It’s more or less a file type. A task to “generalize” MediaFileManager to be FileManager can be created and done beforehand or done if the amount of work is small.
    • Full E2E tests for the download button possible.

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:12
  • Comments:18 (11 by maintainers)

github_iconTop GitHub Comments

1reaction
asainicommented, Mar 2, 2021

@SimonBiggs : As the PM for this feature, sharing some of my thoughts 🙂

Having the filename before the mime type makes sense. Good call!

As a starting point, I would prefer we restrict the scope and ask the user to specify the MIME type. Definitely open to auto-detection in the future, so we can look into the magic functionality in v2.0.

1reaction
SimonBiggscommented, Feb 6, 2021

Hi @nthmost 🙂,

Who’s the best person to ping to get permission to make a PR? Is this still the best way to go about it? Or might it be better that I just start the PR?

Cheers 😊 @SimonBiggs

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to trigger a file download when clicking an HTML button ...
To trigger a file download on a button click we will use a custom function or HTML 5 download attribute. ... The download...
Read more >
How to trigger a file download when clicking ... - Stack Overflow
You can trigger a download with the HTML5 download attribute. <a href="path_to_file" download="proposed_file_name">Download</a>. Where:.
Read more >
Programmatic file downloads in the browser - LogRocket Blog
So far, we have looked at how we can download files that are served from a server and sent to the client over...
Read more >
Download Files using Web API - codeburst
In this article, I will use a demo Web API application in ASP.NET Core to show you how to transmit files through an...
Read more >
Download file on button click in the Browser with Javascript
Let's create the Download Button. As we already know what's a Blob, let's have a look at how to download any data just...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found