'Declare additional dependency to sphinx-build in an extension

TL,DR: From a Sphinx extension, how do I tell sphinx-build to treat an additional file as a dependency? In my immediate use case, this is the extension's source code, but the question could equally apply to some auxiliary file used by the extension.

I'm generating documentation with Sphinx using a custom extension. I'm using sphinx-build to build the documentation. For example, I use this command to generate the HTML (this is the command in the makefile generated by sphinx-quickstart):

sphinx-build -b html -d _build/doctrees   . _build/html

Since my custom extension is maintained together with the source of the documentation, I want sphinx-build to treat it as a dependency of the generated HTML (and LaTeX, etc.). So whenever I change my extension's source code, I want sphinx-build to regenerate the output.

How do I tell sphinx-build to treat an additional file as a dependency? That is not mentioned in the toctree, since it isn't part of the source. Logically, this should be something I do from my extension's setup function.


Sample extension (my_extension.py):

from docutils import nodes
from docutils.parsers.rst import Directive

class Foo(Directive):
    def run(self):
        node = nodes.paragraph(text='Hello world\n')
        return [node]

def setup(app):
    app.add_directive('foo', Foo)

Sample source (index.rst):

.. toctree::
   :maxdepth: 2

.. foo::

Sample conf.py (basically the output of sphinx-quickstart plus my extension):

import sys
import os
sys.path.insert(0, os.path.abspath('.'))
extensions = ['my_extension']
templates_path = ['_templates']
source_suffix = '.rst'
master_doc = 'index'
project = 'Hello directive'
copyright = '2019, Gilles'
author = 'Gilles'
version = '1'
release = '1'
language = None
exclude_patterns = ['_build']
pygments_style = 'sphinx'
todo_include_todos = False
html_theme = 'alabaster'
html_static_path = ['_static']
htmlhelp_basename = 'Hellodirectivedoc'
latex_elements = {
}
latex_documents = [
    (master_doc, 'Hellodirective.tex', 'Hello directive Documentation',
     'Gilles', 'manual'),
]
man_pages = [
    (master_doc, 'hellodirective', 'Hello directive Documentation',
     [author], 1)
]
texinfo_documents = [
    (master_doc, 'Hellodirective', 'Hello directive Documentation',
     author, 'Hellodirective', 'One line description of project.',
     'Miscellaneous'),
]

Validation of a solution:

  1. Run make html (or sphinx-build as above).
  2. Modify my_extension.py to replace Hello world by Hello again.
  3. Run make html again.
  4. The generated HTML (_build/html/index.html) must now contain Hello again instead of Hello world.


Solution 1:[1]

As far as I know app.env.note_dependency can be called within the doctree-read to add any file as a dependency to the document currently being read. So in your use case, I assume this would work:

from typing import Any, Dict
from sphinx.application import Sphinx
import docutils.nodes as nodes


def doctree-read(app: Sphinx, doctree: nodes.document):
    app.env.note_dependency(file)


def setup(app: Sphinx):
    app.connect("doctree-read", doctree-read)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Itay Ziv