summaryrefslogtreecommitdiffstats
path: root/doc/tutorial
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 11:31:33 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 11:31:33 +0000
commite863fd965dd6253243c3342bd6f0adc4fc8aec4d (patch)
treea4c1b6491a82593950043c3f8b2530e80664d768 /doc/tutorial
parentInitial commit. (diff)
downloadsphinx-upstream.tar.xz
sphinx-upstream.zip
Adding upstream version 5.3.0.upstream/5.3.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'doc/tutorial')
-rw-r--r--doc/tutorial/automatic-doc-generation.rst165
-rw-r--r--doc/tutorial/deploying.rst279
-rw-r--r--doc/tutorial/describing-code.rst276
-rw-r--r--doc/tutorial/end.rst6
-rw-r--r--doc/tutorial/first-steps.rst92
-rw-r--r--doc/tutorial/getting-started.rst120
-rw-r--r--doc/tutorial/index.rst39
-rw-r--r--doc/tutorial/more-sphinx-customization.rst78
-rw-r--r--doc/tutorial/narrative-documentation.rst130
9 files changed, 1185 insertions, 0 deletions
diff --git a/doc/tutorial/automatic-doc-generation.rst b/doc/tutorial/automatic-doc-generation.rst
new file mode 100644
index 0000000..b47673d
--- /dev/null
+++ b/doc/tutorial/automatic-doc-generation.rst
@@ -0,0 +1,165 @@
+Automatic documentation generation from code
+============================================
+
+In the :ref:`previous section <tutorial-describing-objects>` of the tutorial
+you manually documented a Python function in Sphinx. However, the description
+was out of sync with the code itself, since the function signature was not
+the same. Besides, it would be nice to reuse :pep:`Python docstrings
+<257#what-is-a-docstring>` in the documentation, rather than having to write
+the information in two places.
+
+Fortunately, :doc:`the autodoc extension </usage/extensions/autodoc>` provides this
+functionality.
+
+Reusing signatures and docstrings with autodoc
+----------------------------------------------
+
+To use autodoc, first add it to the list of enabled extensions:
+
+.. code-block:: python
+ :caption: docs/source/conf.py
+ :emphasize-lines: 4
+
+ extensions = [
+ 'sphinx.ext.duration',
+ 'sphinx.ext.doctest',
+ 'sphinx.ext.autodoc',
+ ]
+
+Next, move the content of the ``.. py:function`` directive to the function
+docstring in the original Python file, as follows:
+
+.. code-block:: python
+ :caption: lumache.py
+ :emphasize-lines: 2-11
+
+ def get_random_ingredients(kind=None):
+ """
+ Return a list of random ingredients as strings.
+
+ :param kind: Optional "kind" of ingredients.
+ :type kind: list[str] or None
+ :raise lumache.InvalidKindError: If the kind is invalid.
+ :return: The ingredients list.
+ :rtype: list[str]
+
+ """
+ return ["shells", "gorgonzola", "parsley"]
+
+Finally, replace the ``.. py:function`` directive from the Sphinx documentation
+with :rst:dir:`autofunction`:
+
+.. code-block:: rst
+ :caption: docs/source/usage.rst
+ :emphasize-lines: 3
+
+ you can use the ``lumache.get_random_ingredients()`` function:
+
+ .. autofunction:: lumache.get_random_ingredients
+
+If you now build the HTML documentation, the output will be the same!
+With the advantage that it is generated from the code itself.
+Sphinx took the reStructuredText from the docstring and included it,
+also generating proper cross-references.
+
+You can also autogenerate documentation from other objects. For example, add
+the code for the ``InvalidKindError`` exception:
+
+.. code-block:: python
+ :caption: lumache.py
+
+ class InvalidKindError(Exception):
+ """Raised if the kind is invalid."""
+ pass
+
+And replace the ``.. py:exception`` directive with :rst:dir:`autoexception`
+as follows:
+
+.. code-block:: rst
+ :caption: docs/source/usage.rst
+ :emphasize-lines: 4
+
+ or ``"veggies"``. Otherwise, :py:func:`lumache.get_random_ingredients`
+ will raise an exception.
+
+ .. autoexception:: lumache.InvalidKindError
+
+And again, after running ``make html``, the output will be the same as before.
+
+Generating comprehensive API references
+---------------------------------------
+
+While using ``sphinx.ext.autodoc`` makes keeping the code and the documentation
+in sync much easier, it still requires you to write an ``auto*`` directive
+for every object you want to document. Sphinx provides yet another level of
+automation: the :doc:`autosummary </usage/extensions/autosummary>` extension.
+
+The :rst:dir:`autosummary` directive generates documents that contain all the
+necessary ``autodoc`` directives. To use it, first enable the autosummary
+extension:
+
+.. code-block:: python
+ :caption: docs/source/conf.py
+ :emphasize-lines: 5
+
+ extensions = [
+ 'sphinx.ext.duration',
+ 'sphinx.ext.doctest',
+ 'sphinx.ext.autodoc',
+ 'sphinx.ext.autosummary',
+ ]
+
+Next, create a new ``api.rst`` file with these contents:
+
+.. code-block:: rst
+ :caption: docs/source/api.rst
+
+ API
+ ===
+
+ .. autosummary::
+ :toctree: generated
+
+ lumache
+
+Remember to include the new document in the root toctree:
+
+.. code-block:: rst
+ :caption: docs/source/index.rst
+ :emphasize-lines: 7
+
+ Contents
+ --------
+
+ .. toctree::
+
+ usage
+ api
+
+Finally, after you build the HTML documentation running ``make html``, it will
+contain two new pages:
+
+- ``api.html``, corresponding to ``docs/source/api.rst`` and containing a table
+ with the objects you included in the ``autosummary`` directive (in this case,
+ only one).
+- ``generated/lumache.html``, corresponding to a newly created reST file
+ ``generated/lumache.rst`` and containing a summary of members of the module,
+ in this case one function and one exception.
+
+.. figure:: /_static/tutorial/lumache-autosummary.png
+ :width: 80%
+ :align: center
+ :alt: Summary page created by autosummary
+
+ Summary page created by autosummary
+
+Each of the links in the summary page will take you to the places where you
+originally used the corresponding ``autodoc`` directive, in this case in the
+``usage.rst`` document.
+
+.. note::
+
+ The generated files are based on `Jinja2
+ templates <https://jinja2docs.readthedocs.io/>`_ that
+ :ref:`can be customized <autosummary-customizing-templates>`,
+ but that is out of scope for this tutorial.
diff --git a/doc/tutorial/deploying.rst b/doc/tutorial/deploying.rst
new file mode 100644
index 0000000..76b68c3
--- /dev/null
+++ b/doc/tutorial/deploying.rst
@@ -0,0 +1,279 @@
+Appendix: Deploying a Sphinx project online
+===========================================
+
+When you are ready to show your documentation project to the world, there are
+many options available to do so. Since the HTML generated by Sphinx is static,
+you can decouple the process of building your HTML documentation from hosting
+such files in the platform of your choice. You will not need a sophisticated
+server running Python: virtually every web hosting service will suffice.
+
+Therefore, the challenge is less how or where to serve the static HTML, but
+rather how to pick a workflow that automatically updates the deployed
+documentation every time there is a change in the source files.
+
+The following sections describe some of the available options to deploy
+your online documentation, and give some background information. If you want
+to go directly to the practical part, you can skip to :ref:`publishing-sources`.
+
+Sphinx-friendly deployment options
+----------------------------------
+
+There are several possible options you have to host your Sphinx documentation.
+Some of them are:
+
+**Read the Docs**
+ `Read the Docs`_ is an online service specialized in hosting technical
+ documentation written in Sphinx, as well as MkDocs. They have a
+ number of extra features, such as versioned documentation, traffic and
+ search analytics, custom domains, user-defined redirects, and more.
+
+**GitHub Pages**
+ `GitHub Pages`_ is a simple static web hosting tightly integrated with
+ `GitHub`_: static HTML is served from one of the branches of a project,
+ and usually sources are stored in another branch so that the output
+ can be updated every time the sources change (for example using `GitHub
+ Actions`_). It is free to use and supports custom domains.
+
+**GitLab Pages**
+ `GitLab Pages`_ is a similar concept to GitHub Pages, integrated with
+ `GitLab`_ and usually automated with `GitLab CI`_ instead.
+
+**Netlify**
+ `Netlify`_ is a sophisticated hosting for static sites enhanced by
+ client-side web technologies like JavaScript (so-called `"Jamstack"`_).
+ They offer support for headless content management systems and
+ serverless computing.
+
+**Your own server**
+ You can always use your own web server to host Sphinx HTML documentation.
+ It is the option that gives more flexibility, but also more complexity.
+
+All these options have zero cost, with the option of paying for extra features.
+
+.. _Read the Docs: https://readthedocs.org/
+.. _GitHub Pages: https://pages.github.com/
+.. _GitHub: https://github.com/
+.. _GitHub Actions: https://github.com/features/actions
+.. _GitLab Pages: https://about.gitlab.com/stages-devops-lifecycle/pages/
+.. _GitLab: https://gitlab.com/
+.. _GitLab CI: https://about.gitlab.com/stages-devops-lifecycle/continuous-integration/
+.. _Netlify: https://www.netlify.com/
+.. _"Jamstack": https://jamstack.org/
+
+Embracing the "Docs as Code" philosophy
+---------------------------------------
+
+The free offerings of most of the options listed above require your
+documentation sources to be publicly available. Moreover, these services
+expect you to use a `Version Control System`_, a technology that tracks the
+evolution of a collection of files as a series of snapshots ("commits").
+The practice of writing documentation in plain text files with the same tools
+as the ones used for software development is commonly known as `"Docs as Code"`_.
+
+The most popular Version Control System nowadays is Git_, a free and open
+source tool that is the backbone of services like GitHub and GitLab.
+Since both Read the Docs and Netlify have integrations with GitHub and GitLab,
+and both GitHub and GitLab have an integrated Pages product, the most effective
+way of automatically build your documentation online is to upload your sources
+to either of these Git hosting services.
+
+.. _Version Control System: https://en.wikipedia.org/wiki/Version_control
+.. _"Docs as Code": https://www.writethedocs.org/guide/docs-as-code/
+.. _Git: https://git-scm.com/
+
+.. _publishing-sources:
+
+Publishing your documentation sources
+-------------------------------------
+
+GitHub
+~~~~~~
+
+The quickest way to upload an existing project to GitHub is to:
+
+1. `Sign up for a GitHub account <https://github.com/signup>`_.
+2. `Create a new repository <https://github.com/new>`_.
+3. Open `the "Upload files" page`_ of your new repository.
+4. Select the files on your operating system file browser (in your case
+ ``README.rst``, ``lumache.py``, the makefiles under the ``docs`` directory,
+ and everything under ``docs/source``) and drag them to the GitHub interface
+ to upload them all.
+5. Click on the :guilabel:`Commit changes` button.
+
+.. _the "Upload files" page: https://docs.github.com/en/repositories/working-with-files/managing-files/adding-a-file-to-a-repository
+
+.. note::
+
+ Make sure you don't upload the ``docs/build`` directory, as it contains the
+ output generated by Sphinx and it will change every time you change the
+ sources, complicating your workflow.
+
+These steps do not require access to the command line or installing any
+additional software. To learn more, you can:
+
+- Follow `this interactive GitHub course`_ to learn more about how the GitHub
+ interface works.
+- Read `this quickstart tutorial`_ to install extra software on your machine
+ and have more flexibility. You can either use the Git command line, or the
+ GitHub Desktop application.
+
+.. _this interactive GitHub course: https://lab.github.com/githubtraining/introduction-to-github
+.. _this quickstart tutorial: https://docs.github.com/en/get-started/quickstart
+
+GitLab
+~~~~~~
+
+Similarly to GitHub, the fastest way to upload your project to GitLab is
+using the web interface:
+
+1. `Sign up for a GitLab account <https://gitlab.com/users/sign_up>`_.
+2. `Create a new blank project <https://gitlab.com/projects/new>`_.
+3. Upload the project files (in your case ``README.rst``, ``lumache.py``, the
+ makefiles under the ``docs`` directory, and everything under
+ ``docs/source``) one by one using the :guilabel:`Upload File` button [#f1]_.
+
+Again, these steps do not require additional software on your computer. To
+learn more, you can:
+
+- Follow `this tutorial`_ to install Git on your machine.
+- Browse the `GitLab User documentation`_ to understand the possibilities of
+ the platform.
+
+.. _this tutorial: https://docs.gitlab.com/ee/gitlab-basics/start-using-git.html
+.. _GitLab User documentation: https://docs.gitlab.com/ee/user/index.html
+
+.. note::
+
+ Make sure you don't upload the ``docs/build`` directory, as it contains the
+ output generated by Sphinx and it will change every time you change the
+ sources, complicating your workflow.
+
+.. [#f1] At the time of writing, `uploading whole directories to GitLab using
+ only the web
+ interface <https://gitlab.com/gitlab-org/gitlab/-/issues/228490>`_ is
+ not yet implemented.
+
+Publishing your HTML documentation
+----------------------------------
+
+Read the Docs
+~~~~~~~~~~~~~
+
+`Read the Docs`_ offers integration with both GitHub and GitLab. The quickest
+way of getting started is to follow :doc:`the RTD
+tutorial <readthedocs:tutorial/index>`, which is loosely based on this one.
+You can publish your sources on GitHub as explained :ref:`in the previous
+section <publishing-sources>`, then skip directly to
+:ref:`readthedocs:tutorial/index:Sign up for Read the Docs`.
+If you choose GitLab instead, the process is similar.
+
+GitHub Pages
+~~~~~~~~~~~~
+
+`GitHub Pages`_ requires you to :ref:`publish your
+sources <publishing-sources>` on `GitHub`_. After that, you will need an
+automated process that performs the ``make html`` step every time the sources
+change. That can be achieved using `GitHub Actions`_.
+
+After you have published your sources on GitHub, create a file named
+``.github/workflows/sphinx.yml`` in your repository with the following
+contents:
+
+.. code-block:: yaml
+ :caption: .github/workflows/
+
+ name: Sphinx build
+
+ on: push
+
+ jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - name: Build HTML
+ uses: ammaraskar/sphinx-action@master
+ - name: Upload artifacts
+ uses: actions/upload-artifact@v3
+ with:
+ name: html-docs
+ path: docs/build/html/
+ - name: Deploy
+ uses: peaceiris/actions-gh-pages@v3
+ if: github.ref == 'refs/heads/main'
+ with:
+ github_token: ${{ secrets.GITHUB_TOKEN }}
+ publish_dir: docs/build/html
+
+This contains a GitHub Actions workflow with a single job of four steps:
+
+1. Checkout the code.
+2. Build the HTML documentation using Sphinx.
+3. Attach the HTML output the artifacts to the GitHub Actions job, for easier
+ inspection.
+4. If the change happens on the default branch, take the contents of
+ ``docs/build/html`` and push it to the ``gh-pages`` branch.
+
+Next, you need to specify the dependencies for the ``make html`` step to be
+successful. For that, create a file ``docs/requirements.txt`` and add the
+following contents:
+
+.. code-block::
+ :caption: docs/requirements.txt
+
+ furo==2021.11.16
+
+And finally, you are ready to `enable GitHub Pages on your repository`_. For
+that, go to :guilabel:`Settings`, then :guilabel:`Pages` on the left sidebar,
+select the ``gh-pages`` branch in the "Source" dropdown menu, and click
+:guilabel:`Save`. After a few minutes, you should be able to see your HTML at
+the designated URL.
+
+.. _enable GitHub Pages on your repository: https://docs.github.com/en/pages/getting-started-with-github-pages/configuring-a-publishing-source-for-your-github-pages-site
+
+GitLab Pages
+~~~~~~~~~~~~
+
+`GitLab Pages`_, on the other hand, requires you to :ref:`publish your
+sources <publishing-sources>` on `GitLab`_. When you are ready, you can
+automate the process of running ``make html`` using `GitLab CI`_.
+
+After you have published your sources on GitLab, create a file named
+``.gitlab-ci.yml`` in your repository with these contents:
+
+.. code-block:: yaml
+ :caption: .gitlab-ci.yml
+
+ stages:
+ - deploy
+
+ pages:
+ stage: deploy
+ image: python:3.9-slim
+ before_script:
+ - apt-get update && apt-get install make --no-install-recommends -y
+ - python -m pip install sphinx furo
+ script:
+ - cd docs && make html
+ after_script:
+ - mv docs/build/html/ ./public/
+ artifacts:
+ paths:
+ - public
+ rules:
+ - if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH
+
+This contains a GitLab CI workflow with one job of several steps:
+
+1. Install the necessary dependencies.
+2. Build the HTML documentation using Sphinx.
+3. Move the output to a known artifacts location.
+
+.. note::
+ You will need to `validate your account`_ by entering a payment method
+ (you will be charged a small amount that will then be reimbursed).
+
+.. _validate your account: https://about.gitlab.com/blog/2021/05/17/prevent-crypto-mining-abuse/#validating-an-account
+
+After that, if the pipeline is successful, you should be able to see your HTML
+at the designated URL.
diff --git a/doc/tutorial/describing-code.rst b/doc/tutorial/describing-code.rst
new file mode 100644
index 0000000..24fea38
--- /dev/null
+++ b/doc/tutorial/describing-code.rst
@@ -0,0 +1,276 @@
+Describing code in Sphinx
+=========================
+
+In the :doc:`previous sections of the tutorial </tutorial/index>` you can read
+how to write narrative or prose documentation in Sphinx. In this section you
+will describe code objects instead.
+
+Sphinx supports documenting code objects in several languages, namely Python,
+C, C++, JavaScript, and reStructuredText. Each of them can be documented using
+a series of directives and roles grouped by
+:doc:`domain </usage/restructuredtext/domains>`. For the remainder of the
+tutorial you will use the Python domain, but all the concepts seen in this
+section apply for the other domains as well.
+
+.. _tutorial-describing-objects:
+
+Python
+------
+
+Documenting Python objects
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Sphinx offers several roles and directives to document Python objects,
+all grouped together in :ref:`the Python domain <python-domain>`. For example,
+you can use the :rst:dir:`py:function` directive to document a Python function,
+as follows:
+
+.. code-block:: rst
+ :caption: docs/source/usage.rst
+
+ Creating recipes
+ ----------------
+
+ To retrieve a list of random ingredients,
+ you can use the ``lumache.get_random_ingredients()`` function:
+
+ .. py:function:: lumache.get_random_ingredients(kind=None)
+
+ Return a list of random ingredients as strings.
+
+ :param kind: Optional "kind" of ingredients.
+ :type kind: list[str] or None
+ :return: The ingredients list.
+ :rtype: list[str]
+
+Which will render like this:
+
+.. figure:: /_static/tutorial/lumache-py-function.png
+ :width: 80%
+ :align: center
+ :alt: HTML result of documenting a Python function in Sphinx
+
+ The rendered result of documenting a Python function in Sphinx
+
+Notice several things:
+
+- Sphinx parsed the argument of the ``.. py:function`` directive and
+ highlighted the module, the function name, and the parameters appropriately.
+- The directive content includes a one-line description of the function,
+ as well as an :ref:`info field list <info-field-lists>` containing the function
+ parameter, its expected type, the return value, and the return type.
+
+.. note::
+
+ The ``py:`` prefix specifies the :term:`domain`. You may configure the
+ default domain so you can omit the prefix, either globally using the
+ :confval:`primary_domain` configuration, or use the
+ :rst:dir:`default-domain` directive to change it from the point it is called
+ until the end of the file.
+ For example, if you set it to ``py`` (the default), you can write
+ ``.. function::`` directly.
+
+Cross-referencing Python objects
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+By default, most of these directives generate entities that can be
+cross-referenced from any part of the documentation by using
+:ref:`a corresponding role <python-roles>`. For the case of functions,
+you can use :rst:role:`py:func` for that, as follows:
+
+.. code-block:: rst
+ :caption: docs/source/usage.rst
+
+ The ``kind`` parameter should be either ``"meat"``, ``"fish"``,
+ or ``"veggies"``. Otherwise, :py:func:`lumache.get_random_ingredients`
+ will raise an exception.
+
+When generating code documentation, Sphinx will generate a
+cross-reference automatically just by using the name of the object,
+without you having to explicitly use a role for that. For example, you
+can describe the custom exception raised by the function using the
+:rst:dir:`py:exception` directive:
+
+.. code-block:: rst
+ :caption: docs/source/usage.rst
+
+ .. py:exception:: lumache.InvalidKindError
+
+ Raised if the kind is invalid.
+
+Then, add this exception to the original description of the function:
+
+.. code-block:: rst
+ :caption: docs/source/usage.rst
+ :emphasize-lines: 7
+
+ .. py:function:: lumache.get_random_ingredients(kind=None)
+
+ Return a list of random ingredients as strings.
+
+ :param kind: Optional "kind" of ingredients.
+ :type kind: list[str] or None
+ :raise lumache.InvalidKindError: If the kind is invalid.
+ :return: The ingredients list.
+ :rtype: list[str]
+
+And finally, this is how the result would look:
+
+.. figure:: /_static/tutorial/lumache-py-function-full.png
+ :width: 80%
+ :align: center
+ :alt: HTML result of documenting a Python function in Sphinx
+ with cross-references
+
+ HTML result of documenting a Python function in Sphinx with cross-references
+
+Beautiful, isn't it?
+
+Including doctests in your documentation
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Since you are now describing code from a Python library, it will become useful
+to keep both the documentation and the code as synchronized as possible.
+One of the ways to do that in Sphinx is to include code snippets in the
+documentation, called *doctests*, that are executed when the documentation is
+built.
+
+To demonstrate doctests and other Sphinx features covered in this tutorial,
+Sphinx will need to be able to import the code. To achieve that, write this
+at the beginning of ``conf.py``:
+
+.. code-block:: python
+ :caption: docs/source/conf.py
+ :emphasize-lines: 3-5
+
+ # If extensions (or modules to document with autodoc) are in another directory,
+ # add these directories to sys.path here.
+ import pathlib
+ import sys
+ sys.path.insert(0, pathlib.Path(__file__).parents[2].resolve().as_posix())
+
+.. note::
+
+ An alternative to changing the :py:data:`sys.path` variable is to create a
+ ``pyproject.toml`` file and make the code installable,
+ so it behaves like any other Python library. However, the ``sys.path``
+ approach is simpler.
+
+Then, before adding doctests to your documentation, enable the
+:doc:`doctest </usage/extensions/doctest>` extension in ``conf.py``:
+
+.. code-block:: python
+ :caption: docs/source/conf.py
+ :emphasize-lines: 3
+
+ extensions = [
+ 'sphinx.ext.duration',
+ 'sphinx.ext.doctest',
+ ]
+
+Next, write a doctest block as follows:
+
+.. code-block:: rst
+ :caption: docs/source/usage.rst
+
+ >>> import lumache
+ >>> lumache.get_random_ingredients()
+ ['shells', 'gorgonzola', 'parsley']
+
+Doctests include the Python instructions to be run preceded by ``>>>``,
+the standard Python interpreter prompt, as well as the expected output
+of each instruction. This way, Sphinx can check whether the actual output
+matches the expected one.
+
+To observe how a doctest failure looks like (rather than a code error as
+above), let's write the return value incorrectly first. Therefore, add a
+function ``get_random_ingredients`` like this:
+
+.. code-block:: python
+ :caption: lumache.py
+
+ def get_random_ingredients(kind=None):
+ return ["eggs", "bacon", "spam"]
+
+You can now run ``make doctest`` to execute the doctests of your documentation.
+Initially this will display an error, since the actual code does not behave
+as specified:
+
+.. code-block:: console
+
+ (.venv) $ make doctest
+ Running Sphinx v4.2.0
+ loading pickled environment... done
+ ...
+ running tests...
+
+ Document: usage
+ ---------------
+ **********************************************************************
+ File "usage.rst", line 44, in default
+ Failed example:
+ lumache.get_random_ingredients()
+ Expected:
+ ['shells', 'gorgonzola', 'parsley']
+ Got:
+ ['eggs', 'bacon', 'spam']
+ **********************************************************************
+ ...
+ make: *** [Makefile:20: doctest] Error 1
+
+As you can see, doctest reports the expected and the actual results,
+for easy examination. It is now time to fix the function:
+
+.. code-block:: python
+ :caption: lumache.py
+ :emphasize-lines: 2
+
+ def get_random_ingredients(kind=None):
+ return ["shells", "gorgonzola", "parsley"]
+
+And finally, ``make test`` reports success!
+
+For big projects though, this manual approach can become a bit tedious.
+In the next section, you will see :doc:`how to automate the
+process </tutorial/automatic-doc-generation>`.
+
+Other languages (C, C++, others)
+--------------------------------
+
+Documenting and cross-referencing objects
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Sphinx also supports documenting and cross-referencing objects written in
+other programming languages. There are four additional built-in domains:
+C, C++, JavaScript, and reStructuredText. Third-party extensions may
+define domains for more languages, such as
+
+- `Fortran <https://sphinx-fortran.readthedocs.io>`_,
+- `Julia <http://bastikr.github.io/sphinx-julia>`_, or
+- `PHP <https://github.com/markstory/sphinxcontrib-phpdomain>`_.
+
+For example, to document a C++ type definition, you would use the built-in
+:rst:dir:`cpp:type` directive, as follows:
+
+.. code-block:: rst
+
+ .. cpp:type:: std::vector<int> CustomList
+
+ A typedef-like declaration of a type.
+
+Which would give the following result:
+
+.. cpp:type:: std::vector<int> CustomList
+
+ A typedef-like declaration of a type.
+
+All such directives then generate references that can be
+cross-referenced by using the corresponding role. For example, to reference
+the previous type definition, you can use the :rst:role:`cpp:type` role
+as follows:
+
+.. code-block:: rst
+
+ Cross reference to :cpp:type:`CustomList`.
+
+Which would produce a hyperlink to the previous definition: :cpp:type:`CustomList`.
diff --git a/doc/tutorial/end.rst b/doc/tutorial/end.rst
new file mode 100644
index 0000000..9f35b07
--- /dev/null
+++ b/doc/tutorial/end.rst
@@ -0,0 +1,6 @@
+Where to go from here
+=====================
+
+This tutorial covered the very first steps to create a documentation project
+with Sphinx. To continue learning more about Sphinx, check out the `rest of the
+documentation <../contents.html>`__.
diff --git a/doc/tutorial/first-steps.rst b/doc/tutorial/first-steps.rst
new file mode 100644
index 0000000..fd5c631
--- /dev/null
+++ b/doc/tutorial/first-steps.rst
@@ -0,0 +1,92 @@
+First steps to document your project using Sphinx
+=================================================
+
+Building your HTML documentation
+--------------------------------
+
+The ``index.rst`` file that ``sphinx-quickstart`` created has some content
+already, and it gets rendered as the front page of your HTML documentation. It
+is written in reStructuredText, a powerful markup language.
+
+Modify the file as follows:
+
+.. code-block:: rst
+ :caption: docs/source/index.rst
+
+ Welcome to Lumache's documentation!
+ ===================================
+
+ **Lumache** (/lu'make/) is a Python library for cooks and food lovers that
+ creates recipes mixing random ingredients. It pulls data from the `Open Food
+ Facts database <https://world.openfoodfacts.org/>`_ and offers a *simple* and
+ *intuitive* API.
+
+ .. note::
+
+ This project is under active development.
+
+This showcases several features of the reStructuredText syntax, including:
+
+- a **section header** using ``===`` for the underline,
+- two examples of :ref:`rst-inline-markup`: ``**strong emphasis**`` (typically
+ bold) and ``*emphasis*`` (typically italics),
+- an **inline external link**,
+- and a ``note`` **admonition** (one of the available :ref:`directives
+ <rst-directives>`)
+
+Now to render it with the new content, you can use the ``sphinx-build`` command
+as before, or leverage the convenience script as follows:
+
+.. code-block:: console
+
+ (.venv) $ cd docs
+ (.venv) $ make html
+
+After running this command, you will see that ``index.html`` reflects the new
+changes!
+
+Building your documentation in other formats
+--------------------------------------------
+
+Sphinx supports a variety of formats apart from HTML, including PDF, EPUB,
+:ref:`and more <builders>`. For example, to build your documentation
+in EPUB format, run this command from the ``docs`` directory:
+
+.. code-block:: console
+
+ (.venv) $ make epub
+
+After that, you will see the files corresponding to the e-book under
+``docs/build/epub/``. You can either open ``Lumache.epub`` with an
+EPUB-compatible e-book viewer, like `Calibre <https://calibre-ebook.com/>`_,
+or preview ``index.xhtml`` on a web browser.
+
+.. note::
+
+ To quickly display a complete list of possible output formats, plus some
+ extra useful commands, you can run :code:`make help`.
+
+Each output format has some specific configuration options that you can tune,
+:ref:`including EPUB <epub-options>`. For instance, the default value of
+:confval:`epub_show_urls` is ``inline``, which means that, by default, URLs are
+shown right after the corresponding link, in parentheses. You can change that
+behavior by adding the following code at the end of your ``conf.py``:
+
+.. code-block:: python
+
+ # EPUB options
+ epub_show_urls = 'footnote'
+
+With this configuration value, and after running ``make epub`` again, you will
+notice that URLs appear now as footnotes, which avoids cluttering the text.
+Sweet! Read on to explore :doc:`other ways to customize
+Sphinx </tutorial/more-sphinx-customization>`.
+
+.. note::
+
+ Generating a PDF using Sphinx can be done running ``make latexpdf``,
+ provided that the system has a working LaTeX installation,
+ as explained in the documentation of :class:`sphinx.builders.latex.LaTeXBuilder`.
+ Although this is perfectly feasible, such installations are often big,
+ and in general LaTeX requires careful configuration in some cases,
+ so PDF generation is out of scope for this tutorial.
diff --git a/doc/tutorial/getting-started.rst b/doc/tutorial/getting-started.rst
new file mode 100644
index 0000000..5cf0b38
--- /dev/null
+++ b/doc/tutorial/getting-started.rst
@@ -0,0 +1,120 @@
+Getting started
+===============
+
+Setting up your project and development environment
+---------------------------------------------------
+
+In a new directory, create a file called ``README.rst`` with the following
+content.
+
+.. code-block:: rst
+ :caption: README.rst
+
+ Lumache
+ =======
+
+ **Lumache** (/lu'make/) is a Python library for cooks and food lovers that
+ creates recipes mixing random ingredients.
+
+It is a good moment to create a Python virtual environment and install the
+required tools. For that, open a command line terminal, ``cd`` into the
+directory you just created, and run the following commands:
+
+.. code-block:: console
+
+ $ python -m venv .venv
+ $ source .venv/bin/activate
+ (.venv) $ python -m pip install sphinx
+
+.. note::
+
+ The installation method used above is described in more detail in
+ :ref:`install-pypi`. For the rest of this tutorial, the instructions will
+ assume a Python virtual environment.
+
+If you executed these instructions correctly, you should have the Sphinx command
+line tools available. You can do a basic verification running this command:
+
+.. code-block:: console
+
+ (.venv) $ sphinx-build --version
+ sphinx-build 4.0.2
+
+If you see a similar output, you are on the right path!
+
+Creating the documentation layout
+---------------------------------
+
+Then from the command line, run the following command:
+
+.. code-block:: console
+
+ (.venv) $ sphinx-quickstart docs
+
+This will present to you a series of questions required to create the basic
+directory and configuration layout for your project inside the ``docs`` folder.
+To proceed, answer each question as follows:
+
+- ``> Separate source and build directories (y/n) [n]``: Write "``y``" (without
+ quotes) and press :kbd:`Enter`.
+- ``> Project name``: Write "``Lumache``" (without quotes) and press
+ :kbd:`Enter`.
+- ``> Author name(s)``: Write "``Graziella``" (without quotes) and press
+ :kbd:`Enter`.
+- ``> Project release []``: Write "``0.1``" (without quotes) and press
+ :kbd:`Enter`.
+- ``> Project language [en]``: Leave it empty (the default, English) and press
+ :kbd:`Enter`.
+
+After the last question, you will see the new ``docs`` directory with the
+following content.
+
+.. code-block:: text
+
+ docs
+ ├── build
+ ├── make.bat
+ ├── Makefile
+ └── source
+ ├── conf.py
+ ├── index.rst
+ ├── _static
+ └── _templates
+
+The purpose of each of these files is:
+
+``build/``
+ An empty directory (for now) that will hold the rendered documentation.
+
+``make.bat`` and ``Makefile``
+ Convenience scripts to simplify some common Sphinx operations, such as
+ rendering the content.
+
+``source/conf.py``
+ A Python script holding the configuration of the Sphinx project. It contains
+ the project name and release you specified to ``sphinx-quickstart``, as well
+ as some extra configuration keys.
+
+``source/index.rst``
+ The :term:`root document` of the project, which serves as welcome page and
+ contains the root of the "table of contents tree" (or *toctree*).
+
+Thanks to this bootstrapping step, you already have everything needed to render
+the documentation as HTML for the first time. To do that, run this command:
+
+.. code-block:: console
+
+ (.venv) $ sphinx-build -b html docs/source/ docs/build/html
+
+And finally, open ``docs/build/html/index.html`` in your browser. You should see
+something like this:
+
+.. figure:: /_static/tutorial/lumache-first-light.png
+ :width: 80%
+ :align: center
+ :alt: Freshly created documentation of Lumache
+
+ Freshly created documentation of Lumache
+
+There we go! You created your first HTML documentation using Sphinx.
+Now you can start :doc:`customizing it </tutorial/first-steps>`.
diff --git a/doc/tutorial/index.rst b/doc/tutorial/index.rst
new file mode 100644
index 0000000..57a055f
--- /dev/null
+++ b/doc/tutorial/index.rst
@@ -0,0 +1,39 @@
+.. _tutorial:
+
+========================
+Build your first project
+========================
+
+In this tutorial you will build a simple documentation project using Sphinx, and
+view it in your browser as HTML. The project will include narrative,
+handwritten documentation, as well as autogenerated API documentation.
+
+The tutorial is aimed towards Sphinx newcomers willing to learn the fundamentals
+of how projects are created and structured. You will create a fictional
+software library to generate random food recipes that will serve as a guide
+throughout the process, with the objective of properly documenting it.
+
+To showcase Sphinx capabilities for code documentation you will use Python,
+which also supports *automatic* documentation generation.
+
+.. note::
+
+ Several other languages are natively supported in Sphinx for *manual* code
+ documentation, however they require extensions for *automatic* code
+ documentation, like `Breathe <https://breathe.readthedocs.io/>`_.
+
+To follow the instructions you will need access to a Linux-like command line and
+a basic understanding of how it works, as well as a working Python installation
+for development, since you will use *Python virtual environments* to create the
+project.
+
+.. toctree::
+
+ getting-started
+ first-steps
+ more-sphinx-customization
+ narrative-documentation
+ describing-code
+ automatic-doc-generation
+ deploying
+ end
diff --git a/doc/tutorial/more-sphinx-customization.rst b/doc/tutorial/more-sphinx-customization.rst
new file mode 100644
index 0000000..c28263c
--- /dev/null
+++ b/doc/tutorial/more-sphinx-customization.rst
@@ -0,0 +1,78 @@
+More Sphinx customization
+=========================
+
+There are two main ways to customize your documentation beyond what is possible
+with core Sphinx: extensions and themes.
+
+Enabling a built-in extension
+-----------------------------
+
+In addition to these configuration values, you can customize Sphinx even more
+by using :doc:`extensions </usage/extensions/index>`. Sphinx ships several
+:ref:`builtin ones <builtin-extensions>`, and there are many more
+:ref:`maintained by the community <third-party-extensions>`.
+
+For example, to enable the :mod:`sphinx.ext.duration` extension,
+locate the ``extensions`` list in your ``conf.py`` and add one element as
+follows:
+
+.. code-block:: python
+ :caption: docs/source/conf.py
+
+ # Add any Sphinx extension module names here, as strings. They can be
+ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+ # ones.
+ extensions = [
+ 'sphinx.ext.duration',
+ ]
+
+After that, every time you generate your documentation, you will see a short
+durations report at the end of the console output, like this one:
+
+.. code-block:: console
+
+ (.venv) $ make html
+ ...
+ The HTML pages are in build/html.
+
+ ====================== slowest reading durations =======================
+ 0.042 temp/source/index
+
+Using a third-party HTML theme
+------------------------------
+
+Themes, on the other hand, are a way to customize the appearance of your
+documentation. Sphinx has several :ref:`builtin themes <builtin-themes>`, and
+there are also `third-party ones <https://sphinx-themes.org/>`_.
+
+For example, to use the `Furo <https://pradyunsg.me/furo/>`_ third-party theme
+in your HTML documentation, first you will need to install it with ``pip`` in
+your Python virtual environment, like this:
+
+.. code-block:: console
+
+ (.venv) $ pip install furo
+
+And then, locate the ``html_theme`` variable on your ``conf.py`` and replace
+its value as follows:
+
+.. code-block:: python
+ :caption: docs/source/conf.py
+
+ # The theme to use for HTML and HTML Help pages. See the documentation for
+ # a list of builtin themes.
+ #
+ html_theme = 'furo'
+
+With this change, you will notice that your HTML documentation has now a new
+appearance:
+
+.. figure:: /_static/tutorial/lumache-furo.png
+ :width: 80%
+ :align: center
+ :alt: HTML documentation of Lumache with the Furo theme
+
+ HTML documentation of Lumache with the Furo theme
+
+It is now time to :doc:`expand the narrative documentation and split it into
+several documents </tutorial/narrative-documentation>`.
diff --git a/doc/tutorial/narrative-documentation.rst b/doc/tutorial/narrative-documentation.rst
new file mode 100644
index 0000000..a81204d
--- /dev/null
+++ b/doc/tutorial/narrative-documentation.rst
@@ -0,0 +1,130 @@
+Narrative documentation in Sphinx
+=================================
+
+Structuring your documentation across multiple pages
+----------------------------------------------------
+
+The file ``index.rst`` created by ``sphinx-quickstart`` is the :term:`root
+document`, whose main function is to serve as a welcome page and to contain the
+root of the "table of contents tree" (or *toctree*). Sphinx allows you to
+assemble a project from different files, which is helpful when the project
+grows.
+
+As an example, create a new file ``docs/source/usage.rst`` (next to
+``index.rst``) with these contents:
+
+.. code-block:: rst
+ :caption: docs/source/usage.rst
+
+ Usage
+ =====
+
+ Installation
+ ------------
+
+ To use Lumache, first install it using pip:
+
+ .. code-block:: console
+
+ (.venv) $ pip install lumache
+
+This new file contains two :ref:`section <rst-sections>` headers, normal
+paragraph text, and a :rst:dir:`code-block` directive that renders
+a block of content as source code, with appropriate syntax highlighting
+(in this case, generic ``console`` text).
+
+The structure of the document is determined by the succession of heading
+styles, which means that, by using ``---`` for the "Installation" section
+after ``===`` for the "Usage" section, you have declared "Installation" to
+be a *subsection* of "Usage".
+
+To complete the process, add a ``toctree`` :ref:`directive <rst-directives>` at
+the end of ``index.rst`` including the document you just created, as follows:
+
+.. code-block:: rst
+ :caption: docs/source/index.rst
+
+ Contents
+ --------
+
+ .. toctree::
+
+ usage
+
+This step inserts that document in the root of the *toctree*, so now it belongs
+to the structure of your project, which so far looks like this:
+
+.. code-block:: text
+
+ index
+ └── usage
+
+If you build the HTML documentation running ``make html``, you will see
+that the ``toctree`` gets rendered as a list of hyperlinks, and this allows you
+to navigate to the new page you just created. Neat!
+
+.. warning::
+
+ Documents outside a *toctree* will result in ``WARNING: document isn't
+ included in any toctree`` messages during the build process, and will be
+ unreachable for users.
+
+Adding cross-references
+-----------------------
+
+One powerful feature of Sphinx is the ability to seamlessly add
+:ref:`cross-references <xref-syntax>` to specific parts of the documentation:
+a document, a section, a figure, a code object, etc. This tutorial is full of
+them!
+
+To add a cross-reference, write this sentence right after the
+introduction paragraph in ``index.rst``:
+
+.. code-block:: rst
+ :caption: docs/source/index.rst
+
+ Check out the :doc:`usage` section for further information.
+
+The :rst:role:`doc` :ref:`role <rst-roles-alt>` you used automatically
+references a specific document in the project, in this case the ``usage.rst``
+you created earlier.
+
+Alternatively, you can also add a cross-reference to an arbitrary part of the
+project. For that, you need to use the :rst:role:`ref` role, and add an
+explicit *label* that acts as :duref:`a target <hyperlink-targets>`.
+
+For example, to reference the "Installation" subsection, add a label right
+before the heading, as follows:
+
+.. code-block:: rst
+ :caption: docs/source/usage.rst
+ :emphasize-lines: 4
+
+ Usage
+ =====
+
+ .. _installation:
+
+ Installation
+ ------------
+
+ ...
+
+And make the sentence you added in ``index.rst`` look like this:
+
+.. code-block:: rst
+ :caption: docs/source/index.rst
+
+ Check out the :doc:`usage` section for further information, including how to
+ :ref:`install <installation>` the project.
+
+Notice a trick here: the ``install`` part specifies how the link will look like
+(we want it to be a specific word, so the sentence makes sense), whereas the
+``<installation>`` part refers to the actual label we want to add a
+cross-reference to. If you do not include an explicit title, hence using
+``:ref:`installation```, the section title will be used (in this case,
+``Installation``). Both the ``:doc:`` and the ``:ref:`` roles will be rendered
+as hyperlinks in the HTML documentation.
+
+What about :doc:`documenting code objects in Sphinx </tutorial/describing-code>`?
+Read on!