merge with 1.0

This commit is contained in:
Georg Brandl
2010-08-23 16:27:25 +00:00
17 changed files with 244 additions and 165 deletions

23
CHANGES
View File

@@ -11,6 +11,29 @@ Release 1.1 (in development)
* #443: Allow referencing external graphviz files.
Release 1.0.3 (in development)
==============================
* #495: Fix internal vs. external link distinction for links coming
from a docutils table-of-contents.
* #494: Fix the ``maxdepth`` option for the ``toctree()`` template
callable when used with ``collapse=True``.
* #507: Fix crash parsing Python argument lists containing brackets
in string literals.
* #501: Fix regression when building LaTeX docs with figures that
don't have captions.
* #510: Fix inheritance diagrams for classes that are not picklable.
* #497: Introduce separate background color for the sidebar collapse
button, making it easier to see.
* #502, #503, #496: Fix small layout bugs in several builtin themes.
Release 1.0.2 (Aug 14, 2010)
============================

View File

@@ -141,8 +141,50 @@ Referencing downloadable files
suitable link generated to it.
Cross-referencing other items of interest
-----------------------------------------
The following roles do possibly create a cross-reference, but do not refer to
objects:
.. rst:role:: envvar
An environment variable. Index entries are generated. Also generates a link
to the matching :rst:dir:`envvar` directive, if it exists.
.. rst:role:: token
The name of a grammar token (used to create links between
:rst:dir:`productionlist` directives).
.. rst:role:: keyword
The name of a keyword in Python. This creates a link to a reference label
with that name, if it exists.
.. rst:role:: option
A command-line option to an executable program. The leading hyphen(s) must
be included. This generates a link to a :rst:dir:`option` directive, if it
exists.
The following role creates a cross-reference to the term in the glossary:
.. rst:role:: term
Reference to a term in the glossary. The glossary is created using the
``glossary`` directive containing a definition list with terms and
definitions. It does not have to be in the same file as the ``term`` markup,
for example the Python docs have one global glossary in the ``glossary.rst``
file.
If you use a term that's not explained in a glossary, you'll get a warning
during build.
Other semantic markup
---------------------
~~~~~~~~~~~~~~~~~~~~~
The following roles don't do anything special except formatting the text
in a different style:
@@ -289,52 +331,10 @@ Note that there are no special roles for including hyperlinks as you can use
the standard reST markup for that purpose.
Cross-referencing other items of interest
-----------------------------------------
The following roles do possibly create a cross-reference, but do not refer to
objects:
.. rst:role:: envvar
An environment variable. Index entries are generated. Also generates a link
to the matching :rst:dir:`envvar` directive, if it exists.
.. rst:role:: token
The name of a grammar token (used to create links between
:rst:dir:`productionlist` directives).
.. rst:role:: keyword
The name of a keyword in Python. This creates a link to a reference label
with that name, if it exists.
.. rst:role:: option
A command-line option to an executable program. The leading hyphen(s) must
be included. This generates a link to a :rst:dir:`option` directive, if it
exists.
The following role creates a cross-reference to the term in the glossary:
.. rst:role:: term
Reference to a term in the glossary. The glossary is created using the
``glossary`` directive containing a definition list with terms and
definitions. It does not have to be in the same file as the ``term`` markup,
for example the Python docs have one global glossary in the ``glossary.rst``
file.
If you use a term that's not explained in a glossary, you'll get a warning
during build.
.. _default-substitutions:
Substitutions
-------------
~~~~~~~~~~~~~
The documentation system provides three substitutions that are defined by default.
They are set in the build configuration file.

View File

@@ -119,6 +119,8 @@ These themes are:
- **footerbgcolor** (CSS color): Background color for the footer line.
- **footertextcolor** (CSS color): Text color for the footer line.
- **sidebarbgcolor** (CSS color): Background color for the sidebar.
- **sidebarbtncolor** (CSS color): Background color for the sidebar collapse
button (used when *collapsiblesidebar* is true).
- **sidebartextcolor** (CSS color): Text color for the sidebar.
- **sidebarlinkcolor** (CSS color): Link color for the sidebar.
- **relbarbgcolor** (CSS color): Background color for the relation bar.

View File

@@ -200,7 +200,7 @@ class HTMLHelpBuilder(StandaloneHTMLBuilder):
outdir += os.sep
olen = len(outdir)
for root, dirs, files in os.walk(outdir):
staticdir = (root == path.join(outdir, '_static'))
staticdir = root.startswith(path.join(outdir, '_static'))
for fn in files:
if (staticdir and not fn.endswith('.js')) or \
fn.endswith('.html'):

View File

@@ -13,8 +13,8 @@ from sphinx import addnodes
from sphinx.domains import Domain, ObjType
from sphinx.locale import l_, _
from sphinx.directives import ObjectDescription
from sphinx.domains.python import py_paramlist_re as js_paramlist_re
from sphinx.roles import XRefRole
from sphinx.domains.python import _pseudo_parse_arglist
from sphinx.util.nodes import make_refnode
from sphinx.util.docfields import Field, GroupedField, TypedField
@@ -68,28 +68,10 @@ class JSObject(ObjectDescription):
signode += addnodes.desc_addname(nameprefix + '.', nameprefix + '.')
signode += addnodes.desc_name(name, name)
if self.has_arguments:
signode += addnodes.desc_parameterlist()
if not arglist:
return fullname, nameprefix
stack = [signode[-1]]
for token in js_paramlist_re.split(arglist):
if token == '[':
opt = addnodes.desc_optional()
stack[-1] += opt
stack.append(opt)
elif token == ']':
try:
stack.pop()
except IndexError:
raise ValueError()
elif not token or token == ',' or token.isspace():
pass
if not arglist:
signode += addnodes.desc_parameterlist()
else:
token = token.strip()
stack[-1] += addnodes.desc_parameter(token, token)
if len(stack) != 1:
raise ValueError()
_pseudo_parse_arglist(signode, arglist)
return fullname, nameprefix
def add_target_and_index(self, name_obj, sig, signode):

View File

@@ -33,7 +33,52 @@ py_sig_re = re.compile(
)? $ # and nothing more
''', re.VERBOSE)
py_paramlist_re = re.compile(r'([\[\],])') # split at '[', ']' and ','
def _pseudo_parse_arglist(signode, arglist):
""""Parse" a list of arguments separated by commas.
Arguments can have "optional" annotations given by enclosing them in
brackets. Currently, this will split at any comma, even if it's inside a
string literal (e.g. default argument value).
"""
paramlist = addnodes.desc_parameterlist()
stack = [paramlist]
try:
for argument in arglist.split(','):
argument = argument.strip()
ends_open = ends_close = 0
while argument.startswith('['):
stack.append(addnodes.desc_optional())
stack[-2] += stack[-1]
argument = argument[1:].strip()
while argument.startswith(']'):
stack.pop()
argument = argument[1:].strip()
while argument.endswith(']'):
ends_close += 1
argument = argument[:-1].strip()
while argument.endswith('['):
ends_open += 1
argument = argument[:-1].strip()
if argument:
stack[-1] += addnodes.desc_parameter(argument, argument)
while ends_open:
stack.append(addnodes.desc_optional())
stack[-2] += stack[-1]
ends_open -= 1
while ends_close:
stack.pop()
ends_close -= 1
if len(stack) != 1:
raise IndexError
except IndexError:
# if there are too few or too many elements on the stack, just give up
# and treat the whole argument list as one argument, discarding the
# already partially populated paramlist node
signode += addnodes.desc_parameterlist()
signode[-1] += addnodes.desc_parameter(arglist, arglist)
else:
signode += paramlist
class PyObject(ObjectDescription):
@@ -141,26 +186,7 @@ class PyObject(ObjectDescription):
if retann:
signode += addnodes.desc_returns(retann, retann)
return fullname, name_prefix
signode += addnodes.desc_parameterlist()
stack = [signode[-1]]
for token in py_paramlist_re.split(arglist):
if token == '[':
opt = addnodes.desc_optional()
stack[-1] += opt
stack.append(opt)
elif token == ']':
try:
stack.pop()
except IndexError:
raise ValueError
elif not token or token == ',' or token.isspace():
pass
else:
token = token.strip()
stack[-1] += addnodes.desc_parameter(token, token)
if len(stack) != 1:
raise ValueError
_pseudo_parse_arglist(signode, arglist)
if retann:
signode += addnodes.desc_returns(retann, retann)
return fullname, name_prefix

View File

@@ -1183,32 +1183,62 @@ class BuildEnvironment:
def _walk_depth(node, depth, maxdepth):
"""Utility: Cut a TOC at a specified depth."""
# For reading this function, it is useful to keep in mind the node
# structure of a toctree (using HTML-like node names for brevity):
#
# <ul>
# <li>
# <p><a></p>
# <p><a></p>
# ...
# <ul>
# ...
# </ul>
# </li>
# </ul>
for subnode in node.children[:]:
if isinstance(subnode, (addnodes.compact_paragraph,
nodes.list_item)):
# for <p> and <li>, just indicate the depth level and
# recurse to children
subnode['classes'].append('toctree-l%d' % (depth-1))
_walk_depth(subnode, depth, maxdepth)
elif isinstance(subnode, nodes.bullet_list):
# for <ul>, determine if the depth is too large or if the
# entry is to be collapsed
if maxdepth > 0 and depth > maxdepth:
subnode.parent.replace(subnode, [])
else:
# to find out what to collapse, *first* walk subitems,
# since that determines which children point to the
# current page
_walk_depth(subnode, depth+1, maxdepth)
# cull sub-entries whose parents aren't 'current'
if (collapse and
depth > 1 and
'current' not in subnode.parent['classes']):
if (collapse and depth > 1 and
'iscurrent' not in subnode.parent):
subnode.parent.remove(subnode)
elif isinstance(subnode, nodes.reference):
# identify the toc entry pointing to the current document
if subnode['refuri'] == docname and \
not subnode['anchorname']:
# tag the whole branch as 'current'
p = subnode
while p:
p['classes'].append('current')
p = p.parent
# for <a>, identify which entries point to the current
# document and therefore may not be collapsed
if subnode['refuri'] == docname:
if not subnode['anchorname']:
# give the whole branch a 'current' class
# (useful for styling it differently)
branchnode = subnode
while branchnode:
branchnode['classes'].append('current')
branchnode = branchnode.parent
# mark the list_item as "on current page"
if subnode.parent.parent.get('iscurrent'):
# but only if it's not already done
return
while subnode:
subnode['iscurrent'] = True
subnode = subnode.parent
def _entries_from_toctree(toctreenode, separate=False, subtree=False):
"""Return TOC entries for a toctree node."""

View File

@@ -66,19 +66,18 @@ class InheritanceGraph(object):
from all the way to the root "object", and then is able to generate a
graphviz dot graph from them.
"""
def __init__(self, class_names, currmodule, show_builtins=False):
def __init__(self, class_names, currmodule, show_builtins=False, parts=0):
"""*class_names* is a list of child classes to show bases from.
If *show_builtins* is True, then Python builtins will be shown
in the graph.
"""
self.class_names = class_names
self.classes = self._import_classes(class_names, currmodule)
self.all_classes = self._all_classes(self.classes)
if len(self.all_classes) == 0:
classes = self._import_classes(class_names, currmodule)
self.class_info = self._class_info(classes, show_builtins, parts)
if not self.class_info:
raise InheritanceException('No classes found for '
'inheritance diagram')
self.show_builtins = show_builtins
def _import_class_or_module(self, name, currmodule):
"""Import a class using its fully-qualified *name*."""
@@ -132,20 +131,36 @@ class InheritanceGraph(object):
classes.extend(self._import_class_or_module(name, currmodule))
return classes
def _all_classes(self, classes):
"""Return a list of all classes that are ancestors of *classes*."""
def _class_info(self, classes, show_builtins, parts):
"""Return name and bases for all classes that are ancestors of
*classes*.
*parts* gives the number of dotted name parts that is removed from the
displayed node names.
"""
all_classes = {}
builtins = __builtins__.values()
def recurse(cls):
all_classes[cls] = None
for c in cls.__bases__:
if c not in all_classes:
recurse(c)
if not show_builtins and cls in builtins:
return
nodename = self.class_name(cls, parts)
fullname = self.class_name(cls, 0)
baselist = []
all_classes[cls] = (nodename, fullname, baselist)
for base in cls.__bases__:
if not show_builtins and base in builtins:
return
baselist.append(self.class_name(base, parts))
if base not in all_classes:
recurse(base)
for cls in classes:
recurse(cls)
return all_classes.keys()
return all_classes.values()
def class_name(self, cls, parts=0):
"""Given a class object, return a fully-qualified name.
@@ -165,7 +180,7 @@ class InheritanceGraph(object):
def get_all_class_names(self):
"""Get all of the class names involved in the graph."""
return [self.class_name(x) for x in self.all_classes]
return [fullname for (_, fullname, _) in self.class_info]
# These are the default attrs for graphviz
default_graph_attrs = {
@@ -191,7 +206,7 @@ class InheritanceGraph(object):
def _format_graph_attrs(self, attrs):
return ''.join(['%s=%s;\n' % x for x in attrs.items()])
def generate_dot(self, name, parts=0, urls={}, env=None,
def generate_dot(self, name, urls={}, env=None,
graph_attrs={}, node_attrs={}, edge_attrs={}):
"""Generate a graphviz dot graph from the classes that were passed in
to __init__.
@@ -218,26 +233,17 @@ class InheritanceGraph(object):
res.append('digraph %s {\n' % name)
res.append(self._format_graph_attrs(g_attrs))
for cls in self.all_classes:
if not self.show_builtins and cls in __builtins__.values():
continue
name = self.class_name(cls, parts)
for name, fullname, bases in self.class_info:
# Write the node
this_node_attrs = n_attrs.copy()
url = urls.get(self.class_name(cls))
url = urls.get(fullname)
if url is not None:
this_node_attrs['URL'] = '"%s"' % url
res.append(' "%s" [%s];\n' %
(name, self._format_node_attrs(this_node_attrs)))
# Write the edges
for base in cls.__bases__:
if not self.show_builtins and base in __builtins__.values():
continue
base_name = self.class_name(base, parts)
for base_name in bases:
res.append(' "%s" -> "%s" [%s];\n' %
(base_name, name,
self._format_node_attrs(e_attrs)))
@@ -270,11 +276,15 @@ class InheritanceDiagram(Directive):
env = self.state.document.settings.env
class_names = self.arguments[0].split()
class_role = env.get_domain('py').role('class')
# Store the original content for use as a hash
node['parts'] = self.options.get('parts', 0)
node['content'] = ', '.join(class_names)
# Create a graph starting with the list of classes
try:
graph = InheritanceGraph(class_names,
env.temp_data.get('py:module'))
graph = InheritanceGraph(
class_names, env.temp_data.get('py:module'),
parts=node['parts'])
except InheritanceException, err:
return [node.document.reporter.warning(err.args[0],
line=self.lineno)]
@@ -290,9 +300,6 @@ class InheritanceDiagram(Directive):
# Store the graph object so we can use it to generate the
# dot file later
node['graph'] = graph
# Store the original content for use as a hash
node['parts'] = self.options.get('parts', 0)
node['content'] = ', '.join(class_names)
return [node]
@@ -306,7 +313,6 @@ def html_visit_inheritance_diagram(self, node):
image map.
"""
graph = node['graph']
parts = node['parts']
graph_hash = get_graph_hash(node)
name = 'inheritance%s' % graph_hash
@@ -319,7 +325,7 @@ def html_visit_inheritance_diagram(self, node):
elif child.get('refid') is not None:
urls[child['reftitle']] = '#' + child.get('refid')
dotcode = graph.generate_dot(name, parts, urls, env=self.builder.env)
dotcode = graph.generate_dot(name, urls, env=self.builder.env)
render_dot_html(self, node, dotcode, [], 'inheritance', 'inheritance',
alt='Inheritance diagram of ' + node['content'])
raise nodes.SkipNode
@@ -330,12 +336,11 @@ def latex_visit_inheritance_diagram(self, node):
Output the graph for LaTeX. This will insert a PDF.
"""
graph = node['graph']
parts = node['parts']
graph_hash = get_graph_hash(node)
name = 'inheritance%s' % graph_hash
dotcode = graph.generate_dot(name, parts, env=self.builder.env,
dotcode = graph.generate_dot(name, env=self.builder.env,
graph_attrs={'size': '"6.0,6.0"'})
render_dot_latex(self, node, dotcode, [], 'inheritance')
raise nodes.SkipNode

View File

@@ -446,7 +446,10 @@
linkcolor=InnerLinkColor,filecolor=OuterLinkColor,
menucolor=OuterLinkColor,urlcolor=OuterLinkColor,
citecolor=InnerLinkColor]{hyperref}
\RequirePackage[figure,table]{hypcap}
% Fix anchor placement for figures with captions.
% (Note: we don't use a package option here; instead, we give an explicit
% \capstart for figures that actually have a caption.)
\RequirePackage{hypcap}
% From docutils.writers.latex2e
\providecommand{\DUspan}[2]{%

View File

@@ -22,7 +22,7 @@
<h1><a href="{{ pathto(master_doc) }}">{{ shorttitle|e }}</a></h1>
{%- endblock %}
<div class="rel">
{%- for rellink in rellinks %}
{%- for rellink in rellinks|reverse %}
<a href="{{ pathto(rellink[0]) }}" title="{{ rellink[1]|striptags|e }}"
{{ accesskey(rellink[2]) }}>{{ rellink[3] }}</a>
{%- if not loop.last %}{{ reldelim2 }}{% endif %}
@@ -67,7 +67,7 @@
<div class="footer-wrapper">
<div class="footer">
<div class="left">
{%- for rellink in rellinks %}
{%- for rellink in rellinks|reverse %}
<a href="{{ pathto(rellink[0]) }}" title="{{ rellink[1]|striptags|e }}"
{{ accesskey(rellink[2]) }}>{{ rellink[3] }}</a>
{%- if not loop.last %}{{ reldelim2 }}{% endif %}

View File

@@ -147,6 +147,12 @@ div.sphinxsidebar input {
font-size: 1em;
}
{% if theme_collapsiblesidebar|tobool %}
/* for collapsible sidebar */
div#sidebarbutton {
background-color: {{ theme_sidebarbtncolor }};
}
{% endif %}
/* -- hyperlink styles ------------------------------------------------------ */
@@ -174,6 +180,11 @@ a.external:hover {
text-decoration: none;
border-bottom: none;
}
a.external:visited {
text-decoration: none;
border-bottom: 1px dashed {{ theme_visitedlinkcolor }};
}
{% endif %}
/* -- body styles ----------------------------------------------------------- */

View File

@@ -91,6 +91,7 @@ $(function() {
'<div id="sidebarbutton"><span>&laquo;</span></div>'
);
var sidebarbutton = $('#sidebarbutton');
light_color = sidebarbutton.css('background-color');
// find the height of the viewport to center the '<<' in the page
var viewport_height;
if (window.innerHeight)
@@ -144,4 +145,4 @@ $(function() {
add_sidebar_button();
var sidebarbutton = $('#sidebarbutton');
set_position_from_cookie();
});
});

View File

@@ -12,6 +12,7 @@ externalrefs = false
footerbgcolor = #11303d
footertextcolor = #ffffff
sidebarbgcolor = #1c4e63
sidebarbtncolor = #3c6e83
sidebartextcolor = #ffffff
sidebarlinkcolor = #98dbcc
relbarbgcolor = #133f52

View File

@@ -292,7 +292,7 @@ li {
line-height: 1.3;
}
div.content li {
div.content ul > li {
-moz-background-clip:border;
-moz-background-inline-policy:continuous;
-moz-background-origin:padding;

View File

@@ -1,5 +1,6 @@
r"""
This is based on SmartyPants.py by `Chad Miller`_.
This is based on SmartyPants.py by `Chad Miller`_ <smartypantspy@chad.org>,
version 1.5_1.6.
Copyright and License
=====================
@@ -75,8 +76,8 @@ import re
def sphinx_smarty_pants(t):
t = t.replace('&quot;', '"')
t = educateDashesOldSchool(t)
t = educateQuotes(t)
t = educate_dashes_oldschool(t)
t = educate_quotes(t)
t = t.replace('"', '&quot;')
return t
@@ -152,7 +153,7 @@ closing_single_quotes_regex_2 = re.compile(r"""
(\s | s\b)
""" % (close_class,), re.VERBOSE)
def educateQuotes(s):
def educate_quotes(s):
"""
Parameter: String.
@@ -191,7 +192,7 @@ def educateQuotes(s):
return s.replace('"', "&#8220;")
def educateQuotesLatex(s, dquotes=("``", "''")):
def educate_quotes_latex(s, dquotes=("``", "''")):
"""
Parameter: String.
@@ -234,7 +235,7 @@ def educateQuotesLatex(s, dquotes=("``", "''")):
replace("\x03", "`").replace("\x04", "'")
def educateBackticks(s):
def educate_backticks(s):
"""
Parameter: String.
Returns: The string, with ``backticks'' -style double quotes
@@ -245,7 +246,7 @@ def educateBackticks(s):
return s.replace("``", "&#8220;").replace("''", "&#8221;")
def educateSingleBackticks(s):
def educate_single_backticks(s):
"""
Parameter: String.
Returns: The string, with `backticks' -style single quotes
@@ -257,7 +258,7 @@ def educateSingleBackticks(s):
return s.replace('`', "&#8216;").replace("'", "&#8217;")
def educateDashesOldSchool(s):
def educate_dashes_oldschool(s):
"""
Parameter: String.
@@ -268,7 +269,7 @@ def educateDashesOldSchool(s):
return s.replace('---', "&#8212;").replace('--', "&#8211;")
def educateDashesOldSchoolInverted(s):
def educate_dashes_oldschool_inverted(s):
"""
Parameter: String.
@@ -276,7 +277,7 @@ def educateDashesOldSchoolInverted(s):
an em-dash HTML entity, and each "---" translated to
an en-dash HTML entity. Two reasons why: First, unlike the
en- and em-dash syntax supported by
EducateDashesOldSchool(), it's compatible with existing
educate_dashes_oldschool(), it's compatible with existing
entries written before SmartyPants 1.1, back when "--" was
only used for em-dashes. Second, em-dashes are more
common than en-dashes, and so it sort of makes sense that
@@ -286,8 +287,7 @@ def educateDashesOldSchoolInverted(s):
return s.replace('---', "&#8211;").replace('--', "&#8212;")
def educateEllipses(s):
def educate_ellipses(s):
"""
Parameter: String.
Returns: The string, with each instance of "..." translated to
@@ -297,11 +297,3 @@ def educateEllipses(s):
Example output: Huh&#8230;?
"""
return s.replace('...', "&#8230;").replace('. . .', "&#8230;")
__author__ = "Chad Miller <smartypantspy@chad.org>"
__version__ = "1.5_1.5: Sat, 13 Aug 2005 15:50:24 -0400"
__url__ = "http://wiki.chad.org/SmartyPantsPy"
__description__ = \
"Smart-quotes, smart-ellipses, and smart-dashes for weblog entries" \
" in pyblosxom"

View File

@@ -159,7 +159,7 @@ class HTMLTranslator(BaseTranslator):
# overwritten
def visit_reference(self, node):
atts = {'class': 'reference'}
if node.get('internal'):
if node.get('internal') or 'refuri' not in node:
atts['class'] += ' internal'
else:
atts['class'] += ' external'

View File

@@ -24,8 +24,9 @@ from sphinx import highlighting
from sphinx.errors import SphinxError
from sphinx.locale import admonitionlabels, versionlabels, _
from sphinx.util.osutil import ustrftime
from sphinx.util.pycompat import any
from sphinx.util.texescape import tex_escape_map, tex_replace_map
from sphinx.util.smartypants import educateQuotesLatex
from sphinx.util.smartypants import educate_quotes_latex
HEADER = r'''%% Generated by Sphinx.
\def\sphinxdocclass{%(docclass)s}
@@ -614,7 +615,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.body = self._body
if not self.table.longtable and self.table.caption is not None:
self.body.append(u'\n\\begin{threeparttable}\n'
u'\\caption{%s}\n' % self.table.caption)
u'\\capstart\\caption{%s}\n' % self.table.caption)
if self.table.longtable:
self.body.append('\n\\begin{longtable}')
elif self.table.has_verbatim:
@@ -634,7 +635,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
else:
self.body.append('{|' + ('L|' * self.table.colcount) + '}\n')
if self.table.longtable and self.table.caption is not None:
self.body.append(u'\\caption{%s} \\\\\n' % self.table.caption)
self.body.append(u'\\capstart\\caption{%s} \\\\\n' % self.table.caption)
if self.table.caption is not None:
for id in self.next_table_ids:
self.body.append(self.hypertarget(id, anchor=False))
@@ -912,6 +913,8 @@ class LaTeXTranslator(nodes.NodeVisitor):
align = '\\begin{flush%s}' % node.attributes['align']
align_end = '\\end{flush%s}' % node.attributes['align']
self.body.append('\\begin{figure}[htbp]%s\n' % align)
if any(isinstance(child, nodes.caption) for child in node):
self.body.append('\\capstart\n')
self.context.append(ids + align_end + '\\end{figure}\n')
def depart_figure(self, node):
self.body.append(self.context.pop())
@@ -1396,7 +1399,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.verbatim += node.astext()
else:
text = self.encode(node.astext())
self.body.append(educateQuotesLatex(text))
self.body.append(educate_quotes_latex(text))
def depart_Text(self, node):
pass