Tutorial

The esbonio.tutorial extension’s aim is to make it easy to export tutorials written as part of your project’s documentation to Jupyter Notebooks allowing the reader to follow along in an interactive environment and further explore for themselves.

With online services such as Binder it’s also possible to create fully interactive online versions of your tutorials allowing the user to just try things out bypassing any (potentially) complicated setup steps.

This extension is available through the esbonio-extensions Python package but the tutorial extra is required due to some additional dependencies.

$ pip install esbonio-extensions[tutorial]

Getting Started

Ensure the extension is enabled by including esbonio.tutorial in your extensions list inside your project’s conf.py:

extensions = [
   "esbonio.tutorial",
]

Tutorials are then written in the same way as you would write any other Sphinx based documentation. Here is a simple “Hello, World!” Python tutorial.

:tutorial: notebook

Hello World
===========

Here is how you print the string ``Hello, World!`` in Python::

   print("Hello, World!")

Note the only thing specific to this extension is the :tutorial: notebook field list at the start of the document to indicate that this document is a tutorial.

This extension includes a Sphinx Builder called tutorial that can then be used to export tutorials as *.ipynb files.

$ sphinx-build -b tutorial docs/ docs/_build/

Inside the docs/_build/tutorial directory, there should then be a hello-world.ipynb file containing the “Hello, World!” tutorial.

Writing Tutorials

Solutions

If you want your tutorials to include exercises that the reader is meant to solve the solution directive can be used to insert solutions.

Solution (click to reveal)
x = 1 + 3
print(x)
.. solution::

Mark the content of the directive as being the solution to a tutorial exercise.

Example

.. solution::

   .. code-block:: python

      x = 1 + 3
      print(x)

Translations

Since the notebook version of the tutorial is generated from your documentation you can also leverage Sphinx’s Internationalization support to produce translated versions of your tutorials!

If you are already familair with producing translated versions of your documentation then the process is almost identicial, just replace your final build step with one that invokes the tutorial builder e.g.

$ SPHINXOPTS=-Dlanguage=cy make tutorial

If you haven’t worked with translations before, here is a brief overview of a potential translation workflow, be sure to check the documentation for details.

  1. Install the sphinx-intl package

    $ pip install sphinx-intl
    
  2. Update your conf.py to specify where to store your translation strings

    locale_dirs = ["locale/"]
    gettext_compact = False    # optional.
    

    See locale_dirs and gettext_compact for more details.

  3. Extract your translation strings from the documentation for each of your target languages

    $ make gettext
    $ sphinx-intl update -p _build/gettext -l cy  # -l fr -l de ... etc.
    

    This will produce a folder locale/<language_code>/LC_MESSAGES for each language you specified containing *.po files ready to be translated.

  4. Translate each of the files in the locale/<language_code>/LC_MESSAGES folder for your language. A *.po file is a long sequence of msgid, msgstr pairs.

    #: ../../extensions/tutorial/hello-world.rst:4
    msgid "Hello World"
    msgstr ""
    

    Each msgid corresponds with the text to be translated, to provide a translation “simply” replace the empty string next to msgstr with the translation for the string above and save the file

    #: ../../extensions/tutorial/hello-world.rst:4
    msgid "Hello World"
    msgstr "Shwmae i gyd"
    
  5. Assuming that you build your docs with something like the default Makefile you can produce a translated build by setting the SPHINXOPTS environment variable to specify the language.

    $ SPHINXOPTS=-Dlanguage=cy make tutorial
    

Deploying Tutorials

Once you’ve written and exported your tutorials, you probably want to make them accessible to your users. Below are a few examples on ways you could distribute them.

Local

Perhaps the most straightforward way is to package the tutorial alongside your project. You could then provide a cli command that will automate the process of copying the tutorial into a location on the user’s machine and starting up a Jupyter Lab instance.

Packaging

The exported tutorial can be bundled in your Python package using the Data Files support built into setuptools. This requires you to add the following flag to your setup.cfg (or setup.py) file

[options]
include_package_data = True

Additionally you need to specify the folder(s) to include in your MANIFEST.in file (create one in the same folder as your setup.cfg) file if you don’t have one already). To use the esbonio-extensions package as an example, you would add the following line

recursive-include esbonio/tutorial/demo *

If it’s setup correctly, you should see your tutorial files listed in the build output when you run

$ python setup.py sdist bdist_wheel
...
adding 'esbonio/tutorial/__init__.py'
adding 'esbonio/tutorial/__main__.py'
adding 'esbonio/tutorial/commands.py'
adding 'esbonio/tutorial/demo/extensions/tutorial/formatting-example.ipynb'
adding 'esbonio/tutorial/demo/extensions/tutorial/hello-world.ipynb'
adding 'esbonio/tutorial/demo/extensions/tutorial/solution-example.ipynb'
adding 'esbonio/tutorial/demo/resources/extensions/tutorial/formatting-example/vscode-screenshot.png'
adding 'esbonio/tutorial/demo/resources/extensions/tutorial/solution-example/solution-example-soln-01.py'
adding 'esbonio/tutorial/demo/resources/extensions/tutorial/solution-example/solution-example-soln-02.py'
adding 'esbonio/tutorial/demo/resources/extensions/tutorial/solution-example/solution-example-soln-03.py'
adding 'esbonio_extensions-0.0.2.dist-info/LICENSE'
adding 'esbonio_extensions-0.0.2.dist-info/METADATA'
adding 'esbonio_extensions-0.0.2.dist-info/WHEEL'
adding 'esbonio_extensions-0.0.2.dist-info/top_level.txt'
adding 'esbonio_extensions-0.0.2.dist-info/RECORD'

Examples