Search code examples
jupyter-notebookipythonjupytervoila

File download in Voila from Jupyter Notebook


There are many questions with great answers about downloading a file from a Jupyter Notebook. Here's one I added to earlier. That works, but I am unable to click and download that file for a server started with Voila.

Originally I realized I could not download the basic case when clicked through Voila.

from IPython.display import display, FileLink

local_file = FileLink('./demo.xlsx', result_html_prefix="Click here to download: ")
display(local_file)

output screenshot

That is from my notebook. I am able to click on the link and download the file. When I start my notebook with Voila it looks more like this.. enter image description here

Clicking the link give a 404 ☝️ for a voila server started with

voila mynotebook.ipynb

Since the file clearly isn't being served... I found this link here and tried:

voila mynotebook.ipynb --VoilaConfiguration.file_whitelist="['demo.xlsx']"

which unfortunately didn't work.

I saw static content can be served in voila.. I'll keep playing down this road. Has anyone done this before?


Solution

  • I was able to make it work by hosting my file to download as static content as I was trying before. All of this is for a Mac, but it'll be similar for other platforms.

    I had to define a custom template in order to get files at static_root so they could be served. Relevant documentation is here for setting up a custom template.

    It isn't difficult.. you essentially create a directory where it's expected, copy over some of the default files, then add/change what you will. terminal record might look something like this:

    cd ~/Library/Jupyter/voila/templates/
    mkdir foobar
    export DEFAULT_TEMPLATE_PATH=~/anaconda3/envs/voilatest/share/jupyter/voila/templates/default
    export TEMPLATE_PATH=~/Library/Jupyter/voila/templates/foobar
    cp -r $DEFAULT_TEMPLATE_PATH/nbconvert_templates $TEMPLATE_PATH
    cp -r $DEFAULT_TEMPLATE_PATH/templates $TEMPLATE_PATH
    

    to which the tree will look like this in my new custom template:

     {~/Library/Jupyter/voila/templates/foobar}$  tree .
    .
    ├── nbconvert_templates
    │   ├── base.tpl
    │   ├── lab.tpl
    │   └── voila.tpl
    ├── static
    │   └── demo.xlsx
    └── templates
        ├── 404.html
        ├── browser-open.html
        ├── error.html
        ├── page.html
        └── tree.html
    
    3 directories, 9 files
    

    notice the static directory with demo.xlsx. I added that in. That is the file I wanted to download via the link.

    Starting voila like this...

    voila mynotebook.ipynb --template=foobar
    

    Now.. in mynotebook.ipynb

    Use an HTML Anchor tag to do the download. At least FileLink fails for me with the following error.

    Path (/voila/static/demo.xlsx) doesn't exist. It may still be in the process of being generated, or you may have the incorrect path.

    which isn't much of a surprise since the actual path the file is stored at isn't that. It just happens to be the static content uri.

    %%html
    <a href="./voila/static/demo.xlsx" download="demo.xlsx">Download Excel Sheet</a>
    

    Using an anchor will make it hardcoded and I didn't have any issues. I'll also be able to style the anchor more anyways. One catch.. This doesn't work in a regular notebook anymore since it's a URI to a served resource under voila.