diff options
author | Jason Pellerin <jpellerin@gmail.com> | 2009-04-18 19:00:45 +0000 |
---|---|---|
committer | Jason Pellerin <jpellerin@gmail.com> | 2009-04-18 19:00:45 +0000 |
commit | c5bd03442781ce1c974920708e958d58d1ff6289 (patch) | |
tree | 04041c48ada439b6ca6510bb34007f7dd94b33be /scripts | |
parent | 296fee10bf942cf860326c88d5c5df6e906a8c7b (diff) | |
download | nose-c5bd03442781ce1c974920708e958d58d1ff6289.tar.gz |
Committed PyCon sprint work.
Diffstat (limited to 'scripts')
-rwxr-xr-x | scripts/mkdocs.py | 554 | ||||
-rwxr-xr-x | scripts/mkrelease.py | 84 |
2 files changed, 23 insertions, 615 deletions
diff --git a/scripts/mkdocs.py b/scripts/mkdocs.py deleted file mode 100755 index a1671ec..0000000 --- a/scripts/mkdocs.py +++ /dev/null @@ -1,554 +0,0 @@ -#!/usr/bin/env python - -import os -import re -import time -from docutils.core import publish_string, publish_parts -from docutils.readers.standalone import Reader -from docutils.writers.html4css1 import Writer, HTMLTranslator -from pudge.browser import Browser -import inspect -import nose -import textwrap -from optparse import OptionParser -from nose.util import resolve_name, odict -from pygments import highlight -from pygments.lexers import PythonLexer, PythonConsoleLexer -from pygments.formatters import HtmlFormatter - - -remove_at = re.compile(r' at 0x[0-9a-f]+') -root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) -doc = os.path.join(root, 'doc') -tpl = open(os.path.join(doc, 'doc.html.tpl'), 'r').read() -api_tpl = open(os.path.join(doc, 'plugin_api.html.tpl'), 'r').read() -plug_tpl = open(os.path.join(doc, 'plugin.html.tpl'), 'r').read() -std_info = { - 'version': nose.__version__, - 'date': time.ctime() - } -to_write = [] - - -def defining_class(cls, attr): - if hasattr(cls, '__bases__'): - try: - bases = list(cls.__bases__) - except (ValueError, TypeError): - return cls - for base in bases: - if attr in base.__dict__: - return base - return cls - - -def write(filename, tpl, ctx): - print filename - ctx.setdefault('submenu', '') - fp = open(filename, 'w') - try: - fp.write(tpl % ctx) - except UnicodeEncodeError: - print ctx - fp.close() - - -def doc_word(node): - - # handle links like package.module and module.Class - # as wellas 'foo bar' - - orig = name = node.astext() - if '.' in name: - parts = name.split('.') - # if the first letter of a part is capitalized, assume it's - # a class name, and put all parts from that part on into - # the anchor part of the link - link, anchor = [], [] - addto = link - while parts: - part = parts.pop(0) - if addto == link: - if part[0].upper() == part[0]: - addto = anchor - elif part.endswith('()'): - addto = anchor - part = part[:-2] - addto.append(part) - if (name.startswith('nose.plugins') - and 'plugintest' not in name): - base = 'plugin_' - link = link[-1:] - else: - base = 'module_' - node['refuri'] = base + '.'.join(link) + '.html' - if anchor: - node['refuri'] += '#' + '.'.join(anchor) - else: - # pad out wiki-words - name = name[0].lower() + name[1:] - name = re.sub(r'([A-Z])', r' \1', name).lower() - node['refuri'] = '_'.join(name.split(' ')) + '.html' - - print "Unknown ref %s -> %s" % (orig, node['refuri']) - del node['refname'] - node.resolved = True - return True -doc_word.priority = 100 - - - -class DocReader(Reader): - unknown_reference_resolvers = (doc_word,) - - -class PygHTMLTranslator(HTMLTranslator): - """HTML translator that uses pygments to highlight doctests. - """ - def visit_doctest_block(self, node): - self.body.append( - highlight(node.rawsource, PythonConsoleLexer(), HtmlFormatter())) - # hacky way of capturing children -- we've processed the whole node - self._body = self.body - self.body = [] - - def depart_doctest_block(self, node): - # restore the real body, doctest node is done - self.body = self._body - del self._body - -class PygWriter(Writer): - def __init__(self): - Writer.__init__(self) - self.translator_class = PygHTMLTranslator - -def formatargspec(func, exclude=()): - try: - args, varargs, varkw, defaults = inspect.getargspec(func) - except TypeError: - return "(...)" - if defaults: - defaults = map(clean_default, defaults) - for a in exclude: - if a in args: - ix = args.index(a) - args.remove(a) - try: - defaults.pop(ix) - except AttributeError: - pass - return inspect.formatargspec( - args, varargs, varkw, defaults).replace("'os.environ'", 'os.environ') - - -def clean_default(val): - if isinstance(val, os._Environ): - return 'os.environ' - return val - - -def to_html_parts(rst): - return publish_parts(rst, reader=DocReader(), writer=PygWriter()) - - -def to_html(rst): - return to_html_parts(rst)['body'] - - -def document_module(mod): - name = mod.qualified_name() - print name - body = to_html(mod.doc()) - - # for classes: prepend with note on what highlighted means - cls_note = "<p>Highlighted methods are defined in this class.</p>" - - submenu = [] - - # classes - mod_classes = get_classes(mod) - classes = [document_class(cls) for cls in mod_classes] - if classes: - body += '<h2>Classes</h2>\n' + cls_note + '\n'.join(classes) - submenu.extend(make_submenu('Classes', mod_classes)) - - # functions - mod_funcs = list(mod.routines()) - funcs = [document_function(func) for func in mod_funcs] - if funcs: - body += '<h2>Functions</h2>\n' + '\n'.join(funcs) - submenu.extend(make_submenu('Functions', mod_funcs)) - - # attributes - mod_attrs = list(mod.attributes()) - attrs = [document_attribute(attr) for attr in mod_attrs] - if attrs: - body += '<h2>Attributes</h2>\n' + '\n'.join(attrs) - submenu.extend(make_submenu('Attributes', mod_attrs)) - - pg = {'body': body, - 'title': name, - 'submenu': ''.join(submenu)} - pg.update(std_info) - to_write.append(( - 'Modules', - 'Module: %s' % name, - os.path.join(doc, 'module_%s.html' % name), - tpl, pg)) - - -def make_submenu(name, objs): - sm = ['<h2>%s</h2>' % name, '<ul>'] - sm.extend(['<li><a href="#%s">%s</a></li>' % (o.name, o.name) - for o in objs] + ['</ul>']) - return sm - -def get_classes(mod): - # some "invisible" items I do want, but not others - # really only those classes defined in the module itself - # with some per-module alias list handling (eg, - # TestLoader and defaultTestLoader shouldn't both be fully doc'd) - all = list(mod.classes(visible_only=0)) - - # sort by place in __all__ - names = odict() # list comprehension didn't work? possible bug in odict - for c in all: - if c is not None and not c.isalias(): - names[c.name] = c - ordered = [] - try: - for name in mod.obj.__all__: - if name in names: - cls = names[name] - del names[name] - if cls is not None: - ordered.append(cls) - except AttributeError: - pass - for name, cls in names.items(): - ordered.append(cls) - wanted = [] - classes = set([]) - for cls in ordered: - if cls.obj in classes: - cls.alias_for = cls.obj - else: - classes.add(cls.obj) - wanted.append(cls) - return wanted - - -def document_class(cls): - print " %s" % cls.qualified_name() - alias = False - if hasattr(cls, 'alias_for'): - alias = True - doc = '(Alias for %s)' % link_to_class(cls.alias_for) - else: - doc = to_html(cls.doc()) - bases = ', '.join(link_to_class(c) for c in cls.obj.__bases__) - html = ['<a name="%s"></a><div class="cls section">' % cls.name, - '<span class="cls name">%s</span> (%s)' % (cls.name, bases), - '<div class="cls doc">%s' % doc] - - if not alias: - real_class = cls.obj - methods = list(cls.routines(visible_only=False)) - if methods: - methods.sort(lambda a, b: cmp(a.name, b.name)) - html.append('<h3>Methods</h3>') - for method in methods: - print " %s" % method.qualified_name() - defined_in = defining_class(real_class, method.name) - if defined_in == real_class: - inherited = '' - inh_cls = '' - else: - inherited = '<span class="method inherited">' \ - '(inherited from %s)</span>' \ - % defined_in.__name__ - inh_cls = ' inherited' - html.extend([ - '<div class="method section%s">' % inh_cls, - '<span class="method name">%s' % method.name, - '<span class="args">%s</span></span>' - % formatargspec(method.obj), - inherited, - '<div class="method doc">%s</div>' % to_html(method.doc()), - '</div>']) - - attrs = list(cls.attributes(visible_only=False)) - if attrs: - attrs.sort(lambda a, b: cmp(a.name, b.name)) - html.append('<h3>Attributes</h3>') - for attr in attrs: - print " a %s" % attr.qualified_name() - defined_in = defining_class(real_class, attr.name) - if defined_in == real_class: - inherited = '' - inh_cls = '' - else: - inherited = '<span class="attr inherited">' \ - '(inherited from %s)</span>' \ - % defined_in.__name__ - inh_cls = ' inherited' - val = format_attr(attr.parent.obj, attr.name) - html.extend([ - '<div class="attr section%s">' % inh_cls, - '<span class="attr name">%s</span>' % attr.name, - '<pre class="attr value">Default value: %(a)s</pre>' % - {'a': val}, - '<div class="attr doc">%s</div>' % to_html(attr.doc()), - '</div>']) - - html.append('</div></div>') - - return ''.join(html) - - -def document_function(func): - print " %s" % func.name - html = [ - '<a name="%s"></a><div class="func section">' % func.name, - '<span class="func name">%s' % func.name, - '<span class="args">%s</span></span>' - % formatargspec(func.obj, exclude=['self']), - '<div class="func doc">%s</div>' % to_html(func.doc()), - '</div>'] - return ''.join(html) - - -def document_attribute(attr): - print " %s" % attr.name - value = format_attr(attr.parent.obj, attr.name) - html = [ - '<a name="%s"></a><div class="attr section">' % attr.name, - '<span class="attr name">%s</span>' % attr.name, - '<pre class="attr value">Default value: %(a)s</pre>' % - {'a': value}, - '<div class="attr doc">%s</div>' % to_html(attr.doc()), - '</div>'] - return ''.join(html) - - -def format_attr(obj, attr): - val = getattr(obj, attr) - if isinstance(val, property): - # value makes no sense when it's a property - return '(property)' - val = str(val).replace( - '&', '&').replace('<', '<').replace('>', '>').replace( - '"', '"').replace("'", ''') - val = remove_at.sub('', val) - return val - - -def link_to_class(cls): - mod = cls.__module__ - name = cls.__name__ - if mod.startswith('_'): - qname = name - else: - qname = "%s.%s" % (mod, name) - if not mod.startswith('nose'): - return qname - return '<a href="module_%s.html#%s">%s</a>' % (mod, name, name) - - -def plugin_example_tests(): - dt_root = os.path.join(root, 'functional_tests', 'doc_tests') - for dirpath, dirnames, filenames in os.walk(dt_root): - for filename in filenames: - if filename.startswith('.'): - continue - base, ext = os.path.splitext(filename) - if ext == '.rst': - yield os.path.join(dirpath, filename) - if '.svn' in dirnames: - dirnames.remove('.svn') - - -def document_rst_test(filename, section): - base, ext = os.path.splitext(os.path.basename(filename)) - rst = open(filename, 'r').read() - parts = to_html_parts(rst) - parts.update(std_info) - to_write.append((section, - parts['title'], - os.path.join(doc, base + '.html'), - tpl, - parts)) - -def main(): - # plugins - from nose import plugins - from nose.plugins.base import IPluginInterface - from nose.plugins import errorclass - - # writing plugins guide - writing_plugins = {'body': to_html(plugins.__doc__)} - writing_plugins.update(std_info) - writing_plugins['title'] = 'Writing Plugins' - to_write.append( - ('Plugins', - 'Writing Plugins', - os.path.join(doc, 'writing_plugins.html'), tpl, writing_plugins)) - - - # error class plugins - ecp = {'body': to_html(errorclass.__doc__)} - ecp.update(std_info) - ecp['title'] = 'ErrorClass Plugins' - to_write.append( - ('Plugins', - 'ErrorClass Plugins', - os.path.join(doc, 'error_class_plugin.html'), tpl, ecp)) - - # interface - itf = {'body': to_html(textwrap.dedent(IPluginInterface.__doc__))} - - # methods - attr = [(a, getattr(IPluginInterface, a)) for a in dir(IPluginInterface)] - methods = [m for m in attr if inspect.ismethod(m[1])] - methods.sort() - # print "Documenting methods", [a[0] for a in methods] - - method_html = [] - method_tpl = """ - <div class="method %(extra_class)s"> - <a name="%(name)s"> - <span class="name">%(name)s</span><span class="arg">%(arg)s</span></a> - <div class="doc">%(body)s</div> - </div> - """ - - menu_links = {} - - m_attrs = ('_new', 'changed', 'deprecated', 'generative', 'chainable') - for m in methods: - name, meth = m - ec = [] - for att in m_attrs: - if hasattr(meth, att): - ec.append(att.replace('_', '')) - menu_links.setdefault(att.replace('_', ''), []).append(name) - # padding evens the lines - print name - mdoc = {'body': to_html(textwrap.dedent(' ' + meth.__doc__))} - argspec = formatargspec(meth) - mdoc.update({'name': name, - 'extra_class': ' '.join(ec), - 'arg': argspec}) - method_html.append(method_tpl % mdoc) - - itf['methods'] = ''.join(method_html) - itf.update(std_info) - itf['title'] = 'Plugin Interface' - - menu = [] - for section in ('new', 'changed', 'deprecated'): - menu.append('<h2>%s methods</h2>' % section.title()) - menu.append('<ul><li>') - menu.append('</li><li>'.join([ - '<a href="#%(name)s">%(name)s</a>' % {'name': n} - for n in menu_links[section]])) - menu.append('</li></ul>') - itf['sub_menu'] = ''.join(menu) - - to_write.append( - ('Plugins', - 'Plugin Interface', - os.path.join(doc, 'plugin_interface.html'), api_tpl, itf)) - - - # individual plugin usage docs - from nose.plugins.builtin import builtins - - pmeths = [m[0] for m in methods[:] - if not 'options' in m[0].lower()] - pmeths.append('options') - pmeths.sort() - - for modulename, clsname in builtins: - _, _, modname = modulename.split('.') - mod = resolve_name(modulename) - cls = getattr(mod, clsname) - filename = os.path.join(doc, 'plugin_%s.html' % modname) - print modname, filename - if not mod.__doc__: - print "No docs" - continue - pdoc = {'body': to_html(mod.__doc__)} - pdoc.update(std_info) - pdoc['title'] = 'builtin plugin: %s' % modname - - # options - parser = OptionParser(add_help_option=False) - plug = cls() - plug.addOptions(parser) - options = parser.format_option_help() - pdoc['options'] = options - - # hooks used - hooks = [] - for m in pmeths: - if getattr(cls, m, None): - hooks.append('<li><a href="plugin_interface.html#%(name)s">' - '%(name)s</a></li>' % {'name': m}) - pdoc['hooks'] = ''.join(hooks) - - source = inspect.getsource(mod) - pdoc['source'] = highlight(source, PythonLexer(), HtmlFormatter()) - to_write.append( - ('Plugins', - 'Builtin Plugin: %s' % modname, - os.path.join(doc, filename), plug_tpl, pdoc)) - - - # individual module docs - b = Browser(['nose','nose.plugins.manager', 'nose.plugins.plugintest'], - exclude_modules=['nose.plugins', 'nose.ext']) - for mod in b.modules(recursive=1): - if mod.name == 'nose': - # no need to regenerate, this is the source of the doc index page - continue - print mod.qualified_name() - document_module(mod) - - - # plugin examples doctests - for testfile in plugin_example_tests(): - document_rst_test(testfile, "Plugin Examples") - - - # finally build the menu and write all pages - menu = [] - sections = odict() - for page in to_write: - section, _, _, _, _ = page - sections.setdefault(section, []).append(page) - - for section, pages in sections.items(): - menu.append('<h2>%s</h2>' % section) - menu.append('<ul>') - pages.sort() - menu.extend([ - '<li><a href="%s">%s</a></li>' % (os.path.basename(filename), title) - for _, title, filename, _, _ in pages ]) - menu.append('</ul>') - - menu = ''.join(menu) - for section, title, filename, template, ctx in to_write: - ctx['menu'] = menu - write(filename, template, ctx) - - # doc section index page - idx_tpl = open(os.path.join(doc, 'index.html.tpl'), 'r').read() - idx = { - 'title': 'API documentation', - 'menu': menu} - idx.update(std_info) - write(os.path.join(doc, 'index.html'), idx_tpl, idx) - -if __name__ == '__main__': - main() diff --git a/scripts/mkrelease.py b/scripts/mkrelease.py index 76b4a30..0331b70 100755 --- a/scripts/mkrelease.py +++ b/scripts/mkrelease.py @@ -9,25 +9,11 @@ from commands import getstatusoutput success = 0 -current = os.getcwd() -version = nose.__version__ -here = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) -parts = here.split('/') -if 'branches' in parts: - lindex = parts.index('branches') -elif 'tags' in parts: - lindex = parts.index('tags') -elif 'trunk' in parts: - lindex = parts.index('trunk') -else: - raise Exception("Unable to find svnroot from %s" % here) -svnroot = os.path.join('/', *parts[:lindex]) -branchroot = os.path.join(svnroot, 'branches') -tagroot = os.path.join(svnroot, 'tags') -svntrunk = os.path.join(svnroot, 'trunk') +version = nose.__version__ svn_base_url = 'https://python-nose.googlecode.com/svn' svn_trunk_url = 'https://python-nose.googlecode.com/svn/trunk' +svn_tags_url = 'https://python-nose.googlecode.com/svn/tags' SIMULATE = 'exec' not in sys.argv if SIMULATE: @@ -50,60 +36,37 @@ def cd(dir): def main(): - cd(svnroot) - branch = 'branches/%s-stable' % version - tag = 'tags/%s-release' % version - - svn_branch_url = '%s/%s' % (svn_base_url, branch) - svn_tag_url = '%s/%s' % (svn_base_url, tag) - - if os.path.isdir(tag): - raise Exception( - "Tag path %s already exists. Can't release same version twice!" - % tag) - - # make branch, if needed - if not os.path.isdir(os.path.join(svnroot, branch)): - # make branch - runcmd("svn copy %s %s -m 'Release branch for %s'" - % (svn_trunk_url, svn_branch_url, version)) - # clean up setup.cfg and check in tag - cd(branchroot) - runcmd('svn co %s' % svn_branch_url) - else: - # re-releasing branch - cd(branch) - runcmd('svn up') - - # make tag from branch - runcmd('svn copy %s %s -m "Release tag for %s"' - % (svn_branch_url, svn_tag_url, version)) + tag = 'nose_rel_%s' % version + svn_tag_url = "%s/%s" % (svn_tags_url, tag) + # create tag + runcmd("svn copy %s %s -m 'Tagged release %s'" % + (svn_trunk_url, svn_tag_url, version)) + # check out tag - cd(tagroot) + cd('/tmp') runcmd('svn co %s' % svn_tag_url) - cd(svnroot) cd(tag) # remove dev tag from setup runcmd('cp setup.cfg.release setup.cfg') runcmd('svn rm setup.cfg.release --force') runcmd("svn ci -m 'Updated setup.cfg to release status'") - - # wiki pages must be built from tag checkout - runcmd('./scripts/mkwiki.py') - + runcmd("rm -rf /tmp/%s" % tag) + # need to build dist from an *export* to limit files included # (setuptools includes too many files when run under a checkout) # export tag cd('/tmp') - runcmd('svn export %s nose_rel_%s' % (svn_tag_url, version)) - cd('nose_rel_%s' % version) + runcmd('svn export %s %s' % (svn_tag_url, tag)) + cd(tag) # make docs - runcmd('./scripts/mkindex.py') - runcmd('./scripts/mkdocs.py') + #runcmd('./scripts/mkindex.py') + cd('doc') + runcmd('make html') + cd('..') # make sdist runcmd('python setup.py sdist') @@ -113,7 +76,7 @@ def main(): up = os.environ['NOSE_UPLOAD'] cv = { 'host': up[:up.index(':')], - 'path': up[up.index(':')+1:], + 'path': up[up.index(':')+1:-1], 'version':version, 'upload': up, 'upload_docs': "%s/%s" % (up, version) } @@ -126,19 +89,18 @@ def main(): cmd = 'ssh %(host)s "mkdir -p %(docpath)s"' % cv runcmd(cmd) - cmd = 'scp -C index.html %(upload_docs)s' % cv - runcmd(cmd) + #cmd = 'scp -C index.html %(upload_docs)s' % cv + #runcmd(cmd) cmd = ('scp -C doc/*.html doc/*.css doc/*.png ' '%(upload_docs)s/doc' % cv) runcmd(cmd) cmd = ('ssh %(host)s ' - '"ln -nfs %(versionpath)s/index.html %(path)s/index.html; ' - 'ln -nfs %(docpath)s %(path)s/doc"' % cv) + 'ln -nfs %(docpath)s %(path)s/doc"; ' + '"ln -nfs %(path)s/doc/main_index.html %(path)s/index.html' + % cv) runcmd(cmd) - - cd(current) if __name__ == '__main__': main() |