Let's say you've written some Python code and along the way you realized that other people might want to look at your code or even use it in their own projects. Luckily, you've documented your code using docstrings, right? Well, if you haven't, I'd recommend doing it from the very beginning. Saving it for last will definitely cause you a lot of headaches down the road. So, let's start with documenting our code properly.
Docstrings are small snippets of text that you use to explain the why and what behind your code. This is different from commenting your code, which is useful for explaining how your code works.
It might be easier to demonstrate this with an example:
def random_number(n): """Generates a random int of any length. Args: n (int): number of digits desired Returns: int: A random int with n digits """ # Make sure random number range doesn't start at zero. range_start = 10 ** (n - 1) range_end = (10 ** n) - 1 return random.randint(range_start, range_end)
The comment that comes directly after
def random_number(n): is called the docstring. As you can see, the first line explains what the function does, but not how it does it. We also want to inform the user what arguments the function accepts and what it returns. In this scenario, the user could be a lot of different people; another developer peer-reviewing your code, someone who is trying to use your function in their own project, or an open-source contributor. This docstring will help that person understand the intent behind your code and speed up the process. Sometimes lack of documentation prevents people from looking at your code altogether.
This is a very simple example, but if you want to learn more about how to document your code better, take a look at an extensive example.
If you've documented your code with docstrings, you've done the bulk of the work, congrats! 🥳 But we can still make it better.
There exists a python library called Sphinx that will automatically convert your docstrings to HTML files, which can then be published anywhere you want. How cool is that? Cmon, It's kinda cool, no? Well... at least it's useful.
Let's first install it.
$ pip install Sphinx
Then, open your terminal and navigate to the root of your project. Now we can run the following:
$ sphinx-quickstart ./docs
After you run this, just accept the defaults when prompted. This will create a folder called
docs/ inside your project and fill it with some files we're going to use to document our project. You don't need to know what all these files and folders do, so don't worry. The first file we'll look at is
index.rst. You can go ahead and open that file with any text editor and it should something like this:
Welcome to Hello's documentation! ================================= .. toctree:: :maxdepth: 2 :caption: Contents: Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search`
The format this file is created in is called reStructuredText. Feel free to read up on that, but for our purposes, we don't need to know much to be able to generate our documentation.
Let's test things out:
$ cd docs $ make html
The terminal should tell you that
The HTML pages are in _build/html. We can take a look at that folder in finder or whatever file explorer you have, and we'll notice an
index.html file. Go ahead and open that file with your web browser. You should see something like this:
It's empty, but this is our starting point.
Okay, so Sphinx is all set up, but how do we actually get to see the documentation from all the docstrings that we wrote show up in this HTML file? Let's go through that.
Let's say your project looks something like this now:
my_project/ src/ my_code.py docs/ _build/ _static/ _templates/ conf.py index.rst make.bat Makefile
docs/conf.py in a text editor and make the following changes:
extensions = [ ]
extensions = ["sphinx.ext.autodoc", "sphinx.ext.coverage", "sphinx.ext.napoleon"]
Also, around line 15 we should see something like:
# import os # import sys # sys.path.insert(0, os.path.abspath('.'))
Let's replace that with
import os import sys sys.path.insert(0, os.path.abspath("../src"))
Now let's navigate back to the root of the directory and run the following command:
$ sphinx-apidoc -f -o docs/source src
Sphinx let's us know that it's created some files:
Creating file docs/source/my_code.rst. Creating file docs/source/modules.rst.
Now if we go back to the
docs/ folder and
make html we should see something along the lines of:
**Running Sphinx v2.1.2** **loading pickled environment...** done **building [mo]:** targets for 0 po files that are out of date **building [html]**: targets for 0 source files that are out of date **updating environment:**  0 added, 1 changed, 0 removed **reading sources...** [100%] source/my_code **looking for now-outdated files...** none found **pickling environment...** done **checking consistency...** **/path/to/proj/docs/source/modules.rst: WARNING: document isn't included in any toctree** done **preparing documents...** done **writing output...** [100%] source/my_code **generating indices...** genindex py-modindex **writing additional pages...** search **copying static files...** done **copying extra files...** done **dumping search index in English (code: en) ...** done **dumping object inventory...** done **build succeeded, 1 warning.**
So it succeeded, that's awesome! But there's a warning.. oh no, what the hell went wrong? Well, if we recall,
index.rst is the starting point for our documentation. But we haven't referenced any of the autogenerated documentation from within that file. So, let's do that. Open
index.rst in a text editor and make the following changes:
Welcome to Hello's documentation! ================================= .. toctree:: :maxdepth: 2 :caption: Contents: source/modules Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search`
source/modules to the table of contents. Now, lets navigate to the
docs/ folder and
make html again.
Now, if we open up
docs/_build/html/index.html we should see:
If we click on
my_code_module, we'll finally be able to see our docstrings beautified!
At this point we've documented all of our code for developers and users alike to look at, and we've also been able to automatically generate HTML documentation for our code so that we may publish it to a website in the future, much like other large and respectable projects like Django and pytest. If you look closely, pytest's documentation almost looks exactly like the default theme for the HTML files from this very tutorial!