Skip to content

Module targets moved in Sphinx 5.2 #10872

@domdfcoding

Description

@domdfcoding

Describe the bug

In earlier versions, the node structure for a module was as follows:

<section>
  <title>
  <index>
  <paragraph>  # The docstring

This produced HTML like this:

<section id="module-module">
 <span id="module">
 </span>
 <h1>
  <a class="reference internal" href="#module-module" title="module">
   <code class="xref py py-mod docutils literal notranslate">
    <span class="pre">module</span>
   </code>
  </a>
 <a class="headerlink" href="#module-module" title="Permalink to this heading"></a>
 </h1>
 <p>This is the module docstring</p>
</section>

However, in Sphinx 5.2 (specifically #10807) the target has moved, and now shows up as its its own node.

<section>
  <title>
  <paragraph>  # The docstring
  <target>
  <index>
<section id="module">
 <h1>
  <a class="reference internal" href="#module-module" title="module">
   <code class="xref py py-mod docutils literal notranslate">
    <span class="pre">module</span>
   </code>
  </a>
  <a class="headerlink" href="#module" title="Permalink to this heading"></a> 
 </h1>
 <p>This is the module docstring</p>
 <span class="target" id="module-module"></span></section>
</section>

The effect is that cross references take you to the bottom of the docstring, not the top. See here for an example with a long docstring: https://domdfcoding.github.io/sphinx-issue/build/html/module.html

The same page but built with Sphinx 5.1: https://domdfcoding.github.io/sphinx-issue/build_51/html/module.html


With this patch the previous behaviour is restored:

diff --git a/sphinx/domains/python.py b/sphinx/domains/python.py
index 6076eb7fb..bd507a21c 100644
--- a/sphinx/domains/python.py
+++ b/sphinx/domains/python.py
@@ -1024,7 +1024,7 @@ class PyModule(SphinxDirective):
             content_node.document = self.state.document
             nested_parse_with_titles(self.state, self.content, content_node)
 
-        ret: List[Node] = [*content_node.children]
+        ret: List[Node] = []
         if not noindex:
             # note module to the domain
             node_id = make_id(self.env, self.state.document, 'module', modname)
@@ -1045,6 +1045,7 @@ class PyModule(SphinxDirective):
             indextext = '%s; %s' % (pairindextypes['module'], modname)
             inode = addnodes.index(entries=[('pair', indextext, node_id, '', None)])
             ret.append(inode)
+        ret.extend(content_node.children)
         return ret
 
     def make_old_id(self, name: str) -> str:

How to Reproduce

$ git clone https://github.com/domdfcoding/sphinx-issue
$ cd sphinx-issue
$ pip install sphinx
$ make html
$ # open build/html/module.html, click the heading xref "module" and see that you're taken to the bottom of the docstring.

Repeat with Sphinx==5.1 and see that you're taken to the top of the docstring.

Expected behavior

The xref target is at the top of the docstring.

Your project

https://github.com/domdfcoding/sphinx-issue

Screenshots

No response

OS

Ubuntu 20.04

Python version

3.8

Sphinx version

5.2.1

Sphinx extensions

sphinx.ext.autodoc

Extra tools

No response

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions