2009-07-15 03:17:13 +08:00
|
|
|
|
2009-10-27 23:49:38 +08:00
|
|
|
import os, sys
|
2009-07-15 03:17:13 +08:00
|
|
|
WIDTH = 75
|
|
|
|
|
|
|
|
plugins = [
|
2009-11-05 10:18:55 +08:00
|
|
|
('advanced python testing',
|
2010-02-10 23:11:19 +08:00
|
|
|
'skipping mark pdb figleaf '
|
2010-04-12 22:08:12 +08:00
|
|
|
'monkeypatch coverage capture capturelog recwarn tmpdir',),
|
2010-01-18 23:18:59 +08:00
|
|
|
('distributed testing, CI and deployment',
|
|
|
|
'xdist pastebin junitxml resultlog genscript',),
|
2010-04-12 22:08:12 +08:00
|
|
|
('testing domains and conventions codecheckers',
|
2010-01-18 23:18:59 +08:00
|
|
|
'oejskit django unittest nose doctest restdoc'),
|
2010-01-18 23:26:26 +08:00
|
|
|
('internal, debugging, help functionality',
|
|
|
|
'helpconfig terminal hooklog')
|
2009-07-22 22:09:49 +08:00
|
|
|
#('internal plugins / core functionality',
|
2009-11-05 10:18:55 +08:00
|
|
|
# #'runner execnetcleanup # pytester',
|
|
|
|
# 'runner execnetcleanup' # pytester',
|
2009-07-22 22:09:49 +08:00
|
|
|
#)
|
2009-07-15 03:17:13 +08:00
|
|
|
]
|
|
|
|
|
|
|
|
externals = {
|
2009-11-05 10:18:55 +08:00
|
|
|
'oejskit': "run javascript tests in real life browsers",
|
2010-01-18 23:18:59 +08:00
|
|
|
'xdist': None,
|
|
|
|
'figleaf': None,
|
2010-04-12 22:08:12 +08:00
|
|
|
'capturelog': None,
|
|
|
|
'coverage': None,
|
|
|
|
'codecheckers': None,
|
2009-11-05 10:18:55 +08:00
|
|
|
'django': "for testing django applications",
|
2009-07-21 00:54:08 +08:00
|
|
|
}
|
2009-10-16 02:10:06 +08:00
|
|
|
|
2009-07-21 00:54:08 +08:00
|
|
|
def warn(*args):
|
|
|
|
msg = " ".join(map(str, args))
|
|
|
|
print >>sys.stderr, "WARN:", msg
|
2009-07-15 03:17:13 +08:00
|
|
|
|
2009-07-21 00:54:08 +08:00
|
|
|
class RestWriter:
|
2009-07-31 20:43:04 +08:00
|
|
|
_all_links = {}
|
|
|
|
|
2009-07-21 00:54:08 +08:00
|
|
|
def __init__(self, target):
|
|
|
|
self.target = py.path.local(target)
|
|
|
|
self.links = []
|
2009-07-15 03:17:13 +08:00
|
|
|
|
2009-07-21 00:54:08 +08:00
|
|
|
def _getmsg(self, args):
|
|
|
|
return " ".join(map(str, args))
|
2009-07-15 03:17:13 +08:00
|
|
|
|
2009-07-21 00:54:08 +08:00
|
|
|
def Print(self, *args, **kwargs):
|
|
|
|
msg = self._getmsg(args)
|
|
|
|
if 'indent' in kwargs:
|
|
|
|
indent = kwargs['indent'] * " "
|
|
|
|
lines = [(indent + x) for x in msg.split("\n")]
|
|
|
|
msg = "\n".join(lines)
|
|
|
|
self.out.write(msg)
|
|
|
|
if not msg or msg[-1] != "\n":
|
|
|
|
self.out.write("\n")
|
|
|
|
self.out.flush()
|
|
|
|
|
|
|
|
def sourcecode(self, source):
|
|
|
|
lines = str(source).split("\n")
|
|
|
|
self.Print(".. sourcecode:: python")
|
|
|
|
self.Print()
|
|
|
|
for line in lines:
|
|
|
|
self.Print(" ", line)
|
|
|
|
|
|
|
|
def _sep(self, separator, args):
|
|
|
|
msg = self._getmsg(args)
|
|
|
|
sep = len(msg) * separator
|
|
|
|
self.Print()
|
|
|
|
self.Print(msg)
|
|
|
|
self.Print(sep)
|
|
|
|
self.Print()
|
|
|
|
|
|
|
|
|
|
|
|
def h1(self, *args):
|
|
|
|
self._sep('=', args)
|
|
|
|
|
|
|
|
def h2(self, *args):
|
|
|
|
self._sep('-', args)
|
|
|
|
|
|
|
|
def h3(self, *args):
|
|
|
|
self._sep('+', args)
|
|
|
|
|
|
|
|
def li(self, *args):
|
|
|
|
msg = self._getmsg(args)
|
|
|
|
sep = "* %s" %(msg)
|
|
|
|
self.Print(sep)
|
|
|
|
|
|
|
|
def dt(self, term):
|
|
|
|
self.Print("``%s``" % term)
|
|
|
|
|
|
|
|
def dd(self, doc):
|
|
|
|
self.Print(doc, indent=4)
|
|
|
|
|
|
|
|
def para(self, *args):
|
|
|
|
msg = self._getmsg(args)
|
|
|
|
self.Print(msg)
|
|
|
|
|
|
|
|
def add_internal_link(self, name, path):
|
|
|
|
relpath = path.new(ext=".html").relto(self.target.dirpath())
|
|
|
|
self.links.append((name, relpath))
|
|
|
|
|
|
|
|
def write_links(self):
|
|
|
|
self.Print()
|
2009-07-31 20:43:04 +08:00
|
|
|
self.Print(".. include:: links.txt")
|
2009-07-21 00:54:08 +08:00
|
|
|
for link in self.links:
|
2009-07-31 20:43:04 +08:00
|
|
|
key = link[0]
|
|
|
|
if key in self._all_links:
|
|
|
|
assert self._all_links[key] == link[1], (key, link[1])
|
|
|
|
else:
|
|
|
|
self._all_links[key] = link[1]
|
|
|
|
|
|
|
|
def write_all_links(cls, linkpath):
|
|
|
|
p = linkpath.new(basename="links.txt")
|
|
|
|
p_writer = RestWriter(p)
|
|
|
|
p_writer.out = p_writer.target.open("w")
|
|
|
|
for name, value in cls._all_links.items():
|
|
|
|
p_writer.Print(".. _`%s`: %s" % (name, value))
|
|
|
|
p_writer.out.close()
|
|
|
|
del p_writer.out
|
|
|
|
write_all_links = classmethod(write_all_links)
|
2009-07-21 00:54:08 +08:00
|
|
|
|
|
|
|
def make(self, **kwargs):
|
|
|
|
self.out = self.target.open("w")
|
|
|
|
self.makerest(**kwargs)
|
|
|
|
self.write_links()
|
|
|
|
|
|
|
|
self.out.close()
|
|
|
|
print "wrote", self.target
|
|
|
|
del self.out
|
2009-10-16 02:10:06 +08:00
|
|
|
|
2009-07-21 00:54:08 +08:00
|
|
|
class PluginOverview(RestWriter):
|
|
|
|
def makerest(self, config):
|
2010-01-11 21:30:50 +08:00
|
|
|
plugindir = py._pydir.join('plugin')
|
2009-07-21 00:54:08 +08:00
|
|
|
for cat, specs in plugins:
|
|
|
|
pluginlist = specs.split()
|
|
|
|
self.h1(cat)
|
|
|
|
for name in pluginlist:
|
|
|
|
oneliner = externals.get(name, None)
|
|
|
|
docpath = self.target.dirpath(name).new(ext=".txt")
|
|
|
|
if oneliner is not None:
|
|
|
|
htmlpath = docpath.new(ext='.html')
|
2010-01-13 07:47:20 +08:00
|
|
|
self.para("%s_ (external) %s" %(name, oneliner))
|
2009-07-21 00:54:08 +08:00
|
|
|
self.add_internal_link(name, htmlpath)
|
|
|
|
else:
|
|
|
|
doc = PluginDoc(docpath)
|
|
|
|
doc.make(config=config, name=name)
|
|
|
|
self.add_internal_link(name, doc.target)
|
2010-01-18 23:18:59 +08:00
|
|
|
if name in externals:
|
|
|
|
self.para("%s_ (external) %s" %(name, doc.oneliner))
|
|
|
|
else:
|
|
|
|
self.para("%s_ %s" %(name, doc.oneliner))
|
2009-07-21 00:54:08 +08:00
|
|
|
self.Print()
|
|
|
|
|
|
|
|
class HookSpec(RestWriter):
|
|
|
|
def makerest(self, config):
|
2010-05-06 03:01:54 +08:00
|
|
|
for module in config.pluginmanager.hook._hookspecs:
|
|
|
|
source = py.code.Source(module)
|
|
|
|
self.h1("hook specification sourcecode")
|
|
|
|
self.sourcecode(source)
|
2009-07-21 00:54:08 +08:00
|
|
|
|
|
|
|
class PluginDoc(RestWriter):
|
|
|
|
def makerest(self, config, name):
|
|
|
|
config.pluginmanager.import_plugin(name)
|
|
|
|
plugin = config.pluginmanager.getplugin(name)
|
|
|
|
assert plugin is not None, plugin
|
2010-01-13 23:00:33 +08:00
|
|
|
print plugin
|
2009-07-15 03:17:13 +08:00
|
|
|
doc = plugin.__doc__.strip()
|
|
|
|
i = doc.find("\n")
|
|
|
|
if i == -1:
|
2009-07-21 00:54:08 +08:00
|
|
|
oneliner = doc
|
|
|
|
moduledoc = ""
|
2009-07-15 03:17:13 +08:00
|
|
|
else:
|
2009-07-21 00:54:08 +08:00
|
|
|
oneliner = doc[:i].strip()
|
|
|
|
moduledoc = doc[i+1:].strip()
|
|
|
|
|
2010-01-13 23:00:33 +08:00
|
|
|
self.name = oneliner # plugin.__name__.split(".")[-1]
|
2009-07-21 00:54:08 +08:00
|
|
|
self.oneliner = oneliner
|
|
|
|
self.moduledoc = moduledoc
|
|
|
|
|
2010-01-13 23:00:33 +08:00
|
|
|
#self.h1("%s plugin" % self.name) # : %s" %(self.name, self.oneliner))
|
|
|
|
self.h1(oneliner)
|
|
|
|
#self.Print(self.oneliner)
|
2009-07-21 00:54:08 +08:00
|
|
|
self.Print()
|
2009-07-22 22:09:49 +08:00
|
|
|
self.Print(".. contents::")
|
|
|
|
self.Print(" :local:")
|
|
|
|
self.Print()
|
2009-07-21 00:54:08 +08:00
|
|
|
|
|
|
|
self.Print(moduledoc)
|
|
|
|
|
|
|
|
self.emit_funcargs(plugin)
|
|
|
|
self.emit_options(plugin)
|
2010-02-10 21:21:49 +08:00
|
|
|
if name not in externals:
|
|
|
|
self.emit_source(plugin, config.hg_changeset)
|
2009-07-21 00:54:08 +08:00
|
|
|
#self.sourcelink = (purename,
|
|
|
|
# "http://bitbucket.org/hpk42/py-trunk/src/tip/py/test/plugin/" +
|
|
|
|
# purename + ".py")
|
|
|
|
#
|
|
|
|
def emit_source(self, plugin, hg_changeset):
|
|
|
|
basename = py.path.local(plugin.__file__).basename
|
|
|
|
if basename.endswith("pyc"):
|
|
|
|
basename = basename[:-1]
|
|
|
|
#self.para("`%s`_ source code" % basename)
|
|
|
|
#self.links.append((basename,
|
|
|
|
# "http://bitbucket.org/hpk42/py-trunk/src/tip/py/test/plugin/" +
|
|
|
|
# basename))
|
2009-07-22 22:09:49 +08:00
|
|
|
self.h1("Start improving this plugin in 30 seconds")
|
2009-07-21 00:54:08 +08:00
|
|
|
self.para(py.code.Source("""
|
|
|
|
1. Download `%s`_ plugin source code
|
|
|
|
2. put it somewhere as ``%s`` into your import path
|
2009-07-22 22:09:49 +08:00
|
|
|
3. a subsequent ``py.test`` run will use your local version
|
2009-07-21 00:54:08 +08:00
|
|
|
|
2009-08-19 01:04:57 +08:00
|
|
|
Checkout customize_, other plugins_ or `get in contact`_.
|
2009-07-21 00:54:08 +08:00
|
|
|
""" % (basename, basename)))
|
|
|
|
# your work appreciated if you offer back your version. In this case
|
|
|
|
# it probably makes sense if you `checkout the py.test
|
|
|
|
# development version`_ and apply your changes to the plugin
|
|
|
|
# version in there.
|
2009-08-19 01:04:57 +08:00
|
|
|
#self.links.append((basename,
|
|
|
|
# "http://bitbucket.org/hpk42/py-trunk/raw/%s/"
|
|
|
|
# "py/test/plugin/%s" %(hg_changeset, basename)))
|
2009-07-21 00:54:08 +08:00
|
|
|
self.links.append((basename,
|
|
|
|
"http://bitbucket.org/hpk42/py-trunk/raw/%s/"
|
2010-01-22 02:34:42 +08:00
|
|
|
"py/_plugin/%s" %(pyversion, basename)))
|
2009-08-19 01:04:57 +08:00
|
|
|
self.links.append(('customize', '../customize.html'))
|
2009-07-21 00:54:08 +08:00
|
|
|
self.links.append(('plugins', 'index.html'))
|
2009-08-19 01:04:57 +08:00
|
|
|
self.links.append(('get in contact', '../../contact.html'))
|
2009-07-21 00:54:08 +08:00
|
|
|
self.links.append(('checkout the py.test development version',
|
2009-11-02 20:00:48 +08:00
|
|
|
'../../install.html#checkout'))
|
2009-07-22 22:09:49 +08:00
|
|
|
|
|
|
|
if 0: # this breaks the page layout and makes large doc files
|
|
|
|
#self.h2("plugin source code")
|
|
|
|
self.Print()
|
|
|
|
self.para("For your convenience here is also an inlined version "
|
|
|
|
"of ``%s``:" %basename)
|
|
|
|
#self(or copy-paste from below)
|
|
|
|
self.Print()
|
|
|
|
self.sourcecode(py.code.Source(plugin))
|
2009-07-21 00:54:08 +08:00
|
|
|
|
|
|
|
def emit_funcargs(self, plugin):
|
|
|
|
funcargfuncs = []
|
|
|
|
prefix = "pytest_funcarg__"
|
|
|
|
for name in vars(plugin):
|
|
|
|
if name.startswith(prefix):
|
|
|
|
funcargfuncs.append(getattr(plugin, name))
|
|
|
|
if not funcargfuncs:
|
|
|
|
return
|
|
|
|
for func in funcargfuncs:
|
|
|
|
argname = func.__name__[len(prefix):]
|
2009-07-22 22:09:49 +08:00
|
|
|
self.Print()
|
2009-07-21 00:54:08 +08:00
|
|
|
self.Print(".. _`%s funcarg`:" % argname)
|
|
|
|
self.Print()
|
|
|
|
self.h2("the %r test function argument" % argname)
|
|
|
|
if func.__doc__:
|
|
|
|
doclines = func.__doc__.split("\n")
|
|
|
|
source = py.code.Source("\n".join(doclines[1:]))
|
|
|
|
source.lines.insert(0, doclines[0])
|
|
|
|
self.para(str(source))
|
|
|
|
else:
|
|
|
|
self.para("XXX missing docstring")
|
|
|
|
warn("missing docstring", func)
|
|
|
|
|
|
|
|
def emit_options(self, plugin):
|
2010-01-14 00:15:54 +08:00
|
|
|
from py._test.parseopt import Parser
|
2009-07-21 00:54:08 +08:00
|
|
|
options = []
|
|
|
|
parser = Parser(processopt=options.append)
|
|
|
|
if hasattr(plugin, 'pytest_addoption'):
|
|
|
|
plugin.pytest_addoption(parser)
|
|
|
|
if not options:
|
|
|
|
return
|
|
|
|
self.h2("command line options")
|
|
|
|
self.Print()
|
2009-08-28 03:12:55 +08:00
|
|
|
formatter = py.std.optparse.IndentedHelpFormatter()
|
2009-07-21 00:54:08 +08:00
|
|
|
for opt in options:
|
|
|
|
switches = formatter.format_option_strings(opt)
|
|
|
|
self.Print("``%s``" % switches)
|
|
|
|
self.Print(opt.help, indent=4)
|
2009-07-15 03:17:13 +08:00
|
|
|
|
|
|
|
if __name__ == "__main__":
|
2009-10-27 23:49:38 +08:00
|
|
|
if os.path.exists("py"):
|
|
|
|
sys.path.insert(0, os.getcwd())
|
|
|
|
import py
|
2009-07-21 00:54:08 +08:00
|
|
|
_config = py.test.config
|
|
|
|
_config.parse([])
|
|
|
|
_config.pluginmanager.do_configure(_config)
|
2009-07-15 03:17:13 +08:00
|
|
|
|
2009-07-21 00:54:08 +08:00
|
|
|
pydir = py.path.local(py.__file__).dirpath()
|
2009-08-19 01:04:57 +08:00
|
|
|
pyversion = py.version
|
2009-07-21 00:54:08 +08:00
|
|
|
|
|
|
|
cmd = "hg tip --template '{node}'"
|
|
|
|
old = pydir.dirpath().chdir()
|
|
|
|
_config.hg_changeset = py.process.cmdexec(cmd).strip()
|
|
|
|
|
|
|
|
testdir = pydir.dirpath("doc", 'test')
|
2009-07-15 03:17:13 +08:00
|
|
|
|
2009-07-21 00:54:08 +08:00
|
|
|
ov = PluginOverview(testdir.join("plugin", "index.txt"))
|
|
|
|
ov.make(config=_config)
|
|
|
|
|
|
|
|
ov = HookSpec(testdir.join("plugin", "hookspec.txt"))
|
|
|
|
ov.make(config=_config)
|
|
|
|
|
2009-07-31 20:43:04 +08:00
|
|
|
RestWriter.write_all_links(testdir.join("plugin", "links.txt"))
|
|
|
|
|