[Python-checkins] r59309 - in doctools/trunk/sphinx: builder.py directives.py environment.py htmlwriter.py util/__init__.py writer.py
georg.brandl
python-checkins at python.org
Mon Dec 3 23:38:25 CET 2007
Author: georg.brandl
Date: Mon Dec 3 23:38:25 2007
New Revision: 59309
Added:
doctools/trunk/sphinx/htmlwriter.py
- copied, changed from r58585, doctools/trunk/sphinx/writer.py
Removed:
doctools/trunk/sphinx/writer.py
Modified:
doctools/trunk/sphinx/builder.py
doctools/trunk/sphinx/directives.py
doctools/trunk/sphinx/environment.py
doctools/trunk/sphinx/util/__init__.py
Log:
Apply Tim Golden's patch from #1520, which resolves confusion between
file paths and relative URIs so that building on Windows is flawlessly
possible.
Modified: doctools/trunk/sphinx/builder.py
==============================================================================
--- doctools/trunk/sphinx/builder.py (original)
+++ doctools/trunk/sphinx/builder.py Mon Dec 3 23:38:25 2007
@@ -27,13 +27,15 @@
from docutils.frontend import OptionParser
from .util import (get_matching_files, attrdict, status_iterator,
- ensuredir, get_category, relative_uri)
-from .writer import HTMLWriter
-from .util.console import bold, purple, green
+ ensuredir, get_category, relative_uri,
+ webify_filepath, unwebify_filepath)
from .htmlhelp import build_hhx
from .patchlevel import get_version_info, get_sys_version_info
+from .htmlwriter import HTMLWriter
+#from .latexwriter import LaTeXWriter
from .environment import BuildEnvironment
from .highlighting import pygments, get_stylesheet
+from .util.console import bold, purple, green
# side effect: registers roles and directives
from . import roles
@@ -234,7 +236,7 @@
# build all
filenames_set = set(self.env.all_files)
- self.prepare_writing(filenames)
+ self.prepare_writing(filenames_set)
# write target files
with collect_env_warnings(self):
@@ -483,12 +485,12 @@
self.srcdir, '*.rst', exclude=set(self.config.get('unused_files', ()))):
try:
targetmtime = path.getmtime(path.join(self.outdir,
- filename[:-4] + '.html'))
+ unwebify_filepath(filename)[:-4] + '.html'))
except:
targetmtime = 0
if filename not in self.env.all_files:
yield filename
- elif path.getmtime(path.join(self.srcdir, filename)) > targetmtime:
+ elif path.getmtime(path.join(self.srcdir, unwebify_filepath(filename))) > targetmtime:
yield filename
@@ -513,7 +515,7 @@
ctx = self.globalcontext.copy()
ctx.update(context)
output = self.templates[templatename].render(ctx)
- outfilename = path.join(self.outdir, filename[:-4] + '.html')
+ outfilename = path.join(self.outdir, unwebify_filepath(filename)[:-4] + '.html')
ensuredir(path.dirname(outfilename)) # normally different from self.outdir
try:
with codecs.open(outfilename, 'w', 'utf-8') as fp:
@@ -522,7 +524,7 @@
print >>self.warning_stream, "Error writing file %s: %s" % (outfilename, err)
if self.copysource and context.get('sourcename'):
# copy the source file for the "show source" link
- shutil.copyfile(path.join(self.srcdir, filename),
+ shutil.copyfile(path.join(self.srcdir, unwebify_filepath(filename)),
path.join(self.outdir, context['sourcename']))
def handle_finish(self):
@@ -547,10 +549,10 @@
self.srcdir, '*.rst', exclude=set(self.config.get('unused_files', ()))):
try:
targetmtime = path.getmtime(path.join(self.outdir,
- filename[:-4] + '.fpickle'))
+ unwebify_filepath(filename)[:-4] + '.fpickle'))
except:
targetmtime = 0
- if path.getmtime(path.join(self.srcdir, filename)) > targetmtime:
+ if path.getmtime(path.join(self.srcdir, unwebify_filepath(filename))) > targetmtime:
yield filename
def get_target_uri(self, source_filename):
@@ -577,7 +579,7 @@
self.indexer.feed(filename, category, title, doctree)
def handle_file(self, filename, context, templatename='page'):
- outfilename = path.join(self.outdir, filename[:-4] + '.fpickle')
+ outfilename = path.join(self.outdir, unwebify_filepath(filename)[:-4] + '.fpickle')
ensuredir(path.dirname(outfilename))
context.pop('pathto', None) # can't be pickled
with file(outfilename, 'wb') as fp:
@@ -587,7 +589,7 @@
if context.get('sourcename'):
source_name = path.join(self.outdir, 'sources', context['sourcename'])
ensuredir(path.dirname(source_name))
- shutil.copyfile(path.join(self.srcdir, filename), source_name)
+ shutil.copyfile(path.join(self.srcdir, unwebify_filepath(filename)), source_name)
def handle_finish(self):
# dump the global context
@@ -632,8 +634,43 @@
build_hhx(self, self.outdir, self.options.get('outname') or 'pydoc')
+class LaTeXBuilder(Builder):
+ """
+ Builds LaTeX output to create PDF.
+ """
+ name = 'latex'
+
+ def init(self):
+ pass
+
+ def get_outdated_files(self):
+ # always rebuild everything for now
+ return self.env.all_files
+
+ def get_target_uri(self, source_filename):
+ # XXX: returns nothing for now
+ return ''
+
+ def prepare_writing(self, filenames):
+ self.docwriter = LaTeXWriter(self.config, self.name)
+ self.docsettings = OptionParser(
+ defaults=self.env.settings,
+ components=(self.docwriter,)).get_default_values()
+
+
+ def write_file(self, filename, doctree):
+ destination = StringOutput(encoding='utf-8')
+ doctree.settings = self.docsettings
+ output = self.docwriter.write(doctree, destination)
+ print output
+
+ def finish(self):
+ pass
+
+
builders = {
'html': StandaloneHTMLBuilder,
'web': WebHTMLBuilder,
'htmlhelp': HTMLHelpBuilder,
+# 'latex': LaTeXBuilder,
}
Modified: doctools/trunk/sphinx/directives.py
==============================================================================
--- doctools/trunk/sphinx/directives.py (original)
+++ doctools/trunk/sphinx/directives.py Mon Dec 3 23:38:25 2007
@@ -19,6 +19,7 @@
from docutils.parsers.rst.directives import admonitions
from . import addnodes
+from .util import webify_filepath, unwebify_filepath
# ------ index markup --------------------------------------------------------------
@@ -554,7 +555,8 @@
subnode = addnodes.toctree()
includefiles = filter(None, content)
# absolutize filenames
- includefiles = map(lambda x: path.normpath(path.join(dirname, x)), includefiles)
+ includefiles = [webify_filepath(path.normpath(path.join (dirname, x))) for x in includefiles]
+ #~ includefiles = map(lambda x: path.normpath(path.join(dirname, x)), includefiles)
subnode['includefiles'] = includefiles
subnode['maxdepth'] = options.get('maxdepth', -1)
return [subnode]
@@ -599,9 +601,9 @@
return [state.document.reporter.warning('File insertion disabled', line=lineno)]
env = state.document.settings.env
fn = arguments[0]
- source_dir = path.dirname(path.abspath(state_machine.input_lines.source(
- lineno - state_machine.input_offset - 1)))
- fn = path.normpath(path.join(source_dir, fn))
+ source_dir = webify_filepath(path.dirname(path.abspath(state_machine.input_lines.source(
+ lineno - state_machine.input_offset - 1))))
+ fn = webify_filepath(path.normpath(path.join(source_dir, fn)))
try:
with open(fn) as f:
Modified: doctools/trunk/sphinx/environment.py
==============================================================================
--- doctools/trunk/sphinx/environment.py (original)
+++ doctools/trunk/sphinx/environment.py Mon Dec 3 23:38:25 2007
@@ -38,7 +38,7 @@
Body.enum.converters['upperroman'] = lambda x: None
from . import addnodes
-from .util import get_matching_files
+from .util import get_matching_files, unwebify_filepath, WEB_SEP
from .refcounting import Refcounts
default_settings = {
@@ -278,11 +278,11 @@
else:
# if the doctree file is not there, rebuild
if not path.isfile(path.join(self.doctreedir,
- filename[:-3] + 'doctree')):
+ unwebify_filepath(filename)[:-3] + 'doctree')):
changed.append(filename)
continue
mtime, md5 = self.all_files[filename]
- newmtime = path.getmtime(path.join(self.srcdir, filename))
+ newmtime = path.getmtime(path.join(self.srcdir, unwebify_filepath(filename)))
if newmtime == mtime:
continue
# check the MD5
@@ -297,6 +297,8 @@
"""
(Re-)read all files new or changed since last update.
Yields a summary and then filenames as it processes them.
+ Store all environment filenames as webified (ie using "/"
+ as a separator in place of os.path.sep).
"""
added, changed, removed = self.get_outdated_files(config)
msg = '%s added, %s changed, %s removed' % (len(added), len(changed),
@@ -329,7 +331,7 @@
self.clear_file(filename)
if src_path is None:
- src_path = path.join(self.srcdir, filename)
+ src_path = path.join(self.srcdir, unwebify_filepath(filename))
self.filename = filename
doctree = publish_doctree(None, src_path, FileInput,
@@ -360,7 +362,7 @@
if save_parsed:
# save the parsed doctree
- doctree_filename = path.join(self.doctreedir, filename[:-3] + 'doctree')
+ doctree_filename = path.join(self.doctreedir, unwebify_filepath(filename)[:-3] + 'doctree')
dirname = path.dirname(doctree_filename)
if not path.isdir(dirname):
os.makedirs(dirname)
@@ -516,7 +518,7 @@
def get_doctree(self, filename):
"""Read the doctree for a file from the pickle and return it."""
- doctree_filename = path.join(self.doctreedir, filename[:-3] + 'doctree')
+ doctree_filename = path.join(self.doctreedir, unwebify_filepath(filename)[:-3] + 'doctree')
with file(doctree_filename, 'rb') as f:
doctree = pickle.load(f)
doctree.reporter = Reporter(filename, 2, 4, stream=self.warning_stream)
@@ -862,6 +864,6 @@
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 + path.sep + 'index.rst':
+ for rstname in filename + '.rst', filename + WEB_SEP + 'index.rst':
if rstname in self.all_files:
return rstname
Copied: doctools/trunk/sphinx/htmlwriter.py (from r58585, doctools/trunk/sphinx/writer.py)
==============================================================================
--- doctools/trunk/sphinx/writer.py (original)
+++ doctools/trunk/sphinx/htmlwriter.py Mon Dec 3 23:38:25 2007
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
"""
- sphinx.writer
- ~~~~~~~~~~~~~
+ sphinx.htmlwriter
+ ~~~~~~~~~~~~~~~~~
docutils writers handling Sphinx' custom nodes.
Modified: doctools/trunk/sphinx/util/__init__.py
==============================================================================
--- doctools/trunk/sphinx/util/__init__.py (original)
+++ doctools/trunk/sphinx/util/__init__.py Mon Dec 3 23:38:25 2007
@@ -15,17 +15,35 @@
from os import path
+#
+# Define WEB_SEP as a manifest constant, not
+# so much because we expect it to change in
+# the future as to avoid the suspicion that
+# a stray "/" in the code is a hangover from
+# more *nix-oriented origins.
+#
+WEB_SEP = "/"
+
+
+def webify_filepath(filepath):
+ return filepath.replace(os.path.sep, WEB_SEP)
+
+
+def unwebify_filepath(webpath):
+ return webpath.replace(WEB_SEP, os.path.sep)
+
+
def relative_uri(base, to):
"""Return a relative URL from ``base`` to ``to``."""
- b2 = base.split('/')
- t2 = to.split('/')
+ b2 = base.split(WEB_SEP)
+ t2 = to.split(WEB_SEP)
# remove common segments
for x, y in zip(b2, t2):
if x != y:
break
b2.pop(0)
t2.pop(0)
- return '../' * (len(b2)-1) + '/'.join(t2)
+ return ('..' + WEB_SEP) * (len(b2)-1) + WEB_SEP.join(t2)
def ensuredir(path):
@@ -60,12 +78,12 @@
qualified_name = path.join(root[dirlen:], sfile)
if qualified_name in exclude:
continue
- yield qualified_name
+ yield webify_filepath(qualified_name)
def get_category(filename):
"""Get the "category" part of a RST filename."""
- parts = filename.split('/', 1)
+ parts = filename.split(WEB_SEP, 1)
if len(parts) < 2:
return
return parts[0]
Deleted: /doctools/trunk/sphinx/writer.py
==============================================================================
--- /doctools/trunk/sphinx/writer.py Mon Dec 3 23:38:25 2007
+++ (empty file)
@@ -1,292 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- sphinx.writer
- ~~~~~~~~~~~~~
-
- docutils writers handling Sphinx' custom nodes.
-
- :copyright: 2007 by Georg Brandl.
- :license: Python license.
-"""
-
-from docutils import nodes
-from docutils.writers.html4css1 import Writer, HTMLTranslator as BaseTranslator
-
-from .util.smartypants import sphinx_smarty_pants
-
-
-class HTMLWriter(Writer):
- def __init__(self, config, buildername):
- Writer.__init__(self)
- self.translator_class = translator_class(config, buildername)
-
-
-version_text = {
- 'deprecated': 'Deprecated in version %s',
- 'versionchanged': 'Changed in version %s',
- 'versionadded': 'New in version %s',
-}
-
-def translator_class(config, buildername):
- 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 buildername != '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_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):
- 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:
- 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 .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
-
- # 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 buildername != 'htmlhelp' and \
- close_tag.startswith(('</h', '</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.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
-
- def encode(self, text):
- text = HTMLTranslator.encode(self, text)
- if self.no_smarty <= 0:
- text = sphinx_smarty_pants(text)
- return text
-
- if config.get('use_smartypants', False):
- return SmartyPantsHTMLTranslator
- else:
- return HTMLTranslator
More information about the Python-checkins
mailing list