spatialaudio / nbsphinx

:ledger: Sphinx source parser for Jupyter notebooks
https://nbsphinx.readthedocs.io/
MIT License
449 stars 128 forks source link

Download buttons/links #745

Closed wpbonelli closed 4 months ago

wpbonelli commented 1 year ago

Hi, does nbsphinx offer a similar feature to sphinx-gallery where notebooks are zipped and can be downloaded from the rendered page? One option I see is linking in prolog/epilog to GitHub but I would like to keep notebooks as jupytext paired scripts and avoid version controlling ipynbs, while allowing the docs visitor to download either a .py or an .ipynb.

mgeier commented 1 year ago

You can just change .html to .ipynb, for example:

This will give you the executed notebook (if you didn't disable execution).

Does that help?

The problem is that, depending on the webserver configuration, the file might be displayed as JSON in the browser. This is the reason why I didn't provide a download link in the docs but instead created a "View in nbviewer" link: https://nbviewer.org/urls/nbsphinx.readthedocs.io/en/0.9.1/custom-formats.ipynb

https://github.com/spatialaudio/nbsphinx/blob/ce39da6798d9f654a3942b255cbe4d6a266d02d1/doc/conf.py#L55-L61

.zip files are currently not available.

I have thought about customizing the provided downloads, but up to now nobody has asked for it!

wpbonelli commented 1 year ago

Thanks! Got downloads working with :download: role in the prolog, e.g. prolog.rst

.. only:: html

    .. role:: raw-html(raw)
        :format: html

    .. note::

        | Download :download:`Jupyter notebook (.ipynb) <{{ docname }}>` or :download:`Python script (.py) <{{ docname[:-6] }}.py>`

and in conf.py

nbsphinx_prolog = r"""
{% set docname = env.doc2path(env.docname, base=None) %}
""" + Path("prolog.rst").read_text()
mgeier commented 1 year ago

I'm glad you found a solution that works for you!

If your project is public, would you mind providing a link, just out of curiosity?

Does the :download: link work better for you than directly linking to the notebook file? I guess it's not really a problem, but now you have two copies of all .ipynb files on your server, right?

wpbonelli commented 1 year ago

would you mind providing a link, just out of curiosity?

Sure, here is a sample notebook.

I used :download: because it renders a download link, where the direct link shows the file as JSON in-browser first, then user needs to click save. I guess a download link would be easy with custom HTML, and avoid sphinx duplicating ipynbs in _downloads. Maybe I will do that instead.

agriyakhetarpal commented 1 year ago

Another solution for this is to add an anchor tag for the notebook with .. raw:: html in this fashion and customise nbsphinx_prolog with the links and file paths as needed:


nbsphinx_prolog = r"""
.. raw:: html

    <div class="admonition tip">
        <p class="admonition-title">
            Tip
        </p>
        <p>
            Alternatively, you may
            <a href="{{ readthedocs_download_url | e }}{{ doc_path | e }}"
            target="_blank" download>
            download this notebook</a> and run it offline.
        </p>
    </div>
  """

Here, in the <a> anchor, the target="_blank" and download attributes combined open a download prompt directly. A caveat is that it only works for same-origin links (reference: https://caniuse.com/download), which should be fine for a general use case since the files are downloaded from where they are hosted. Otherwise, it reverts to opening the JSON-formatted file in a new tab.

See a notebook in the PyBaMM docs for a simple working example.

mgeier commented 1 year ago

Thanks @w-bonelli for the link! The download link uses

<a class="reference download internal" download="" ...>

Thanks @agriyakhetarpal for the additional information, that's very interesting. Is target="_blank" even necessary if download is given?

Based on that, I have made #751 to add a download link to the nbsphinx docs so that users can simply copy the line of HTML. Please review!

wpbonelli commented 1 year ago

Thanks much, that looks like a nice solution.