| 
 | 1 | +from typing import TYPE_CHECKING, Any  | 
 | 2 | +from CPAC.pipeline.nodeblock import NodeBlockFunction  | 
 | 3 | +from docutils.statemachine import StringList  | 
 | 4 | +from sphinx.ext.autodoc import Documenter, FunctionDocumenter, bool_option  | 
 | 5 | + | 
 | 6 | + | 
 | 7 | +class NBFMixin(Documenter):  | 
 | 8 | +    def add_directive_header(self, sig: str) -> None:  | 
 | 9 | +        """Prepend "NodeBlockFunction" to the name & add the directive  | 
 | 10 | +        header and options to the generated content."""  | 
 | 11 | +        domain = getattr(self, 'domain', 'py')  | 
 | 12 | +        directive = getattr(self, 'directivetype', self.objtype)  | 
 | 13 | +        name = self.format_name()  | 
 | 14 | +        sourcename = self.get_sourcename()  | 
 | 15 | + | 
 | 16 | +        # Prepend NodeBlockFunction pseudoheader  | 
 | 17 | +        self.add_line(f'*NodeBlockFunction*: **{self.object.name}**',  | 
 | 18 | +                      sourcename)  | 
 | 19 | +        self.add_line('', sourcename)  | 
 | 20 | +        # one signature per line, indented by column  | 
 | 21 | +        prefix = f'.. {domain}:{directive}:: '  | 
 | 22 | +        for i, sig_line in enumerate(sig.split("\n")):  | 
 | 23 | +            self.add_line(f'{prefix}{name}{sig_line}',  | 
 | 24 | +                          sourcename)  | 
 | 25 | +            if i == 0:  | 
 | 26 | +                prefix = " " * len(prefix)  | 
 | 27 | + | 
 | 28 | +        if self.options.no_index or self.options.noindex:  | 
 | 29 | +            self.add_line('   :no-index:', sourcename)  | 
 | 30 | +        if self.objpath:  | 
 | 31 | +            # Be explicit about the module, this is necessary since .. class::  | 
 | 32 | +            # etc. don't support a prepended module name  | 
 | 33 | +            self.add_line('   :module: %s' % self.modname, sourcename)  | 
 | 34 | + | 
 | 35 | + | 
 | 36 | +class NodeBlockFunctionDocumenter(NBFMixin, FunctionDocumenter):  | 
 | 37 | +    """Sphinx Documenter for NodeBlockFunction"""  | 
 | 38 | +    objtype = 'NodeBlockFunction'  | 
 | 39 | +    directivetype = FunctionDocumenter.objtype  | 
 | 40 | +    priority = 10 + FunctionDocumenter.priority  | 
 | 41 | +    option_spec = dict(FunctionDocumenter.option_spec)  | 
 | 42 | +    option_spec['hex'] = bool_option  | 
 | 43 | + | 
 | 44 | +    @classmethod  | 
 | 45 | +    def can_document_member(cls, member: Any, membername: str, isattr: bool,  | 
 | 46 | +                            parent: Any) -> bool:  | 
 | 47 | +        """Determine if a member is a NodeBlockFunction"""  | 
 | 48 | +        return isinstance(member, NodeBlockFunction)  | 
 | 49 | + | 
 | 50 | +    def add_content(self,  | 
 | 51 | +                    more_content: StringList | None  | 
 | 52 | +                    ) -> None:  | 
 | 53 | + | 
 | 54 | +        super().add_content(more_content)  | 
 | 55 | + | 
 | 56 | +        source_name = self.get_sourcename()  | 
 | 57 | +        # nbf_object: NodeBlockFunction = self.object  | 
 | 58 | +        self.add_line('', source_name)  | 
 | 59 | +      | 
 | 60 | + | 
 | 61 | + | 
 | 62 | +def setup(app: 'Sphinx') -> dict[str, Any]:  | 
 | 63 | +    app.setup_extension('sphinx.ext.autodoc')  # Require autodoc extension  | 
 | 64 | +    app.add_autodocumenter(NodeBlockFunctionDocumenter)  | 
 | 65 | +    return {  | 
 | 66 | +        'version': '0.1',  | 
 | 67 | +        'parallel_read_safe': True,  | 
 | 68 | +        'parallel_write_safe': True,  | 
 | 69 | +    }  | 
0 commit comments