Sphinx Documentation¶
README¶
For quick start, installation, usage, and contribution guidelines, see README - the complete user guide for the dingx Sphinx documentation repository.
CLAUDE Quick Reference¶
For development with Claude Code, see CLAUDE - a comprehensive guide on project structure, configuration, JIRA integration, common workflows, and important conventions for AI-assisted development.
Apple Script¶
The apple script Script Sphinx dingx Docu creates the different build versions.
JIRA Integration¶
This Sphinx documentation system includes bidirectional synchronization with JIRA for task management:
JIRA Sphinx-Needs Sync - Guide to JIRA ↔ Sphinx-Needs synchronization
JIRA Sphinx Sync - Documentation for JIRA synchronization
JIRA Config Reference - JIRA configuration reference and jade.yml documentation
VM Deployment¶
Guide for deploying and managing the Sphinx documentation on Google Cloud virtual machines:
VM Deployment Guide - Complete VM deployment guide
Settings¶
The settings are defined in the conf.py file which is in the root directory of the Sphinx implementation:
# Sphinx Configuration
# Configuration file for the Sphinx documentation builder
# Documentation: http://www.sphinx-doc.org/en/master/config
# Coding: UTF-8
# -- Python libraries ------------------------------------------
import os
import pathlib
import sys
import logging
import django
import subprocess
import sphinx_bootstrap_theme
# To obtain timestamp data
from datetime import datetime
# Used when defining custom directives in reStructuredText
from docutils import nodes
# Log custom messages during the Sphinx build process
from sphinx.util.logging import getLogger
# Imports the entire logging module under the name sphinx_logging
from sphinx.util import logging as sphinx_logging
# Modifies Sphinx documents after the initial transformation phase
from sphinx.transforms.post_transforms import SphinxPostTransform
# For the usage of 'literalinclude' directive
from sphinx.highlighting import lexers
# All available syntax highlighters for customizing code block
from pygments.lexers import get_all_lexers
# For the usage of 'Pygments' generic syntax highlighter
from pygments.lexers.configs import IniLexer
# -- Setting the timestamps ------------------------------------
# get the current year
year = datetime.now().year
# get the current date and time
today_fmt = '%d.%m.%Y at %H:%M'
# -- Project information ---------------------------------------
project = 'dingx Project'
author = 'Friedrich Moehring'
subject = 'Move to Simplicity'
# Base filename for all output formats (no spaces)
filename = 'dingx'
# set the copyright information for the generated documentation
copyright = f'{year} {project} {author}'
# Major and minor version
major = '4'
minor = '8'
patch = '2'
# The short X version
version = f'{major}'
# The full version, including alpha/beta/rc tags
release = f'{major}.{minor}.{patch}'
# -- Important settings ----------------------------------------
# Language for content autogenerated by Sphinx
language = 'en'
# Master toctree document
master_doc = 'index'
# html: path to the logo
path_logo = '_static/logo_dingx.png'
# html: favicon image for the browser tab
html_favicon = '_static/favicon_dingx.png'
# epub: book cover including the title of the cover image
epub_cover = ('_static/cover_dingx.png', '')
# -- JIRA Integration Configuration ----------------------------
# JIRA credentials for bidirectional sync
jira_user = 'info@dingx.co'
jira_api_token = 'ATATT3xFfGF0aCoCqQAtiVsTB7LwK7C09yUUXJNNQPLFS8z297TAIaVNOmUNRgtCFGAkADIHkaqPqZBTgOtyh_FlmCCnPcqrwjR4IRLmfCb3h1EB7nVN-rWMJKKZw63O02JE1wwzy4fY3X694CYKMW-kzPi1E9zi2lCIEVAdzyfmi8ZCPBeizN4=69A65618'
jira_url = 'https://dingx.atlassian.net'
jira_project_key = 'BUS'
# -- Path setup ------------------------------------------------
# If extensions or modules to document with autodoc are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute.
# Base paths for development projects
REPO_PATH = '/Users/Friedrich/Documents/Project/Development/Python/repo'
VENV_PATH = '/Users/Friedrich/Documents/Logistics/venv'
# Add repository parent path for package-qualified imports
sys.path.insert(0, REPO_PATH)
# Add virtual environments FIRST so dependencies are available
# venv django_landing_simple
sys.path.insert(0, os.path.join(VENV_PATH, 'django_landing_simple/lib/python3.12/site-packages'))
# venv django_webapps_fullstack
sys.path.insert(0, os.path.join(VENV_PATH, 'django_webapps_fullstack/lib/python3.12/site-packages'))
# venv odoo_xmlrpc_twisted
sys.path.insert(0, os.path.join(VENV_PATH, 'odoo_xmlrpc_twisted/lib/python3.12/site-packages'))
# venv inventory_rfid_node
sys.path.insert(0, os.path.join(VENV_PATH, 'inventory_rfid_node/lib/python3.12/site-packages'))
# venv inventory_camera_node
sys.path.insert(0, os.path.join(VENV_PATH, 'inventory_camera_node/lib/python3.12/site-packages'))
# venv inventory_scale_node
sys.path.insert(0, os.path.join(VENV_PATH, 'inventory_scale_node/lib/python3.12/site-packages'))
# venv inventory_control_system
sys.path.insert(0, os.path.join(VENV_PATH, 'inventory_control_system/lib/python3.12/site-packages'))
# Add the repo paths for the Python modules in the repos
# repo django_landing_simple
sys.path.insert(0, os.path.join(REPO_PATH, 'django_landing_simple'))
# test django_landing_simple
sys.path.insert(0, os.path.join(REPO_PATH, 'django_landing_simple/test'))
# repo django_webapps_fullstack
sys.path.insert(0, os.path.join(REPO_PATH, 'django_webapps_fullstack'))
# test django_webapps_fullstack
sys.path.insert(0, os.path.join(REPO_PATH, 'django_webapps_fullstack/test'))
# root repo odoo_xmlrpc_twisted
sys.path.insert(0, os.path.join(REPO_PATH, 'odoo_xmlrpc_twisted'))
# functions odoo_xmlrpc_twisted
sys.path.insert(0, os.path.join(REPO_PATH, 'odoo_xmlrpc_twisted/functions'))
# models odoo_xmlrpc_twisted
sys.path.insert(0, os.path.join(REPO_PATH, 'odoo_xmlrpc_twisted/models'))
# scripts odoo_xmlrpc_twisted
sys.path.insert(0, os.path.join(REPO_PATH, 'odoo_xmlrpc_twisted/scripts'))
# test odoo_xmlrpc_twisted
sys.path.insert(0, os.path.join(REPO_PATH, 'odoo_xmlrpc_twisted/test'))
# support odoo_xmlrpc_twisted
sys.path.insert(0, os.path.join(REPO_PATH, 'odoo_xmlrpc_twisted/support'))
# repo inventory_rfid_node
sys.path.insert(0, os.path.join(REPO_PATH, 'inventory_rfid_node'))
# functions inventory_rfid_node
sys.path.insert(0, os.path.join(REPO_PATH, 'inventory_rfid_node/functions'))
# repo inventory_camera_node
sys.path.insert(0, os.path.join(REPO_PATH, 'inventory_camera_node'))
# functions inventory_camera_node
sys.path.insert(0, os.path.join(REPO_PATH, 'inventory_camera_node/functions'))
# test inventory_camera_node
sys.path.insert(0, os.path.join(REPO_PATH, 'inventory_camera_node/test'))
# repo inventory_scale_node
sys.path.insert(0, os.path.join(REPO_PATH, 'inventory_scale_node'))
# functions inventory_scale_node
sys.path.insert(0, os.path.join(REPO_PATH, 'inventory_scale_node/functions'))
# test inventory_scale_node
sys.path.insert(0, os.path.join(REPO_PATH, 'inventory_scale_node/test'))
# repo inventory_control_system
sys.path.insert(0, os.path.join(REPO_PATH, 'inventory_control_system'))
# functions inventory_control_system
sys.path.insert(0, os.path.join(REPO_PATH, 'inventory_control_system/functions'))
# support inventory_control_system
sys.path.insert(0, os.path.join(REPO_PATH, 'inventory_control_system/support'))
# test inventory_control_system
sys.path.insert(0, os.path.join(REPO_PATH, 'inventory_control_system/test'))
# For the documentation of the the Django Project
os.environ['DJANGO_SETTINGS_MODULE'] = 'django.settings'
# Indicate building the Sphinx documentation
os.environ['SPHINX_BUILD'] = '1'
from django.conf import settings
settings.configure()
# Setup Django
django.setup()
# -- Setup(app) function (moved to end of file) ---------------
# Dynamically excludes autosummary only for PDF build as autosummary results in build errors
def exclude_autosummary_for_pdf(app):
"""Exclude the table of contents when building HTML documentation."""
if app.builder.name == "pdf":
app.config.exclude_patterns.append('development/autosummary/**')
# Avoid the '.. contents:: directive error' when building HTML documentation with the Furo theme
def remove_contents_for_furo_html(app, doctree, docname):
"""Remove ".. contents::" directive only for "furo" "html" builds."""
if app.builder.name == "html" and app.config.html_theme == "furo":
for contents in doctree.traverse(nodes.topic):
if "contents" in contents.get("classes", []):
contents.parent.remove(contents)
# Configures Furo theme options to hide the sidebar project name, disable keyboard navigation, and set the logo
def modify_furo_options(app, config):
"""Dynamically update theme options to hide the sidebar and set the logo when using Furo."""
if config.html_theme == "furo":
# Hide project name in sidebar
config.html_theme_options["sidebar_hide_name"] = True
# Disable sidebar navigation with keys (optional)
config.html_theme_options["navigation_with_keys"] = False
# Places the logo at the top of the left sidebar
config.html_logo = path_logo
# Remove unsupported theme options ["color_primary", "color_accent"] when the Sphinx theme is not "sphinx_material"
def remove_unsupported_theme_options(app, config):
"""Remove unsupported theme options when not using "sphinx_material"."""
if config.html_theme != "sphinx_material":
if hasattr(config, "html_theme_options") and config.html_theme_options:
# Create a new dict without the unsupported keys
theme_options = dict(config.html_theme_options)
for key in ["color_primary", "color_accent"]:
theme_options.pop(key, None)
# Reassign the cleaned options
config.html_theme_options = theme_options
# prints a LaTeX SVG note but doesn't actually process SVG files
def setup(app):
"""Setup function for handling LaTeX-specific configurations"""
def exclude_svg_for_latex(app, env, docnames):
"""Skip SVG processing for LaTeX builder to avoid errors"""
if hasattr(app.builder, 'name') and app.builder.name == 'latex':
print("Note: SVG images may need manual conversion for LaTeX output")
# Connect the handler
app.connect('env-before-read-docs', exclude_svg_for_latex)
# Suppress the warnings "Ignore unknown node autosummary_table" and "Ignore unknown node autosummary_toc" when build with "docx"
def suppress_autosummary_warnings(app, doctree, docname):
"""Remove Remove autosummary_toc nodes and autosummary_table nodes when building with docx."""
if app.builder.name == "docx":
for node in doctree.traverse():
if node.__class__.__name__ in ["autosummary_toc", "autosummary_table"]:
node.parent.remove(node)
# Suppress SVG warnings when building DOCX (similar to autosummary suppression)
def suppress_svg_warnings(app, doctree, docname):
"""Remove image nodes with SVG sources when building with docx to avoid warnings."""
if app.builder.name == "docx":
from docutils import nodes
for node in doctree.traverse(nodes.image):
if node.get('uri', '').lower().endswith('.svg'):
# Simply remove the SVG image node to avoid warnings
node.parent.remove(node)
# Suppress duplicate object description warnings
def setup_duplicate_warning_filter(app):
"""Setup warning filter to suppress duplicate object description warnings."""
import logging
from sphinx.util.logging import getLogger
class DuplicateObjectFilter(logging.Filter):
def filter(self, record):
message = record.getMessage()
# Filter out duplicate object description warnings
if ('duplicate object description' in message and
'use :no-index: for one of them' in message):
return False
# Filter out duplicate label warnings (both formats)
if ('duplicate label' in message and
('autosectionlabel' in message or 'other instance in' in message)):
return False
return True
# Apply filter to multiple logger levels to catch Sphinx warnings
loggers_to_filter = [
logging.getLogger('sphinx'),
logging.getLogger('sphinx.environment'),
logging.getLogger('sphinx.environment.collectors.asset'),
logging.getLogger(), # root logger
]
duplicate_filter = DuplicateObjectFilter()
for logger in loggers_to_filter:
logger.addFilter(duplicate_filter)
# JIRA synchronization before build
def run_jira_sync(app):
"""Run JIRA synchronization before building documentation."""
# Only run for HTML builds to avoid slowing down other builds
if app.builder.name not in ["html"]:
return
print("Running JIRA ↔ Sphinx bidirectional sync...")
try:
# Import and run sync directly using this module's configuration
project_root = pathlib.Path(__file__).parent.parent
sys.path.insert(0, str(project_root))
from tools.jira_sphinx_sync import JiraSphinxSync
# Create a configuration object with our JIRA settings
class JiraConfig:
def __init__(self):
# Use the globals from this module directly
self.jira_user = jira_user
self.jira_api_token = jira_api_token
self.jira_url = jira_url
self.jira_project_key = jira_project_key
jira_config = JiraConfig()
syncer = JiraSphinxSync(sphinx_config=jira_config)
# Run bidirectional sync
syncer.sync()
print("JIRA bidirectional sync completed successfully!")
except Exception as e:
print(f"❌ JIRA sync failed: {e}")
print("⚠️ Continuing with build anyway...")
# -- General configuration -------------------------------------
# use 'sphinx.ext.extlinks': markup to shorten external links
extlinks = {
'mewe': ('https://mewe.com/group/5c978b56aeb33427c0511ee9/%s', ''),
'jira': ('https://dingx.atlassian.net/jira/projects/%s', ''),
'keepass': ('https://drive.google.com/open?id=11PzaQyIP8zzONCq8rtG87soWG6M1n5ix&usp=drive_fs/%s', ''),
'planning_folder': ('https://drive.google.com/open?id=1713JA-BzjdTkXU0I2MBEx6SZj32YF1U-&usp=drive_fs/%s', ''),
'sprint_folder': ('https://drive.google.com/open?id=10i680n9SZtZKaXWw_oj7VFLKsnAvMt7z&usp=drive_fs/%s', ''),
'workflow_processes': ('https://docs.google.com/spreadsheets/d/17Mxs0iRcqm-jQTPmk_VmWfXfJrxXsZoT?rtpof=true&usp=drive_fs/%s', ''),
'project_tasks': ('https://docs.google.com/spreadsheets/d/1GL5-c0Yk-Nt10mgg4j_Ao2pIdoLDN_mW?rtpof=true&usp=drive_fs/%s', ''),
'project_plan': ('https://docs.google.com/spreadsheets/d/1GL5-c0Yk-Nt10mgg4j_Ao2pIdoLDN_mW?rtpof=true&usp=drive_fs/%s', ''),
'google_drive': ('https://drive.google.com/drive/u/0/folders/1uJN97n5WovhQCGhOzbFOh4suD47wpW9-/%s', ''),
'google_cloud': ('https://cloud.google.com/%s', ''),
'bitbucket': ('https://bitbucket.org/dingx_workspace/%s', ''),
# domain registrator and e-mail provider
'domain_factory': ('https://www.df.eu/%s', ''),
'vadian': ('https://www.vadian.net/%s', ''),
'spaceship': ('https://www.spaceship.com/%s', ''),
'ionos': ('https://www.ionos.com/%s', ''),
'infomaniak': ('https://www.infomaniak.com/%s', ''),
'papaki': ('https://www.papaki.com/%s', ''),
'sedo': ('https://sedo.com/%s', ''),
'google_workspace': ('https://workspace.google.com/%s', ''),
'zoho': ('https://www.zoho.com/%s', ''),
}
# Ignore external library references that Sphinx cannot resolve
# These are references to classes/modules in external packages (Django, FastAPI, unittest, etc.)
nitpick_ignore = [
# Django framework
('py:class', 'django.apps.config.AppConfig'),
('py:class', 'django.forms.forms.Form'),
('py:class', 'django.test.testcases.TestCase'),
('py:mod', 'settings.urls'),
# Python standard library
('py:class', 'unittest.case.TestCase'),
('py:class', 'datetime.timedelta'),
# FastAPI framework
('py:class', 'fastapi.Request'),
('py:class', 'fastapi.HTTPException'),
('py:class', 'fastapi.security.HTTPAuthorizationCredentials'),
# Twisted framework
('py:class', 'twisted.web.xmlrpc.XMLRPC'),
# Pydantic models (internal to odoo_xmlrpc_twisted)
('py:class', 'models.schemas.CreateOrder'),
('py:class', 'models.schemas.CreateUser'),
('py:class', 'models.schemas.UserLogin'),
# API modules not included in autosummary (filtered out by generate_autosummary_package.py)
('py:mod', 'inventory_camera_node.api'),
('py:mod', 'inventory_scale_node.api'),
# PyQt6 base classes (external GUI library)
('py:class', 'PyQt6.QtCore.QThread'),
('py:class', 'PyQt6.QtWidgets.QMainWindow'),
('py:class', 'PyQt6.QtWidgets.QFrame'),
]
# Add any Sphinx extension module names here as strings. These can be
# extensions that come with Sphinx (named 'sphinx.ext.*') or custom ones.
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.autosummary',
'sphinx.ext.doctest',
'sphinx.ext.coverage',
'sphinx.ext.viewcode',
'sphinx.ext.extlinks',
# enables SVG support for various builders including DOCX
'sphinx.ext.imgmath',
# manage requirements and traceability, sync with JIRA
"sphinx_needs",
# allows to link to documentation in other project
'sphinx.ext.intersphinx',
# for Google-style or NumPy-style docstrings
'sphinx.ext.napoleon',
# auto-generate section labels.
'sphinx.ext.autosectionlabel',
# enables modern, styled UI elements like colored blocks, cards, and grids
'sphinx_design',
# add a "copy" button to code blocks
# see https://pypi.org/project/sphinx-copybutton/
'sphinx_copybutton',
# pdf output from sphinx with rst2pdf
# see https://sphinx-test-docs.readthedocs.io/en/latest/sphinxTut/render_pdf.html
'rst2pdf.pdfbuilder',
# extension to generate Markdown files
# see https://pypi.org/project/sphinx-markdown-builder/
"sphinx_markdown_builder",
# builder extension to generate Office OpenXML (OOXML) document with "docx" file extension
# see https://docxbuilder.readthedocs.io/en/latest/docxbuilder.html
'docxbuilder',
# MyST is a rich and extensible flavor of Markdown meant for technical documentation and publishing
# see https://myst-parser.readthedocs.io/en/v0.17.2/sphinx/intro.html
'myst_parser',
]
# Intersphinx mapping for cross-referencing external documentation
intersphinx_mapping = {
'python': ('https://docs.python.org/3', None),
}
# settings for 'sphinx-needs', see https://sphinx-needs.readthedocs.io/en/
needs_types = [dict(directive="task", title="Task", prefix="TD", color="#FFCC00", style="node"),]
needs_extra_options = ["assignee", "priority", "sprint", "story_points", "duedate"]
# define the statuses wanted to use
needs_statuses = [
{"name": "to-do", "description": "Not started / planned", "color": "#d3d3d3"},
{"name": "in-progress", "description": "Actively being worked on", "color": "#87ceeb"},
{"name": "done", "description": "Completed", "color": "#90ee90"},
{"name": "parking", "description": "On hold / blocked", "color": "#ffa500"},
]
# Disable specific warning messages during the build process
suppress_warnings = [
'epub.unknown_project_files', # Suppress warnings about missing or extra files
'epub.duplicated_toc_entry', # Suppress duplicate ToC entry warnings for EPUB
'myst.header', # Suppress warnings related to MyST headers
'myst.nested', # Suppress nested parsing warnings
'toc.not_in_toctree', # Suppress warnings for autosummary files not in toctree
]
# Add any paths that contain templates here, relative to this directory
templates_path = ['_templates']
# If true, 'todo' and 'todoList' produce output, else nothing
todo_include_todos = True
# Hide the ToDo section if it's empty
todo_link_only = True
# Prefix document path to section labels, otherwise autogenerated labels would look like 'heading'
# rather than 'path/to/file:heading'
autosectionlabel_prefix_document = True
# 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 = []
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# Usage of 'literalinclude' directive to include '.ini' files directly into the Sphinx documentation.
lexers['ini'] = IniLexer()
# Automatically generate stub .rst files for any items listed in an
# '.. autosummary::' directive during the documentation build process.
autosummary_generate = True
# Use custom autosummary templates to show members and source code links
# Templates are in source/_templates/autosummary/
autodoc_default_options = {
'members': True,
'undoc-members': True,
'show-inheritance': True,
}
# Mock imports for modules that can't be imported during documentation build
# This allows FastAPI application files (api.py) to be documented
autodoc_mock_imports = [
# FastAPI and related
'uvicorn',
'fastapi',
'fastapi.responses',
'fastapi.middleware',
'fastapi.middleware.cors',
'fastapi.middleware.trustedhost',
'fastapi.testclient',
# Pydantic
'pydantic',
'pydantic.fields',
'pydantic.main',
'pydantic_core',
'typing_extensions',
# Hardware-specific libraries
'RPi',
'RPi.GPIO',
'mfrc522',
'hx711',
'picamera2',
# GUI libraries
'PyQt6',
'PyQt6.QtWidgets',
'PyQt6.QtCore',
'PyQt6.QtGui',
]
# Adjust the logging level for autosummary to warning
autosummary_logger = getLogger("sphinx.ext.autosummary")
autosummary_logger.setLevel(logging.WARNING)
# Set the logging level for myst_parser to WARNING or ERROR
sphinx_logging.getLogger('myst_parser').setLevel(logging.ERROR)
# Adjust the global logging level for Sphinx to warning
root_logger = logging.getLogger()
root_logger.setLevel(logging.WARNING) # or logging.ERROR
# -- Options for Linkcheck Builder -----------------------------
# Adjust the timeout and retry settings for the linkcheck to prevent hanging on slow or unresponsive links.
linkcheck_timeout = 10 # Timeout in seconds
linkcheck_retries = 1 # Number of retries
linkcheck_workers = 10 # Number of workers for link checking
# A list of URL that should not be checked when doing a linkcheck build.
linkcheck_ignore = [
r'http://localhost',
r'https://bitbucket.org',
r'https://stackoverflow.com',
r'https://loopings.ch',
r'https://app.dealum.com',
r'https://www.spaceship.com',
r'https://www.ifj.ch',
r'https://kivy.org',
r'https://www.venturekick.ch',
r'https://www.innosuisse.venturelab.ch',
r'https://www.easygov.swiss',
r'https://docs.google.com/presentation', # shared documents on Google Drive
r'https://docs.google.com/document', # shared documents on Google Drive
r'https://docs.google.com/spreadsheets', # shared documents on Google Drive
r'https://drive.google.com/open\?id=.*', # private Google Drive files/folders
r'.*dingx.*', # Ignore any link containing 'dingx' as not all domains are active.
# r'https://zurich.impacthub.ch', # link not always works
# r'https://www.figma.com', # link not always works
]
# -- Options for HTML output -----------------------------------
# The theme to use for HTML and HTML Help pages.
# See the documentation for a list of builtin themes.
#
# 'alabaster': default theme
# html_theme = 'alabaster'
# 'furo': clean documentation with a sidebar
html_theme = 'furo'
# 'sphinx_material': inspired by Google's Material Design
# html_theme = 'sphinx_material'
# 'bootstrap': responsive, modern design based on Bootstrap
# html_theme = 'bootstrap'
# html_theme = 'classic'
# html_theme = 'nature'
# Path containing custom static files
html_static_path = ['_static']
# Custom CSS files
html_css_files = [
'custom.css',
]
# Theme options are theme-specific and customize the look and feel of a theme further.
html_theme_options = {
# Visible levels of the global TOC; -1 means unlimited
# 'globaltoc_depth': -1,
# If False, expand all TOC entries
'globaltoc_collapse': False,
# If True, show hidden TOC entries
'globaltoc_includehidden': False,
# "Sphinx Material" theme options (only used when html_theme = 'sphinx_material')
# see https://bashtage.github.io/sphinx-material/
# Set the color and the accent color
'color_primary': 'blue',
'color_accent': 'light-blue',
}
# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
#
# The default sidebars (for documents that don't match any pattern) are
# defined by theme itself. Builtin themes are using these templates by
# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
# 'searchbox.html']``.
#
html_sidebars = {}
# -- Options for LaTeX output ----------------------------------
# Settings for the creating of the LaTeX documentation
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
('index', # Starting document
f"{filename}.tex", # Output filename
f"{project}", # Document title
author, # Author
'manual', # Document class
),
]
# explicitly set UTF-8 encoding for LaTeX
latex_engine = 'xelatex'
# Configure image converters for LaTeX to handle SVG files
latex_show_pagerefs = True
latex_show_urls = 'footnote'
# Configure LaTeX compilation to use batchmode (no interactive prompts)
latex_use_latex_multicolumn = True
latex_toplevel_sectioning = 'chapter'
# Configure LaTeX to be more tolerant of errors
latex_show_pagerefs = True
latex_show_urls = 'footnote'
latex_elements = {
# Disables the inputenc package because xelatex handle UTF-8 natively
'inputenc': '',
# Ensures no extra UTF-8 settings are applied, as they are not needed with xelatex
'utf8extra': '',
# The paper size ('letterpaper' or 'a4paper').
'papersize': 'a4paper',
# The font size ('10pt', '11pt' or '12pt').
'pointsize': '10pt',
# Custom LaTeX options
'fncychap': '\\usepackage[Bjornstrup]{fncychap}',
'printindex': '\\footnotesize\\raggedright\\printindex',
# Additional stuff for the LaTeX preamble.
'preamble': r'''
% Silence LaTeX Warnings with Silence Package
\usepackage{silence}
\WarningsOff* % Suppress ALL warnings
% Handle graphics with robust error handling
\usepackage{caption}
% Set graphics extensions for xelatex (exclude SVG)
\DeclareGraphicsExtensions{.pdf,.png,.jpg,.jpeg}
% Unicode character support for monospace font
\usepackage{newunicodechar}
% Define fallbacks for problematic Unicode characters
\newunicodechar{↔}{\ensuremath{\leftrightarrow}}
\newunicodechar{❌}{\textcolor{red}{\textbf{X}}}
\newunicodechar{⚠}{\textcolor{orange}{\textbf{!}}}
\newunicodechar{️}{} % Zero-width joiner, ignore
% Simple approach: just exclude SVG from graphics search path
% LaTeX will show a simple error message for missing graphics but continue
% Ignore Underfull and Overfull Boxes
\hbadness=10000 % Suppress underfull hbox warnings
\hfuzz=9999pt % Ignore minor overfull hbox warnings
\vbadness=10000 % Suppress underfull vbox warnings
\vfuzz=9999pt % Ignore minor overfull vbox warnings
\emergencystretch=1em % Allow more flexible spacing
\tolerance=5000 % Increase tolerance for bad boxes
\hbadness=5000 % Suppress badness warnings
\hfuzz=2pt % Ignore small overfull boxes
% Completely Disable Warnings
\makeatletter
\renewcommand{\@latex@warning}[1]{}
\renewcommand{\@latex@warning@no@line}[1]{}
\makeatother
% Sloppy typesetting to prevent warnings
\sloppy
% Additional tolerance for long words and code blocks
\tolerance=10000
\emergencystretch=3em
\renewcommand{\ttdefault}{lmtt} % Use a better monospace font
''',
# Latex figure (float) alignment
'figure_align': 'htbp',
# enable forced wrapping for code:
'sphinxsetup': 'verbatimforcewraps, verbatimmaxoverfull=0',
}
# -- Options for EPUB output -----------------------------------
# Bibliographic Dublin Core info.
epub_basename = filename
epub_title = project
epub_author = author
epub_publisher = author
epub_copyright = copyright
epub_language = language
epub_description = f'{project} version {release}'
# Individual configurations.
epub_show_urls = 'no'
# A list of files that should not be packed into the epub file.
epub_exclude_files = ['search.html']
# -- Options for DOCX (Docxbuilder) output ---------------------
docx_documents = [
('index',
f"{filename}.docx",
{'title': project,
'creator': author,
'subject': subject,
'keywords': [''], },
True,
),
]
docx_style = ''
docx_pagebreak_before_section = 1
# Automatically updates TOC (= Table of Contents) when opening the document
docx_update_fields = False
# -- Options for Manual output ---------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc,
filename, # Command name
f"{project} Documentation", # Description
[author], # Authors
1, # Manual section
),
]
# -- Options for Texinfo output --------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc,
filename, # Target name
f"{project}", # Title
author, # Author
filename, # Dir menu entry
subject, # Description
'Miscellaneous', # Category
),
]
# -- Setup(app) function ---------------------------------------
# The setup(app) function is a special function in Sphinx that allows
# to connect custom functions (event handlers) to specific Sphinx events
def setup(app):
app.connect("builder-inited", exclude_autosummary_for_pdf) # Exclude autosummary only for PDF build
app.connect("builder-inited", run_jira_sync) # Add JIRA sync before build
app.connect("builder-inited", setup_duplicate_warning_filter) # Filter duplicate warnings
app.connect("doctree-resolved", remove_contents_for_furo_html) # Avoid the '.. contents:: directive error'
app.connect("config-inited", modify_furo_options) # Configure Furo theme options
app.connect("config-inited", remove_unsupported_theme_options) # If theme is not "sphinx_material"
app.connect("doctree-resolved", suppress_autosummary_warnings) # When build with "docx"
app.connect("doctree-resolved", suppress_svg_warnings) # Suppress SVG warnings for DOCX
return {
'version': '0.1',
'parallel_read_safe': True,
'parallel_write_safe': True,
}
Build Automation¶
The Makefile provides build automation commands for generating documentation in multiple formats and managing JIRA synchronization:
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= /Users/Friedrich/Documents/Logistics/venv/sphinx/bin/sphinx-build
SOURCEDIR = source
BUILDDIR = build
PYTHON = /Users/Friedrich/Documents/Logistics/venv/sphinx/bin/python
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
@echo ""
@echo "JIRA Synchronization Commands:"
@echo " jira-pull Pull tasks from JIRA into Sphinx"
@echo " jira-push Push Sphinx changes to JIRA"
@echo " jira-sync Bidirectional synchronization"
@echo " jira-status Show synchronization status"
@echo " html-with-sync Build HTML with JIRA sync"
@echo ""
@echo "Link Checking Commands:"
@echo " linkcheck Check all links (full output)"
.PHONY: help Makefile jira-pull jira-push jira-sync jira-status html-with-sync
# JIRA synchronization targets
jira-pull:
@echo "🔄 Pulling tasks from JIRA..."
@$(PYTHON) tools/jira_sphinx_sync.py pull
jira-push:
@echo "🔄 Pushing changes to JIRA..."
@$(PYTHON) tools/jira_sphinx_sync.py push
jira-sync:
@echo "🔄 Running bidirectional JIRA sync..."
@$(PYTHON) tools/jira_sphinx_sync.py sync
jira-status:
@echo "📊 JIRA Sync Status:"
@if [ -f "tools/sync_state.json" ]; then \
echo " Last sync: Never"; \
echo " JIRA issues: 0"; \
else \
echo " No sync history found"; \
fi
@echo " JIRA credentials: $$([ -n \"$$JIRA_USER\" ] && echo \"✅ Set\" || echo \"❌ Not set\")"
html-with-sync: jira-pull html
# Custom latexpdf target that handles SVG issues gracefully
latexpdf: latex
@echo "Building PDF from LaTeX (removing SVG files and references)..."
@echo "Removing problematic SVG files from LaTeX build..."
@find "$(BUILDDIR)/latex" -name "*.svg" -delete 2>/dev/null || true
@echo " Removing SVG references from LaTeX source..."
@cd "$(BUILDDIR)/latex" && \
sed -i.bak '/includegraphics.*\.svg/d' dingx.tex && \
latexmk -pdf -f -interaction=nonstopmode dingx.tex; \
if [ -f "dingx.pdf" ]; then \
echo "PDF successfully created: $$(ls -lh dingx.pdf | awk '{print $$5}')"; \
echo "Location: $(BUILDDIR)/latex/dingx.pdf"; \
else \
echo "❌ PDF creation failed"; \
exit 1; \
fi
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)