HTML document your Python program with Sphinx

1.First of all

I decided to extend the functionality of a Python program developed in one project while maintaining it in another new project. By taking over, I decided to keep the HTML document generated by Sphinx as an internal document. I have experience of converting to HTML with Doxygen in the past, and I embedded the same amount of information as comments in the source code, so I should support Sphinx. The background.

The detailed design document is automatically generated.

I'm new to Sphinx, so make a note of what you're doing. In addition, the original rule is adopted for the field of docstring.


2. Usage environment

As follows.


3. Determining the docstring format

There are Google format and numpy format, but reStructureText (commonly known as reST) was adopted. The reason is as follows.


4. Install Sphinx

It's a procedure for Windows environment, but it seems that macOS and Linux are not so different.

pip install Sphinx sphinx-autodoc-typehints
pip install sphinx_rtd_theme

sphinx_rtd_theme is used for HTML document themes. The default is a little hard to see.


5. Generate HTML document

5-1. Target file configuration example

The following file structure is assumed.

.
├── src/  #The complete source code is below
│   ├── __init__.py
│   ├── Foo.py
│   ├── Bar.py
│   └── Hoge/
│       ├── __init__.py
│       └── Hoge.py
│
└── doc/  #This is the working directory of Sphinx

5-2. Document generation procedure

Execute the following command from the terminal.

sphinx-apidoc -F -a -o .\doc .\src
cd doc
make html
.\_build\html\index.html

make htmlGenerate an html document with. If you change the source code docstring, you only need to re-execute this command.

The command with the last index.html launches the default browser and opens the HTML document.


5-3. Things to note

Sphinx seems to pass the target Python code to the processing system, and if there is an error in the target code, an error will occur with `` `make html``` and no document will be generated. Check the operation in advance.

Therefore, for example, if the target code uses a package that is unique to Windows, it cannot be documented in a macOS or Linux environment unless a dummy package is created by yourself.


6. Change Sphinx settings

It's not good to keep the default, so add the following line to the configuration file doc / conf.py.

doc/conf.py


html_theme = 'sphinx_rtd_theme'    #Specify display theme
autodoc_typehints = 'description'  #Enable type hints
autoclass_content = 'both'         # __init__()Also output
autodoc_default_options = {'private-members': True,   #Output private method
                           'show-inheritance': True}  #Show inheritance

What we are doing above is as follows.

After changing the settings, execute make html.

I referred to this page for the settings. Import documentation from sphinx.ext.autodoc --docstring

By the way, I used it with language = en. The layout didn't look right with ja.


7. reST notation

The reST notation of the adopted docstring is shown.


7-1. Package initialization file (\ _ \ _ init \ _ \ _. Py)

A description of the package is given here.

__init__.py


"""Package title

|Detailed information is written here.
|Be sure to open one line from the package title.
|← If you use a line block, the line feed state is maintained.

:author:Name of person in charge of this program
:copyright:Copyright notice
"""

Strings between colons, such as `: author: ``` and `: copyright: ``` above, are called fields and can be defined independently. When HTML is output, it is displayed as follows.

package_header.png


7-2. File header

The file header is the same as the package.

Foo.py


"""Module title

|Detailed information is written here.
|Be sure to open one line from the module title.

:note:If there are any notes, describe them here.

:author:Name of person in charge of this program
:copyright:Copyright notice
"""

The above shows an example of adding the : note: field. The : note: field is used in all docstrings where necessary as a note.


7-3. Class header

The description of the class header is shown.

class Foo(object):
    """Class summary

    |Detailed description of the class.
    |Be sure to open one line from the class summary.
    |← Line blocks can also be used.
    """

7-4. Method header

The description of the method header is shown.

class Foo(object):

    def method(self, name: str, val: int) -> str:
        '''Method summary

        |Detailed description of the class.
        |Be sure to open one line from the class summary.
        |← Line blocks can also be used.

        :param name:Name ← See type hints if type name is omitted
        :param int val:Value ← You can write the type name directly
        :returns:(Explanation of return value)
        :rtype str:← Can be omitted if there is a return type and type hint
        '''
        ...

To write a type hint, set `` `-> None``` for methods that have no return value.

2020/8/1: Supplement When I happened to look at the SudachiPy source code, I found that the type hints used only public methods. If maintenance is difficult, is there such a division?


7-5. Members of the enumeration class

The description of the members of the enumeration class is described as follows.

class State(enum.Enum):
    """State
    """

    UNINIT = enum.auto()  #:Uninitialized
    READY = enum.auto()   #:Wait
    BUSY = enum.auto()    #:processing

7-6. Line wrapping

If the line of description becomes long, you can continue with `\` or `\`.

"""Module summary

Module description. ¥
This line is displayed from the top line without line breaks.
"""

8. Type hint

When I introduced type hints for the purpose of documentation, I ended up getting stuck with type hints.


8-1. Refers to your class (Forward References)

If you use your class as a type hint as it is, an error will occur.

class Foo(object):

    def method(self, obj: Foo) -> None:
        #↑ Foo becomes Undefined
        pass

You can avoid the error by using a character string as shown below.

class Foo(object):

    def method(self, obj: 'Foo') -> None:
        #                  ↑ OK!
        pass

It was also written properly on PEP-484.

PEP-484: Forward references


8-2. List and Dict (Type Aliaces)

If `list``` or dict``` is specified as the argument or return type, the type of the element cannot be described. Therefore, it is described using `` List and `` `Dict of the typing package.

from typing import List
from typing import Dict
import Bar.Bar

class Foo(object):

    def method(self, bars: List[Bar],
                     map: Dict[str, int]) -> List[str]:
        ...

The specifications of Foo.method () are as follows.

Click here for details. PEP-484: Type Aliases


8-3. Avoiding and Compromising Circular Import

When importing between modules, an error occurs in circular import because it is in a mutual import state, and an error message such as ʻImportError: Cannot import name ...` is displayed. In such a case, the stance is basically "Please change the structure", but if the structure cannot be changed by all means, the following compromise was made.

(1) Give up the type hint and write the type name in the docstring (2) Make the type name a character string like Forward refences

Later, in the correspondence of (2), it was found that the check of F821 undefined name was caught when passing through flake8, and in fact, all correspondence was done in (1).


Special Thanks

Recommended Posts

HTML document your Python program with Sphinx
Document Python code with Doxygen
Debug python multiprocess program with VSCode
Automatically build Python documentation with Sphinx
Write documentation in Sphinx with Python Livereload
[Python] A program that creates stairs with #
Get html from element with Python selenium
Automatically create Python API documentation with Sphinx
HTML email with image to send with python
Comfortable document life with Sphinx + Drone + S3
2D FEM stress analysis program with Python
Automatic document generation from docstring with sphinx
Try HTML scraping with a Python library
Publish your own Python library with Homebrew
[Automation] Read a Word document with Python
FizzBuzz with Python3
Scraping with Python
Statistics with python
Scraping with Python
Python with Go
[Note] Export the html of the site with python.
Twilio with Python
Integrate with Python
Play with 2016-Python
AES256 with python
Tested with Python
Make your own module quickly with setuptools (python)
Try to automatically generate Python documents with Sphinx
python starts with ()
with syntax (Python)
Bingo with python
Zundokokiyoshi with python
Python here document
Sample program that outputs syslog with Python logging
Excel with Python
Make your Python environment "easy" with VS Code
Microcomputer with Python
Cast with python
Flow of creating your own package with setup.py with python
Memo to create your own Box with Pepper's Python
Dynamic HTML pages made with AWS Lambda and Python
Let's call your own C ++ library with Python (Preferences)
From buying a computer to running a program with python
A program to write Lattice Hinge with Rhinoceros with Python
Automate Chrome with Python and Selenium on your Chromebook
[Python] Create a Tkinter program distribution file with cx_Freeze
Using a Python program with fluentd's exec_filter Output Plugin
Programming with your smartphone anywhere! (Recommended for C / Python)
Using a python program with fluentd's exec Output Plugin
Serial communication with Python
Zip, unzip with python
Django 1.11 started with Python3.6
Primality test with Python
Python with eclipse + PyDev.
Socket communication with Python
Data analysis with python 2
Scraping with Python (preparation)
Try scraping with Python.
Learning Python with ChemTHEATER 03
Sequential search with Python
"Object-oriented" learning with python