Sphinx is a popular tool for documenting Python projects,
including the ability to automatically generate documentation using docstrings in your
source code.
cat docs/requirements.txt
# bring in requirements for my app (excepting the optional database):
-r../requirements-django.txt
# stuff needed for sphinx documentation:
Sphinx==1.8.2
sphinx-markdown-tables==0.0.9
sphinx-rtd-theme==0.4.2
sphinxcontrib-apidoc==0.3.0
sphinxcontrib-confluencebuilder==0.9
sphinxcontrib-django==0.4
sphinxcontrib-websupport==1.1.0
recommonmark==0.4.0
Then run the quickstart:
1
sphinx-quickstart
This creates a conf.py which is the core configuration file for Sphinx. And, since it's Python code,
you can do all kinds of cool stuff. Here are a few of my changes after the quickstart, which notably
includes some django-specific stuff, automatic API documentation and support for Markdown and Markdown Tables:
diff --git b/docs/conf.py a/docs/conf.pyindex 55c2351..dc4c7a4 100644--- b/docs/conf.py+++ a/docs/conf.py@@ -12,22 +12,37 @@
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
-# import os-# import sys-# sys.path.insert(0, os.path.abspath('.'))+import os+import sys+import datetime+import django+from recommonmark.parser import CommonMarkParser+django_version = ".".join(map(str, django.VERSION[0:2]))+python_version = ".".join(map(str, sys.version_info[0:2]))++sys.path.insert(0, os.path.abspath('..'))++os.environ['DJANGO_SETTINGS_MODULE'] = 'training.settings'+django.setup()
# -- Project information -----------------------------------------------------
+# See https://pypi.org/project/sphinxcontrib-django/
project = 'Django {json:api} training'
-copyright = '2018, Alan Crosswell'+year = datetime.date.today().year+copyright = '2018-{}, The Trustees of Columbia University in the City of New York'.format(year)
author = 'Alan Crosswell'
# The short X.Y version
-version = ''+from myapp import VERSION+version = VERSION
# The full version, including alpha/beta/rc tags
-release = ''+release = VERSION+# Auto-generate API documentation.+#os.environ['SPHINX_APIDOC_OPTIONS'] = "members,undoc-members,show-inheritance"+os.environ['SPHINX_APIDOC_OPTIONS'] = "members,show-inheritance"
# -- General configuration ---------------------------------------------------
@@ -39,23 +54,30 @@ release = ''
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
- 'sphinx.ext.autodoc',- 'sphinx.ext.intersphinx',- 'sphinx.ext.todo',- 'sphinx.ext.viewcode',+ 'sphinxcontrib.apidoc', # runs sphinx-apidoc automatically as part of sphinx-build+ 'sphinx.ext.autodoc', # the autodoc extensions uses files generated by apidoc+ 'sphinxcontrib_django', # does some nicer django autodoc formatting, but:+ # https://github.com/edoburu/sphinxcontrib-django/issues/12+ 'sphinx.ext.viewcode', # enable viewing autodoc'd code+ 'sphinx.ext.intersphinx', # make links between different sphinx-documented packages+ 'sphinx.ext.todo', # TODO: figure out how to use this;-)+ 'sphinx_markdown_tables', # CommonMark doesn't do tables: This extensions does!+ 'sphinxcontrib.confluencebuilder', # supposedly installs docs on Confluence
]
-
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
+source_parsers = {+ '.md': CommonMarkParser,+}+
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
-source_suffix = '.rst'+source_suffix = ['.rst', '.md']
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
@@ -67,7 +89,7 @@ language = None
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
-exclude_patterns = []+exclude_patterns = ['build']
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = None
@@ -78,13 +100,23 @@ pygments_style = None
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
-html_theme = 'alabaster'+# html_theme = 'alabaster'+# html_theme = 'default'+html_theme = 'sphinx_rtd_theme'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#
-# html_theme_options = {}+html_theme_options = {+ # these are for sphinx_rtd_theme:+ 'prev_next_buttons_location': 'both',+ 'collapse_navigation': True,+ # these are for alabaster:+ # 'show_relbars': True,+ # 'fixed_sidebar': True,+ # 'sidebar_collapse': True,+}
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
@@ -99,8 +131,16 @@ html_static_path = ['_static']
# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
# 'searchbox.html']``.
#
-# html_sidebars = {}-+# also for alabaster theme:+# html_sidebars = {+# '**': [+# 'about.html',+# 'navigation.html',+# 'relations.html',+# 'searchbox.html',+# 'donate.html',+# ]+# }
# -- Extension configuration -------------------------------------------------
+autodoc_member_order = 'bysource'+autodoc_inherit_docstrings = False++apidoc_module_dir = '../myapp'+apidoc_output_dir = 'apidoc'+apidoc_excluded_paths = ['../myapp/migrations']+apidoc_separate_modules = True+apidoc_toc_file = False+apidoc_module_first = True+apidoc_extra_args = ['-f']++confluence_publish = True+confluence_server_url = os.environ.get('CONFLUENCE_SERVER', "https://confluence.columbia.edu")+confluence_space_name = os.environ.get('CONFLUENCE_SPACE', None)+confluence_parent_page = os.environ.get('CONFLUENCE_PARENT', None)+confluence_server_user = os.environ.get('CONFLUENCE_USER', None)+confluence_server_pass = os.environ.get('CONFLUENCE_PASS', None)+
# -- Options for intersphinx extension ---------------------------------------
-intersphinx_mapping = {'https://docs.python.org/': None}+intersphinx_mapping = {+ 'python': ('https://docs.python.org/{}'.format(python_version), None),+ 'django': ('https://docs.djangoproject.com/en/{}/'.format(django_version), + 'https://docs.djangoproject.com/en/{}/_objects/'.format(django_version)),+ # not sure why but the default lookup of objects.inv fails with None+ 'djangorestframework-jsonapi': ('https://django-rest-framework-json-api.readthedocs.io/en/stable/',+ 'https://django-rest-framework-json-api.readthedocs.io/en/stable/objects.inv'),+ # DRF doesn't use sphinx but rather mkdocs:-(+ #'djangorestframework': ('https://django-rest-framework.org/', None),+}
The sphinxcontrib-confluencebuilder attempts to generate Confluence content but suffers from
several shortcomings. An
example of hosting this document
demonstrates the problems.
Several common code languages are not recognized, yielding these errors:
Some of these can be easily worked-around (e.g. substitute sql for tsql) but lack of text is pretty basic stuff.
Certain instances of curly braces are not properly quoted, leading to 500 macro unknown errors like this:
12345678
An unsupported Confluence API call has been made.
REQ: POST
RSP: 500
URL: https://confluence.columbia.edu/confluence/rest/api
API: contentbody/convert/storage
MSG: com.atlassian.confluence.content.render.xhtml.migration.exceptions.UnknownMacroMigrationException: The macro 'json' is unknown.
---
Curly braces appear to be OK for normal body text but break down in:
browser link titles such as [See {json:api}](https://jsonapi.org)
autodoc-generated code blocks:
1 2 3 4 5 6 7 8 9101112131415161718
diff --git a/myapp/serializers.py b/myapp/serializers.pyindex beb962c..e8e15ac 100644--- a/myapp/serializers.py+++ b/myapp/serializers.py@@ -70,8 +70,8 @@ class CourseSerializer(HyperlinkedModelSerializer):
related_link_view_name='course-related',
)
- #: `{json:api} compound document <https://jsonapi.org/format/#document-compound-documents>`_- #: (also used for `related_serializers` for DJA 2.6.0)+ # `JSON:API compound document <https://jsonapi.org/format/#document-compound-documents>`_+ # (also used for `related_serializers` for DJA 2.6.0)
included_serializers = {
'course_terms': 'myapp.serializers.CourseTermSerializer',
}
@@ -111,8 +111,8 @@ class CourseTermSerializer(HyperlinkedModelSerializer):
related_link_view_name='course_term-related',
)
These can be worked around by excluding undocumented members
and removing docstrings or #: comments (which sphinx treats like docstrings).
This was supposedly fixed but is apparently
not (or this is a new way to trigger the issue). A
fix is in the works.
My conclusion: Just find a way to locally host the HTML tree generated by sphinx-build rather than trying to
force this into Confluence. For example, this works:
readthedocs.io (RTD or rtfd.io)
is where most open-source projects host their documentation. While your project is probably internal,
here's how to do it if you are open-sourcing it.
Once we've got sphinx working locally, and the project hosted on github, getting it working with RTD is pretty
straightforward. See the
sphinx getting started guide.
Separating deployment from documentation generation requirements¶
I did have to split up the project requirements.txt into multiple pieces since I import Django and myapp into
conf.py to enable autoapi and autodoc.
Then, in docs/requirements.txt we bring in the necessary django and sphinx pieces:
1 2 3 4 5 6 7 8 91011
# bring in requirements for my app
-r../requirements-django.txt
# stuff needed for sphinx documentation:
Sphinx==1.8.2
sphinx-markdown-tables==0.0.9
sphinx-rtd-theme==0.4.2
sphinxcontrib-apidoc==0.3.0
sphinxcontrib-confluencebuilder==0.9
sphinxcontrib-django==0.4
sphinxcontrib-websupport==1.1.0
recommonmark==0.4.0
In anticipation of adding travis support on github,
I also changed tox.ini to have a separate section for local sphinx builds: tox -e sphinx.
Use this to build the local docs/build/html/ tree:
123
(env) django-training$ tox -e sphinx
...
(env) django-training$ open docs/build/html/index.html