Fix the serializing and changes builders, and really test them.

This commit is contained in:
Georg Brandl
2009-02-21 17:17:21 +01:00
parent 2ba9ec3456
commit bc9a351853
10 changed files with 112 additions and 64 deletions

View File

@@ -367,11 +367,15 @@ class TemplateBridge(object):
that renders templates given a template name and a context.
"""
def init(self, builder):
def init(self, builder, theme=None, dirs=None):
"""
Called by the builder to initialize the template system. *builder*
is the builder object; you'll probably want to look at the value of
``builder.config.templates_path``.
Called by the builder to initialize the template system.
*builder* is the builder object; you'll probably want to look at the
value of ``builder.config.templates_path``.
*theme* is a :class:`sphinx.theming.Theme` object or None; in the latter
case, *dirs* can be list of fixed directories to look for templates.
"""
raise NotImplementedError('must be implemented in subclasses')

View File

@@ -72,23 +72,16 @@ class Builder(object):
"""
pass
def init_templates(self):
def create_template_bridge(self):
"""
Initialize the theme and template system.
Call this method from init() if you need templates in your builder.
Return the template bridge configured.
"""
from sphinx.theming import Theme
Theme.init_themes(self)
self.theme = Theme(self.config.html_theme)
if self.config.template_bridge:
self.templates = self.app.import_object(
self.config.template_bridge, 'template_bridge setting')()
else:
from sphinx.jinja2glue import BuiltinTemplateLoader
self.templates = BuiltinTemplateLoader()
self.templates.init(self)
def get_target_uri(self, docname, typ=None):
"""

View File

@@ -15,7 +15,8 @@ from os import path
from cgi import escape
from sphinx import package_dir
from sphinx.util import ensuredir, os_path
from sphinx.util import ensuredir, os_path, copy_static_entry
from sphinx.theming import Theme
from sphinx.builders import Builder
from sphinx.util.console import bold
@@ -27,7 +28,10 @@ class ChangesBuilder(Builder):
name = 'changes'
def init(self):
self.init_templates()
self.create_template_bridge()
Theme.init_themes(self)
self.theme = Theme('default')
self.templates.init(self, self.theme)
def get_outdated_docs(self):
return self.outdir
@@ -44,11 +48,13 @@ class ChangesBuilder(Builder):
apichanges = []
otherchanges = {}
if version not in self.env.versionchanges:
self.info(bold('no changes in this version.'))
self.info(bold('no changes in version %s.' % version))
return
self.info(bold('writing summary file...'))
for type, docname, lineno, module, descname, content in \
self.env.versionchanges[version]:
if isinstance(descname, tuple):
descname = descname[0]
ttext = self.typemap[type]
context = content.replace('\n', ' ')
if descname and docname.startswith('c-api'):
@@ -129,12 +135,15 @@ class ChangesBuilder(Builder):
f.write(self.templates.render('changes/rstsource.html', ctx))
finally:
f.close()
shutil.copyfile(path.join(package_dir, 'themes', 'default',
'static', 'default.css'),
path.join(self.outdir, 'default.css'))
shutil.copyfile(path.join(package_dir, 'themes', 'basic',
'static', 'basic.css'),
path.join(self.outdir, 'basic.css'))
themectx = dict(('theme_' + key, val) for (key, val) in
self.theme.get_options({}).iteritems())
copy_static_entry(path.join(package_dir, 'themes', 'default',
'static', 'default.css_t'),
path.join(self.outdir, 'default.css_t'),
self, themectx)
copy_static_entry(path.join(package_dir, 'themes', 'basic',
'static', 'basic.css'),
path.join(self.outdir, 'basic.css'), self)
def hl(self, text, version):
text = escape(text)

View File

@@ -32,8 +32,9 @@ from docutils.readers.doctree import Reader as DoctreeReader
from sphinx import package_dir, __version__
from sphinx.util import SEP, os_path, relative_uri, ensuredir, \
movefile, ustrftime
movefile, ustrftime, copy_static_entry
from sphinx.search import js_index
from sphinx.theming import Theme
from sphinx.builders import Builder, ENV_PICKLE_FILENAME
from sphinx.application import SphinxError
from sphinx.highlighting import PygmentsBridge
@@ -95,12 +96,20 @@ class StandaloneHTMLBuilder(Builder):
if path.isfile(jsfile):
self.script_files.append('_static/translations.js')
def init_templates(self):
Theme.init_themes(self)
self.theme = Theme(self.config.html_theme)
self.create_template_bridge()
self.templates.init(self, self.theme)
def init_highlighter(self):
# determine Pygments style and create the highlighter
if self.config.pygments_style is not None:
style = self.config.pygments_style
else:
elif self.theme:
style = self.theme.get_confstr('theme', 'pygments_style', 'none')
else:
style = 'sphinx'
self.highlighter = PygmentsBridge('html', style)
def init_translator_class(self):
@@ -219,8 +228,10 @@ class StandaloneHTMLBuilder(Builder):
if self.config.html_style is not None:
stylename = self.config.html_style
else:
elif self.theme:
stylename = self.theme.get_confstr('theme', 'stylesheet')
else:
stylename = 'default.css'
self.globalcontext = dict(
embedded = self.embedded,
@@ -246,9 +257,11 @@ class StandaloneHTMLBuilder(Builder):
logo = logo,
favicon = favicon,
)
self.globalcontext.update(
('theme_' + key, val) for (key, val) in
self.theme.get_options(self.config.html_theme_options).iteritems())
if self.theme:
self.globalcontext.update(
('theme_' + key, val) for (key, val) in
self.theme.get_options(
self.config.html_theme_options).iteritems())
self.globalcontext.update(self.config.html_context)
def get_doc_context(self, docname, body, metatags):
@@ -509,10 +522,13 @@ class StandaloneHTMLBuilder(Builder):
shutil.copyfile(jsfile, path.join(self.outdir, '_static',
'translations.js'))
# then, copy over all user-supplied static files
staticdirnames = [path.join(themepath, 'static')
for themepath in self.theme.get_dirchain()[::-1]] + \
[path.join(self.confdir, spath)
for spath in self.config.html_static_path]
if self.theme:
staticdirnames = [path.join(themepath, 'static')
for themepath in self.theme.get_dirchain()[::-1]]
else:
staticdirnames = []
staticdirnames += [path.join(self.confdir, spath)
for spath in self.config.html_static_path]
for staticdirname in staticdirnames:
if not path.isdir(staticdirname):
self.warn('static directory %r does not exist' % staticdirname)
@@ -522,23 +538,8 @@ class StandaloneHTMLBuilder(Builder):
continue
fullname = path.join(staticdirname, filename)
targetname = path.join(self.outdir, '_static', filename)
if path.isfile(fullname):
if fullname.lower().endswith('_t'):
# templated!
fsrc = open(fullname, 'rb')
fdst = open(targetname[:-2], 'wb')
fdst.write(self.templates.render_string(
fsrc.read(), self.globalcontext))
fsrc.close()
fdst.close()
else:
shutil.copyfile(fullname, targetname)
elif path.isdir(fullname):
if filename in self.config.exclude_dirnames:
continue
if path.exists(targetname):
shutil.rmtree(targetname)
shutil.copytree(fullname, targetname)
copy_static_entry(fullname, targetname, self,
self.globalcontext)
# last, copy logo file (handled differently)
if self.config.html_logo:
logobase = path.basename(self.config.html_logo)
@@ -563,7 +564,8 @@ class StandaloneHTMLBuilder(Builder):
def cleanup(self):
# clean up theme stuff
self.theme.cleanup()
if self.theme:
self.theme.cleanup()
def post_process_images(self, doctree):
"""
@@ -733,9 +735,12 @@ class SerializingHTMLBuilder(StandaloneHTMLBuilder):
'image/gif', 'image/jpeg']
def init(self):
self.config_hash = ''
self.tags_hash = ''
self.theme = None # no theme necessary
self.templates = None # no template bridge necessary
self.init_translator_class()
self.init_highlighter()
self.templates = None # no template bridge necessary
def get_target_uri(self, docname, typ=None):
if docname == 'index':

View File

@@ -34,13 +34,17 @@ class BuiltinTemplateLoader(TemplateBridge, BaseLoader):
# TemplateBridge interface
def init(self, builder):
self.theme = builder.theme
# create a chain of paths to search:
# the theme's own dir and its bases' dirs
chain = self.theme.get_dirchain()
# then the theme parent paths (XXX doc)
chain.extend(self.theme.themepath)
def init(self, builder, theme=None, dirs=None):
# create a chain of paths to search
if theme:
# the theme's own dir and its bases' dirs
chain = theme.get_dirchain()
# then the theme parent paths
chain.extend(theme.themepath)
elif dirs:
chain = list(dirs)
else:
chain = []
# prepend explicit template paths
self.templatepathlen = len(builder.config.templates_path)

View File

@@ -30,11 +30,11 @@ class Theme(object):
"""
Represents the theme chosen in the configuration.
"""
themes = {}
@classmethod
def init_themes(cls, builder):
"""Search all theme paths for available themes."""
cls.themes = {}
cls.themepath = list(builder.config.html_theme_path)
cls.themepath.append(
path.join(path.abspath(path.dirname(__file__)), 'themes'))

View File

@@ -14,6 +14,7 @@ import re
import sys
import time
import types
import shutil
import fnmatch
import tempfile
import posixpath
@@ -392,6 +393,25 @@ def movefile(source, dest):
os.rename(source, dest)
def copy_static_entry(source, target, builder, context={}):
if path.isfile(source):
if source.lower().endswith('_t'):
# templated!
fsrc = open(source, 'rb')
fdst = open(target[:-2], 'wb')
fdst.write(builder.templates.render_string(fsrc.read(), context))
fsrc.close()
fdst.close()
else:
shutil.copyfile(source, target)
elif path.isdir(source):
if filename in builder.config.exclude_dirnames:
return
if path.exists(target):
shutil.rmtree(target)
shutil.copytree(source, target)
# monkey-patch Node.traverse to get more speed
# traverse() is called so many times during a build that it saves
# on average 20-25% overall build time!

View File

@@ -16,6 +16,7 @@ source_suffix = '.txt'
project = 'Sphinx <Tests>'
copyright = '2008, Georg Brandl & Team'
# If this is changed, remember to update the versionchanges!
version = '0.6'
release = '0.6alpha1'
today_fmt = '%B %d, %Y'

View File

@@ -84,13 +84,13 @@ Tables
Version markup
--------------
.. versionadded:: 0.5
.. versionadded:: 0.6
Some funny **stuff**.
.. versionchanged:: 0.5
.. versionchanged:: 0.6
Even more funny stuff.
.. deprecated:: 0.4
.. deprecated:: 0.6
Boring stuff.

View File

@@ -239,6 +239,10 @@ def test_latex(app):
# just let the remaining ones run for now
@with_app(buildername='pickle')
def test_pickle(app):
app.builder.build_all()
@with_app(buildername='linkcheck')
def test_linkcheck(app):
app.builder.build_all()
@@ -247,6 +251,14 @@ def test_linkcheck(app):
def test_text(app):
app.builder.build_all()
@with_app(buildername='changes', cleanenv=True)
@with_app(buildername='htmlhelp')
def test_htmlhelp(app):
app.builder.build_all()
@with_app(buildername='qthelp')
def test_qthelp(app):
app.builder.build_all()
@with_app(buildername='changes')
def test_changes(app):
app.builder.build_all()