0

I have developed a sphinx extension for creating dependencies between different sections of a document. The primary application is plain text requirements management.

The main object in the extension is a 'Vertex' directive. Arbitrary content can be wrapped inside a Vertex directive, and annotated with 'parent' vertexes that it depends on.

.. vertex:: SYS-002
   :parents: USR-001:4sMl

   this is a system requirement derived from some user requirement

    .. note::
      it contains nested restructured text

This works fine, until the nested content contains a glossary term-

.. vertex:: SYS-002
   :parents: USR-001:4sMl

   this is a system requirement derived from some user requirement

   it has an embedded glossary term - :term:`Some Term`

this causes a build failure when using the latexpdf builder, and fails silently when using the html builder-

Exception occurred:
  File "/home/daniel.eades/Code/python/sphinx-graph/.venv/lib/python3.10/site-packages/docutils/nodes.py", line 652, in __getitem__
    return self.attributes[key]
KeyError: 'refdocname'

i'm guessing this is something to do with the order in which references are resolved.

I'm processing the Vertex directive like this-

@dataclass
class Args:
    """Parsed arguments for the Vertex directive."""

    uid: str
    parents: list[Link] = field(default_factory=list)
    layout: str = DEFAULT_LAYOUT


class Directive(SphinxDirective):
    """An RST node representing a To-Do item."""

    has_content = True
    required_arguments = 1
    option_spec = {
        "parents": parse.parents,
        "layout": parse.string,
    }

    def run(self) -> Sequence[nodes.Node]:
        """Run the directive and return a Vertex node."""
        args = Args(uid=self.arguments[0], **self.options)

        content_node = Node("\n".join(self.content))
        self.state.nested_parse(self.content, self.content_offset, content_node)

        fingerprint = base64.b64encode(
            hashlib.md5(content_node.astext().encode()).digest()
        )[:4].decode()

        targetnode = nodes.target("", "", ids=[args.uid])
        placeholder_node = Node(graph_uid=args.uid)

        with get_state(self.env) as state:
            state.insert_vertex(
                args.uid,
                Info(
                    docname=self.env.docname,
                    lineno=self.lineno,
                    node=content_node,
                    target=targetnode,
                    parents=args.parents,
                    fingerprint=fingerprint,
                    layout=args.layout,
                ),
            )

        return [targetnode, placeholder_node]

this is probably the part i'm least confident is correct-

content_node = Node("\n".join(self.content))
self.state.nested_parse(self.content, self.content_offset, content_node)

There's a reproduction here - https://github.com/danieleades/sphinx-graph/tree/bug-42

cd docs/
poetry run make latexpdf

(you'll need poetry installed)

mzjn
  • 48,958
  • 13
  • 128
  • 248

0 Answers0