I'm updating Django-DBBackup's documentation and don't want to copy/paste piece of code in docs, especialy commands' usages text. Fortunately optparse
and argparse
have the helpful parser.print_usage()
method. Unfortunately there's no Sphinx plugin to simply get these outputs and include in docs. It's time to get on the job.
What I want to do ?
Have a simple RST markup for get the --help
of a Django command. I want to be able to do:
.. djcommand:: myapp.management.commands.mycmd
And Bim! I have:
Usage: manage.py mycmd [options]
Options:
--version show program's version number and exit
-h, --help show this help message and exit
The requirements are:
- Understand how to create a Sphinx plugin
- Know how to print usage
We'll begin by the 2nd, less boring...
It is not hard to have pretty nice help message, Django uses argparse
(optparse
for old versions) and it has a print_help()
method:
>>> argparse.ArgumentParser.print_help??
Signature: argparse.ArgumentParser.print_help(self, file=None)
Source:
def print_help(self, file=None):
if file is None:
file = _sys.stdout
self._print_message(self.format_help(), file)
File: /usr/lib/python2.7/argparse.py
Type: instancemethod
This method takes an optional argument file, if passed output will be written on that file object. Next thing, Django can print_help
, but it can only on stdout (the default output file of argparse.ArgumentParser.print_help
if you follow everything):
>>> django.core.management.base.BaseCommand.print_help??
Signature: django.core.management.base.BaseCommand.print_help(self, prog_name, subcommand)
Source:
def print_help(self, prog_name, subcommand):
"""
Print the help message for this command, derived from
``self.usage()``.
"""
parser = self.create_parser(prog_name, subcommand)
parser.print_help()
We just have to create the parser and print help in a BytesIO
.
And the bridge between RST and Python
Sphinx has already a tons of plugin, just look at sphinx-contrib to have an overview. There is a quite great tutorial to understand how to create your plugin but I think it is too complex for get a first approach of how to do. What I am doing is pretty simple and a 6 pages tutorial is too much, I prefer to look at source code and I found sphinxcontrib/examplecode. From this reference I created the following code:
from importlib import import_module
from docutils import nodes
from docutils.parsers.rst import Directive
from io import BytesIO
class djcommand(nodes.Element):
pass
def visit_djcommand_node(self, node):
self.visit_admonition(node)
self.body.append(self.starttag(node, "pre"))
command_name = node.rawsource.split('.')[-1]
command_module = import_module(node.rawsource)
command = command_module.Command()
parser = command.create_parser('manage.py', command_name)
command_help = BytesIO()
parser.print_help(command_help)
command_help.seek(0)
self.body.append(command_help.read())
self.body.append("</pre>")
def depart_djcommand_node(self, node):
self.depart_admonition(node)
class DjCommandDirective(Directive):
has_content = True
node_class = djcommand
def run(self):
self.assert_has_content()
text = '\n'.join(self.content)
node = self.node_class(text)
return [node]
Do not copy/paste, it is packaged
I created this repository: sphinx-django-command, as said it is a Sphinx plugin, you won't have to pull your hairs like me. Just pip install sphinx-django-command.
Comments
No comments yet.