#!/usr/bin/env python
from commands import getstatusoutput
from docutils.core import publish_string, publish_parts
from docutils.nodes import SparseNodeVisitor
from docutils.readers.standalone import Reader
from docutils.writers import Writer
import nose
import os
import pudge.browser
import re
import sys
import textwrap
import time
# constants
success = 0
div = '\n----\n'
warning = """
*Do not edit above this line. Content above this line is automatically
generated and edits above this line will be discarded.*
= Comments =
"""
def ucfirst(s):
return s[0].upper() + s[1:].lower()
def words(s):
return s.split(' ')
def wiki_word(node):
print "Unknown ref %s" % node.astext()
node['refuri'] = ''.join(map(ucfirst, words(node.astext())))
del node['refname']
node.resolved = True
return True
wiki_word.priority = 100
class WWReader(Reader):
unknown_reference_resolvers = (wiki_word,)
class WikiWriter(Writer):
def translate(self):
visitor = WikiVisitor(self.document)
self.document.walkabout(visitor)
self.output = visitor.astext()
class WikiVisitor(SparseNodeVisitor):
def __init__(self, document):
SparseNodeVisitor.__init__(self, document)
self.list_depth = 0
self.list_item_prefix = None
self.indent = self.old_indent = ''
self.output = []
self.preformat = False
def astext(self):
return ''.join(self.output)
def visit_Text(self, node):
#print "Text", node
data = node.astext()
if not self.preformat:
data = data.lstrip('\n\r')
data = data.replace('\r', '')
data = data.replace('\n', ' ')
self.output.append(data)
def visit_bullet_list(self, node):
self.list_depth += 1
self.list_item_prefix = (' ' * self.list_depth) + '* '
def depart_bullet_list(self, node):
self.list_depth -= 1
if self.list_depth == 0:
self.list_item_prefix = None
else:
(' ' * self.list_depth) + '* '
self.output.append('\n\n')
def visit_list_item(self, node):
self.old_indent = self.indent
self.indent = self.list_item_prefix
def depart_list_item(self, node):
self.indent = self.old_indent
def visit_literal_block(self, node):
self.output.extend(['{{{', '\n'])
self.preformat = True
def depart_literal_block(self, node):
self.output.extend(['\n', '}}}', '\n\n'])
self.preformat = False
def visit_paragraph(self, node):
self.output.append(self.indent)
def depart_paragraph(self, node):
self.output.append('\n\n')
if self.indent == self.list_item_prefix:
# we're in a sub paragraph of a list item
self.indent = ' ' * self.list_depth
def visit_reference(self, node):
if node.has_key('refuri'):
href = node['refuri']
elif node.has_key('refid'):
href = '#' + node['refid']
else:
href = None
self.output.append('[' + href + ' ')
def depart_reference(self, node):
self.output.append(']')
def visit_subtitle(self, node):
self.output.append('=== ')
def depart_subtitle(self, node):
self.output.append(' ===\n\n')
self.list_depth = 0
self.indent = ''
def visit_title(self, node):
self.output.append('== ')
def depart_title(self, node):
self.output.append(' ==\n\n')
self.list_depth = 0
self.indent = ''
def visit_title_reference(self, node):
self.output.append("`")
def depart_title_reference(self, node):
self.output.append("`")
def visit_emphasis(self, node):
self.output.append('*')
def depart_emphasis(self, node):
self.output.append('*')
def visit_literal(self, node):
self.output.append('`')
def depart_literal(self, node):
self.output.append('`')
def runcmd(cmd):
print cmd
(status,output) = getstatusoutput(cmd)
if status != success:
raise Exception(output)
def section(doc, name):
m = re.search(r'(%s\n%s.*?)\n[^\n-]{3,}\n-{3,}\n' %
(name, '-' * len(name)), doc, re.DOTALL)
if m:
return m.groups()[0]
raise Exception('Section %s not found' % name)
def wikirst(doc):
return publish_string(doc, reader=WWReader(), writer=WikiWriter())
def plugin_interface():
"""use pudge browser to generate interface docs
from nose.plugins.base.PluginInterface
"""
b = pudge.browser.Browser(['nose.plugins.base'], None)
m = b.modules()[0]
intf = list([ c for c in m.classes() if c.name ==
'IPluginInterface'])[0]
doc = wikirst(intf.doc())
methods = [ m for m in intf.routines() if not m.name.startswith('_') ]
methods.sort(lambda a, b: cmp(a.name, b.name))
mdoc = []
for m in methods:
mdoc.append('*%s%s*\n\n' % (m.name, m.formatargs()))
mdoc.append(' ' + m.doc().replace('\n', '\n '))
mdoc.append('\n\n')
doc = doc + ''.join(mdoc)
return doc
def example_plugin():
# FIXME dump whole example plugin code from setup.py and plug.py
# into python source sections
root = os.path.abspath(os.path.join(os.path.dirname(__file__),
'..'))
exp = os.path.join(root, 'examples', 'plugin')
setup = file(os.path.join(exp, 'setup.py'), 'r').read()
plug = file(os.path.join(exp, 'plug.py'), 'r').read()
wik = "*%s:*\n{{{\n%s\n}}}\n"
return wik % ('setup.py', setup) + wik % ('plug.py', plug)
def tools():
top = wikirst(nose.tools.__doc__)
b = pudge.browser.Browser(['nose.tools'], None)
m = b.modules()[0]
funcs = [ (f.name, f.formatargs().replace('(self, ', '('), f.doc())
for f in m.routines() ]
funcs.sort()
mdoc = [top, '\n\n']
for name, args, doc in funcs:
mdoc.append("*%s%s*\n\n" % (name, args))
mdoc.append(' ' + doc.replace('\n', '\n '))
mdoc.append('\n\n')
return ''.join(mdoc)
def usage():
doc = nose.core.TestProgram.__doc__.replace("\\", "\\\\")
parser = nose.core.get_parser(env={}, builtin_only=True, doc=doc)
out = '{{{\n' + \
parser.format_help().replace('mkwiki.py', 'nosetests') + \
'\n}}}\n'
return out
def mkwiki(path):
#
# Pages to publish and the docstring(s) to load for that page
#
pages = { #'SandBox': wikirst(section(nose.__doc__, 'Writing tests'))
'WritingTests': wikirst(section(nose.__doc__, 'Writing tests')),
'NoseFeatures': wikirst(section(nose.__doc__, 'Features')),
'WritingPlugins': wikirst(nose.plugins.__doc__),
'PluginInterface': plugin_interface(),
'TestingTools': tools(),
'FindingAndRunningTests': wikirst(
section(nose.__doc__, 'Finding and running tests')),
# FIXME finish example plugin doc... add some explanation
'ExamplePlugin': example_plugin(),
'NosetestsUsage': usage(),
}
current = os.getcwd()
w = Wiki(path)
for page, doc in pages.items():
print "====== %s ======" % page
w.update_docs(page, doc)
print "====== %s ======" % page
os.chdir(current)
class Wiki(object):
doc_re = re.compile(r'(.*?)' + div, re.DOTALL)
def __init__(self, path):
self.path = path
self.newpages = []
os.chdir(path)
runcmd('svn up')
def filename(self, page):
if not page.endswith('.wiki'):
page = page + '.wiki'
return page
def get_page(self, page):
headers = []
content = []
try:
fh = file(self.filename(page), 'r')
in_header = True
for line in fh:
if in_header:
if line.startswith('#'):
headers.append(line)
else:
in_header = False
content.append(line)
else:
content.append(line)
fh.close()
return (headers, ''.join(content))
except IOError:
self.newpages.append(page)
return ''
def set_docs(self, page, headers, page_src, docs):
wikified = docs + div
if not page_src:
new_src = wikified + warning
print "! Adding new page"
else:
m = self.doc_re.search(page_src)
if m:
print "! Updating doc section"
new_src = self.doc_re.sub(wikified, page_src, 1)
else:
print "! Adding new doc section"
new_src = wikified + page_src
if new_src == page_src:
print "! No changes"
return
# Restore any headers (lines marked by # at start of file)
if headers:
new_src = ''.join(headers) + '\n' + new_src
fh = file(self.filename(page), 'w')
fh.write(new_src)
fh.close()
def update_docs(self, page, doc):
headers, current = self.get_page(page)
self.set_docs(page, headers, current, doc)
if page in self.newpages:
runcmd('svn add %s' % self.filename(page))
def main():
path = os.path.abspath(
os.path.join(os.path.dirname(__file__), '..', '..', '..', 'wiki'))
mkwiki(path)
if __name__ == '__main__':
main()
syntax highlighted by Code2HTML, v. 0.9.1