296 lines
		
	
	
		
			9.7 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			296 lines
		
	
	
		
			9.7 KiB
		
	
	
	
		
			Python
		
	
	
	
 | 
						|
import os, sys
 | 
						|
WIDTH = 75
 | 
						|
 | 
						|
plugins = [
 | 
						|
    ('advanced python testing', 
 | 
						|
            'skipping mark pdb figleaf coverage '
 | 
						|
            'monkeypatch capture recwarn tmpdir',),
 | 
						|
    ('testing domains', 
 | 
						|
            'oejskit django'),
 | 
						|
    ('reporting and failure logging', 
 | 
						|
            'pastebin xmlresult resultlog terminal',),
 | 
						|
    ('other testing conventions',
 | 
						|
            'unittest nose doctest restdoc'),
 | 
						|
    ('core debugging / help functionality', 
 | 
						|
          'helpconfig hooklog')
 | 
						|
    #('internal plugins / core functionality', 
 | 
						|
    #    #'runner execnetcleanup # pytester',
 | 
						|
    #    'runner execnetcleanup' # pytester',
 | 
						|
    #)
 | 
						|
]
 | 
						|
 | 
						|
externals = {
 | 
						|
    'oejskit': "run javascript tests in real life browsers", 
 | 
						|
    'django': "for testing django applications", 
 | 
						|
    'coverage': "for testing with Ned's coverage module ", 
 | 
						|
    'xmlresult': "for generating xml reports " 
 | 
						|
                 "and CruiseControl integration",
 | 
						|
}
 | 
						|
 | 
						|
def warn(*args):
 | 
						|
    msg = " ".join(map(str, args))
 | 
						|
    print >>sys.stderr, "WARN:", msg
 | 
						|
 | 
						|
class RestWriter:
 | 
						|
    _all_links = {}
 | 
						|
 | 
						|
    def __init__(self, target):
 | 
						|
        self.target = py.path.local(target)
 | 
						|
        self.links = []
 | 
						|
 | 
						|
    def _getmsg(self, args):
 | 
						|
        return " ".join(map(str, args))
 | 
						|
 | 
						|
    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()
 | 
						|
        self.Print(".. include:: links.txt")
 | 
						|
        for link in self.links:
 | 
						|
            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)
 | 
						|
 | 
						|
    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
 | 
						|
 | 
						|
class PluginOverview(RestWriter):
 | 
						|
    def makerest(self, config):
 | 
						|
        plugindir = py._dir.join('plugin')
 | 
						|
        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')
 | 
						|
                    self.para("%s_ (3rd) %s" %(name, oneliner))
 | 
						|
                    self.add_internal_link(name, htmlpath)
 | 
						|
                else:
 | 
						|
                    doc = PluginDoc(docpath)
 | 
						|
                    doc.make(config=config, name=name) 
 | 
						|
                    self.add_internal_link(name, doc.target)
 | 
						|
                    self.para("%s_ %s" %(name, doc.oneliner))
 | 
						|
                self.Print()
 | 
						|
 | 
						|
class HookSpec(RestWriter):
 | 
						|
    def makerest(self, config):
 | 
						|
        module = config.pluginmanager.hook._hookspecs
 | 
						|
        source = py.code.Source(module)
 | 
						|
        self.h1("hook specification sourcecode")
 | 
						|
        self.sourcecode(source)
 | 
						|
 | 
						|
class PluginDoc(RestWriter):
 | 
						|
    def makerest(self, config, name):
 | 
						|
        config.pluginmanager.import_plugin(name)
 | 
						|
        plugin = config.pluginmanager.getplugin(name)
 | 
						|
        assert plugin is not None, plugin
 | 
						|
 | 
						|
        doc = plugin.__doc__.strip()
 | 
						|
        i = doc.find("\n")
 | 
						|
        if i == -1:
 | 
						|
            oneliner = doc
 | 
						|
            moduledoc = ""
 | 
						|
        else:
 | 
						|
            oneliner = doc[:i].strip()
 | 
						|
            moduledoc = doc[i+1:].strip()
 | 
						|
 | 
						|
        self.name = plugin.__name__.split(".")[-1]
 | 
						|
        self.oneliner = oneliner 
 | 
						|
        self.moduledoc = moduledoc
 | 
						|
       
 | 
						|
        self.h1("%s plugin" % self.name) # : %s" %(self.name, self.oneliner))
 | 
						|
        self.Print(self.oneliner)
 | 
						|
        self.Print()
 | 
						|
        self.Print(".. contents::")
 | 
						|
        self.Print("  :local:")
 | 
						|
        self.Print()
 | 
						|
 | 
						|
        self.Print(moduledoc)
 | 
						|
    
 | 
						|
        self.emit_funcargs(plugin)
 | 
						|
        self.emit_options(plugin)
 | 
						|
        self.emit_source(plugin, config.hg_changeset)
 | 
						|
        #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))
 | 
						|
        self.h1("Start improving this plugin in 30 seconds")
 | 
						|
        self.para(py.code.Source("""
 | 
						|
            1. Download `%s`_ plugin source code 
 | 
						|
            2. put it somewhere as ``%s`` into your import path 
 | 
						|
            3. a subsequent ``py.test`` run will use your local version
 | 
						|
 | 
						|
            Checkout customize_, other plugins_ or `get in contact`_. 
 | 
						|
        """ % (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. 
 | 
						|
        #self.links.append((basename, 
 | 
						|
        #    "http://bitbucket.org/hpk42/py-trunk/raw/%s/" 
 | 
						|
        #    "py/test/plugin/%s" %(hg_changeset, basename)))
 | 
						|
        self.links.append((basename, 
 | 
						|
            "http://bitbucket.org/hpk42/py-trunk/raw/%s/" 
 | 
						|
            "py/plugin/%s" %(pyversion, basename)))
 | 
						|
        self.links.append(('customize', '../customize.html'))
 | 
						|
        self.links.append(('plugins', 'index.html'))
 | 
						|
        self.links.append(('get in contact', '../../contact.html'))
 | 
						|
        self.links.append(('checkout the py.test development version', 
 | 
						|
            '../../install.html#checkout'))
 | 
						|
       
 | 
						|
        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))
 | 
						|
 | 
						|
    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):]
 | 
						|
            self.Print()
 | 
						|
            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):
 | 
						|
        from py.impl.test.parseopt import Parser
 | 
						|
        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()
 | 
						|
        formatter = py.std.optparse.IndentedHelpFormatter()
 | 
						|
        for opt in options:
 | 
						|
            switches = formatter.format_option_strings(opt)
 | 
						|
            self.Print("``%s``" % switches)
 | 
						|
            self.Print(opt.help, indent=4)
 | 
						|
 | 
						|
if __name__ == "__main__":
 | 
						|
    if os.path.exists("py"):
 | 
						|
        sys.path.insert(0, os.getcwd())
 | 
						|
    import py
 | 
						|
    _config = py.test.config
 | 
						|
    _config.parse([])
 | 
						|
    _config.pluginmanager.do_configure(_config)
 | 
						|
 | 
						|
    pydir = py.path.local(py.__file__).dirpath()
 | 
						|
    pyversion = py.version
 | 
						|
 | 
						|
    cmd = "hg tip --template '{node}'" 
 | 
						|
    old = pydir.dirpath().chdir()
 | 
						|
    _config.hg_changeset = py.process.cmdexec(cmd).strip()
 | 
						|
 | 
						|
    testdir = pydir.dirpath("doc", 'test')
 | 
						|
   
 | 
						|
    ov = PluginOverview(testdir.join("plugin", "index.txt"))
 | 
						|
    ov.make(config=_config)
 | 
						|
    
 | 
						|
    ov = HookSpec(testdir.join("plugin", "hookspec.txt"))
 | 
						|
    ov.make(config=_config)
 | 
						|
 | 
						|
    RestWriter.write_all_links(testdir.join("plugin", "links.txt"))
 | 
						|
 |