[Python-checkins] r60174 - in doctools/trunk/sphinx: __init__.py builder.py config.py directives.py environment.py extension.py htmlhelp.py htmlwriter.py latexwriter.py patchlevel.py roles.py templates/layout.html
georg.brandl
python-checkins at python.org
Mon Jan 21 21:20:38 CET 2008
Author: georg.brandl
Date: Mon Jan 21 21:20:37 2008
New Revision: 60174
Added:
doctools/trunk/sphinx/config.py
doctools/trunk/sphinx/extension.py
Removed:
doctools/trunk/sphinx/patchlevel.py
Modified:
doctools/trunk/sphinx/__init__.py
doctools/trunk/sphinx/builder.py
doctools/trunk/sphinx/directives.py
doctools/trunk/sphinx/environment.py
doctools/trunk/sphinx/htmlhelp.py
doctools/trunk/sphinx/htmlwriter.py
doctools/trunk/sphinx/latexwriter.py
doctools/trunk/sphinx/roles.py
doctools/trunk/sphinx/templates/layout.html
Log:
Further refactorings, add extensibility API.
Modified: doctools/trunk/sphinx/__init__.py
==============================================================================
--- doctools/trunk/sphinx/__init__.py (original)
+++ doctools/trunk/sphinx/__init__.py Mon Jan 21 21:20:37 2008
@@ -9,15 +9,51 @@
:license: BSD.
"""
+import os
import sys
import getopt
from os import path
from cStringIO import StringIO
+from sphinx.config import Config, ConfigError
from sphinx.builder import builders
+from sphinx.extension import EventManager
from sphinx.util.console import nocolor
-__version__ = '$Revision: 5369 $'
+__version__ = '$Revision: 5369 $'[11:-2]
+
+
+def init_builder(buildername, srcdirname, outdirname, doctreedir,
+ confoverrides, status, warning=sys.stderr, freshenv=False):
+ # read config
+ config = Config(srcdirname, 'conf.py')
+ if confoverrides:
+ for key, val in confoverrides.items():
+ setattr(config, key, val)
+
+ # extensibility
+ events = EventManager()
+ for extension in config.extensions:
+ try:
+ mod = __import__(extension, None, None, ['setup'])
+ except ImportError, err:
+ raise ConfigError('Could not import extension %s' % module, err)
+ if hasattr(mod, 'setup'):
+ mod.setup(events, builders)
+
+ if buildername not in builders:
+ print >>warning, 'Builder name %s not registered' % buildername
+ return None
+
+ if buildername is None:
+ print >>status, 'No builder selected, using default: html'
+ buildername = 'html'
+
+ builderclass = builders[buildername]
+ builder = builderclass(srcdirname, outdirname, doctreedir,
+ status_stream=status, warning_stream=warning,
+ events=events, config=config, freshenv=freshenv)
+ events.emit('builder-created', builder)
def usage(argv, msg=None):
@@ -42,6 +78,10 @@
def main(argv):
+ if not sys.stdout.isatty() or sys.platform == 'win32':
+ # Windows' poor cmd box doesn't understand ANSI sequences
+ nocolor()
+
try:
opts, args = getopt.getopt(argv[1:], 'ab:d:D:NEqP')
srcdirname = path.abspath(args[0])
@@ -68,17 +108,14 @@
if err:
return 1
- builder = all_files = None
+ buildername = all_files = None
freshenv = use_pdb = False
status = sys.stdout
confoverrides = {}
doctreedir = path.join(outdirname, '.doctrees')
for opt, val in opts:
if opt == '-b':
- if val not in builders:
- usage(argv, 'Invalid builder value specified.')
- return 1
- builder = val
+ buildername = val
elif opt == '-a':
if filenames:
usage(argv, 'Cannot combine -a option and filenames.')
@@ -101,28 +138,18 @@
elif opt == '-P':
use_pdb = True
- if not sys.stdout.isatty() or sys.platform == 'win32':
- # Windows' cmd box doesn't understand ANSI sequences
- nocolor()
-
- if builder is None:
- print >>status, 'No builder selected, using default: html'
- builder = 'html'
-
- builderobj = builders[builder]
+ builder = init_builder(buildername, srcdirname, outdirname, doctreedir,
+ confoverrides, status, sys.stderr, freshenv)
+ if not builder:
+ return 1
try:
- builderobj = builderobj(srcdirname, outdirname, doctreedir,
- status_stream=status,
- warning_stream=sys.stderr,
- confoverrides=confoverrides,
- freshenv=freshenv)
if all_files:
- builderobj.build_all()
+ builder.build_all()
elif filenames:
- builderobj.build_specific(filenames)
+ builder.build_specific(filenames)
else:
- builderobj.build_update()
+ builder.build_update()
except:
if not use_pdb:
raise
Modified: doctools/trunk/sphinx/builder.py
==============================================================================
--- doctools/trunk/sphinx/builder.py (original)
+++ doctools/trunk/sphinx/builder.py Mon Jan 21 21:20:37 2008
@@ -12,7 +12,6 @@
import os
import sys
import time
-import types
import codecs
import shutil
import cPickle as pickle
@@ -31,8 +30,9 @@
from sphinx.util import (get_matching_files, attrdict, status_iterator,
ensuredir, relative_uri, os_path, SEP)
from sphinx.htmlhelp import build_hhx
+from sphinx.extension import DummyEventManager, import_object
from sphinx.patchlevel import get_version_info, get_sys_version_info
-from sphinx.htmlwriter import HTMLWriter
+from sphinx.htmlwriter import HTMLWriter, HTMLTranslator, SmartyPantsHTMLTranslator
from sphinx.latexwriter import LaTeXWriter
from sphinx.environment import BuildEnvironment, NoUri
from sphinx.highlighting import pygments, highlight_block, get_stylesheet
@@ -45,25 +45,13 @@
ENV_PICKLE_FILENAME = 'environment.pickle'
LAST_BUILD_FILENAME = 'last_build'
-# Helper objects
-
-class relpath_to(object):
- def __init__(self, builder, filename):
- self.baseuri = builder.get_target_uri(filename)
- self.builder = builder
- def __call__(self, otheruri, resource=False):
- if not resource:
- otheruri = self.builder.get_target_uri(otheruri + '.rst')
- return relative_uri(self.baseuri, otheruri)
-
-
class Builder(object):
"""
Builds target formats from the reST sources.
"""
def __init__(self, srcdirname, outdirname, doctreedirname,
- confoverrides=None, env=None, freshenv=False,
+ config, env=None, freshenv=False, events=None,
status_stream=None, warning_stream=None):
self.srcdir = srcdirname
self.outdir = outdirname
@@ -75,35 +63,11 @@
self.status_stream = status_stream or sys.stdout
self.warning_stream = warning_stream or sys.stderr
- # probably set in load_env()
+ self.config = config
+ # if None, this is set in load_env()
self.env = env
- self.config = {}
- olddir = os.getcwd()
- try:
- os.chdir(srcdirname)
- execfile(path.join(srcdirname, 'conf.py'), self.config)
- finally:
- os.chdir(olddir)
- # remove potentially pickling-problematic values
- del self.config['__builtins__']
- for key, val in self.config.items():
- if isinstance(val, types.ModuleType):
- del self.config[key]
- if confoverrides:
- self.config.update(confoverrides)
- # replace version info if '<auto>'
- if self.config['version'] == '<auto>' or self.config['release'] == '<auto>':
- try:
- version, release = get_version_info(srcdirname)
- except (IOError, OSError):
- version, release = get_sys_version_info()
- self.warn('Can\'t get version info from Include/patchlevel.h, '
- 'using version of this interpreter (%s).' % release)
- if self.config['version'] == '<auto>':
- self.config['version'] = version
- if self.config['release'] == '<auto>':
- self.config['release'] = release
+ self.events = events or DummyEventManager()
self.init()
@@ -124,12 +88,34 @@
"""Load necessary templates and perform initialization."""
raise NotImplementedError
+ def init_templates(self):
+ """Call if you need Jinja templates in the builder."""
+ # lazily import this, maybe other builders won't need it
+ from sphinx._jinja import Environment, SphinxFileSystemLoader
+
+ # load templates
+ self.templates = {}
+ templates_path = [path.join(path.dirname(__file__), 'templates')]
+ templates_path.extend(self.config.templates_path)
+ self.jinja_env = Environment(loader=SphinxFileSystemLoader(templates_path),
+ # disable traceback, more likely that something
+ # in the application is broken than in the templates
+ friendly_traceback=False)
+
+ def get_template(self, name):
+ if name in self.templates:
+ return self.templates[name]
+ template = self.templates[name] = self.jinja_env.get_template(name)
+ return template
+
def get_target_uri(self, source_filename, typ=None):
"""Return the target URI for a source filename."""
raise NotImplementedError
def get_relative_uri(self, from_, to, typ=None):
- """Return a relative URI between two source filenames."""
+ """Return a relative URI between two source filenames.
+ May raise environment.NoUri if there's no way to return a
+ sensible URI."""
return relative_uri(self.get_target_uri(from_),
self.get_target_uri(to, typ))
@@ -196,7 +182,9 @@
warnings = []
self.env.set_warnfunc(warnings.append)
self.msg('reading, updating environment:', nonl=1)
- iterator = self.env.update(self.config)
+ iterator = self.env.update(
+ self.config,
+ hook=lambda doctree: self.events.emit('doctree-read', doctree))
self.msg(iterator.next(), nonl=1, nobold=1)
for filename in iterator:
if not updated_filenames:
@@ -274,25 +262,14 @@
def init(self):
"""Load templates."""
- # lazily import this, maybe other builders won't need it
- from sphinx._jinja import Environment, SphinxFileSystemLoader
-
- # load templates
- self.templates = {}
- templates_path = path.join(path.dirname(__file__), 'templates')
- self.jinja_env = Environment(loader=SphinxFileSystemLoader([templates_path]),
- # disable traceback, more likely that something
- # in the application is broken than in the templates
- friendly_traceback=False)
- # pre-load built-in templates
- for fname in os.listdir(templates_path):
- if fname.endswith('.html'):
- self.templates[fname] = self.jinja_env.get_template(fname)
-
- def get_template(self, name):
- if name in self.templates:
- return self.templates[name]
- return self.jinja_env.get_template(name)
+ self.init_templates()
+ if self.config.html_translator_class:
+ self.translator_class = import_object(self.config.html_translator_class,
+ 'html_translator_class setting')
+ elif self.config.html_use_smartypants:
+ self.translator_class = SmartyPantsHTMLTranslator
+ else:
+ self.translator_class = HTMLTranslator
def render_partial(self, node):
"""Utility: Render a lone doctree node."""
@@ -317,17 +294,17 @@
# format the "last updated on" string, only once is enough since it
# typically doesn't include the time of day
- lufmt = self.config.get('html_last_updated_fmt')
+ lufmt = self.config.html_last_updated_fmt
if lufmt:
self.last_updated = time.strftime(lufmt)
else:
self.last_updated = None
self.globalcontext = dict(
- project = self.config.get('project', 'Python'),
- copyright = self.config.get('copyright', ''),
- release = self.config['release'],
- version = self.config['version'],
+ project = self.config.project,
+ copyright = self.config.copyright,
+ release = self.config.release,
+ version = self.config.version,
last_updated = self.last_updated,
builder = self.name,
parents = [],
@@ -336,6 +313,7 @@
)
def write_file(self, filename, doctree):
+ pagename = filename[:-4]
destination = StringOutput(encoding='utf-8')
doctree.settings = self.docsettings
@@ -366,7 +344,7 @@
else:
title = ''
self.globalcontext['titles'][filename] = title
- sourcename = filename[:-4] + '.txt'
+ sourcename = pagename + '.txt'
context = dict(
title = title,
sourcename = sourcename,
@@ -379,8 +357,8 @@
next = next,
)
- self.index_file(filename, doctree, title)
- self.handle_page(filename[:-4], context)
+ self.index_page(pagename, doctree, title)
+ self.handle_page(pagename, context)
def finish(self):
self.msg('writing additional files...')
@@ -446,12 +424,12 @@
self.handle_page('search', {}, 'search.html')
# additional pages from conf.py
- for pagename, template in self.config.get('html_additional_pages', {}).items():
+ for pagename, template in self.config.html_additional_pages.items():
template = path.join(self.srcdir, template)
self.handle_page(pagename, {}, template)
# the index page
- indextemplate = self.config.get('html_index')
+ indextemplate = self.config.html_index
if indextemplate:
indextemplate = path.join(self.srcdir, indextemplate)
self.handle_page('index', {'indextemplate': indextemplate}, 'index.html')
@@ -480,7 +458,7 @@
def get_outdated_files(self):
for filename in get_matching_files(
- self.srcdir, '*.rst', exclude=set(self.config.get('unused_files', ()))):
+ self.srcdir, '*.rst', exclude=set(self.config.unused_files)):
try:
rstname = path.join(self.outdir, os_path(filename))
targetmtime = path.getmtime(rstname[:-4] + '.html')
@@ -504,21 +482,26 @@
# delete all entries for files that will be rebuilt
self.indexer.prune([fn[:-4] for fn in set(self.env.all_files) - set(filenames)])
- def index_file(self, filename, doctree, title):
+ def index_page(self, pagename, doctree, title):
# only index pages with title
if self.indexer is not None and title:
- self.indexer.feed(self.get_target_uri(filename)[:-5], # strip '.html'
- title, doctree)
+ self.indexer.feed(pagename, title, doctree)
- def handle_page(self, pagename, context, templatename='page.html'):
+ def handle_page(self, pagename, addctx, templatename='page.html'):
ctx = self.globalcontext.copy()
ctx['current_page_name'] = pagename
- ctx['pathto'] = relpath_to(self, self.get_target_uri(pagename+'.rst'))
+
+ def pathto(otheruri, resource=False,
+ baseuri=self.get_target_uri(pagename+'.rst')):
+ if not resource:
+ otheruri = self.get_target_uri(otheruri+'.rst')
+ return relative_uri(baseuri, otheruri)
+ ctx['pathto'] = pathto
ctx['hasdoc'] = lambda name: name+'.rst' in self.env.all_files
- sidebarfile = self.config.get('html_sidebars', {}).get(pagename)
+ sidebarfile = self.config.html_sidebars.get(pagename)
if sidebarfile:
ctx['customsidebar'] = path.join(self.srcdir, sidebarfile)
- ctx.update(context)
+ ctx.update(addctx)
output = self.get_template(templatename).render(ctx)
outfilename = path.join(self.outdir, os_path(pagename) + '.html')
@@ -531,14 +514,14 @@
f.close()
except (IOError, OSError), err:
self.warn("Error writing file %s: %s" % (outfilename, err))
- if self.copysource and context.get('sourcename'):
+ if self.copysource and ctx.get('sourcename'):
# copy the source file for the "show source" link
shutil.copyfile(path.join(self.srcdir, os_path(pagename+'.rst')),
- path.join(self.outdir, os_path(context['sourcename'])))
+ path.join(self.outdir, os_path(ctx['sourcename'])))
def handle_finish(self):
self.msg('dumping search index...')
- self.indexer.prune([self.get_target_uri(fn)[:-5] for fn in self.env.all_files])
+ self.indexer.prune([fn[:-4] for fn in self.env.all_files])
f = open(path.join(self.outdir, 'searchindex.json'), 'w')
try:
self.indexer.dump(f, 'json')
@@ -558,7 +541,7 @@
def get_outdated_files(self):
for filename in get_matching_files(
- self.srcdir, '*.rst', exclude=set(self.config.get('unused_files', ()))):
+ self.srcdir, '*.rst', exclude=set(self.config.unused_files)):
try:
targetmtime = path.getmtime(
path.join(self.outdir, os_path(filename)[:-4] + '.fpickle'))
@@ -587,14 +570,14 @@
# delete all entries for files that will be rebuilt
self.indexer.prune(set(self.env.all_files) - set(filenames))
- def index_file(self, filename, doctree, title):
+ def index_page(self, pagename, doctree, title):
# only index pages with title
if self.indexer is not None and title:
- self.indexer.feed(filename, title, doctree)
+ self.indexer.feed(pagename+'.rst', title, doctree)
def handle_page(self, pagename, context, templatename='page.html'):
context['current_page_name'] = pagename
- sidebarfile = self.config.get('html_sidebars', {}).get(pagename, '')
+ sidebarfile = self.confightml_sidebars.get(pagename, '')
if sidebarfile:
context['customsidebar'] = path.join(self.srcdir, sidebarfile)
outfilename = path.join(self.outdir, os_path(pagename) + '.fpickle')
@@ -654,7 +637,7 @@
copysource = False
def handle_finish(self):
- build_hhx(self, self.outdir, self.config.get('htmlhelp_basename', 'pydoc'))
+ build_hhx(self, self.outdir, self.config.htmlhelp_basename)
class LaTeXBuilder(Builder):
@@ -665,13 +648,12 @@
def init(self):
self.filenames = []
- self.document_data = map(list, self.config.get('latex_documents', ()))
+ self.document_data = map(list, self.config.latex_documents)
# assign subdirs to titles
self.titles = []
for entry in self.document_data:
# replace version with real version
- entry[0] = entry[0].replace('<auto>', self.config['version'])
sourcename = entry[0]
if sourcename.endswith('/index.rst'):
sourcename = sourcename[:-9]
@@ -693,7 +675,7 @@
def write(self, *ignored):
# first, assemble the "appendix" docs that are in every PDF
appendices = []
- for fname in self.config.get('latex_appendices', []):
+ for fname in self.config.latex_appendices:
appendices.append(self.env.get_doctree(fname))
docwriter = LaTeXWriter(self)
@@ -780,15 +762,10 @@
name = 'changes'
def init(self):
- from sphinx._jinja import Environment, FileSystemLoader
- templates_path = path.join(path.dirname(__file__), 'templates')
- jinja_env = Environment(loader=SphinxFileSystemLoader([templates_path]),
- # disable traceback, more likely that something in the
- # application is broken than in the templates
- friendly_traceback=False)
- self.ftemplate = jinja_env.get_template('changes/frameset.html')
- self.vtemplate = jinja_env.get_template('changes/versionchanges.html')
- self.stemplate = jinja_env.get_template('changes/rstsource.html')
+ self.init_templates()
+ self.ftemplate = self.get_template('changes/frameset.html')
+ self.vtemplate = self.get_template('changes/versionchanges.html')
+ self.stemplate = self.get_template('changes/rstsource.html')
def get_outdated_files(self):
return self.outdir
@@ -800,13 +777,13 @@
}
def write(self, *ignored):
- ver = self.config['version']
+ version = self.config.version
libchanges = {}
apichanges = []
otherchanges = {}
self.msg('writing summary file...')
for type, filename, lineno, module, descname, content in \
- self.env.versionchanges[ver]:
+ self.env.versionchanges[version]:
ttext = self.typemap[type]
context = content.replace('\n', ' ')
if descname and filename.startswith('c-api'):
@@ -836,8 +813,8 @@
(entry, filename, lineno))
ctx = {
- 'project': self.config.get('project', 'Python'),
- 'version': ver,
+ 'project': self.config.project,
+ 'version': version,
'libchanges': sorted(libchanges.iteritems()),
'apichanges': sorted(apichanges),
'otherchanges': sorted(otherchanges.iteritems()),
@@ -853,9 +830,9 @@
finally:
f.close()
- hltext = ['.. versionadded:: %s' % ver,
- '.. versionchanged:: %s' % ver,
- '.. deprecated:: %s' % ver]
+ hltext = ['.. versionadded:: %s' % version,
+ '.. versionchanged:: %s' % version,
+ '.. deprecated:: %s' % version]
def hl(no, line):
line = '<a name="L%s"> </a>' % no + escape(line)
@@ -881,11 +858,11 @@
shutil.copyfile(path.join(path.dirname(__file__), 'style', 'default.css'),
path.join(self.outdir, 'default.css'))
- def hl(self, text, ver):
+ def hl(self, text, version):
text = escape(text)
for directive in ['versionchanged', 'versionadded', 'deprecated']:
- text = text.replace('.. %s:: %s' % (directive, ver),
- '<b>.. %s:: %s</b>' % (directive, ver))
+ text = text.replace('.. %s:: %s' % (directive, version),
+ '<b>.. %s:: %s</b>' % (directive, version))
return text
def finish(self):
Added: doctools/trunk/sphinx/config.py
==============================================================================
--- (empty file)
+++ doctools/trunk/sphinx/config.py Mon Jan 21 21:20:37 2008
@@ -0,0 +1,103 @@
+# -*- coding: utf-8 -*-
+"""
+ sphinx.config
+ ~~~~~~~~~~~~~
+
+ Build configuration file handling.
+
+ :copyright: 2008 by Georg Brandl.
+ :license: BSD license.
+"""
+
+import os
+import sys
+import types
+from os import path
+
+
+class ConfigError(Exception):
+ """Raised if something's wrong with the configuration."""
+
+ def __init__(self, message, orig_exc=None):
+ self.message = message
+ self.orig_exc = orig_exc
+
+ def __repr__(self):
+ if self.orig_exc:
+ return 'ConfigError(%r, %r)' % (self.message, self.orig_exc)
+ return 'ConfigError(%r)' % self.message
+
+ def __str__(self):
+ if self.orig_exc:
+ return '%s (exception: %s)' % (self.message, self.orig_exc)
+ return self.message
+
+
+class Config(object):
+ """Configuration file abstraction."""
+
+ # the values are: (default, needs fresh doctrees if changed)
+
+ config_values = dict(
+ # general substitutions
+ project = ('Python', True),
+ copyright = ('', False),
+ version = ('', True),
+ release = ('', True),
+ today = ('', True),
+ today_fmt = ('%B %d, %Y', True),
+
+ # extensibility
+ templates_path = ([], False),
+ extensions = ([], True),
+
+ # general reading options
+ unused_files = ([], True),
+ refcount_file = ('', True),
+ add_function_parentheses = (True, True),
+ add_module_names = (True, True),
+
+ # HTML options
+ html_last_updated_fmt = ('%b %d, %Y', False),
+ html_use_smartypants = (True, False),
+ html_translator_class = (None, False),
+ html_index = ('', False),
+ html_sidebars = ({}, False),
+ html_additional_pages = ({}, False),
+
+ # HTML help options
+ htmlhelp_basename = ('pydoc', False),
+
+ # LaTeX options
+ latex_paper_size = ('letter', False),
+ latex_font_size = ('10pt', False),
+ latex_documents = ([], False),
+ latex_preamble = ('', False),
+ latex_appendices = ([], False),
+ )
+
+ def __init__(self, dirname, filename):
+ config = {}
+ olddir = os.getcwd()
+ try:
+ os.chdir(dirname)
+ execfile(path.join(dirname, filename), config)
+ finally:
+ os.chdir(olddir)
+ # remove potentially pickling-problematic values
+ for key, val in config.items():
+ if key.startswith('_') or isinstance(val, types.ModuleType):
+ del config[key]
+ self.__dict__.update(config)
+
+ def __getattr__(self, name):
+ if name in self.config_values:
+ defval = self.config_values[name][0]
+ setattr(self, name, defval)
+ return defval
+ if name[0:1] == '_':
+ return object.__getattr__(self, name)
+ raise AttributeError('no configuration value named %r' % name)
+
+ def __getitem__(self, name):
+ return getattr(self, name)
Modified: doctools/trunk/sphinx/directives.py
==============================================================================
--- doctools/trunk/sphinx/directives.py (original)
+++ doctools/trunk/sphinx/directives.py Mon Jan 21 21:20:37 2008
@@ -147,7 +147,7 @@
signode += addnodes.desc_classname(classname, classname)
# exceptions are a special case, since they are documented in the
# 'exceptions' module.
- elif env.config.get('add_module_names', True) and \
+ elif env.config.add_module_names and \
env.currmodule and env.currmodule != 'exceptions':
nodetext = env.currmodule + '.'
signode += addnodes.desc_classname(nodetext, nodetext)
Modified: doctools/trunk/sphinx/environment.py
==============================================================================
--- doctools/trunk/sphinx/environment.py (original)
+++ doctools/trunk/sphinx/environment.py Mon Jan 21 21:20:37 2008
@@ -22,6 +22,7 @@
import hashlib
md5 = hashlib.md5
except:
+ # 2.4 compatibility
import md5
md5 = md5.new
@@ -102,10 +103,10 @@
for ref in self.document.traverse(nodes.substitution_reference):
refname = ref['refname']
if refname in to_handle:
- text = config.get(refname, '')
+ text = config[refname]
if refname == 'today' and not text:
# special handling: can also specify a strftime format
- text = time.strftime(config.get('today_fmt', '%B %d, %Y'))
+ text = time.strftime(config.today_fmt)
ref.replace_self(nodes.Text(text, text))
@@ -186,7 +187,7 @@
def __init__(self, srcdir, doctreedir):
self.doctreedir = doctreedir
self.srcdir = srcdir
- self.config = {}
+ self.config = None
# refcount data if present
self.refcounts = {}
@@ -203,6 +204,7 @@
# Build times -- to determine changed files
# Also use this as an inventory of all existing and built filenames.
+ # All "filenames" here are /-separated and relative and include '.rst'.
self.all_files = {} # filename -> (mtime, md5sum) at the time of build
# File metadata
@@ -279,7 +281,7 @@
Return (added, changed, removed) iterables.
"""
all_source_files = list(get_matching_files(
- self.srcdir, '*.rst', exclude=set(config.get('unused_files', ()))))
+ self.srcdir, '*.rst', exclude=set(config.unused_files)))
# clear all files no longer present
removed = set(self.all_files) - set(all_source_files)
@@ -312,27 +314,26 @@
return added, changed, removed
- # If one of these config values changes, all files need to be re-read.
- influential_config_values = [
- 'version', 'release', 'today', 'today_fmt', 'unused_files',
- 'project', 'refcount_file', 'add_function_parentheses', 'add_module_names'
- ]
-
- def update(self, config):
- """
- (Re-)read all files new or changed since last update.
- Yields a summary and then filenames as it processes them.
- Store all environment filenames in the canonical format
- (ie using SEP as a separator in place of os.path.sep).
- """
+ def update(self, config, hook=None):
+ """(Re-)read all files new or changed since last update. Yields a summary
+ and then filenames as it processes them. Store all environment filenames
+ in the canonical format (ie using SEP as a separator in place of
+ os.path.sep)."""
config_changed = False
- for val in self.influential_config_values:
- if self.config.get(val) != config.get(val):
- msg = '[config changed] '
- config_changed = True
- break
+ if self.config is None:
+ msg = '[new config] '
+ config_changed = True
else:
- msg = ''
+ # check if a config value was changed that affects how doctrees are read
+ for key, descr in config.config_values.iteritems():
+ if not descr[1]:
+ continue
+ if self.config[key] != config[key]:
+ msg = '[config changed] '
+ config_changed = True
+ break
+ else:
+ msg = ''
added, changed, removed = self.get_outdated_files(config, config_changed)
msg += '%s added, %s changed, %s removed' % (len(added), len(changed),
len(removed))
@@ -341,9 +342,9 @@
self.config = config
# read the refcounts file
- if self.config.get('refcount_file'):
+ if self.config.refcount_file:
self.refcounts = Refcounts.fromfile(
- path.join(self.srcdir, self.config['refcount_file']))
+ path.join(self.srcdir, self.config.refcount_file))
# clear all files no longer present
for filename in removed:
@@ -354,9 +355,12 @@
yield filename
self.read_file(filename)
+ if 'contents.rst' not in self.all_files:
+ self._warnfunc('no master file contents.rst found')
+
# --------- SINGLE FILE BUILDING -------------------------------------------
- def read_file(self, filename, src_path=None, save_parsed=True):
+ def read_file(self, filename, src_path=None, save_parsed=True, hook=None):
"""Parse a file and add/update inventory entries for the doctree.
If srcpath is given, read from a different source file."""
# remove all inventory entries for that file
@@ -382,6 +386,10 @@
f.close()
self.all_files[filename] = (path.getmtime(src_path), md5sum)
+ # run post-read hook
+ if hook:
+ hook(doctree)
+
# make it picklable
doctree.reporter = None
doctree.transformer = None
Added: doctools/trunk/sphinx/extension.py
==============================================================================
--- (empty file)
+++ doctools/trunk/sphinx/extension.py Mon Jan 21 21:20:37 2008
@@ -0,0 +1,83 @@
+# -*- coding: utf-8 -*-
+"""
+ sphinx.extension
+ ~~~~~~~~~~~~~~~~
+
+ Gracefully adapted from the TextPress event system by Armin.
+
+ :copyright: 2008 by Georg Brandl, Armin Ronacher.
+ :license: BSD.
+"""
+
+from sphinx.config import ConfigError
+
+
+def import_object(objname, source=None):
+ """Import an object from a 'module.name' string."""
+ try:
+ module, name = objname.rsplit('.', 1)
+ except ValueError, err:
+ raise ConfigError('Invalid full object name %s' % objname +
+ (source and ' (needed for %s)' % source or ''), err)
+ try:
+ return getattr(__import__(module, None, None, [name]), name)
+ except ImportError, err:
+ raise ConfigError('Could not import %s' % module +
+ (source and ' (needed for %s)' % source or ''), err)
+ except AttributeError, err:
+ raise ConfigError('Could not find %s' % objname +
+ (source and ' (needed for %s)' % source or ''), err)
+
+
+# List of all known events. Maps name to arguments description.
+events = {
+ 'builder-created' : 'builder instance',
+ 'doctree-read' : 'the doctree before being pickled',
+}
+
+class EventManager(object):
+ """
+ Helper class that handles event listeners and events.
+
+ This is *not* a public interface. Always use the emit_event()
+ functions to access it or the connect_event() / disconnect_event()
+ functions on the application.
+ """
+
+ def __init__(self):
+ self.next_listener_id = 0
+ self._listeners = {}
+
+ def _validate(self, event):
+ event = intern(event)
+ if event not in events:
+ raise RuntimeError('unknown event name: %s' % event)
+
+ def connect(self, event, callback):
+ self._validate(event)
+ listener_id = self.next_listener_id
+ if event not in self._listeners:
+ self._listeners[event] = {listener_id: callback}
+ else:
+ self._listeners[event][listener_id] = callback
+ self.next_listener_id += 1
+ return listener_id
+
+ def remove(self, listener_id):
+ for event in self._listeners:
+ event.pop(listener_id, None)
+
+ def emit(self, event, *args):
+ self._validate(event)
+ if event in self._listeners:
+ for listener_id, callback in self._listeners[event].iteritems():
+ yield listener_id, callback(*args)
+
+
+class DummyEventManager(EventManager):
+ def connect(self, event, callback):
+ self._validate(event)
+ def remove(self, listener_id):
+ pass
+ def emit(self, event, *args):
+ self._validate(event)
Modified: doctools/trunk/sphinx/htmlhelp.py
==============================================================================
--- doctools/trunk/sphinx/htmlhelp.py (original)
+++ doctools/trunk/sphinx/htmlhelp.py Mon Jan 21 21:20:37 2008
@@ -129,8 +129,8 @@
f = open(path.join(outdir, outname+'.hhp'), 'w')
try:
f.write(project_template % {'outname': outname,
- 'version': builder.config['version'],
- 'project': builder.config['project']})
+ 'version': builder.config.version,
+ 'project': builder.config.project})
if not outdir.endswith(os.sep):
outdir += os.sep
olen = len(outdir)
Modified: doctools/trunk/sphinx/htmlwriter.py
==============================================================================
--- doctools/trunk/sphinx/htmlwriter.py (original)
+++ doctools/trunk/sphinx/htmlwriter.py Mon Jan 21 21:20:37 2008
@@ -18,7 +18,18 @@
class HTMLWriter(Writer):
def __init__(self, builder):
Writer.__init__(self)
- self.translator_class = translator_class(builder)
+ self.builder = builder
+
+ def translate(self):
+ # sadly, this is mostly copied from parent class
+ self.visitor = visitor = self.builder.translator_class(self.builder,
+ self.document)
+ self.document.walkabout(visitor)
+ self.output = visitor.astext()
+ for attr in ('head_prefix', 'stylesheet', 'head', 'body_prefix',
+ 'body_pre_docinfo', 'docinfo', 'body', 'fragment',
+ 'body_suffix'):
+ setattr(self, attr, getattr(visitor, attr))
version_text = {
@@ -27,283 +38,278 @@
'versionadded': 'New in version %s',
}
-def translator_class(builder):
- class HTMLTranslator(BaseTranslator):
- """
- Our custom HTML translator.
- """
-
- def __init__(self, *args, **kwds):
- self.no_smarty = 0
- BaseTranslator.__init__(self, *args, **kwds)
- self.highlightlang = 'python'
- self.language.labels['warning'] = 'Caveat'
-
- def visit_desc(self, node):
- self.body.append(self.starttag(node, 'dl', CLASS=node['desctype']))
- def depart_desc(self, node):
- self.body.append('</dl>\n\n')
-
- def visit_desc_signature(self, node):
- # the id is set automatically
- self.body.append(self.starttag(node, 'dt'))
- # anchor for per-desc interactive data
- if node.parent['desctype'] != 'describe' and node['ids'] and node['first']:
- self.body.append('<!--#%s#-->' % node['ids'][0])
- if node.parent['desctype'] in ('class', 'exception'):
- self.body.append('%s ' % node.parent['desctype'])
- def depart_desc_signature(self, node):
- if node['ids'] and builder.name != 'htmlhelp':
- self.body.append(u'<a class="headerlink" href="#%s" ' % node['ids'][0] +
- u'title="Permalink to this definition">\u00B6</a>')
- self.body.append('</dt>\n')
-
- def visit_desc_classname(self, node):
- self.body.append(self.starttag(node, 'tt', '', CLASS='descclassname'))
- def depart_desc_classname(self, node):
- self.body.append('</tt>')
-
- def visit_desc_type(self, node):
- # return type of C functions -- nothing to do here
- pass
- def depart_desc_type(self, node):
- pass
-
- def visit_desc_name(self, node):
- self.body.append(self.starttag(node, 'tt', '', CLASS='descname'))
- def depart_desc_name(self, node):
- self.body.append('</tt>')
-
- def visit_desc_parameterlist(self, node):
- self.body.append('<big>(</big>')
- self.first_param = 1
- def depart_desc_parameterlist(self, node):
- self.body.append('<big>)</big>')
-
- def visit_desc_parameter(self, node):
- if not self.first_param:
- self.body.append(', ')
- else:
- self.first_param = 0
- if not node.hasattr('noemph'):
- self.body.append('<em>')
- def depart_desc_parameter(self, node):
- if not node.hasattr('noemph'):
- self.body.append('</em>')
-
- def visit_desc_optional(self, node):
- self.body.append('<span class="optional">[</span>')
- def depart_desc_optional(self, node):
- self.body.append('<span class="optional">]</span>')
-
- def visit_desc_content(self, node):
- self.body.append(self.starttag(node, 'dd', ''))
- def depart_desc_content(self, node):
- self.body.append('</dd>')
-
- def visit_refcount(self, node):
- self.body.append(self.starttag(node, 'em', '', CLASS='refcount'))
- def depart_refcount(self, node):
+class HTMLTranslator(BaseTranslator):
+ """
+ Our custom HTML translator.
+ """
+
+ def __init__(self, builder, *args, **kwds):
+ BaseTranslator.__init__(self, *args, **kwds)
+ self.no_smarty = 0
+ self.builder = builder
+ self.highlightlang = 'python'
+ self.language.labels['warning'] = 'Caveat'
+
+ def visit_desc(self, node):
+ self.body.append(self.starttag(node, 'dl', CLASS=node['desctype']))
+ def depart_desc(self, node):
+ self.body.append('</dl>\n\n')
+
+ def visit_desc_signature(self, node):
+ # the id is set automatically
+ self.body.append(self.starttag(node, 'dt'))
+ # anchor for per-desc interactive data
+ if node.parent['desctype'] != 'describe' and node['ids'] and node['first']:
+ self.body.append('<!--#%s#-->' % node['ids'][0])
+ if node.parent['desctype'] in ('class', 'exception'):
+ self.body.append('%s ' % node.parent['desctype'])
+ def depart_desc_signature(self, node):
+ if node['ids'] and self.builder.name != 'htmlhelp':
+ self.body.append(u'<a class="headerlink" href="#%s" ' % node['ids'][0] +
+ u'title="Permalink to this definition">\u00B6</a>')
+ self.body.append('</dt>\n')
+
+ def visit_desc_classname(self, node):
+ self.body.append(self.starttag(node, 'tt', '', CLASS='descclassname'))
+ def depart_desc_classname(self, node):
+ self.body.append('</tt>')
+
+ def visit_desc_type(self, node):
+ # return type of C functions -- nothing to do here
+ pass
+ def depart_desc_type(self, node):
+ pass
+
+ def visit_desc_name(self, node):
+ self.body.append(self.starttag(node, 'tt', '', CLASS='descname'))
+ def depart_desc_name(self, node):
+ self.body.append('</tt>')
+
+ def visit_desc_parameterlist(self, node):
+ self.body.append('<big>(</big>')
+ self.first_param = 1
+ def depart_desc_parameterlist(self, node):
+ self.body.append('<big>)</big>')
+
+ def visit_desc_parameter(self, node):
+ if not self.first_param:
+ self.body.append(', ')
+ else:
+ self.first_param = 0
+ if not node.hasattr('noemph'):
+ self.body.append('<em>')
+ def depart_desc_parameter(self, node):
+ if not node.hasattr('noemph'):
self.body.append('</em>')
- def visit_versionmodified(self, node):
- self.body.append(self.starttag(node, 'p'))
- text = version_text[node['type']] % node['version']
- if len(node):
- text += ': '
+ def visit_desc_optional(self, node):
+ self.body.append('<span class="optional">[</span>')
+ def depart_desc_optional(self, node):
+ self.body.append('<span class="optional">]</span>')
+
+ def visit_desc_content(self, node):
+ self.body.append(self.starttag(node, 'dd', ''))
+ def depart_desc_content(self, node):
+ self.body.append('</dd>')
+
+ def visit_refcount(self, node):
+ self.body.append(self.starttag(node, 'em', '', CLASS='refcount'))
+ def depart_refcount(self, node):
+ self.body.append('</em>')
+
+ def visit_versionmodified(self, node):
+ self.body.append(self.starttag(node, 'p'))
+ text = version_text[node['type']] % node['version']
+ if len(node):
+ text += ': '
+ else:
+ text += '.'
+ self.body.append('<span class="versionmodified">%s</span>' % text)
+ def depart_versionmodified(self, node):
+ self.body.append('</p>\n')
+
+ # overwritten
+ def visit_reference(self, node):
+ BaseTranslator.visit_reference(self, node)
+ if node.hasattr('reftitle'):
+ # ugly hack to add a title attribute
+ starttag = self.body[-1]
+ if not starttag.startswith('<a '):
+ return
+ self.body[-1] = '<a title="%s"' % self.attval(node['reftitle']) + \
+ starttag[2:]
+
+ # overwritten -- we don't want source comments to show up in the HTML
+ def visit_comment(self, node):
+ raise nodes.SkipNode
+
+ # overwritten
+ def visit_admonition(self, node, name=''):
+ self.body.append(self.start_tag_with_title(
+ node, 'div', CLASS=('admonition ' + name)))
+ if name and name != 'seealso':
+ node.insert(0, nodes.title(name, self.language.labels[name]))
+ self.set_first_last(node)
+
+ def visit_seealso(self, node):
+ self.visit_admonition(node, 'seealso')
+ def depart_seealso(self, node):
+ self.depart_admonition(node)
+
+ # overwritten
+ def visit_title(self, node, move_ids=1):
+ # if we have a section we do our own processing in order
+ # to have ids in the hN-tags and not in additional a-tags
+ if isinstance(node.parent, nodes.section):
+ h_level = self.section_level + self.initial_header_level - 1
+ if node.parent.get('ids'):
+ attrs = {'ids': node.parent['ids']}
else:
- text += '.'
- self.body.append('<span class="versionmodified">%s</span>' % text)
- def depart_versionmodified(self, node):
- self.body.append('</p>\n')
-
- # overwritten
- def visit_reference(self, node):
- BaseTranslator.visit_reference(self, node)
- if node.hasattr('reftitle'):
- # ugly hack to add a title attribute
- starttag = self.body[-1]
- if not starttag.startswith('<a '):
- return
- self.body[-1] = '<a title="%s"' % self.attval(node['reftitle']) + \
- starttag[2:]
-
- # overwritten -- we don't want source comments to show up in the HTML
- def visit_comment(self, node):
- raise nodes.SkipNode
-
- # overwritten
- def visit_admonition(self, node, name=''):
- self.body.append(self.start_tag_with_title(
- node, 'div', CLASS=('admonition ' + name)))
- if name and name != 'seealso':
- node.insert(0, nodes.title(name, self.language.labels[name]))
- self.set_first_last(node)
-
- def visit_seealso(self, node):
- self.visit_admonition(node, 'seealso')
- def depart_seealso(self, node):
- self.depart_admonition(node)
-
- # overwritten
- def visit_title(self, node, move_ids=1):
- # if we have a section we do our own processing in order
- # to have ids in the hN-tags and not in additional a-tags
- if isinstance(node.parent, nodes.section):
- h_level = self.section_level + self.initial_header_level - 1
- if node.parent.get('ids'):
- attrs = {'ids': node.parent['ids']}
- else:
- attrs = {}
- self.body.append(self.starttag(node, 'h%d' % h_level, '', **attrs))
- self.context.append('</h%d>\n' % h_level)
+ attrs = {}
+ self.body.append(self.starttag(node, 'h%d' % h_level, '', **attrs))
+ self.context.append('</h%d>\n' % h_level)
+ else:
+ BaseTranslator.visit_title(self, node, move_ids)
+
+ # overwritten
+ def visit_literal_block(self, node):
+ from sphinx.highlighting import highlight_block
+ self.body.append(highlight_block(node.rawsource, self.highlightlang))
+ raise nodes.SkipNode
+
+ # overwritten
+ def visit_literal(self, node):
+ if len(node.children) == 1 and \
+ node.children[0] in ('None', 'True', 'False'):
+ node['classes'].append('xref')
+ BaseTranslator.visit_literal(self, node)
+
+ def visit_productionlist(self, node):
+ self.body.append(self.starttag(node, 'pre'))
+ names = []
+ for production in node:
+ names.append(production['tokenname'])
+ maxlen = max(len(name) for name in names)
+ for production in node:
+ if production['tokenname']:
+ self.body.append(self.starttag(production, 'strong', ''))
+ self.body.append(production['tokenname'].ljust(maxlen) +
+ '</strong> ::= ')
+ lastname = production['tokenname']
else:
- BaseTranslator.visit_title(self, node, move_ids)
-
- # overwritten
- def visit_literal_block(self, node):
- from sphinx.highlighting import highlight_block
- self.body.append(highlight_block(node.rawsource, self.highlightlang))
- raise nodes.SkipNode
-
- # overwritten
- def visit_literal(self, node):
- if len(node.children) == 1 and \
- node.children[0] in ('None', 'True', 'False'):
- node['classes'].append('xref')
- BaseTranslator.visit_literal(self, node)
-
- def visit_productionlist(self, node):
- self.body.append(self.starttag(node, 'pre'))
- names = []
- for production in node:
- names.append(production['tokenname'])
- maxlen = max(len(name) for name in names)
- for production in node:
- if production['tokenname']:
- self.body.append(self.starttag(production, 'strong', ''))
- self.body.append(production['tokenname'].ljust(maxlen) +
- '</strong> ::= ')
- lastname = production['tokenname']
- else:
- self.body.append('%s ' % (' '*len(lastname)))
- production.walkabout(self)
- self.body.append('\n')
- self.body.append('</pre>\n')
- raise nodes.SkipNode
- def depart_productionlist(self, node):
- pass
-
- def visit_production(self, node):
- pass
- def depart_production(self, node):
- pass
-
- def visit_centered(self, node):
- self.body.append(self.starttag(node, 'p', CLASS="centered") + '<strong>')
- def depart_centered(self, node):
- self.body.append('</strong></p>')
-
- def visit_compact_paragraph(self, node):
- pass
- def depart_compact_paragraph(self, node):
- pass
-
- def visit_highlightlang(self, node):
- self.highlightlang = node['lang']
- def depart_highlightlang(self, node):
- pass
-
- def visit_toctree(self, node):
- # this only happens when formatting a toc from env.tocs -- in this
- # case we don't want to include the subtree
- raise nodes.SkipNode
-
- def visit_index(self, node):
- raise nodes.SkipNode
-
- def visit_glossary(self, node):
- pass
- def depart_glossary(self, node):
- pass
-
- def visit_acks(self, node):
- pass
- def depart_acks(self, node):
- pass
-
- def visit_module(self, node):
- pass
- def depart_module(self, node):
- pass
-
- # these are only handled specially in the SmartyPantsHTMLTranslator
- def visit_literal_emphasis(self, node):
- return self.visit_emphasis(node)
- def depart_literal_emphasis(self, node):
- return self.depart_emphasis(node)
-
- def depart_title(self, node):
- close_tag = self.context[-1]
- if builder.name != 'htmlhelp' and \
- (close_tag.startswith('</h') or
- close_tag.startswith('</a></h')) and \
- node.parent.hasattr('ids') and node.parent['ids']:
- aname = node.parent['ids'][0]
- # add permalink anchor
- self.body.append(u'<a class="headerlink" href="#%s" ' % aname +
- u'title="Permalink to this headline">\u00B6</a>')
- BaseTranslator.depart_title(self, node)
-
-
- class SmartyPantsHTMLTranslator(HTMLTranslator):
- """
- Handle ordinary text via smartypants, converting quotes and dashes
- to the correct entities.
- """
-
- def __init__(self, *args, **kwds):
- self.no_smarty = 0
- HTMLTranslator.__init__(self, *args, **kwds)
-
- def visit_literal(self, node):
- self.no_smarty += 1
- try:
- # this raises SkipNode
- HTMLTranslator.visit_literal(self, node)
- finally:
- self.no_smarty -= 1
-
- def visit_literal_emphasis(self, node):
- self.no_smarty += 1
- self.visit_emphasis(node)
-
- def depart_literal_emphasis(self, node):
- self.depart_emphasis(node)
+ self.body.append('%s ' % (' '*len(lastname)))
+ production.walkabout(self)
+ self.body.append('\n')
+ self.body.append('</pre>\n')
+ raise nodes.SkipNode
+ def depart_productionlist(self, node):
+ pass
+
+ def visit_production(self, node):
+ pass
+ def depart_production(self, node):
+ pass
+
+ def visit_centered(self, node):
+ self.body.append(self.starttag(node, 'p', CLASS="centered") + '<strong>')
+ def depart_centered(self, node):
+ self.body.append('</strong></p>')
+
+ def visit_compact_paragraph(self, node):
+ pass
+ def depart_compact_paragraph(self, node):
+ pass
+
+ def visit_highlightlang(self, node):
+ self.highlightlang = node['lang']
+ def depart_highlightlang(self, node):
+ pass
+
+ def visit_toctree(self, node):
+ # this only happens when formatting a toc from env.tocs -- in this
+ # case we don't want to include the subtree
+ raise nodes.SkipNode
+
+ def visit_index(self, node):
+ raise nodes.SkipNode
+
+ def visit_glossary(self, node):
+ pass
+ def depart_glossary(self, node):
+ pass
+
+ def visit_acks(self, node):
+ pass
+ def depart_acks(self, node):
+ pass
+
+ def visit_module(self, node):
+ pass
+ def depart_module(self, node):
+ pass
+
+ # these are only handled specially in the SmartyPantsHTMLTranslator
+ def visit_literal_emphasis(self, node):
+ return self.visit_emphasis(node)
+ def depart_literal_emphasis(self, node):
+ return self.depart_emphasis(node)
+
+ def depart_title(self, node):
+ close_tag = self.context[-1]
+ if self.builder.name != 'htmlhelp' and \
+ (close_tag.startswith('</h') or
+ close_tag.startswith('</a></h')) and \
+ node.parent.hasattr('ids') and node.parent['ids']:
+ aname = node.parent['ids'][0]
+ # add permalink anchor
+ self.body.append(u'<a class="headerlink" href="#%s" ' % aname +
+ u'title="Permalink to this headline">\u00B6</a>')
+ BaseTranslator.depart_title(self, node)
+
+
+class SmartyPantsHTMLTranslator(HTMLTranslator):
+ """
+ Handle ordinary text via smartypants, converting quotes and dashes
+ to the correct entities.
+ """
+
+ def __init__(self, *args, **kwds):
+ self.no_smarty = 0
+ HTMLTranslator.__init__(self, *args, **kwds)
+
+ def visit_literal(self, node):
+ self.no_smarty += 1
+ try:
+ # this raises SkipNode
+ HTMLTranslator.visit_literal(self, node)
+ finally:
self.no_smarty -= 1
- def visit_desc_signature(self, node):
- self.no_smarty += 1
- HTMLTranslator.visit_desc_signature(self, node)
-
- def depart_desc_signature(self, node):
+ def visit_literal_emphasis(self, node):
+ self.no_smarty += 1
+ self.visit_emphasis(node)
+
+ def depart_literal_emphasis(self, node):
+ self.depart_emphasis(node)
+ self.no_smarty -= 1
+
+ def visit_desc_signature(self, node):
+ self.no_smarty += 1
+ HTMLTranslator.visit_desc_signature(self, node)
+
+ def depart_desc_signature(self, node):
+ self.no_smarty -= 1
+ HTMLTranslator.depart_desc_signature(self, node)
+
+ def visit_productionlist(self, node):
+ self.no_smarty += 1
+ try:
+ HTMLTranslator.visit_productionlist(self, node)
+ finally:
self.no_smarty -= 1
- HTMLTranslator.depart_desc_signature(self, node)
- def visit_productionlist(self, node):
- self.no_smarty += 1
- try:
- HTMLTranslator.visit_productionlist(self, node)
- finally:
- self.no_smarty -= 1
-
- def encode(self, text):
- text = HTMLTranslator.encode(self, text)
- if self.no_smarty <= 0:
- text = sphinx_smarty_pants(text)
- return text
-
- if builder.config.get('html_use_smartypants', False):
- return SmartyPantsHTMLTranslator
- else:
- return HTMLTranslator
+ def encode(self, text):
+ text = HTMLTranslator.encode(self, text)
+ if self.no_smarty <= 0:
+ text = sphinx_smarty_pants(text)
+ return text
Modified: doctools/trunk/sphinx/latexwriter.py
==============================================================================
--- doctools/trunk/sphinx/latexwriter.py (original)
+++ doctools/trunk/sphinx/latexwriter.py Mon Jan 21 21:20:37 2008
@@ -21,7 +21,7 @@
from sphinx import addnodes
from sphinx import highlighting
-
+# Move to a template?
HEADER = r'''%% Generated by Sphinx.
\documentclass[%(papersize)s,%(pointsize)s]{%(docclass)s}
\usepackage[utf8]{inputenc}
@@ -92,18 +92,18 @@
self.builder = builder
self.body = []
docclass = document.settings.docclass
- paper = builder.config.get('latex_paper_size', 'letter') + 'paper'
+ paper = builder.config.latex_paper_size + 'paper'
if paper == 'paper': # e.g. command line "-D latex_paper_size="
paper = 'letterpaper'
- date = time.strftime(builder.config.get('today_fmt', '%B %d, %Y'))
+ date = time.strftime(builder.config.today_fmt)
self.options = {'docclass': docclass,
'papersize': paper,
- 'pointsize': builder.config.get('latex_font_size', '10pt'),
- 'preamble': builder.config['latex_preamble'],
+ 'pointsize': builder.config.latex_font_size,
+ 'preamble': builder.config.latex_preamble,
'author': document.settings.author,
'filename': document.settings.filename,
'title': None, # is determined later
- 'release': builder.config['release'],
+ 'release': builder.config.release,
'date': date,
}
self.context = []
Deleted: /doctools/trunk/sphinx/patchlevel.py
==============================================================================
--- /doctools/trunk/sphinx/patchlevel.py Mon Jan 21 21:20:37 2008
+++ (empty file)
@@ -1,60 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- sphinx.patchlevel
- ~~~~~~~~~~~~~~~~~
-
- Extract version info from Include/patchlevel.h.
- Adapted from Doc/tools/getversioninfo.
-
- XXX Python specific
-
- :copyright: 2007-2008 by Georg Brandl.
- :license: BSD.
-"""
-
-import os
-import re
-import sys
-
-def get_version_info(srcdir):
- patchlevel_h = os.path.join(srcdir, '..', "Include", "patchlevel.h")
-
- # This won't pick out all #defines, but it will pick up the ones we
- # care about.
- rx = re.compile(r"\s*#define\s+([a-zA-Z][a-zA-Z_0-9]*)\s+([a-zA-Z_0-9]+)")
-
- d = {}
- f = open(patchlevel_h)
- try:
- for line in f:
- m = rx.match(line)
- if m is not None:
- name, value = m.group(1, 2)
- d[name] = value
- finally:
- f.close()
-
- release = version = "%s.%s" % (d["PY_MAJOR_VERSION"], d["PY_MINOR_VERSION"])
- micro = int(d["PY_MICRO_VERSION"])
- if micro != 0:
- release += "." + str(micro)
-
- level = d["PY_RELEASE_LEVEL"]
- suffixes = {
- "PY_RELEASE_LEVEL_ALPHA": "a",
- "PY_RELEASE_LEVEL_BETA": "b",
- "PY_RELEASE_LEVEL_GAMMA": "c",
- }
- if level != "PY_RELEASE_LEVEL_FINAL":
- release += suffixes[level] + str(int(d["PY_RELEASE_SERIAL"]))
- return version, release
-
-
-def get_sys_version_info():
- major, minor, micro, level, serial = sys.version_info
- release = version = '%s.%s' % (major, minor)
- if micro:
- release += '.%s' % micro
- if level != 'final':
- release += '%s%s' % (level[0], serial)
- return version, release
Modified: doctools/trunk/sphinx/roles.py
==============================================================================
--- doctools/trunk/sphinx/roles.py (original)
+++ doctools/trunk/sphinx/roles.py Mon Jan 21 21:20:37 2008
@@ -109,7 +109,7 @@
if text.endswith('()'):
# remove parentheses
text = text[:-2]
- if env.config.get('add_function_parentheses', True):
+ if env.config.add_function_parentheses:
# add them back to all occurrences if configured
text += '()'
# if the first character is a bang, don't cross-reference at all
Modified: doctools/trunk/sphinx/templates/layout.html
==============================================================================
--- doctools/trunk/sphinx/templates/layout.html (original)
+++ doctools/trunk/sphinx/templates/layout.html Mon Jan 21 21:20:37 2008
@@ -113,7 +113,8 @@
{% if customsidebar %}
{{ rendertemplate(customsidebar) }}
{% endif %}
- {% if current_page_name != "search" %}
+ {% if current_page_name != "search" and builder == 'web' %}
+ {# HTML builder search is disabled for now #}
<h3>{{ builder == 'web' and 'Keyword' or 'Quick' }} search</h3>
<form class="search" action="{{ pathto('search') }}" method="get">
<input type="text" name="q" size="18"> <input type="submit" value="Go">
More information about the Python-checkins
mailing list