[Python-checkins] r60509 - in doctools/trunk: HACKING README sphinx-build.py sphinx/addons/ifconfig.py sphinx/application.py sphinx/builder.py sphinx/config.py sphinx/directives.py sphinx/environment.py sphinx/htmlhelp.py sphinx/latexwriter.py sphinx/templates/changes/versionchanges.html sphinx/templates/layout.html sphinx/util/__init__.py sphinx/web/application.py
georg.brandl
python-checkins at python.org
Fri Feb 1 21:44:17 CET 2008
Author: georg.brandl
Date: Fri Feb 1 21:44:17 2008
New Revision: 60509
Modified:
doctools/trunk/HACKING
doctools/trunk/README
doctools/trunk/sphinx-build.py
doctools/trunk/sphinx/addons/ifconfig.py
doctools/trunk/sphinx/application.py
doctools/trunk/sphinx/builder.py
doctools/trunk/sphinx/config.py
doctools/trunk/sphinx/directives.py
doctools/trunk/sphinx/environment.py
doctools/trunk/sphinx/htmlhelp.py
doctools/trunk/sphinx/latexwriter.py
doctools/trunk/sphinx/templates/changes/versionchanges.html
doctools/trunk/sphinx/templates/layout.html
doctools/trunk/sphinx/util/__init__.py
doctools/trunk/sphinx/web/application.py
Log:
More refactoring, this time allowing different file extensions
and a different master file. Also fix environment warning reporting
and improve handling of error conditions.
Modified: doctools/trunk/HACKING
==============================================================================
--- doctools/trunk/HACKING (original)
+++ doctools/trunk/HACKING Fri Feb 1 21:44:17 2008
@@ -6,6 +6,8 @@
This document tries to give you a cursory overview of the doctools code.
+TODO: update this.
+
Dependencies
------------
Modified: doctools/trunk/README
==============================================================================
--- doctools/trunk/README (original)
+++ doctools/trunk/README Fri Feb 1 21:44:17 2008
@@ -4,6 +4,8 @@
FIXME: This is already outdated since the conversion has happened and the
reST sources are in the Python tree now.
+TODO: update this.
+
What you need to know
---------------------
Modified: doctools/trunk/sphinx-build.py
==============================================================================
--- doctools/trunk/sphinx-build.py (original)
+++ doctools/trunk/sphinx-build.py Fri Feb 1 21:44:17 2008
@@ -11,10 +11,4 @@
if __name__ == '__main__':
from sphinx import main
- try:
- sys.exit(main(sys.argv))
- except Exception:
- import traceback
- traceback.print_exc()
- import pdb
- pdb.post_mortem(sys.exc_traceback)
+ sys.exit(main(sys.argv))
Modified: doctools/trunk/sphinx/addons/ifconfig.py
==============================================================================
--- doctools/trunk/sphinx/addons/ifconfig.py (original)
+++ doctools/trunk/sphinx/addons/ifconfig.py Fri Feb 1 21:44:17 2008
@@ -34,7 +34,7 @@
return [node]
-def process_ifconfig_nodes(app, doctree, docfilename):
+def process_ifconfig_nodes(app, doctree, docname):
ns = app.config.__dict__.copy()
ns['builder'] = app.builder.name
for node in doctree.traverse(ifconfig):
Modified: doctools/trunk/sphinx/application.py
==============================================================================
--- doctools/trunk/sphinx/application.py (original)
+++ doctools/trunk/sphinx/application.py Fri Feb 1 21:44:17 2008
@@ -42,9 +42,9 @@
# List of all known events. Maps name to arguments description.
events = {
- 'builder-inited': 'builder instance',
+ 'builder-inited': '',
'doctree-read' : 'the doctree before being pickled',
- 'doctree-resolved' : 'the doctree, the filename, the builder',
+ 'doctree-resolved' : 'the doctree, the docname',
}
class Application(object):
Modified: doctools/trunk/sphinx/builder.py
==============================================================================
--- doctools/trunk/sphinx/builder.py (original)
+++ doctools/trunk/sphinx/builder.py Fri Feb 1 21:44:17 2008
@@ -27,13 +27,13 @@
from docutils.readers.doctree import Reader as DoctreeReader
from sphinx import addnodes
-from sphinx.util import (get_matching_files, ensuredir, relative_uri, os_path, SEP)
+from sphinx.util import (get_matching_docs, ensuredir, relative_uri, SEP, os_path)
from sphinx.htmlhelp import build_hhx
from sphinx.htmlwriter import HTMLWriter, HTMLTranslator, SmartyPantsHTMLTranslator
from sphinx.latexwriter import LaTeXWriter
from sphinx.environment import BuildEnvironment, NoUri
from sphinx.highlighting import pygments, get_stylesheet
-from sphinx.util.console import bold, purple, green, red, darkgreen
+from sphinx.util.console import bold, purple, red, darkgreen
# side effect: registers roles and directives
from sphinx import roles
@@ -64,6 +64,7 @@
self.freshenv = freshenv
self.init()
+ self.load_env()
# helper methods
@@ -91,8 +92,11 @@
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."""
+ def get_target_uri(self, docname, typ=None):
+ """
+ Return the target URI for a document name (typ can be used to qualify
+ the link characteristic for individual builders).
+ """
raise NotImplementedError
def get_relative_uri(self, from_, to, typ=None):
@@ -102,7 +106,7 @@
return relative_uri(self.get_target_uri(from_),
self.get_target_uri(to, typ))
- def get_outdated_files(self):
+ def get_outdated_docs(self):
"""Return a list of output files that are outdated."""
raise NotImplementedError
@@ -132,29 +136,33 @@
self.info('done')
except Exception, err:
self.info('failed: %s' % err)
- self.env = BuildEnvironment(self.srcdir, self.doctreedir)
+ self.env = BuildEnvironment(self.srcdir, self.doctreedir, self.config)
else:
- self.env = BuildEnvironment(self.srcdir, self.doctreedir)
+ self.env = BuildEnvironment(self.srcdir, self.doctreedir, self.config)
+ self.env.set_warnfunc(self.warn)
def build_all(self):
"""Build all source files."""
- self.load_env()
self.build(None, summary='all source files')
- def build_specific(self, source_filenames):
+ def build_specific(self, filenames):
"""Only rebuild as much as needed for changes in the source_filenames."""
# bring the filenames to the canonical format, that is,
- # relative to the source directory.
+ # relative to the source directory and without source_suffix.
dirlen = len(self.srcdir) + 1
- to_write = [path.abspath(filename)[dirlen:] for filename in source_filenames]
- self.load_env()
+ to_write = []
+ suffix = self.config.source_suffix
+ for filename in filenames:
+ filename = path.abspath(filename)[dirlen:]
+ if filename.endswith(suffix):
+ filename = filename[:-len(suffix)]
+ to_write.append(filename)
self.build(to_write,
summary='%d source files given on command line' % len(to_write))
def build_update(self):
"""Only rebuild files changed or added since last build."""
- self.load_env()
- to_build = self.get_outdated_files()
+ to_build = self.get_outdated_docs()
if not to_build:
self.info(bold('no target files are out of date, exiting.'))
return
@@ -166,12 +174,12 @@
summary='targets for %d source files that are '
'out of date' % len(to_build))
- def build(self, filenames, summary=None):
+ def build(self, docnames, summary=None):
if summary:
self.info(bold('building [%s]: ' % self.name), nonl=1)
self.info(summary)
- updated_filenames = []
+ updated_docnames = []
# while reading, collect all warnings from docutils
warnings = []
self.env.set_warnfunc(warnings.append)
@@ -179,14 +187,15 @@
iterator = self.env.update(self.config, self.app)
# the first item in the iterator is a summary message
self.info(iterator.next())
- for filename in self.status_iterator(iterator, 'reading... ', purple):
- updated_filenames.append(filename)
+ for docname in self.status_iterator(iterator, 'reading... ', purple):
+ updated_docnames.append(docname)
# nothing further to do, the environment has already done the reading
for warning in warnings:
- self.warn(warning)
+ if warning.strip():
+ self.warn(warning)
self.env.set_warnfunc(self.warn)
- if updated_filenames:
+ if updated_docnames:
# save the environment
self.info(bold('pickling the env... '), nonl=True)
self.env.topickle(path.join(self.doctreedir, ENV_PICKLE_FILENAME))
@@ -198,43 +207,44 @@
# another indirection to support methods which don't build files
# individually
- self.write(filenames, updated_filenames)
+ self.write(docnames, updated_docnames)
# finish (write style files etc.)
self.info(bold('finishing... '))
self.finish()
self.info(bold('build succeeded.'))
- def write(self, build_filenames, updated_filenames):
- if build_filenames is None: # build_all
- build_filenames = self.env.all_files
- filenames = set(build_filenames) | set(updated_filenames)
+ def write(self, build_docnames, updated_docnames):
+ if build_docnames is None: # build_all
+ build_docnames = self.env.all_docs
+ docnames = set(build_docnames) | set(updated_docnames)
# add all toctree-containing files that may have changed
- for filename in list(filenames):
- for tocfilename in self.env.files_to_rebuild.get(filename, []):
- filenames.add(tocfilename)
- filenames.add('contents.rst')
+ for docname in list(docnames):
+ for tocdocname in self.env.files_to_rebuild.get(docname, []):
+ docnames.add(tocdocname)
+ docnames.add(self.config.master_doc)
self.info(bold('creating index...'))
self.env.create_index(self)
- self.prepare_writing(filenames)
+ self.prepare_writing(docnames)
# write target files
warnings = []
self.env.set_warnfunc(warnings.append)
- for filename in self.status_iterator(sorted(filenames),
- 'writing output... ', green):
- doctree = self.env.get_and_resolve_doctree(filename, self)
- self.write_file(filename, doctree)
+ for docname in self.status_iterator(sorted(docnames),
+ 'writing output... ', darkgreen):
+ doctree = self.env.get_and_resolve_doctree(docname, self)
+ self.write_doc(docname, doctree)
for warning in warnings:
- self.warn(warning)
+ if warning.strip():
+ self.warn(warning)
self.env.set_warnfunc(self.warn)
- def prepare_writing(self, filenames):
+ def prepare_writing(self, docnames):
raise NotImplementedError
- def write_file(self, filename, doctree):
+ def write_doc(self, docname, doctree):
raise NotImplementedError
def finish(self):
@@ -252,6 +262,9 @@
def init(self):
"""Load templates."""
self.init_templates()
+ self.init_translator_class()
+
+ def init_translator_class(self):
if self.config.html_translator_class:
self.translator_class = self.app.import_object(
self.config.html_translator_class, 'html_translator_class setting')
@@ -272,10 +285,10 @@
settings_overrides={'output_encoding': 'unicode'}
)
- def prepare_writing(self, filenames):
+ def prepare_writing(self, docnames):
from sphinx.search import IndexBuilder
self.indexer = IndexBuilder()
- self.load_indexer(filenames)
+ self.load_indexer(docnames)
self.docwriter = HTMLWriter(self)
self.docsettings = OptionParser(
defaults=self.env.settings,
@@ -301,8 +314,7 @@
len = len, # the built-in
)
- def write_file(self, filename, doctree):
- pagename = filename[:-4]
+ def write_doc(self, docname, doctree):
destination = StringOutput(encoding='utf-8')
doctree.settings = self.docsettings
@@ -311,43 +323,43 @@
prev = next = None
parents = []
- related = self.env.toctree_relations.get(filename)
+ related = self.env.toctree_relations.get(docname)
if related:
- prev = {'link': self.get_relative_uri(filename, related[1]),
+ prev = {'link': self.get_relative_uri(docname, related[1]),
'title': self.render_partial(self.env.titles[related[1]])['title']}
- next = {'link': self.get_relative_uri(filename, related[2]),
+ next = {'link': self.get_relative_uri(docname, related[2]),
'title': self.render_partial(self.env.titles[related[2]])['title']}
while related:
parents.append(
- {'link': self.get_relative_uri(filename, related[0]),
+ {'link': self.get_relative_uri(docname, related[0]),
'title': self.render_partial(self.env.titles[related[0]])['title']})
related = self.env.toctree_relations.get(related[0])
if parents:
- parents.pop() # remove link to "contents.rst"; we have a generic
+ parents.pop() # remove link to the master file; we have a generic
# "back to index" link already
parents.reverse()
- title = self.env.titles.get(filename)
+ title = self.env.titles.get(docname)
if title:
title = self.render_partial(title)['title']
else:
title = ''
- self.globalcontext['titles'][filename] = title
- sourcename = pagename + '.txt'
- context = dict(
+ self.globalcontext['titles'][docname] = title
+ sourcename = self.config.html_copy_source and docname + '.txt' or ''
+ ctx = dict(
title = title,
sourcename = sourcename,
body = self.docwriter.parts['fragment'],
- toc = self.render_partial(self.env.get_toc_for(filename))['fragment'],
+ toc = self.render_partial(self.env.get_toc_for(docname))['fragment'],
# only display a TOC if there's more than one item to show
- display_toc = (self.env.toc_num_entries[filename] > 1),
+ display_toc = (self.env.toc_num_entries[docname] > 1),
parents = parents,
prev = prev,
next = next,
)
- self.index_page(pagename, doctree, title)
- self.handle_page(pagename, context)
+ self.index_page(docname, doctree, title)
+ self.handle_page(docname, ctx)
def finish(self):
self.info(bold('writing additional files...'))
@@ -369,7 +381,7 @@
# the global module index
# the sorted list of all modules, for the global module index
- modules = sorted(((mn, (self.get_relative_uri('modindex.rst', fn) +
+ modules = sorted(((mn, (self.get_relative_uri('modindex', fn) +
'#module-' + mn, sy, pl, dep))
for (mn, (fn, sy, pl, dep)) in self.env.modules.iteritems()),
key=lambda x: x[0].lower())
@@ -442,24 +454,25 @@
# --------- these are overwritten by the Web builder
- def get_target_uri(self, source_filename, typ=None):
- return source_filename[:-4] + '.html'
+ def get_target_uri(self, docname, typ=None):
+ return docname + '.html'
- def get_outdated_files(self):
- for filename in get_matching_files(
- self.srcdir, '*.rst', exclude=set(self.config.unused_files)):
+ def get_outdated_docs(self):
+ for docname in get_matching_docs(
+ self.srcdir, self.config.source_suffix,
+ exclude=set(self.config.unused_files)):
+ targetname = self.env.doc2path(docname, self.outdir, '.html')
try:
- rstname = path.join(self.outdir, os_path(filename))
- targetmtime = path.getmtime(rstname[:-4] + '.html')
+ targetmtime = path.getmtime(targetname)
except:
targetmtime = 0
- if filename not in self.env.all_files:
- yield filename
- elif path.getmtime(path.join(self.srcdir, os_path(filename))) > targetmtime:
- yield filename
+ if docname not in self.env.all_docs:
+ yield docname
+ elif path.getmtime(self.env.doc2path(docname)) > targetmtime:
+ yield docname
- def load_indexer(self, filenames):
+ def load_indexer(self, docnames):
try:
f = open(path.join(self.outdir, 'searchindex.json'), 'r')
try:
@@ -469,7 +482,7 @@
except (IOError, OSError):
pass
# delete all entries for files that will be rebuilt
- self.indexer.prune([fn[:-4] for fn in set(self.env.all_files) - set(filenames)])
+ self.indexer.prune(set(self.env.all_docs) - set(docnames))
def index_page(self, pagename, doctree, title):
# only index pages with title
@@ -481,12 +494,12 @@
ctx['current_page_name'] = pagename
def pathto(otheruri, resource=False,
- baseuri=self.get_target_uri(pagename+'.rst')):
+ baseuri=self.get_target_uri(pagename)):
if not resource:
- otheruri = self.get_target_uri(otheruri+'.rst')
+ otheruri = self.get_target_uri(otheruri)
return relative_uri(baseuri, otheruri)
ctx['pathto'] = pathto
- ctx['hasdoc'] = lambda name: name+'.rst' in self.env.all_files
+ ctx['hasdoc'] = lambda name: name in self.env.all_docs
sidebarfile = self.config.html_sidebars.get(pagename)
if sidebarfile:
ctx['customsidebar'] = path.join(self.srcdir, sidebarfile)
@@ -505,12 +518,13 @@
self.warn("Error writing file %s: %s" % (outfilename, err))
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(ctx['sourcename'])))
+ source_name = path.join(self.outdir, '_sources', os_path(ctx['sourcename']))
+ ensuredir(path.dirname(source_name))
+ shutil.copyfile(self.env.doc2path(pagename), source_name)
def handle_finish(self):
self.info(bold('dumping search index...'))
- self.indexer.prune([fn[:-4] for fn in self.env.all_files])
+ self.indexer.prune(self.env.all_docs)
f = open(path.join(self.outdir, 'searchindex.json'), 'w')
try:
self.indexer.dump(f, 'json')
@@ -525,29 +539,28 @@
name = 'web'
def init(self):
- # Nothing to do here.
- pass
+ self.init_translator_class()
- def get_outdated_files(self):
- for filename in get_matching_files(
- self.srcdir, '*.rst', exclude=set(self.config.unused_files)):
+ def get_outdated_docs(self):
+ for docname in get_matching_docs(
+ self.srcdir, self.config.source_suffix,
+ exclude=set(self.config.unused_files)):
+ targetname = self.env.doc2path(docname, self.outdir, '.fpickle')
try:
- targetmtime = path.getmtime(
- path.join(self.outdir, os_path(filename)[:-4] + '.fpickle'))
+ targetmtime = path.getmtime(targetname)
except:
targetmtime = 0
- if path.getmtime(path.join(self.srcdir,
- os_path(filename))) > targetmtime:
- yield filename
+ if path.getmtime(self.env.doc2path(docname)) > targetmtime:
+ yield docname
- def get_target_uri(self, source_filename, typ=None):
- if source_filename == 'index.rst':
+ def get_target_uri(self, docname, typ=None):
+ if docname == 'index':
return ''
- if source_filename.endswith(SEP+'index.rst'):
- return source_filename[:-9] # up to sep
- return source_filename[:-4] + SEP
+ if docname.endswith(SEP + 'index'):
+ return docname[:-5] # up to sep
+ return docname + SEP
- def load_indexer(self, filenames):
+ def load_indexer(self, docnames):
try:
f = open(path.join(self.outdir, 'searchindex.pickle'), 'r')
try:
@@ -557,32 +570,32 @@
except (IOError, OSError):
pass
# delete all entries for files that will be rebuilt
- self.indexer.prune(set(self.env.all_files) - set(filenames))
+ self.indexer.prune(set(self.env.all_docs) - set(docnames))
def index_page(self, pagename, doctree, title):
# only index pages with title
if self.indexer is not None and title:
- self.indexer.feed(pagename+'.rst', title, doctree)
+ self.indexer.feed(pagename, title, doctree)
- def handle_page(self, pagename, context, templatename='page.html'):
- context['current_page_name'] = pagename
+ def handle_page(self, pagename, ctx, templatename='page.html'):
+ ctx['current_page_name'] = pagename
sidebarfile = self.config.html_sidebars.get(pagename, '')
if sidebarfile:
- context['customsidebar'] = path.join(self.srcdir, sidebarfile)
+ ctx['customsidebar'] = path.join(self.srcdir, sidebarfile)
outfilename = path.join(self.outdir, os_path(pagename) + '.fpickle')
ensuredir(path.dirname(outfilename))
f = open(outfilename, 'wb')
try:
- pickle.dump(context, f, 2)
+ pickle.dump(ctx, f, 2)
finally:
f.close()
# if there is a source file, copy the source file for the "show source" link
- if context.get('sourcename'):
+ if ctx.get('sourcename'):
source_name = path.join(self.outdir, 'sources',
- os_path(context['sourcename']))
+ os_path(ctx['sourcename']))
ensuredir(path.dirname(source_name))
- shutil.copyfile(path.join(self.srcdir, os_path(pagename)+'.rst'), source_name)
+ shutil.copyfile(self.env.doc2path(pagename), source_name)
def handle_finish(self):
# dump the global context
@@ -594,7 +607,7 @@
f.close()
self.info(bold('dumping search index...'))
- self.indexer.prune(self.env.all_files)
+ self.indexer.prune(self.env.all_docs)
f = open(path.join(self.outdir, 'searchindex.pickle'), 'wb')
try:
self.indexer.dump(f, 'pickle')
@@ -636,31 +649,41 @@
name = 'latex'
def init(self):
- self.filenames = []
- self.document_data = map(list, self.config.latex_documents)
+ self.docnames = []
+ self.document_data = []
- # assign subdirs to titles
- self.titles = []
- for entry in self.document_data:
- # replace version with real version
- sourcename = entry[0]
- if sourcename.endswith('/index.rst'):
- sourcename = sourcename[:-9]
- self.titles.append((sourcename, entry[2]))
-
- def get_outdated_files(self):
+ def get_outdated_docs(self):
return 'all documents' # for now
- def get_target_uri(self, source_filename, typ=None):
+ def get_target_uri(self, docname, typ=None):
if typ == 'token':
# token references are always inside production lists and must be
# replaced by \token{} in LaTeX
return '@token'
- if source_filename not in self.filenames:
+ if docname not in self.docnames:
raise NoUri
else:
return ''
+ def init_document_data(self):
+ preliminary_document_data = map(list, self.config.latex_documents)
+ if not preliminary_document_data:
+ self.warn('No "latex_documents" config value found; no documents '
+ 'will be written.')
+ return
+ # assign subdirs to titles
+ self.titles = []
+ for entry in preliminary_document_data:
+ docname = entry[0]
+ if docname not in self.env.all_docs:
+ self.warn('"latex_documents" config value references unknown '
+ 'document %s' % docname)
+ continue
+ self.document_data.append(entry)
+ if docname.endswith(SEP+'index'):
+ docname = docname[:-5]
+ self.titles.append((docname, entry[2]))
+
def write(self, *ignored):
# first, assemble the "appendix" docs that are in every PDF
appendices = []
@@ -672,43 +695,40 @@
defaults=self.env.settings,
components=(docwriter,)).get_default_values()
- if not self.document_data:
- self.warn('No "latex_documents" config setting found; no documents '
- 'will be written.')
+ self.init_document_data()
- for sourcename, targetname, title, author, docclass in self.document_data:
+ for docname, targetname, title, author, docclass in self.document_data:
destination = FileOutput(
destination_path=path.join(self.outdir, targetname),
encoding='utf-8')
self.info("processing " + targetname + "... ", nonl=1)
doctree = self.assemble_doctree(
- sourcename, appendices=(docclass == 'manual') and appendices or [])
+ docname, appendices=(docclass == 'manual') and appendices or [])
self.info("writing... ", nonl=1)
doctree.settings = docsettings
doctree.settings.author = author
- doctree.settings.filename = sourcename
+ doctree.settings.docname = docname
doctree.settings.docclass = docclass
docwriter.write(doctree, destination)
self.info("done")
def assemble_doctree(self, indexfile, appendices):
- self.filenames = set([indexfile, 'glossary.rst', 'about.rst',
- 'license.rst', 'copyright.rst'])
- self.info(green(indexfile) + " ", nonl=1)
- def process_tree(filename, tree):
+ self.docnames = set([indexfile] + appendices)
+ self.info(darkgreen(indexfile) + " ", nonl=1)
+ def process_tree(docname, tree):
tree = tree.deepcopy()
for toctreenode in tree.traverse(addnodes.toctree):
newnodes = []
includefiles = map(str, toctreenode['includefiles'])
for includefile in includefiles:
try:
- self.info(green(includefile) + " ", nonl=1)
+ self.info(darkgreen(includefile) + " ", nonl=1)
subtree = process_tree(includefile,
self.env.get_doctree(includefile))
- self.filenames.add(includefile)
+ self.docnames.add(includefile)
except:
self.warn('%s: toctree contains ref to nonexisting file %r' %
- (filename, includefile))
+ (docname, includefile))
else:
newnodes.extend(subtree.children)
toctreenode.parent.replace(toctreenode, newnodes)
@@ -721,11 +741,11 @@
# resolve :ref:s to distant tex files -- we can't add a cross-reference,
# but append the document name
for pendingnode in largetree.traverse(addnodes.pending_xref):
- filename = pendingnode['reffilename']
+ docname = pendingnode['refdocname']
sectname = pendingnode['refsectname']
newnodes = [nodes.emphasis(sectname, sectname)]
for subdir, title in self.titles:
- if filename.startswith(subdir):
+ if docname.startswith(subdir):
newnodes.append(nodes.Text(' (in ', ' (in '))
newnodes.append(nodes.emphasis(title, title))
newnodes.append(nodes.Text(')', ')'))
@@ -756,7 +776,7 @@
self.vtemplate = self.get_template('changes/versionchanges.html')
self.stemplate = self.get_template('changes/rstsource.html')
- def get_outdated_files(self):
+ def get_outdated_docs(self):
return self.outdir
typemap = {
@@ -771,18 +791,18 @@
apichanges = []
otherchanges = {}
self.info(bold('writing summary file...'))
- for type, filename, lineno, module, descname, content in \
+ for type, docname, lineno, module, descname, content in \
self.env.versionchanges[version]:
ttext = self.typemap[type]
context = content.replace('\n', ' ')
- if descname and filename.startswith('c-api'):
+ if descname and docname.startswith('c-api'):
if not descname:
continue
if context:
entry = '<b>%s</b>: <i>%s:</i> %s' % (descname, ttext, context)
else:
entry = '<b>%s</b>: <i>%s</i>.' % (descname, ttext)
- apichanges.append((entry, filename, lineno))
+ apichanges.append((entry, docname, lineno))
elif descname or module:
if not module:
module = 'Builtins'
@@ -792,14 +812,14 @@
entry = '<b>%s</b>: <i>%s:</i> %s' % (descname, ttext, context)
else:
entry = '<b>%s</b>: <i>%s</i>.' % (descname, ttext)
- libchanges.setdefault(module, []).append((entry, filename, lineno))
+ libchanges.setdefault(module, []).append((entry, docname, lineno))
else:
if not context:
continue
entry = '<i>%s:</i> %s' % (ttext.capitalize(), context)
- title = self.env.titles[filename].astext()
- otherchanges.setdefault((filename, title), []).append(
- (entry, filename, lineno))
+ title = self.env.titles[docname].astext()
+ otherchanges.setdefault((docname, title), []).append(
+ (entry, docname, lineno))
ctx = {
'project': self.config.project,
@@ -832,15 +852,15 @@
return line
self.info(bold('copying source files...'))
- for filename in self.env.all_files:
- f = open(path.join(self.srcdir, os_path(filename)))
+ for docname in self.env.all_docs:
+ f = open(self.env.doc2path(docname))
lines = f.readlines()
- targetfn = path.join(self.outdir, 'rst', os_path(filename)) + '.html'
+ targetfn = path.join(self.outdir, 'rst', os_path(docname)) + '.html'
ensuredir(path.dirname(targetfn))
f = codecs.open(targetfn, 'w', 'utf8')
try:
text = ''.join(hl(i+1, line) for (i, line) in enumerate(lines))
- ctx = {'filename': filename, 'text': text}
+ ctx = {'filename': self.env.doc2path(docname, None), 'text': text}
f.write(self.stemplate.render(ctx))
finally:
f.close()
@@ -873,25 +893,25 @@
# create output file
open(path.join(self.outdir, 'output.txt'), 'w').close()
- def get_target_uri(self, source_filename, typ=None):
+ def get_target_uri(self, docname, typ=None):
return ''
- def get_outdated_files(self):
- return self.env.all_files
+ def get_outdated_docs(self):
+ return self.env.all_docs
- def prepare_writing(self, filenames):
+ def prepare_writing(self, docnames):
return
- def write_file(self, filename, doctree):
+ def write_doc(self, docname, doctree):
self.info()
for node in doctree.traverse(nodes.reference):
try:
- self.check(node, filename)
+ self.check(node, docname)
except KeyError:
continue
return
- def check(self, node, filename):
+ def check(self, node, docname):
uri = node['refuri']
if '#' in uri:
@@ -920,23 +940,24 @@
elif r == 2:
self.info(' - ' + red('broken: ') + s)
self.broken[uri] = (r, s)
- self.write_entry('broken', filename, lineno, uri + ': ' + s)
+ self.write_entry('broken', docname, lineno, uri + ': ' + s)
else:
self.info(' - ' + purple('redirected') + ' to ' + s)
self.redirected[uri] = (r, s)
- self.write_entry('redirected', filename, lineno, uri + ' to ' + s)
+ self.write_entry('redirected', docname, lineno, uri + ' to ' + s)
elif len(uri) == 0 or uri[0:7] == 'mailto:' or uri[0:4] == 'ftp:':
return
else:
self.info(uri + ' - ' + red('malformed!'))
- self.write_entry('malformed', filename, lineno, uri)
+ self.write_entry('malformed', docname, lineno, uri)
return
- def write_entry(self, what, filename, line, uri):
+ def write_entry(self, what, docname, line, uri):
output = open(path.join(self.outdir, 'output.txt'), 'a')
- output.write("%s:%s [%s] %s\n" % (filename, line, what, uri))
+ output.write("%s:%s [%s] %s\n" % (self.env.doc2path(docname, None),
+ line, what, uri))
output.close()
def resolve(self, uri):
Modified: doctools/trunk/sphinx/config.py
==============================================================================
--- doctools/trunk/sphinx/config.py (original)
+++ doctools/trunk/sphinx/config.py Fri Feb 1 21:44:17 2008
@@ -33,6 +33,8 @@
extensions = ([], True),
# general reading options
+ master_doc = ('contents', True),
+ source_suffix = ('.rst', True),
unused_files = ([], True),
add_function_parentheses = (True, True),
add_module_names = (True, True),
@@ -44,6 +46,7 @@
html_index = ('', False),
html_sidebars = ({}, False),
html_additional_pages = ({}, False),
+ html_copy_source = (True, False),
# HTML help options
htmlhelp_basename = ('pydoc', False),
Modified: doctools/trunk/sphinx/directives.py
==============================================================================
--- doctools/trunk/sphinx/directives.py (original)
+++ doctools/trunk/sphinx/directives.py Fri Feb 1 21:44:17 2008
@@ -539,15 +539,28 @@
def toctree_directive(name, arguments, options, content, lineno,
content_offset, block_text, state, state_machine):
env = state.document.settings.env
- dirname = posixpath.dirname(env.filename)
+ suffix = env.config.source_suffix
+ dirname = posixpath.dirname(env.docname)
+ ret = []
subnode = addnodes.toctree()
- includefiles = filter(None, content)
- # absolutize filenames
- includefiles = [posixpath.normpath(posixpath.join(dirname, x)) for x in includefiles]
+ includefiles = []
+ for docname in content:
+ if not docname:
+ continue
+ # absolutize filenames, remove suffixes
+ if docname.endswith(suffix):
+ docname = docname[:-len(suffix)]
+ docname = posixpath.normpath(posixpath.join(dirname, docname))
+ if docname not in env.found_docs:
+ ret.append(state.document.reporter.warning(
+ 'toctree references unknown document %s' % docname, line=lineno))
+ else:
+ includefiles.append(docname)
subnode['includefiles'] = includefiles
subnode['maxdepth'] = options.get('maxdepth', -1)
- return [subnode]
+ ret.append(subnode)
+ return ret
toctree_directive.content = 1
toctree_directive.options = {'maxdepth': int}
Modified: doctools/trunk/sphinx/environment.py
==============================================================================
--- doctools/trunk/sphinx/environment.py (original)
+++ doctools/trunk/sphinx/environment.py Fri Feb 1 21:44:17 2008
@@ -43,7 +43,7 @@
Body.enum.converters['upperroman'] = lambda x: None
from sphinx import addnodes
-from sphinx.util import get_matching_files, os_path, SEP
+from sphinx.util import get_matching_docs, SEP
default_settings = {
'embed_stylesheet': False,
@@ -56,7 +56,7 @@
# This is increased every time a new environment attribute is added
# to properly invalidate pickle files.
-ENV_VERSION = 15
+ENV_VERSION = 16
def walk_depth(node, depth, maxdepth):
@@ -79,8 +79,11 @@
class RedirStream(object):
- def __init__(self, write):
- self.write = write
+ def __init__(self, writefunc):
+ self.writefunc = writefunc
+ def write(self, text):
+ if text.strip():
+ self.writefunc(text)
class NoUri(Exception):
@@ -183,10 +186,10 @@
# --------- ENVIRONMENT INITIALIZATION -------------------------------------
- def __init__(self, srcdir, doctreedir):
+ def __init__(self, srcdir, doctreedir, config):
self.doctreedir = doctreedir
self.srcdir = srcdir
- self.config = None
+ self.config = config
# the docutils settings for building
self.settings = default_settings.copy()
@@ -198,41 +201,42 @@
# this is to invalidate old pickles
self.version = ENV_VERSION
- # 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
+ # All "docnames" here are /-separated and relative and exclude the source suffix.
+
+ self.found_docs = set() # contains all existing docnames
+ self.all_docs = {} # docname -> (mtime, md5sum) at the time of build
+ # contains all built docnames
# File metadata
- self.metadata = {} # filename -> dict of metadata items
+ self.metadata = {} # docname -> dict of metadata items
# TOC inventory
- self.titles = {} # filename -> title node
- self.tocs = {} # filename -> table of contents nodetree
- self.toc_num_entries = {} # filename -> number of real entries
+ self.titles = {} # docname -> title node
+ self.tocs = {} # docname -> table of contents nodetree
+ self.toc_num_entries = {} # docname -> number of real entries
# used to determine when to show the TOC in a sidebar
# (don't show if it's only one item)
- self.toctree_relations = {} # filename -> ["parent", "previous", "next"] filename
+ self.toctree_relations = {} # docname -> ["parent", "previous", "next"] docname
# for navigating in the toctree
- self.files_to_rebuild = {} # filename -> set of files (containing its TOCs)
+ self.files_to_rebuild = {} # docname -> set of files (containing its TOCs)
# to rebuild too
# X-ref target inventory
- self.descrefs = {} # fullname -> filename, desctype
- self.filemodules = {} # filename -> [modules]
- self.modules = {} # modname -> filename, synopsis, platform, deprecated
- self.labels = {} # labelname -> filename, labelid, sectionname
- self.reftargets = {} # (type, name) -> filename, labelid
+ self.descrefs = {} # fullname -> docname, desctype
+ self.filemodules = {} # docname -> [modules]
+ self.modules = {} # modname -> docname, synopsis, platform, deprecated
+ self.labels = {} # labelname -> docname, labelid, sectionname
+ self.reftargets = {} # (type, name) -> docname, labelid
# where type is term, token, option, envvar
# Other inventories
- self.indexentries = {} # filename -> list of
+ self.indexentries = {} # docname -> list of
# (type, string, target, aliasname)
self.versionchanges = {} # version -> list of
- # (type, filename, lineno, module, descname, content)
+ # (type, docname, lineno, module, descname, content)
# These are set while parsing a file
- self.filename = None # current file name
+ self.docname = None # current document name
self.currmodule = None # current module name
self.currclass = None # current class name
self.currdesc = None # current descref name
@@ -241,78 +245,95 @@
def set_warnfunc(self, func):
self._warnfunc = func
- self.settings['warnfunc'] = func
+ self.settings['warning_stream'] = RedirStream(func)
+
+ def warn(self, docname, msg):
+ if docname:
+ self._warnfunc(self.doc2path(docname) + ':: ' + msg)
+ else:
+ self._warnfunc('GLOBAL:: ' + msg)
- def clear_file(self, filename):
+ def clear_doc(self, docname):
"""Remove all traces of a source file in the inventory."""
- if filename in self.all_files:
- self.all_files.pop(filename, None)
- self.metadata.pop(filename, None)
- self.titles.pop(filename, None)
- self.tocs.pop(filename, None)
- self.toc_num_entries.pop(filename, None)
+ if docname in self.all_docs:
+ self.all_docs.pop(docname, None)
+ self.metadata.pop(docname, None)
+ self.titles.pop(docname, None)
+ self.tocs.pop(docname, None)
+ self.toc_num_entries.pop(docname, None)
for subfn, fnset in self.files_to_rebuild.iteritems():
- fnset.discard(filename)
+ fnset.discard(docname)
for fullname, (fn, _) in self.descrefs.items():
- if fn == filename:
+ if fn == docname:
del self.descrefs[fullname]
- self.filemodules.pop(filename, None)
+ self.filemodules.pop(docname, None)
for modname, (fn, _, _, _) in self.modules.items():
- if fn == filename:
+ if fn == docname:
del self.modules[modname]
for labelname, (fn, _, _) in self.labels.items():
- if fn == filename:
+ if fn == docname:
del self.labels[labelname]
for key, (fn, _) in self.reftargets.items():
- if fn == filename:
+ if fn == docname:
del self.reftargets[key]
- self.indexentries.pop(filename, None)
+ self.indexentries.pop(docname, None)
for version, changes in self.versionchanges.items():
- new = [change for change in changes if change[1] != filename]
+ new = [change for change in changes if change[1] != docname]
changes[:] = new
+ def doc2path(self, docname, base=True, suffix=None):
+ """
+ Return the filename for the document name.
+ If base is True, return absolute path under self.srcdir.
+ If base is None, return relative path to self.srcdir.
+ If base is a path string, return absolute path under that.
+ If suffix is not None, add it instead of config.source_suffix.
+ """
+ suffix = suffix or self.config.source_suffix
+ if base is True:
+ return path.join(self.srcdir, docname.replace(SEP, path.sep)) + suffix
+ elif base is None:
+ return docname.replace(SEP, path.sep) + suffix
+ else:
+ return path.join(base, docname.replace(SEP, path.sep)) + suffix
+
def get_outdated_files(self, config, config_changed):
"""
- Return (added, changed, removed) iterables.
+ Return (added, changed, removed) sets.
"""
- all_source_files = list(get_matching_files(
- self.srcdir, '*.rst', exclude=set(config.unused_files)))
+ self.found_docs = set(get_matching_docs(self.srcdir, config.source_suffix,
+ exclude=set(config.unused_files)))
# clear all files no longer present
- removed = set(self.all_files) - set(all_source_files)
+ removed = set(self.all_docs) - self.found_docs
- added = []
- changed = []
+ added = set()
+ changed = set()
if config_changed:
# config values affect e.g. substitutions
- added = all_source_files
+ added = self.found_docs
else:
- for filename in all_source_files:
- if filename not in self.all_files:
- added.append(filename)
+ for docname in self.found_docs:
+ if docname not in self.all_docs:
+ added.add(docname)
else:
# if the doctree file is not there, rebuild
- if not path.isfile(path.join(self.doctreedir,
- os_path(filename)[:-3] + 'doctree')):
- changed.append(filename)
+ if not path.isfile(self.doc2path(docname, self.doctreedir, '.doctree')):
+ changed.add(docname)
continue
- mtime, md5sum = self.all_files[filename]
- newmtime = path.getmtime(path.join(self.srcdir, os_path(filename)))
+ mtime, md5sum = self.all_docs[docname]
+ newmtime = path.getmtime(self.doc2path(docname))
if newmtime == mtime:
continue
- # check the MD5
- #with file(path.join(self.srcdir, filename), 'rb') as f:
- # newmd5sum = md5(f.read()).digest()
- #if newmd5sum != md5sum:
- changed.append(filename)
+ changed.add(docname)
return added, changed, removed
def update(self, config, app=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
+ and then docnames as it processes them. Store all environment docnames
in the canonical format (ie using SEP as a separator in place of
os.path.sep)."""
config_changed = False
@@ -338,36 +359,36 @@
self.config = config
# clear all files no longer present
- for filename in removed:
- self.clear_file(filename)
+ for docname in removed:
+ self.clear_doc(docname)
# read all new and changed files
- for filename in added + changed:
- yield filename
- self.read_file(filename, app=app)
+ for docname in sorted(added | changed):
+ yield docname
+ self.read_doc(docname, app=app)
- if 'contents.rst' not in self.all_files:
- self._warnfunc('no master file contents.rst found')
+ if config.master_doc not in self.all_docs:
+ self.warn(None, 'no master file %s found' % self.doc2path(config.master_doc))
# --------- SINGLE FILE BUILDING -------------------------------------------
- def read_file(self, filename, src_path=None, save_parsed=True, app=None):
+ def read_doc(self, docname, src_path=None, save_parsed=True, app=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
- self.clear_file(filename)
+ self.clear_doc(docname)
if src_path is None:
- src_path = path.join(self.srcdir, os_path(filename))
+ src_path = self.doc2path(docname)
- self.filename = filename
+ self.docname = docname
doctree = publish_doctree(None, src_path, FileInput,
settings_overrides=self.settings,
reader=MyStandaloneReader())
- self.process_metadata(filename, doctree)
- self.create_title_from(filename, doctree)
- self.note_labels_from(filename, doctree)
- self.build_toc_from(filename, doctree)
+ self.process_metadata(docname, doctree)
+ self.create_title_from(docname, doctree)
+ self.note_labels_from(docname, doctree)
+ self.build_toc_from(docname, doctree)
# calculate the MD5 of the file at time of build
f = open(src_path, 'rb')
@@ -375,7 +396,7 @@
md5sum = md5(f.read()).digest()
finally:
f.close()
- self.all_files[filename] = (path.getmtime(src_path), md5sum)
+ self.all_docs[docname] = (path.getmtime(src_path), md5sum)
if app:
app.emit('doctree-read', doctree)
@@ -383,11 +404,11 @@
# make it picklable
doctree.reporter = None
doctree.transformer = None
+ doctree.settings.warning_stream = None
doctree.settings.env = None
- doctree.settings.warnfunc = None
# cleanup
- self.filename = None
+ self.docname = None
self.currmodule = None
self.currclass = None
self.indexnum = 0
@@ -395,8 +416,7 @@
if save_parsed:
# save the parsed doctree
- doctree_filename = path.join(self.doctreedir,
- os_path(filename)[:-3] + 'doctree')
+ doctree_filename = self.doc2path(docname, self.doctreedir, '.doctree')
dirname = path.dirname(doctree_filename)
if not path.isdir(dirname):
os.makedirs(dirname)
@@ -408,11 +428,11 @@
else:
return doctree
- def process_metadata(self, filename, doctree):
+ def process_metadata(self, docname, doctree):
"""
Process the docinfo part of the doctree as metadata.
"""
- self.metadata[filename] = md = {}
+ self.metadata[docname] = md = {}
docinfo = doctree[0]
if docinfo.__class__ is not nodes.docinfo:
# nothing to see here
@@ -426,7 +446,7 @@
md[name.astext()] = body.astext()
del doctree[0]
- def create_title_from(self, filename, document):
+ def create_title_from(self, docname, document):
"""
Add a title node to the document (just copy the first section title),
and store that title in the environment.
@@ -436,10 +456,10 @@
visitor = MyContentsFilter(document)
node[0].walkabout(visitor)
titlenode += visitor.get_entry_text()
- self.titles[filename] = titlenode
+ self.titles[docname] = titlenode
return
- def note_labels_from(self, filename, document):
+ def note_labels_from(self, docname, document):
for name, explicit in document.nametypes.iteritems():
if not explicit:
continue
@@ -450,27 +470,27 @@
continue
sectname = node[0].astext() # node[0] == title node
if name in self.labels:
- self._warnfunc('duplicate label %s, ' % name +
- 'in %s and %s' % (self.labels[name][0], filename))
- self.labels[name] = filename, labelid, sectname
+ self.warn(docname, 'duplicate label %s, ' % name +
+ 'other instance in %s' % self.doc2path(self.labels[name][0]))
+ self.labels[name] = docname, labelid, sectname
- def note_toctree(self, filename, toctreenode):
+ def note_toctree(self, docname, toctreenode):
"""Note a TOC tree directive in a document and gather information about
file relations from it."""
includefiles = toctreenode['includefiles']
includefiles_len = len(includefiles)
for i, includefile in enumerate(includefiles):
# the "previous" file for the first toctree item is the parent
- previous = i > 0 and includefiles[i-1] or filename
+ previous = i > 0 and includefiles[i-1] or docname
# the "next" file for the last toctree item is the parent again
- next = i < includefiles_len-1 and includefiles[i+1] or filename
- self.toctree_relations[includefile] = [filename, previous, next]
+ next = i < includefiles_len-1 and includefiles[i+1] or docname
+ self.toctree_relations[includefile] = [docname, previous, next]
# note that if the included file is rebuilt, this one must be
# too (since the TOC of the included file could have changed)
- self.files_to_rebuild.setdefault(includefile, set()).add(filename)
+ self.files_to_rebuild.setdefault(includefile, set()).add(docname)
- def build_toc_from(self, filename, document):
+ def build_toc_from(self, docname, document):
"""Build a TOC from the doctree and store it in the inventory."""
numentries = [0] # nonlocal again...
@@ -483,7 +503,7 @@
item = subnode.copy()
entries.append(item)
# do the inventory stuff
- self.note_toctree(filename, subnode)
+ self.note_toctree(docname, subnode)
continue
if not isinstance(subnode, nodes.section):
continue
@@ -500,7 +520,7 @@
else:
anchorname = '#' + subnode['ids'][0]
numentries[0] += 1
- reference = nodes.reference('', '', refuri=filename,
+ reference = nodes.reference('', '', refuri=docname,
anchorname=anchorname,
*nodetext)
para = addnodes.compact_paragraph('', '', reference)
@@ -512,64 +532,66 @@
return []
toc = build_toc(document)
if toc:
- self.tocs[filename] = toc
+ self.tocs[docname] = toc
else:
- self.tocs[filename] = nodes.bullet_list('')
- self.toc_num_entries[filename] = numentries[0]
+ self.tocs[docname] = nodes.bullet_list('')
+ self.toc_num_entries[docname] = numentries[0]
- def get_toc_for(self, filename):
+ def get_toc_for(self, docname):
"""Return a TOC nodetree -- for use on the same page only!"""
- toc = self.tocs[filename].deepcopy()
+ toc = self.tocs[docname].deepcopy()
for node in toc.traverse(nodes.reference):
node['refuri'] = node['anchorname']
return toc
# -------
- # these are called from docutils directives and therefore use self.filename
+ # these are called from docutils directives and therefore use self.docname
#
def note_descref(self, fullname, desctype):
if fullname in self.descrefs:
- self._warnfunc('duplicate canonical description name %s, ' % fullname +
- 'in %s and %s' % (self.descrefs[fullname][0], self.filename))
- self.descrefs[fullname] = (self.filename, desctype)
+ self.warn(self.docname,
+ 'duplicate canonical description name %s, ' % fullname +
+ 'other instance in %s' % self.doc2path(self.descrefs[fullname][0]))
+ self.descrefs[fullname] = (self.docname, desctype)
def note_module(self, modname, synopsis, platform, deprecated):
- self.modules[modname] = (self.filename, synopsis, platform, deprecated)
- self.filemodules.setdefault(self.filename, []).append(modname)
+ self.modules[modname] = (self.docname, synopsis, platform, deprecated)
+ self.filemodules.setdefault(self.docname, []).append(modname)
def note_reftarget(self, type, name, labelid):
- self.reftargets[type, name] = (self.filename, labelid)
+ self.reftargets[type, name] = (self.docname, labelid)
def note_index_entry(self, type, string, targetid, aliasname):
- self.indexentries.setdefault(self.filename, []).append(
+ self.indexentries.setdefault(self.docname, []).append(
(type, string, targetid, aliasname))
def note_versionchange(self, type, version, node, lineno):
self.versionchanges.setdefault(version, []).append(
- (type, self.filename, lineno, self.currmodule, self.currdesc, node.astext()))
+ (type, self.docname, lineno, self.currmodule, self.currdesc, node.astext()))
# -------
# --------- RESOLVING REFERENCES AND TOCTREES ------------------------------
- def get_doctree(self, filename):
+ def get_doctree(self, docname):
"""Read the doctree for a file from the pickle and return it."""
- doctree_filename = path.join(self.doctreedir, os_path(filename)[:-3] + 'doctree')
+ doctree_filename = self.doc2path(docname, self.doctreedir, '.doctree')
f = open(doctree_filename, 'rb')
try:
doctree = pickle.load(f)
finally:
f.close()
- doctree.reporter = Reporter(filename, 2, 4, stream=RedirStream(self._warnfunc))
+ doctree.reporter = Reporter(self.doc2path(docname), 2, 4,
+ stream=RedirStream(self._warnfunc))
return doctree
- def get_and_resolve_doctree(self, filename, builder, doctree=None):
+ def get_and_resolve_doctree(self, docname, builder, doctree=None):
"""Read the doctree from the pickle, resolve cross-references and
toctrees and return it."""
if doctree is None:
- doctree = self.get_doctree(filename)
+ doctree = self.get_doctree(docname)
# resolve all pending cross-references
- self.resolve_references(doctree, filename, builder)
+ self.resolve_references(doctree, docname, builder)
# now, resolve all toctree nodes
def _entries_from_toctree(toctreenode):
@@ -582,8 +604,8 @@
toc = self.tocs[includefile].deepcopy()
except KeyError:
# this is raised if the included file does not exist
- self._warnfunc('%s: toctree contains ref to nonexisting '
- 'file %r' % (filename, includefile))
+ self.warn(docname, 'toctree contains ref to nonexisting '
+ 'file %r' % includefile)
else:
for toctreenode in toc.traverse(addnodes.toctree):
toctreenode.parent.replace_self(
@@ -607,7 +629,7 @@
if node.hasattr('anchorname'):
# a TOC reference
node['refuri'] = builder.get_relative_uri(
- filename, node['refuri']) + node['anchorname']
+ docname, node['refuri']) + node['anchorname']
return doctree
@@ -615,7 +637,7 @@
descroles = frozenset(('data', 'exc', 'func', 'class', 'const', 'attr',
'meth', 'cfunc', 'cdata', 'ctype', 'cmacro'))
- def resolve_references(self, doctree, docfilename, builder):
+ def resolve_references(self, doctree, fromdocname, builder):
for node in doctree.traverse(addnodes.pending_xref):
contnode = node[0].deepcopy()
newnode = None
@@ -627,70 +649,69 @@
if typ == 'ref':
# reference to the named label; the final node will contain the
# section name after the label
- filename, labelid, sectname = self.labels.get(target, ('','',''))
- if not filename:
+ docname, labelid, sectname = self.labels.get(target, ('','',''))
+ if not docname:
newnode = doctree.reporter.system_message(
2, 'undefined label: %s' % target)
- self._warnfunc('%s: undefined label: %s' % (docfilename, target))
+ #self.warn(fromdocname, 'undefined label: %s' % target)
else:
newnode = nodes.reference('', '')
innernode = nodes.emphasis(sectname, sectname)
- if filename == docfilename:
+ if docname == fromdocname:
newnode['refid'] = labelid
else:
# set more info in contnode in case the following call
# raises NoUri, the builder will have to resolve these
contnode = addnodes.pending_xref('')
- contnode['reffilename'] = filename
+ contnode['refdocname'] = docname
contnode['refsectname'] = sectname
newnode['refuri'] = builder.get_relative_uri(
- docfilename, filename) + '#' + labelid
+ fromdocname, docname) + '#' + labelid
newnode.append(innernode)
elif typ == 'keyword':
# keywords are referenced by named labels
- filename, labelid, _ = self.labels.get(target, ('','',''))
- if not filename:
- self._warnfunc('%s: unknown keyword: %s' % (docfilename, target))
+ docname, labelid, _ = self.labels.get(target, ('','',''))
+ if not docname:
+ self.warn(fromdocname, 'unknown keyword: %s' % target)
newnode = contnode
else:
newnode = nodes.reference('', '')
- if filename == docfilename:
+ if docname == fromdocname:
newnode['refid'] = labelid
else:
newnode['refuri'] = builder.get_relative_uri(
- docfilename, filename) + '#' + labelid
+ fromdocname, docname) + '#' + labelid
newnode.append(contnode)
elif typ in ('token', 'term', 'envvar', 'option'):
- filename, labelid = self.reftargets.get((typ, target), ('', ''))
- if not filename:
+ docname, labelid = self.reftargets.get((typ, target), ('', ''))
+ if not docname:
if typ == 'term':
- self._warnfunc('%s: term not in glossary: %s' %
- (docfilename, target))
+ self.warn(fromdocname, 'term not in glossary: %s' % target)
newnode = contnode
else:
newnode = nodes.reference('', '')
- if filename == docfilename:
+ if docname == fromdocname:
newnode['refid'] = labelid
else:
newnode['refuri'] = builder.get_relative_uri(
- docfilename, filename, typ) + '#' + labelid
+ fromdocname, docname, typ) + '#' + labelid
newnode.append(contnode)
elif typ == 'mod':
- filename, synopsis, platform, deprecated = \
+ docname, synopsis, platform, deprecated = \
self.modules.get(target, ('','','', ''))
# just link to an anchor if there are multiple modules in one file
# because the anchor is generally below the heading which is ugly
# but can't be helped easily
anchor = ''
- if not filename or filename == docfilename:
+ if not docname or docname == fromdocname:
# don't link to self
newnode = contnode
else:
- if len(self.filemodules[filename]) > 1:
+ if len(self.filemodules[docname]) > 1:
anchor = '#' + 'module-' + target
newnode = nodes.reference('', '')
newnode['refuri'] = (
- builder.get_relative_uri(docfilename, filename) + anchor)
+ builder.get_relative_uri(fromdocname, docname) + anchor)
newnode['reftitle'] = '%s%s%s' % (
(platform and '(%s) ' % platform),
synopsis, (deprecated and ' (deprecated)' or ''))
@@ -706,11 +727,11 @@
newnode = contnode
else:
newnode = nodes.reference('', '')
- if desc[0] == docfilename:
+ if desc[0] == fromdocname:
newnode['refid'] = name
else:
newnode['refuri'] = (
- builder.get_relative_uri(docfilename, desc[0])
+ builder.get_relative_uri(fromdocname, desc[0])
+ '#' + name)
newnode.append(contnode)
else:
@@ -721,7 +742,7 @@
node.replace_self(newnode)
# allow custom references to be resolved
- builder.app.emit('doctree-resolved', doctree, docfilename)
+ builder.app.emit('doctree-resolved', doctree, fromdocname)
def create_index(self, builder, _fixre=re.compile(r'(.*) ([(][^()]*[)])')):
"""Create the real index from the collected index entries."""
@@ -735,7 +756,7 @@
add_entry(subword, '', dic=entry[1])
else:
try:
- entry[0].append(builder.get_relative_uri('genindex.rst', fn)
+ entry[0].append(builder.get_relative_uri('genindex', fn)
+ '#' + tid)
except NoUri:
pass
@@ -766,7 +787,7 @@
add_entry(string, 'built-in function')
add_entry('built-in function', string)
else:
- self._warnfunc("unknown index entry type %r in %s" % (type, fn))
+ self.warn(fn, "unknown index entry type %r" % type)
newlist = new.items()
newlist.sort(key=lambda t: t[0].lower())
@@ -815,12 +836,12 @@
def check_consistency(self):
"""Do consistency checks."""
- for filename in self.all_files:
- if filename not in self.toctree_relations:
- if filename == 'contents.rst':
+ for docname in self.all_docs:
+ if docname not in self.toctree_relations:
+ if docname == self.config.master_doc:
# the master file is not included anywhere ;)
continue
- self._warnfunc('%s isn\'t included in any toctree' % filename)
+ self.warn(docname, 'document isn\'t included in any toctree')
# --------- QUERYING -------------------------------------------------------
@@ -879,26 +900,26 @@
Keywords searched are: first modules, then descrefs.
Returns: None if nothing found
- (type, filename, anchorname) if exact match found
- list of (quality, type, filename, anchorname, description) if fuzzy
+ (type, docname, anchorname) if exact match found
+ list of (quality, type, docname, anchorname, description) if fuzzy
"""
if keyword in self.modules:
- filename, title, system, deprecated = self.modules[keyword]
- return 'module', filename, 'module-' + keyword
+ docname, title, system, deprecated = self.modules[keyword]
+ return 'module', docname, 'module-' + keyword
if keyword in self.descrefs:
- filename, ref_type = self.descrefs[keyword]
- return ref_type, filename, keyword
+ docname, ref_type = self.descrefs[keyword]
+ return ref_type, docname, keyword
# special cases
if '.' not in keyword:
# exceptions are documented in the exceptions module
if 'exceptions.'+keyword in self.descrefs:
- filename, ref_type = self.descrefs['exceptions.'+keyword]
- return ref_type, filename, 'exceptions.'+keyword
+ docname, ref_type = self.descrefs['exceptions.'+keyword]
+ return ref_type, docname, 'exceptions.'+keyword
# special methods are documented as object methods
if 'object.'+keyword in self.descrefs:
- filename, ref_type = self.descrefs['object.'+keyword]
- return ref_type, filename, 'object.'+keyword
+ docname, ref_type = self.descrefs['object.'+keyword]
+ return ref_type, docname, 'object.'+keyword
if avoid_fuzzy:
return
@@ -919,7 +940,7 @@
yield '.'.join(parts[idx:])
result = []
- for type, filename, title, desc in possibilities():
+ for type, docname, title, desc in possibilities():
best_res = 0
for part in dotsearch(title):
s.set_seq1(part)
@@ -929,16 +950,6 @@
s.ratio() > best_res:
best_res = s.ratio()
if best_res:
- result.append((best_res, type, filename, title, desc))
+ result.append((best_res, type, docname, title, desc))
return heapq.nlargest(n, result)
-
- def get_real_filename(self, filename):
- """
- Pass this function a filename without .rst extension to get the real
- filename. This also resolves the special `index.rst` files. If the file
- does not exist the return value will be `None`.
- """
- for rstname in filename + '.rst', filename + SEP + 'index.rst':
- if rstname in self.all_files:
- return rstname
Modified: doctools/trunk/sphinx/htmlhelp.py
==============================================================================
--- doctools/trunk/sphinx/htmlhelp.py (original)
+++ doctools/trunk/sphinx/htmlhelp.py Fri Feb 1 21:44:17 2008
@@ -149,7 +149,7 @@
f.write('<LI> ' + object_sitemap % ('Main page', 'index.html'))
f.write('<LI> ' + object_sitemap % ('Global Module Index', 'modindex.html'))
# the TOC
- toc = builder.env.get_and_resolve_doctree('contents.rst', builder)
+ toc = builder.env.get_and_resolve_doctree(builder.config.master_doc, builder)
def write_toc(node, ullevel=0):
if isinstance(node, nodes.list_item):
f.write('<LI> ')
Modified: doctools/trunk/sphinx/latexwriter.py
==============================================================================
--- doctools/trunk/sphinx/latexwriter.py (original)
+++ doctools/trunk/sphinx/latexwriter.py Fri Feb 1 21:44:17 2008
@@ -100,7 +100,7 @@
'pointsize': builder.config.latex_font_size,
'preamble': builder.config.latex_preamble,
'author': document.settings.author,
- 'filename': document.settings.filename,
+ 'docname': document.settings.docname,
'title': None, # is determined later
'release': builder.config.release,
'date': date,
@@ -200,7 +200,7 @@
# the environment already handles this
raise nodes.SkipNode
elif self.this_is_the_title:
- if len(node.children) != 1 and not isinstance(node.children[0], Text):
+ if len(node.children) != 1 and not isinstance(node.children[0], nodes.Text):
self.builder.warn('document title is not a single Text node')
self.options['title'] = node.astext()
self.this_is_the_title = 0
@@ -731,5 +731,10 @@
def depart_Text(self, node):
pass
+ def visit_system_message(self, node):
+ pass
+ def depart_system_message(self, node):
+ self.body.append('\n')
+
def unknown_visit(self, node):
raise NotImplementedError("Unknown node: " + node.__class__.__name__)
Modified: doctools/trunk/sphinx/templates/changes/versionchanges.html
==============================================================================
--- doctools/trunk/sphinx/templates/changes/versionchanges.html (original)
+++ doctools/trunk/sphinx/templates/changes/versionchanges.html Fri Feb 1 21:44:17 2008
@@ -1,6 +1,6 @@
{% macro entries changes %}
-<ul>{% for entry, filename, lineno in changes %}
-<li><a href="rst/{{ filename }}.html#L{{ lineno-10 }}" target="src">{{ entry }}</a></li>
+<ul>{% for entry, docname, lineno in changes %}
+<li><a href="rst/{{ docname }}.html#L{{ lineno-10 }}" target="src">{{ entry }}</a></li>
{% endfor %}</ul>
{% endmacro -%}
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
Modified: doctools/trunk/sphinx/templates/layout.html
==============================================================================
--- doctools/trunk/sphinx/templates/layout.html (original)
+++ doctools/trunk/sphinx/templates/layout.html Fri Feb 1 21:44:17 2008
@@ -106,7 +106,7 @@
<li><a href="{{ pathto('@edit/' + sourcename)|e }}">Suggest Change</a></li>
<li><a href="{{ pathto('@source/' + sourcename)|e }}">Show Source</a></li>
{% elif builder == 'html' %}
- <li><a href="{{ pathto(sourcename, true)|e }}">Show Source</a></li>
+ <li><a href="{{ pathto('_sources/' + sourcename, true)|e }}">Show Source</a></li>
{% endif %}
</ul>
{% endif %}
Modified: doctools/trunk/sphinx/util/__init__.py
==============================================================================
--- doctools/trunk/sphinx/util/__init__.py (original)
+++ doctools/trunk/sphinx/util/__init__.py Fri Feb 1 21:44:17 2008
@@ -22,11 +22,8 @@
# hangover from more *nix-oriented origins.
SEP = "/"
-def canonical_path(ospath):
- return ospath.replace(os.path.sep, SEP)
-
-def os_path(canpath):
- return canpath.replace(SEP, os.path.sep)
+def os_path(canonicalpath):
+ return canonicalpath.replace(SEP, os.path.sep)
def relative_uri(base, to):
@@ -51,8 +48,12 @@
raise
-def get_matching_files(dirname, pattern, exclude=()):
- """Get all files matching a pattern in a directory, recursively."""
+def get_matching_docs(dirname, suffix, exclude=()):
+ """
+ Get all file names (without suffix) matching a suffix in a
+ directory, recursively.
+ """
+ pattern = '*' + suffix
# dirname is a normalized absolute path.
dirname = path.normpath(path.abspath(dirname))
dirlen = len(dirname) + 1 # exclude slash
@@ -65,7 +66,7 @@
qualified_name = path.join(root[dirlen:], sfile)
if qualified_name in exclude:
continue
- yield canonical_path(qualified_name)
+ yield qualified_name[:-len(suffix)].replace(os.path.sep, SEP)
def shorten_result(text='', keywords=[], maxlen=240, fuzz=60):
Modified: doctools/trunk/sphinx/web/application.py
==============================================================================
--- doctools/trunk/sphinx/web/application.py (original)
+++ doctools/trunk/sphinx/web/application.py Fri Feb 1 21:44:17 2008
@@ -225,7 +225,7 @@
builder = MockBuilder()
builder.config = env2.config
writer = HTMLWriter(builder)
- doctree = env2.read_file(page_id+'.rst', pathname, save_parsed=False)
+ doctree = env2.read_doc(page_id, pathname, save_parsed=False)
doctree = env2.get_and_resolve_doctree(page_id+'.rst', builder, doctree)
doctree.settings = OptionParser(defaults=env2.settings,
components=(writer,)).get_default_values()
More information about the Python-checkins
mailing list