Sent from my Metro By T-Mobile 4G LTE Android Device
________________________________
From: [email protected] <[email protected]> on behalf 
of Sean Leavey <[email protected]>
Sent: Saturday, April 4, 2020 4:15:59 AM
To: sphinx-users <[email protected]>
Subject: [sphinx-users] Implementing custom "autodoc" style objects

Hello Sphinx users,

I want to create a Sphinx directive that documents custom objects for a 
domain-specific language. I want to define an object like this...

My Custom Item
==============

..  dmn:component:: myitemcls

    This is some extra text!

and have Sphinx document it like it were a Python class, but not quite - 
something like this:

[cid:autoGeneratedInlineImage1]

(That's a mock-up of what I'd like - so far I've not managed it. Note also I'd 
like the "This is some extra text!" text to appear somewhere there too...)

The idea is that the custom Sphinx directive would look up myitemcls in my 
library and introspect its parameters and then document them here.
I figure this is the same as the Python autodoc module, but I'm having trouble 
understanding how it works - I find it's horrendously complicated and makes 
calls to other modules all over the place, not all of which are documented or 
require calls to non-public APIs. I tried to get it to work instead using a 
custom directive class, but I had to do something hacky - in the run method I 
grab the output from the parent (ObjectDescription) and inject some parameters 
into the middle of the node list - the problem is that the ObjectDescription 
directive appears to want the :param A: notation to have already been injected 
in before instantiation, as I believe autodoc would do. In contrast, with my 
method I have to inject these parameter strings into the object after 
instantiation (in run()), and that seems to be my problem. I guess the solution 
is to subclass some part of autodoc, but as I said I find it hard to figure out 
how.

Here's what I've got so far:

import docutils
from docutils import nodes
import sphinx
from docutils.parsers import rst
from docutils.parsers.rst import directives
from docutils.statemachine import StringList
from sphinx.domains import Domain, Index
from sphinx.domains.std import StandardDomain
from sphinx.roles import XRefRole
from sphinx.directives import ObjectDescription
from sphinx.util.nodes import make_refnode
from sphinx.util.docfields import DocFieldTransformer, GroupedField
from sphinx import addnodes


class ComponentNode(ObjectDescription):
    """A custom node that describes a component."""

    required_arguments = 1

    option_spec = {}

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self._component_name = self.arguments[0]

        # Argument node list, filled later.
        self._arglist = None
        self._paramlist = None

        # This is my own function, not shown, that populates self._paramlist 
with a list of strings containing ":param name:" etc. It also builds 
self._arglist with addnodes.desc_parameter nodes.
        self._parse_parameters()

    def run(self, *args, **kwargs):
        nodes = super().run(*args, **kwargs)

        # The following is a bit of a hack. I first overwrite the field type 
map to set up the
        # "param" parser. I then create a list of strings containing ":param 
[x]: [description]"
        # entries and parse the contents into a new node. Finally I stitch this 
node into the
        # middle of the node list returned by the parent run() method.

        self._doc_field_type_map = {
            "param": (
                GroupedField("parameters", label="Parameters", 
names=('param',), can_collapse=True),
                False # is typed
            ),
        }

        # Add parameters to content.
        extra = StringList(
            self._paramlist,
            source=((self.content.parent, 0)*len(self._paramlist)),
            parent=self.content.parent,
            parent_offset=self.content.parent_offset
        )

        contentnode = addnodes.desc_content()
        self.state.nested_parse(extra, self.content_offset, contentnode)

        DocFieldTransformer(self).transform_all(contentnode)

        return nodes[0:2] + [contentnode] + nodes[2:]

I'm not happy with this, it's quite hacky and I figure I'm not doing it 
properly. It also generates documentation that looks different to that of class 
documentation - the "parameter" labels are blue not grey:

[cid:autoGeneratedInlineImage2]

Can anyone help me figure out how to implement this custom directive, ideally 
using autodoc?

--
You received this message because you are subscribed to the Google Groups 
"sphinx-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to 
[email protected]<mailto:[email protected]>.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/sphinx-users/5f306f1b-a565-4d16-a515-8dd2b2861d51%40googlegroups.com<https://groups.google.com/d/msgid/sphinx-users/5f306f1b-a565-4d16-a515-8dd2b2861d51%40googlegroups.com?utm_medium=email&utm_source=footer>.

-- 
You received this message because you are subscribed to the Google Groups 
"sphinx-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/sphinx-users/DM6PR07MB73243C927C5EF2984CBC56B2A1C20%40DM6PR07MB7324.namprd07.prod.outlook.com.

Reply via email to