How to programmatically generate download link?

In a notebook, I want to programmatically generate a download link and pass that URL to a Javascript-based visualization tool for display.

In classic Notebook I was able to do this simply by prepending files/ to the relative URL. For example: files/data/file_to_display.bam. I could then pass that relative URL to the visualization and it would work. In JupyterLab, however, it doesn’t work.

So is there a way to reliably generate a download link to a local file? (from the kernel)

P.S. I noticed that IPython.display.FileLink generates an HTML tag that works when displayed, but I haven’t been able to figure out a way programmatically get the URL in the kernel.

Can you share the code that worked in classic notebook?

The code looks something like what is shown below.

The b object represents a visualization instance (of igv.js). Basically it takes the relative URL shown below and passes it directly to the JS visualization, which is then displayed in another cell.

b.load_track({
        "name": "Local BAM",
        "url": "files/data/gstt1_sample.bam",
        "format": "bam"
    })

Here’s a binder link of the full notebook in action. By default it open in classic notebook and works, but if you change the URL to lab, it does not.

1 Like

Here is how we take a relative URL from the kernel and convert it to a url that can be used in the browser to get a data set in the vega project: jupyterlab/index.ts at a6f5b0c67f86334f42d2dd83ed8c636bbe938b93 · jupyterlab/jupyterlab · GitHub

See also the discussion around where we introduced that change: Use the url resolver to its full capabilities for vega. by jasongrout · Pull Request #7098 · jupyterlab/jupyterlab · GitHub, Vega extension not loading in subdirectory · Issue #7047 · jupyterlab/jupyterlab · GitHub

2 Likes

That is very helpful! Thank you.

This was very useful, we just ran into this very problem today with otter-grader-generated links… Eventually I tracked down this reply by @jasongrout on a related issue, and it put me on track for a quick fix for otter.

But I’m now wondering:

  • Do you think we should also fix IPython.display.FileLink to automatically add the download= attribute?
  • Is there anything we could do to markdown rendering to help smooth the experience with pure markdown file links?

The 2nd seems to be way too convoluted/too many potential pitfalls to be worth the trouble, but I’m thinking the first is perhaps useful… Jason/others - any thoughts on this? I can whip up a PR for IPython as well, this is pretty straightforward…

It became particularly pressing for us b/c I’m pushing to transition large courses (Data 100, with > 1,100 students) to Lab, and this impacts all graded assignments in the semester… Fortunately we can apply the fix in otter instead of requiring changes to Lab, but I’m pondering what other improvements we can make on our (Jupyter’s) end of the tools to help with similar situations.

BTW, I made a simple gist that can be used to illustrate the issues.

You can run it from this binder link to see the various behaviors.

1 Like

What does FileLink do currently? Does it make a link that attempts to open the file in JupyterLab? That can be desirable behavior too. What if we make an argument to FileLink to optionally add the download attribute?

In a classic notebook: clicking on a FileLink behaves like a regular link in an html file: opens the file if it is loadable (e.g., a html or text file), otherwise the file is downloaded.

In Lab: when clicking the link on a displayable file, it is opened in a new tab inside Lab (this is probably better than displaying it in a new browser tab), but for other files Lab displays this error message in a popup:

File Load Error for exported.stl
/home/sliceruser/work/exported.stl is not UTF-8 encoded

Good idea! Without specifying any extra arguments, the default behavior of FileLink would be the same for Lab as for classic notebooks (display supported files, download other files). The additional option could allow forcing the action to: download / show in new Lab tab / show in new browser tab.

Mmmh, @jasongrout - in light of the recent discussion about harmonizing classic/retro/lab behavior as we move to nb7, do you think we should make some fixes here? Not 100% sure if we should open the issue on Lab, retro, or IPython (for the display module). Thoughts?

Hi there,
I hope you can help me with this slightly different use case.
See below example:

image

I need to actually get the absolute URL and send it via an email outside the Jupyter notebook.
However I can’t seem to find a way to actually get the url programmatically.
Effectively I am using jupyter service as a cheap image file server (I know I know security etc… but this is just for a POC).
Maybe is not designed to be used that way?
Cheers.

1 Like

I am curious if anything else came from this. We are having a bunch of users migrating from Classic to Lab and this is biting us really hard, but even in recent versions of Classic it is sending them to HTML pages rather than the raw file, even for something like a .tar.gz.

The ONLY way we have gotten this to work in Lab is to ignore FileLink all together and build html for the link manually add the download attribute display(HTML(“foo”)).

Jupyter Classic, I haven’t found a way around this because display(HTML(“foo”)) and display(FileLink(‘foo.txt’)) in Classic is generating /notebooks/foo.txt but in lab generating /files/foo.txt. The former is an HTML page for editing the the file, while the latter, missing a “download” attribute, is intercepted by Jupyterlab and it opens the file in another tab.

yes, this is what I want, sharing the files with others, but I spent hours looking for solutions, did you find a good way to do this?