diff options
Diffstat (limited to 'doc/tutorial')
-rw-r--r-- | doc/tutorial/automatic-doc-generation.rst | 165 | ||||
-rw-r--r-- | doc/tutorial/deploying.rst | 279 | ||||
-rw-r--r-- | doc/tutorial/describing-code.rst | 276 | ||||
-rw-r--r-- | doc/tutorial/end.rst | 6 | ||||
-rw-r--r-- | doc/tutorial/first-steps.rst | 92 | ||||
-rw-r--r-- | doc/tutorial/getting-started.rst | 120 | ||||
-rw-r--r-- | doc/tutorial/index.rst | 39 | ||||
-rw-r--r-- | doc/tutorial/more-sphinx-customization.rst | 78 | ||||
-rw-r--r-- | doc/tutorial/narrative-documentation.rst | 130 |
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! |