Skip to content

Commit eabda63

Browse files
TomerGodingerstephenfin
authored andcommitted
Add support for post-processing nodes
By providing the option ":post-process: module.path:funcion", the user can direct the directive to run the provided function on the command and its generated node for each command processed. This allows for full per-command customization of the output.
1 parent 017a2e8 commit eabda63

File tree

1 file changed

+36
-13
lines changed

1 file changed

+36
-13
lines changed

sphinx_click/ext.py

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -510,9 +510,10 @@ class ClickDirective(rst.Directive):
510510
'commands': directives.unchanged,
511511
'show-nested': directives.flag,
512512
'hide-header': directives.flag,
513+
'post-process': directives.unchanged_required,
513514
}
514515

515-
def _load_module(self, module_path: str) -> ty.Union[click.Command, click.Group]:
516+
def _load_module(self, module_path: str) -> ty.Any:
516517
"""Load the module."""
517518

518519
try:
@@ -541,14 +542,7 @@ def _load_module(self, module_path: str) -> ty.Union[click.Command, click.Group]
541542
'Module "{}" has no attribute "{}"'.format(module_name, attr_name)
542543
)
543544

544-
parser = getattr(mod, attr_name)
545-
546-
if not isinstance(parser, (click.Command, click.Group)):
547-
raise self.error(
548-
'"{}" of type "{}" is not click.Command or click.Group.'
549-
'"click.BaseCommand"'.format(type(parser), module_path)
550-
)
551-
return parser
545+
return getattr(mod, attr_name)
552546

553547
def _generate_nodes(
554548
self,
@@ -620,13 +614,13 @@ def _generate_nodes(
620614
)
621615
)
622616
else:
623-
commands = _filter_commands(ctx, commands)
624-
for command in commands:
617+
# We use the term "subcommand" here but these can be main commands as well
618+
for subcommand in _filter_commands(ctx, commands):
625619
parent = ctx if not semantic_group else ctx.parent
626620
subcommand_nodes.extend(
627621
self._generate_nodes(
628-
command.name,
629-
command,
622+
subcommand.name,
623+
subcommand,
630624
parent=parent,
631625
nested=nested,
632626
hide_header=False, # Hiding the header should not propagate to children
@@ -659,13 +653,37 @@ def _generate_nodes(
659653
section.append(node)
660654
final_nodes = [section]
661655

656+
self._post_process(command, final_nodes)
657+
662658
return final_nodes
663659

660+
def _post_process(
661+
self,
662+
command: click.Command,
663+
nodes: ty.List[nodes.section],
664+
) -> None:
665+
"""Runs the post-processor, if any, for the given command and nodes.
666+
667+
If a post-processor for the created nodes was set via the
668+
:post-process: option, every set of nodes generated by the directive is
669+
run through the post-processor.
670+
671+
This allows for per-command customization of the output.
672+
"""
673+
if self.postprocessor:
674+
self.postprocessor(command, nodes)
675+
664676
def run(self) -> ty.Sequence[nodes.Element]:
665677
self.env = self.state.document.settings.env
666678

667679
command = self._load_module(self.arguments[0])
668680

681+
if not isinstance(command, (click.Command, click.Group)):
682+
raise self.error(
683+
'"{}" of type "{}" is not click.Command or click.Group.'
684+
'"click.BaseCommand"'.format(type(command), self.arguments[0])
685+
)
686+
669687
if 'prog' not in self.options:
670688
raise self.error(':prog: must be specified')
671689

@@ -674,6 +692,11 @@ def run(self) -> ty.Sequence[nodes.Element]:
674692
nested = self.options.get('nested')
675693
hide_header = 'hide-header' in self.options
676694

695+
self.postprocessor = None
696+
if 'post-process' in self.options:
697+
postprocessor_module_path = self.options.get('post-process')
698+
self.postprocessor = self._load_module(postprocessor_module_path)
699+
677700
if show_nested:
678701
if nested:
679702
raise self.error(

0 commit comments

Comments
 (0)