""" Adds a sphinx directive that can be used to automatically document a plugin. this:: .. autoplugin :: nose.plugins.foo :plugin: Pluggy produces:: .. automodule :: nose.plugins.foo Options ------- .. cmdoption :: --foo=BAR, --fooble=BAR Do the foo thing to the new thing. Plugin ------ .. autoclass :: nose.plugins.foo.Pluggy :members: Source ------ .. include :: path/to/nose/plugins/foo.py :literal: """ import os try: from docutils import nodes, utils from docutils.statemachine import ViewList from docutils.parsers.rst import directives except ImportError: pass # won't run anyway from nose.util import resolve_name from nose.plugins.base import Plugin from nose.plugins.manager import BuiltinPluginManager from nose.config import Config from nose.core import TestProgram from inspect import isclass def autoplugin_directive(dirname, arguments, options, content, lineno, content_offset, block_text, state, state_machine): mod_name = arguments[0] mod = resolve_name(mod_name) plug_name = options.get('plugin', None) if plug_name: obj = getattr(mod, plug_name) else: for entry in dir(mod): obj = getattr(mod, entry) if isclass(obj) and issubclass(obj, Plugin) and obj is not Plugin: plug_name = '%s.%s' % (mod_name, entry) break # mod docstring rst = ViewList() rst.append('.. automodule :: %s\n' % mod_name, '') rst.append('', '') # options rst.append('Options', '') rst.append('-------', '') rst.append('', '') plug = obj() opts = OptBucket() plug.options(opts, {}) for opt in opts: rst.append(opt.options(), '') rst.append(' \n', '') rst.append(' ' + opt.help + '\n', '') rst.append('\n', '') # plugin class rst.append('Plugin', '') rst.append('------', '') rst.append('', '') rst.append('.. autoclass :: %s\n' % plug_name, '') rst.append(' :members:\n', '') rst.append(' :show-inheritance:\n', '') rst.append('', '') # source rst.append('Source', '') rst.append('------', '') rst.append( '.. include :: %s\n' % utils.relative_path( state_machine.document['source'], os.path.abspath(mod.__file__.replace('.pyc', '.py'))), '') rst.append(' :literal:\n', '') rst.append('', '') node = nodes.section() node.document = state.document surrounding_title_styles = state.memo.title_styles surrounding_section_level = state.memo.section_level state.memo.title_styles = [] state.memo.section_level = 0 state.nested_parse(rst, 0, node, match_titles=1) state.memo.title_styles = surrounding_title_styles state.memo.section_level = surrounding_section_level return node.children def autohelp_directive(dirname, arguments, options, content, lineno, content_offset, block_text, state, state_machine): """produces rst from nose help""" config = Config(parserClass=OptBucket, plugins=BuiltinPluginManager()) parser = config.getParser(TestProgram.usage()) rst = ViewList() for line in parser.format_help().split('\n'): rst.append(line, '') rst.append('Options', '') rst.append('-------', '') rst.append('', '') for opt in parser: rst.append(opt.options(), '') rst.append(' \n', '') rst.append(' ' + opt.help + '\n', '') rst.append('\n', '') node = nodes.section() node.document = state.document surrounding_title_styles = state.memo.title_styles surrounding_section_level = state.memo.section_level state.memo.title_styles = [] state.memo.section_level = 0 state.nested_parse(rst, 0, node, match_titles=1) state.memo.title_styles = surrounding_title_styles state.memo.section_level = surrounding_section_level return node.children class OptBucket(object): def __init__(self, doc=None, prog='nosetests'): self.opts = [] self.doc = doc self.prog = prog def __iter__(self): return iter(self.opts) def format_help(self): return self.doc.replace('%prog', self.prog).replace(':\n', '::\n') def add_option(self, *arg, **kw): self.opts.append(Opt(*arg, **kw)) class Opt(object): def __init__(self, *arg, **kw): self.opts = arg self.action = kw.pop('action', None) self.default = kw.pop('default', None) self.metavar = kw.pop('metavar', None) self.help = kw.pop('help', None) def options(self): buf = [] for optstring in self.opts: desc = optstring if self.action not in ('store_true', 'store_false'): desc += '=%s' % self.meta(optstring) buf.append(desc) return '.. cmdoption :: ' + ', '.join(buf) def meta(self, optstring): # FIXME optparser default metavar? return self.metavar or 'DEFAULT' def setup(app): app.add_directive('autoplugin', autoplugin_directive, 1, (1, 0, 1), plugin=directives.unchanged) app.add_directive('autohelp', autohelp_directive, 0, (0, 0, 1))