merge with trunk

This commit is contained in:
Georg Brandl 2010-01-07 19:07:50 +01:00
commit a43738e47a
14 changed files with 119 additions and 30 deletions

View File

@ -5,6 +5,7 @@ Substantial parts of the templates were written by Armin Ronacher
Other contributors, listed alphabetically, are: Other contributors, listed alphabetically, are:
* Henrique Bastos -- SVG support for graphviz extension
* Daniel Bültmann -- todo extension * Daniel Bültmann -- todo extension
* Michael Droettboom -- inheritance_diagram extension * Michael Droettboom -- inheritance_diagram extension
* Charles Duffy -- original graphviz extension * Charles Duffy -- original graphviz extension

View File

@ -9,6 +9,9 @@ Release 1.0 (in development)
* Added Epub builder. * Added Epub builder.
* #309: The ``graphviz`` extension can now output SVG instead of PNG
images, controlled by the ``graphviz_output_format`` config value.
* #284: All docinfo metadata is now put into the document metadata, not * #284: All docinfo metadata is now put into the document metadata, not
just the author. just the author.
@ -60,6 +63,10 @@ Release 1.0 (in development)
Release 0.6.4 (in development) Release 0.6.4 (in development)
============================== ==============================
* The ``alt`` text of inheritance diagrams is now much cleaner.
* Ignore images in section titles when generating link captions.
* #310: support exception messages in the ``testoutput`` blocks of * #310: support exception messages in the ``testoutput`` blocks of
the ``doctest`` extension. the ``doctest`` extension.

View File

@ -8,7 +8,7 @@ all: clean-pyc check test
check: check:
@$(PYTHON) utils/check_sources.py -i build -i dist -i sphinx/style/jquery.js \ @$(PYTHON) utils/check_sources.py -i build -i dist -i sphinx/style/jquery.js \
-i sphinx/pycode/pgen2 -i sphinx/util/smartypants.py \ -i sphinx/pycode/pgen2 -i sphinx/util/smartypants.py -i .ropeproject \
-i doc/_build -i ez_setup.py -i tests/path.py -i tests/coverage.py -i env . -i doc/_build -i ez_setup.py -i tests/path.py -i tests/coverage.py -i env .
clean: clean-pyc clean-patchfiles clean: clean-pyc clean-patchfiles

View File

@ -47,3 +47,8 @@ The extension adds one new config value:
You can also use the usual "explicit title" syntax supported by other roles You can also use the usual "explicit title" syntax supported by other roles
that generate links, i.e. ``:issue:`this issue <123>```. In this case, the that generate links, i.e. ``:issue:`this issue <123>```. In this case, the
*prefix* is not relevant. *prefix* is not relevant.
.. note::
Since links are generated from the role in the reading stage, they appear as
ordinary links to e.g. the ``linkcheck`` builder.

View File

@ -25,8 +25,9 @@ It adds these directives:
"bar" -> "baz"; "bar" -> "baz";
} }
In HTML output, the code will be rendered to a PNG image. In LaTeX output, In HTML output, the code will be rendered to a PNG or SVG image (see
the code will be rendered to an embeddable PDF file. :confval:`graphviz_output_format`). In LaTeX output, the code will be
rendered to an embeddable PDF file.
.. directive:: graph .. directive:: graph
@ -75,3 +76,11 @@ There are also these new config values:
Additional command-line arguments to give to dot, as a list. The default is Additional command-line arguments to give to dot, as a list. The default is
an empty list. This is the right place to set global graph, node or edge an empty list. This is the right place to set global graph, node or edge
attributes via dot's ``-G``, ``-N`` and ``-E`` options. attributes via dot's ``-G``, ``-N`` and ``-E`` options.
.. confval:: graphviz_output_format
The output format for Graphviz when building HTML files. This must be either
``'png'`` or ``'svg'``; the default is ``'png'``.
.. versionadded:: 1.0
Previously, output always was PNG.

View File

@ -128,7 +128,7 @@ These themes are:
on the right side. There are currently no options beyond *nosidebar*. on the right side. There are currently no options beyond *nosidebar*.
* **scrolls** -- A more lightweight theme, based on `the Jinja documentation * **scrolls** -- A more lightweight theme, based on `the Jinja documentation
<http://jinja.pocoo.org/documentation/2>`_. The following color options are <http://jinja.pocoo.org/2/documentation/>`_. The following color options are
available: available:
- **headerbordercolor** - **headerbordercolor**

View File

@ -443,6 +443,10 @@ class StandaloneHTMLBuilder(Builder):
else: else:
stripped = '' stripped = ''
# we stripped the whole module name
if not mn:
continue
if fl != mn[0].lower() and mn[0] != '_': if fl != mn[0].lower() and mn[0] != '_':
# heading # heading
letter = mn[0].upper() letter = mn[0].upper()

View File

@ -70,6 +70,8 @@ class CheckExternalLinksBuilder(Builder):
lineno = node.line lineno = node.line
if uri[0:5] == 'http:' or uri[0:6] == 'https:': if uri[0:5] == 'http:' or uri[0:6] == 'https:':
if lineno:
self.info('(line %3d) ' % lineno, nonl=1)
self.info(uri, nonl=1) self.info(uri, nonl=1)
if uri in self.broken: if uri in self.broken:

View File

@ -35,7 +35,7 @@ from docutils.transforms.parts import ContentsFilter
from sphinx import addnodes from sphinx import addnodes
from sphinx.util import movefile, get_matching_docs, SEP, ustrftime, \ from sphinx.util import movefile, get_matching_docs, SEP, ustrftime, \
docname_join, FilenameUniqDict, url_re, make_refnode docname_join, FilenameUniqDict, url_re, make_refnode, clean_astext
from sphinx.errors import SphinxError, ExtensionError from sphinx.errors import SphinxError, ExtensionError
@ -898,11 +898,11 @@ class BuildEnvironment:
node.line) node.line)
self.anonlabels[name] = docname, labelid self.anonlabels[name] = docname, labelid
if node.tagname == 'section': if node.tagname == 'section':
sectname = node[0].astext() # node[0] == title node sectname = clean_astext(node[0]) # node[0] == title node
elif node.tagname == 'figure': elif node.tagname == 'figure':
for n in node: for n in node:
if n.tagname == 'caption': if n.tagname == 'caption':
sectname = n.astext() sectname = clean_astext(n)
break break
else: else:
continue continue
@ -1130,7 +1130,7 @@ class BuildEnvironment:
# toctree originates # toctree originates
ref = toctreenode['parent'] ref = toctreenode['parent']
if not title: if not title:
title = self.titles[ref].astext() title = clean_astext(self.titles[ref])
reference = nodes.reference('', '', reference = nodes.reference('', '',
refuri=ref, refuri=ref,
anchorname='', anchorname='',
@ -1281,7 +1281,7 @@ class BuildEnvironment:
# reference with explicit title # reference with explicit title
caption = node.astext() caption = node.astext()
else: else:
caption = self.titles[docname].astext() caption = clean_astext(self.titles[docname])
innernode = nodes.emphasis(caption, caption) innernode = nodes.emphasis(caption, caption)
newnode = nodes.reference('', '') newnode = nodes.reference('', '')
newnode['refuri'] = builder.get_relative_uri( newnode['refuri'] = builder.get_relative_uri(

View File

@ -13,6 +13,7 @@
import re import re
import posixpath import posixpath
from os import path from os import path
from math import ceil
from subprocess import Popen, PIPE from subprocess import Popen, PIPE
try: try:
from hashlib import sha1 as sha from hashlib import sha1 as sha
@ -27,6 +28,7 @@ from sphinx.util.compat import Directive
mapname_re = re.compile(r'<map id="(.*?)"') mapname_re = re.compile(r'<map id="(.*?)"')
svg_dim_re = re.compile(r'<svg\swidth="(\d+)pt"\sheight="(\d+)pt"', re.M)
class GraphvizError(SphinxError): class GraphvizError(SphinxError):
@ -128,9 +130,45 @@ def render_dot(self, code, options, format, prefix='graphviz'):
return relfn, outfn return relfn, outfn
def render_dot_html(self, node, code, options, prefix='graphviz', imgcls=None): def get_svg_tag(svgref, svgfile, imgcls=None):
# Webkit can't figure out svg dimensions when using object tag
# so we need to get it from the svg file
fp = open(svgfile, 'r')
try: try:
fname, outfn = render_dot(self, code, options, 'png', prefix) for line in fp:
match = svg_dim_re.match(line)
if match:
dimensions = match.groups()
break
else:
dimensions = None
finally:
fp.close()
# We need this hack to make WebKit show our object tag properly
def pt2px(x):
return int(ceil((96.0/72.0) * float(x)))
if dimensions:
style = ' width="%s" height="%s"' % tuple(map(pt2px, dimensions))
else:
style = ''
# The object tag works fine on Firefox and WebKit
# Besides it's a hack, this strategy does not mess with templates.
imgcss = imgcls and ' class="%s"' % imgcls or ''
return '<object type="image/svg+xml" data="%s"%s%s/>\n' % \
(svgref, imgcss, style)
def render_dot_html(self, node, code, options, prefix='graphviz',
imgcls=None, alt=None):
format = self.builder.config.graphviz_output_format
try:
if format not in ('png', 'svg'):
raise GraphvizError("graphviz_output_format must be one of 'png', "
"'svg', but is %r" % format)
fname, outfn = render_dot(self, code, options, format, prefix)
except GraphvizError, exc: except GraphvizError, exc:
self.builder.warn('dot code %r: ' % code + str(exc)) self.builder.warn('dot code %r: ' % code + str(exc))
raise nodes.SkipNode raise nodes.SkipNode
@ -139,23 +177,29 @@ def render_dot_html(self, node, code, options, prefix='graphviz', imgcls=None):
if fname is None: if fname is None:
self.body.append(self.encode(code)) self.body.append(self.encode(code))
else: else:
mapfile = open(outfn + '.map', 'rb') if alt is None:
try: alt = self.encode(code).strip()
imgmap = mapfile.readlines() if format == 'svg':
finally: svgtag = get_svg_tag(fname, outfn, imgcls)
mapfile.close() self.body.append(svgtag)
imgcss = imgcls and 'class="%s"' % imgcls or ''
if len(imgmap) == 2:
# nothing in image map (the lines are <map> and </map>)
self.body.append('<img src="%s" alt="%s" %s/>\n' %
(fname, self.encode(code).strip(), imgcss))
else: else:
# has a map: get the name of the map and connect the parts mapfile = open(outfn + '.map', 'rb')
mapname = mapname_re.match(imgmap[0]).group(1) try:
self.body.append('<img src="%s" alt="%s" usemap="#%s" %s/>\n' % imgmap = mapfile.readlines()
(fname, self.encode(code).strip(), finally:
mapname, imgcss)) mapfile.close()
self.body.extend(imgmap) imgcss = imgcls and 'class="%s"' % imgcls or ''
if len(imgmap) == 2:
# nothing in image map (the lines are <map> and </map>)
self.body.append('<img src="%s" alt="%s" %s/>\n' %
(fname, alt, imgcss))
else:
# has a map: get the name of the map and connect the parts
mapname = mapname_re.match(imgmap[0]).group(1)
self.body.append('<img src="%s" alt="%s" usemap="#%s" %s/>\n' %
(fname, alt, mapname, imgcss))
self.body.extend(imgmap)
self.body.append('</p>\n') self.body.append('</p>\n')
raise nodes.SkipNode raise nodes.SkipNode
@ -188,3 +232,4 @@ def setup(app):
app.add_directive('digraph', GraphvizSimple) app.add_directive('digraph', GraphvizSimple)
app.add_config_value('graphviz_dot', 'dot', 'html') app.add_config_value('graphviz_dot', 'dot', 'html')
app.add_config_value('graphviz_dot_args', [], 'html') app.add_config_value('graphviz_dot_args', [], 'html')
app.add_config_value('graphviz_output_format', 'png', 'html')

View File

@ -302,7 +302,7 @@ class InheritanceDiagram(Directive):
node['graph'] = graph node['graph'] = graph
# Store the original content for use as a hash # Store the original content for use as a hash
node['parts'] = self.options.get('parts', 0) node['parts'] = self.options.get('parts', 0)
node['content'] = ' '.join(class_names) node['content'] = ', '.join(class_names)
return [node] return [node]
@ -330,7 +330,8 @@ def html_visit_inheritance_diagram(self, node):
urls[child['reftitle']] = '#' + child.get('refid') urls[child['reftitle']] = '#' + child.get('refid')
dotcode = graph.generate_dot(name, parts, urls, env=self.builder.env) dotcode = graph.generate_dot(name, parts, urls, env=self.builder.env)
render_dot_html(self, node, dotcode, [], 'inheritance', 'inheritance') render_dot_html(self, node, dotcode, [], 'inheritance', 'inheritance',
alt='Inheritance diagram of ' + node['content'])
raise nodes.SkipNode raise nodes.SkipNode

View File

@ -250,3 +250,11 @@ tt {
th { th {
background-color: #ede; background-color: #ede;
} }
.warning tt {
background: #efc2c2;
}
.note tt {
background: #d6d6d6;
}

View File

@ -445,6 +445,13 @@ def copy_static_entry(source, target, builder, context={}):
shutil.copytree(source, target) shutil.copytree(source, target)
def clean_astext(node):
"""Like node.astext(), but ignore images."""
node = node.deepcopy()
for img in node.traverse(docutils.nodes.image):
img['alt'] = ''
return node.astext()
def split_explicit_title(text): def split_explicit_title(text):
"""Split role content into title and target, if given.""" """Split role content into title and target, if given."""

View File

@ -30,7 +30,7 @@ def checker(*suffixes, **kwds):
name_mail_re = r'[\w ]+(<.*?>)?' name_mail_re = r'[\w ]+(<.*?>)?'
copyright_re = re.compile(r'^ :copyright: Copyright 200\d(-200\d)? ' copyright_re = re.compile(r'^ :copyright: Copyright 200\d(-20\d\d)? '
r'by %s(, %s)*[,.]$' % r'by %s(, %s)*[,.]$' %
(name_mail_re, name_mail_re)) (name_mail_re, name_mail_re))
license_re = re.compile(r" :license: (.*?).\n") license_re = re.compile(r" :license: (.*?).\n")