jupyter / jupyter-sphinx

Sphinx extension for rendering of Jupyter interactive widgets.
https://jupyter-sphinx.readthedocs.io/
BSD 3-Clause "New" or "Revised" License
188 stars 65 forks source link

Configurable pre-notebook cell #211

Open ryandvmartin opened 2 years ago

ryandvmartin commented 2 years ago

This is an excellent project and has proven very useful, but in some environments we end up having a lot of boilerplate required to setup the notebook before things are run, which gets repeated throughout the codebase when kernels are reset.

To avoid having the hidden block in multiple places:

.. jupyter-kernel:: python3

.. jupyter-execute::
    :hide-code:

    import setup
    setup()

.. jupyter-execute::

    # example code goes here

Instead it would be nice to configure some constant setup cell that is inserted at the top of the notebook

conf.py:

jupyter_execute_pre_notebook = "import setup\nsetup()"

Then all execute blocks are already setup without the extra boilerplate:

.. jupyter-kernel:: python3

.. jupyter-execute::

    # example code goes here
moorepants commented 1 year ago

I'd use this addition. I also have a hidden cell at the top of all of my pages that are identical. How will this look in the latex versions? The hidden cells seem to not be hidden in latex.

akhmerov commented 10 months ago

I thought a bit more about this beyond what I wrote recently in https://github.com/jupyter/jupyter-sphinx/issues/235#issuecomment-1850983358. Adding standard initialization code is a feature users often request, and therefore it makes sense to consider the functionality for executing initialization code everywhere.

On the other hand, this functionality is unusual: I can't think of other tools in the Python, Jupyter, or Sphinx world that do something alike. The amount of code saved is also not too big—it's four lines per kernel, and this also makes the source easier to understand because anyone editing will see where the initialization comes from.

In order to identify a proper way forward, it is worth to consider corner cases and interactions with other jupyter-sphinx features. Here's are some of these questions:

Based on the above, I would say that the initialization code should be added within sphinx, rather than to the notebook, as done in this PR. There's already functionality for finding which Jupyter cell node belongs to which notebook (split_by_notebook) in the source code, so it seems that inserting initialization nodes before the first notebook cell would work well.

This still does not address the considerations about the different use cases and configurations, though. It seems that there may be very different use cases, and adding a lot of configuration upfront seems to add complexity that isn't compensated by the added convenience.

As a reasonable middle ground I propose to document how to achieve this by using a small sphinx Transform. It would insert the initialization node into the doctree before every first notebook cell. We could add this transform to the docs together with instructions on how to include it in conf.py. Further down the line, if the configuration becomes clear, we could move that transform to the library itself.

Does that sound reasonable?