Merge with default

This commit is contained in:
tk0miya 2014-09-28 21:28:45 +09:00
commit 0853176305
19 changed files with 748 additions and 5 deletions

View File

@ -44,6 +44,8 @@ Features added
directive is now supported.
* PR#214: Added stemming support for 14 languages, so that the built-in document
search can now handle these. Thanks to Shibukawa Yoshiki.
* PR#296: numfig feature: Assign numbers to figures, tables and code-blocks.
Thanks to Takeshi Komiya.
* PR#202: Allow "." and "~" prefixed references in ``:param:`` doc fields
for Python.
* PR#184: Add `autodoc_mock_imports`, allowing to mock imports of
@ -83,6 +85,8 @@ Features added
``+``.
* PR#291: The caption of :rst:dir:`code-block` is recognised as a title of ref
target. Thanks to Takeshi Komiya.
* PR#298: Add new API: :meth:`~sphinx.application.Sphinx.add_latex_package`.
Thanks to Takeshi Komiya.
Bugs fixed
----------

View File

@ -288,6 +288,12 @@ package.
.. versionadded:: 1.0
.. method:: Sphinx.add_latex_package(packagename)
Add *packagename* to the list of packages that LaTeX source code will include.
.. versionadded:: 1.3
.. method:: Sphinx.add_lexer(alias, lexer)
Use *lexer*, which must be an instance of a Pygments lexer class, to

View File

@ -694,6 +694,11 @@ class Sphinx(object):
StandaloneHTMLBuilder.css_files.append(
posixpath.join('_static', filename))
def add_latex_package(self, packagename):
self.debug('[app] adding latex package: %r', packagename)
from sphinx.builders.latex import LaTeXBuilder
LaTeXBuilder.usepackages.append(packagename)
def add_lexer(self, alias, lexer):
self.debug('[app] adding lexer: %r', (alias, lexer))
from sphinx.highlighting import lexers

View File

@ -425,7 +425,8 @@ class StandaloneHTMLBuilder(Builder):
doctree.settings = self.docsettings
self.secnumbers = self.env.toc_secnumbers.get(docname, {})
self.imgpath = relative_uri(self.get_target_uri(docname), self.imagedir)
self.fignumbers = self.env.toc_fignumbers.get(docname, {})
self.imgpath = relative_uri(self.get_target_uri(docname), '_images')
self.dlpath = relative_uri(self.get_target_uri(docname), '_downloads')
self.current_docname = docname
self.docwriter.write(doctree, destination)

View File

@ -37,6 +37,7 @@ class LaTeXBuilder(Builder):
format = 'latex'
supported_image_types = ['application/pdf', 'image/png',
'image/gif', 'image/jpeg']
usepackages = []
def init(self):
self.docnames = []

View File

@ -58,6 +58,7 @@ class WebSupportBuilder(PickleHTMLBuilder):
doctree.settings = self.docsettings
self.secnumbers = self.env.toc_secnumbers.get(docname, {})
self.fignumbers = self.env.toc_fignumbers.get(docname, {})
self.imgpath = '/' + posixpath.join(self.virtual_staticdir, self.imagedir)
self.dlpath = '/' + posixpath.join(self.virtual_staticdir, '_downloads')
self.current_docname = docname

View File

@ -70,6 +70,12 @@ class Config(object):
needs_extensions = ({}, None),
nitpicky = (False, 'env'),
nitpick_ignore = ([], 'html'),
numfig = (False, 'env'),
numfig_secnum_depth = (1, 'env'),
numfig_prefix = ({'figure': l_('Fig.'),
'table': l_('Table '),
'code-block': l_('List ')},
'env'),
# HTML options
html_theme = ('default', 'html'),

View File

@ -48,7 +48,7 @@ from sphinx.errors import SphinxError, ExtensionError
from sphinx.locale import _
from sphinx.versioning import add_uids, merge_doctrees
from sphinx.transforms import DefaultSubstitutions, MoveModuleTargets, \
HandleCodeBlocks, SortIds, CitationReferences, Locale, \
HandleCodeBlocks, AutoNumbering, SortIds, CitationReferences, Locale, \
RemoveTranslatableInline, SphinxContentsFilter
@ -98,7 +98,7 @@ class SphinxStandaloneReader(standalone.Reader):
Add our own transforms.
"""
transforms = [Locale, CitationReferences, DefaultSubstitutions,
MoveModuleTargets, HandleCodeBlocks, SortIds,
MoveModuleTargets, HandleCodeBlocks, AutoNumbering, SortIds,
RemoveTranslatableInline]
def get_transforms(self):
@ -234,6 +234,8 @@ class BuildEnvironment:
# used to determine when to show the TOC
# in a sidebar (don't show if it's only one item)
self.toc_secnumbers = {} # docname -> dict of sectionid -> number
self.toc_fignumbers = {} # docname -> dict of figtype ->
# dict of figureid -> number
self.toctree_includes = {} # docname -> list of toctree includefiles
self.files_to_rebuild = {} # docname -> set of files
@ -635,8 +637,8 @@ class BuildEnvironment:
self._warnfunc(*warning)
def check_dependents(self, already):
to_rewrite = self.assign_section_numbers()
for docname in to_rewrite:
to_rewrite = self.assign_section_numbers() + self.assign_figure_numbers()
for docname in set(to_rewrite):
if docname not in already:
yield docname
@ -1693,6 +1695,87 @@ class BuildEnvironment:
return rewrite_needed
def assign_figure_numbers(self):
"""Assign a figure number to each figure under a numbered toctree."""
rewrite_needed = []
assigned = set()
old_fignumbers = getattr(self, 'toc_fignumbers', {}) # compatible with old envs
self.toc_fignumbers = {}
fignum_counter = {}
def has_child(node, cls):
return any(isinstance(child, cls) for child in node)
def get_section_number(docname, section):
anchorname = '#' + section['ids'][0]
secnumbers = self.toc_secnumbers.get(docname, {})
if anchorname in secnumbers:
secnum = secnumbers.get(anchorname)
else:
secnum = secnumbers.get('')
return secnum or tuple()
def get_next_fignumber(figtype, secnum):
counter = fignum_counter.setdefault(figtype, {})
secnum = secnum[:self.config.numfig_secnum_depth]
counter[secnum] = counter.get(secnum, 0) + 1
return secnum + (counter[secnum],)
def register_fignumber(docname, secnum, figtype, figure_id):
self.toc_fignumbers.setdefault(docname, {})
fignumbers = self.toc_fignumbers[docname].setdefault(figtype, {})
fignumbers[figure_id] = get_next_fignumber(figtype, secnum)
def _walk_doctree(docname, doctree, secnum):
for subnode in doctree.children:
if isinstance(subnode, nodes.section):
next_secnum = get_section_number(docname, subnode)
if next_secnum:
_walk_doctree(docname, subnode, next_secnum)
else:
_walk_doctree(docname, subnode, secnum)
continue
elif isinstance(subnode, addnodes.toctree):
for title, subdocname in subnode['entries']:
if url_re.match(subdocname) or subdocname == 'self':
# don't mess with those
continue
_walk_doc(subdocname, secnum)
continue
if isinstance(subnode, nodes.figure):
figure_id = subnode['ids'][0]
register_fignumber(docname, secnum, 'figure', figure_id)
elif isinstance(subnode, nodes.table):
table_id = subnode['ids'][0]
register_fignumber(docname, secnum, 'table', table_id)
elif isinstance(subnode, nodes.container):
if has_child(subnode, nodes.literal_block):
code_block_id = subnode['ids'][0]
register_fignumber(docname, secnum, 'code-block', code_block_id)
_walk_doctree(docname, subnode, secnum)
def _walk_doc(docname, secnum):
if docname not in assigned:
assigned.add(docname)
doctree = self.get_doctree(docname)
_walk_doctree(docname, doctree, secnum)
if self.config.numfig:
_walk_doc(self.config.master_doc, tuple())
for docname, fignums in iteritems(self.toc_fignumbers):
if fignums != old_fignumbers.get(docname):
rewrite_needed.append(docname)
return rewrite_needed
def create_index(self, builder, group_entries=True,
_fixre=re.compile(r'(.*) ([(][^()]*[)])')):
"""Create the real index from the collected index entries."""

View File

@ -101,6 +101,31 @@ class HandleCodeBlocks(Transform):
# del node.parent[parindex+1]
class AutoNumbering(Transform):
"""
Register IDs of tables, figures and literal_blocks to assign numbers.
"""
default_priority = 210
def apply(self):
def has_child(node, cls):
return any(isinstance(child, cls) for child in node)
for node in self.document.traverse(nodes.Element):
if isinstance(node, nodes.figure):
if has_child(node, nodes.caption):
self.document.note_implicit_target(node)
elif isinstance(node, nodes.image):
if has_child(node.parent, nodes.caption):
self.document.note_implicit_target(node.parent)
elif isinstance(node, nodes.table):
if has_child(node, nodes.title):
self.document.note_implicit_target(node)
elif isinstance(node, nodes.literal_block):
if has_child(node.parent, nodes.caption):
self.document.note_implicit_target(node.parent)
class SortIds(Transform):
"""
Sort secion IDs so that the "id[0-9]+" one comes last.

View File

@ -250,6 +250,20 @@ class HTMLTranslator(BaseTranslator):
self.body.append('.'.join(map(str, numbers)) +
self.secnumber_suffix)
def add_fignumber(self, node):
def append_fignumber(figtype, figure_id):
if figure_id in self.builder.fignumbers.get(figtype, {}):
prefix = self.builder.config.numfig_prefix.get(figtype, '')
numbers = self.builder.fignumbers[figtype][figure_id]
self.body.append(prefix + '.'.join(map(str, numbers)) + " ")
if isinstance(node.parent, nodes.figure):
append_fignumber('figure', node.parent['ids'][0])
elif isinstance(node.parent, nodes.table):
append_fignumber('table', node.parent['ids'][0])
elif isinstance(node.parent, nodes.container):
append_fignumber('code-block', node.parent['ids'][0])
# overwritten to avoid emitting empty <ul></ul>
def visit_bullet_list(self, node):
if len(node) == 1 and node[0].tagname == 'toctree':
@ -260,6 +274,7 @@ class HTMLTranslator(BaseTranslator):
def visit_title(self, node):
BaseTranslator.visit_title(self, node)
self.add_secnumber(node)
self.add_fignumber(node)
# overwritten
def visit_literal_block(self, node):
@ -291,6 +306,7 @@ class HTMLTranslator(BaseTranslator):
self.body.append(self.starttag(node, 'div', '', CLASS='code-block-caption'))
else:
BaseTranslator.visit_caption(self, node)
self.add_fignumber(node)
def depart_caption(self, node):
if isinstance(node.parent, nodes.container) and node.parent.get('literal_block'):

View File

@ -42,6 +42,7 @@ HEADER = r'''%% Generated by Sphinx.
%(longtable)s
\usepackage{sphinx}
\usepackage{multirow}
%(usepackages)s
%(preamble)s
\title{%(title)s}
@ -153,6 +154,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
'fontpkg': '\\usepackage{times}',
'fncychap': '\\usepackage[Bjarne]{fncychap}',
'longtable': '\\usepackage{longtable}',
'usepackages': '',
'preamble': '',
'title': '',
'date': '',
@ -234,6 +236,9 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.elements['fncychap'] = ''
else:
self.elements['classoptions'] += ',english'
if getattr(builder, 'usepackages', None):
usepackages = ('\\usepackage{%s}' % p for p in builder.usepackages)
self.elements['usepackages'] += "\n".join(usepackages)
# allow the user to override them all
self.elements.update(builder.config.latex_elements)
if self.elements['extraclassoptions']:

View File

@ -0,0 +1,58 @@
===
Bar
===
Bar A
=====
.. figure:: rimg.png
should be Fig.2.1
.. csv-table:: should be Table 2.1
:header-rows: 0
hello,world
.. code-block:: python
:caption: should be List 2.1
print('hello world')
.. toctree::
baz
.. figure:: rimg.png
should be Fig.2.3
.. csv-table:: should be Table 2.3
:header-rows: 0
hello,world
.. code-block:: python
:caption: should be List 2.3
print('hello world')
Bar B
=====
Bar B1
------
.. figure:: rimg.png
should be Fig.2.4
.. csv-table:: should be Table 2.4
:header-rows: 0
hello,world
.. code-block:: python
:caption: should be List 2.4
print('hello world')

View File

@ -0,0 +1,16 @@
Baz A
-----
.. figure:: rimg.png
should be Fig.2.2
.. csv-table:: should be Table 2.2
:header-rows: 0
hello,world
.. code-block:: python
:caption: should be List 2.2
print('hello world')

View File

@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
master_doc = 'index'

View File

@ -0,0 +1,71 @@
===
Foo
===
.. figure:: rimg.png
should be Fig.1.1
.. csv-table:: should be Table 1.1
:header-rows: 0
hello,world
.. code-block:: python
:caption: should be List 1.1
print('hello world')
Foo A
=====
.. figure:: rimg.png
should be Fig.1.2
.. figure:: rimg.png
should be Fig.1.3
.. csv-table:: should be Table 1.2
:header-rows: 0
hello,world
.. csv-table:: should be Table 1.3
:header-rows: 0
hello,world
.. code-block:: python
:caption: should be List 1.2
print('hello world')
.. code-block:: python
:caption: should be List 1.3
print('hello world')
Foo A1
------
Foo B
=====
Foo B1
------
.. figure:: rimg.png
should be Fig.1.4
.. csv-table:: should be Table 1.4
:header-rows: 0
hello,world
.. code-block:: python
:caption: should be List 1.4
print('hello world')

View File

@ -0,0 +1,36 @@
test-tocdepth
=============
.. toctree::
:numbered:
foo
bar
.. figure:: rimg.png
should be Fig.1
.. figure:: rimg.png
should be Fig.2
.. csv-table:: should be Table 1
:header-rows: 0
hello,world
.. csv-table:: should be Table 2
:header-rows: 0
hello,world
.. code-block:: python
:caption: should be List 1
print('hello world')
.. code-block:: python
:caption: should be List 2
print('hello world')

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 B

View File

@ -455,3 +455,402 @@ def test_tocdepth_singlehtml(app, status, warning):
for xpath, check, be_found in paths:
yield check_xpath, etree, fname, xpath, check, be_found
@gen_with_app(buildername='html', testroot='numfig')
def test_numfig(app, status, warning):
# issue #1251
app.builder.build_all()
expects = {
'index.html': [
(".//div[@class='figure']/p[@class='caption']",
'^should be Fig.1$', True),
(".//div[@class='figure']/p[@class='caption']",
'^should be Fig.2$', True),
(".//table/caption", '^should be Table 1$', True),
(".//table/caption", '^should be Table 2$', True),
(".//div[@class='code-block-caption']",
'^should be List 1$', True),
(".//div[@class='code-block-caption']",
'^should be List 2$', True),
],
'foo.html': [
(".//div[@class='figure']/p[@class='caption']",
'^should be Fig.1.1$', True),
(".//div[@class='figure']/p[@class='caption']",
'^should be Fig.1.2$', True),
(".//div[@class='figure']/p[@class='caption']",
'^should be Fig.1.3$', True),
(".//div[@class='figure']/p[@class='caption']",
'^should be Fig.1.4$', True),
(".//table/caption", '^should be Table 1.1$', True),
(".//table/caption", '^should be Table 1.2$', True),
(".//table/caption", '^should be Table 1.3$', True),
(".//table/caption", '^should be Table 1.4$', True),
(".//div[@class='code-block-caption']",
'^should be List 1.1$', True),
(".//div[@class='code-block-caption']",
'^should be List 1.2$', True),
(".//div[@class='code-block-caption']",
'^should be List 1.3$', True),
(".//div[@class='code-block-caption']",
'^should be List 1.4$', True),
],
'bar.html': [
(".//div[@class='figure']/p[@class='caption']",
'^should be Fig.2.1$', True),
(".//div[@class='figure']/p[@class='caption']",
'^should be Fig.2.3$', True),
(".//div[@class='figure']/p[@class='caption']",
'^should be Fig.2.4$', True),
(".//table/caption", '^should be Table 2.1$', True),
(".//table/caption", '^should be Table 2.3$', True),
(".//table/caption", '^should be Table 2.4$', True),
(".//div[@class='code-block-caption']",
'^should be List 2.1$', True),
(".//div[@class='code-block-caption']",
'^should be List 2.3$', True),
(".//div[@class='code-block-caption']",
'^should be List 2.4$', True),
],
'baz.html': [
(".//div[@class='figure']/p[@class='caption']",
'^should be Fig.2.2$', True),
(".//table/caption", '^should be Table 2.2$', True),
(".//div[@class='code-block-caption']",
'^should be List 2.2$', True),
],
}
for fname, paths in iteritems(expects):
parser = NslessParser()
parser.entity.update(html_entities.entitydefs)
fp = open(os.path.join(app.outdir, fname), 'rb')
try:
etree = ET.parse(fp, parser)
finally:
fp.close()
for xpath, check, be_found in paths:
yield check_xpath, etree, fname, xpath, check, be_found
@gen_with_app(buildername='html', testroot='numfig',
confoverrides={'numfig': True})
def test_numfig_without_numbered_toctree(app, status, warning):
# remove :numbered: option
index = (app.srcdir / 'index.rst').text()
index = re.sub(':numbered:.*', '', index, re.MULTILINE)
(app.srcdir / 'index.rst').write_text(index, encoding='utf-8')
app.builder.build_all()
expects = {
'index.html': [
(".//div[@class='figure']/p[@class='caption']",
'^Fig.9 should be Fig.1$', True),
(".//div[@class='figure']/p[@class='caption']",
'^Fig.10 should be Fig.2$', True),
(".//table/caption", '^Table 9 should be Table 1$', True),
(".//table/caption", '^Table 10 should be Table 2$', True),
(".//div[@class='code-block-caption']",
'^List 9 should be List 1$', True),
(".//div[@class='code-block-caption']",
'^List 10 should be List 2$', True),
],
'foo.html': [
(".//div[@class='figure']/p[@class='caption']",
'^Fig.1 should be Fig.1.1$', True),
(".//div[@class='figure']/p[@class='caption']",
'^Fig.2 should be Fig.1.2$', True),
(".//div[@class='figure']/p[@class='caption']",
'^Fig.3 should be Fig.1.3$', True),
(".//div[@class='figure']/p[@class='caption']",
'^Fig.4 should be Fig.1.4$', True),
(".//table/caption", '^Table 1 should be Table 1.1$', True),
(".//table/caption", '^Table 2 should be Table 1.2$', True),
(".//table/caption", '^Table 3 should be Table 1.3$', True),
(".//table/caption", '^Table 4 should be Table 1.4$', True),
(".//div[@class='code-block-caption']",
'^List 1 should be List 1.1$', True),
(".//div[@class='code-block-caption']",
'^List 2 should be List 1.2$', True),
(".//div[@class='code-block-caption']",
'^List 3 should be List 1.3$', True),
(".//div[@class='code-block-caption']",
'^List 4 should be List 1.4$', True),
],
'bar.html': [
(".//div[@class='figure']/p[@class='caption']",
'^Fig.5 should be Fig.2.1$', True),
(".//div[@class='figure']/p[@class='caption']",
'^Fig.7 should be Fig.2.3$', True),
(".//div[@class='figure']/p[@class='caption']",
'^Fig.8 should be Fig.2.4$', True),
(".//table/caption", '^Table 5 should be Table 2.1$', True),
(".//table/caption", '^Table 7 should be Table 2.3$', True),
(".//table/caption", '^Table 8 should be Table 2.4$', True),
(".//div[@class='code-block-caption']",
'^List 5 should be List 2.1$', True),
(".//div[@class='code-block-caption']",
'^List 7 should be List 2.3$', True),
(".//div[@class='code-block-caption']",
'^List 8 should be List 2.4$', True),
],
'baz.html': [
(".//div[@class='figure']/p[@class='caption']",
'^Fig.6 should be Fig.2.2$', True),
(".//table/caption", '^Table 6 should be Table 2.2$', True),
(".//div[@class='code-block-caption']",
'^List 6 should be List 2.2$', True),
],
}
for fname, paths in iteritems(expects):
parser = NslessParser()
parser.entity.update(html_entities.entitydefs)
fp = open(os.path.join(app.outdir, fname), 'rb')
try:
etree = ET.parse(fp, parser)
finally:
fp.close()
for xpath, check, be_found in paths:
yield check_xpath, etree, fname, xpath, check, be_found
@gen_with_app(buildername='html', testroot='numfig',
confoverrides={'numfig': True})
def test_numfig_with_numbered_toctree(app, status, warning):
app.builder.build_all()
expects = {
'index.html': [
(".//div[@class='figure']/p[@class='caption']",
'^Fig.1 should be Fig.1$', True),
(".//div[@class='figure']/p[@class='caption']",
'^Fig.2 should be Fig.2$', True),
(".//table/caption", '^Table 1 should be Table 1$', True),
(".//table/caption", '^Table 2 should be Table 2$', True),
(".//div[@class='code-block-caption']",
'^List 1 should be List 1$', True),
(".//div[@class='code-block-caption']",
'^List 2 should be List 2$', True),
],
'foo.html': [
(".//div[@class='figure']/p[@class='caption']",
'^Fig.1.1 should be Fig.1.1$', True),
(".//div[@class='figure']/p[@class='caption']",
'^Fig.1.2 should be Fig.1.2$', True),
(".//div[@class='figure']/p[@class='caption']",
'^Fig.1.3 should be Fig.1.3$', True),
(".//div[@class='figure']/p[@class='caption']",
'^Fig.1.4 should be Fig.1.4$', True),
(".//table/caption", '^Table 1.1 should be Table 1.1$', True),
(".//table/caption", '^Table 1.2 should be Table 1.2$', True),
(".//table/caption", '^Table 1.3 should be Table 1.3$', True),
(".//table/caption", '^Table 1.4 should be Table 1.4$', True),
(".//div[@class='code-block-caption']",
'^List 1.1 should be List 1.1$', True),
(".//div[@class='code-block-caption']",
'^List 1.2 should be List 1.2$', True),
(".//div[@class='code-block-caption']",
'^List 1.3 should be List 1.3$', True),
(".//div[@class='code-block-caption']",
'^List 1.4 should be List 1.4$', True),
],
'bar.html': [
(".//div[@class='figure']/p[@class='caption']",
'^Fig.2.1 should be Fig.2.1$', True),
(".//div[@class='figure']/p[@class='caption']",
'^Fig.2.3 should be Fig.2.3$', True),
(".//div[@class='figure']/p[@class='caption']",
'^Fig.2.4 should be Fig.2.4$', True),
(".//table/caption", '^Table 2.1 should be Table 2.1$', True),
(".//table/caption", '^Table 2.3 should be Table 2.3$', True),
(".//table/caption", '^Table 2.4 should be Table 2.4$', True),
(".//div[@class='code-block-caption']",
'^List 2.1 should be List 2.1$', True),
(".//div[@class='code-block-caption']",
'^List 2.3 should be List 2.3$', True),
(".//div[@class='code-block-caption']",
'^List 2.4 should be List 2.4$', True),
],
'baz.html': [
(".//div[@class='figure']/p[@class='caption']",
'^Fig.2.2 should be Fig.2.2$', True),
(".//table/caption", '^Table 2.2 should be Table 2.2$', True),
(".//div[@class='code-block-caption']",
'^List 2.2 should be List 2.2$', True),
],
}
for fname, paths in iteritems(expects):
parser = NslessParser()
parser.entity.update(html_entities.entitydefs)
fp = open(os.path.join(app.outdir, fname), 'rb')
try:
etree = ET.parse(fp, parser)
finally:
fp.close()
for xpath, check, be_found in paths:
yield check_xpath, etree, fname, xpath, check, be_found
@gen_with_app(buildername='html', testroot='numfig',
confoverrides={'numfig': True, 'numfig_prefix': {'figure': 'Figure:', 'table': 'Tab_', 'code-block': 'Code-'}})
def test_numfig_with_prefix(app, status, warning):
app.builder.build_all()
expects = {
'index.html': [
(".//div[@class='figure']/p[@class='caption']",
'^Figure:1 should be Fig.1$', True),
(".//div[@class='figure']/p[@class='caption']",
'^Figure:2 should be Fig.2$', True),
(".//table/caption", '^Tab_1 should be Table 1$', True),
(".//table/caption", '^Tab_2 should be Table 2$', True),
(".//div[@class='code-block-caption']",
'^Code-1 should be List 1$', True),
(".//div[@class='code-block-caption']",
'^Code-2 should be List 2$', True),
],
'foo.html': [
(".//div[@class='figure']/p[@class='caption']",
'^Figure:1.1 should be Fig.1.1$', True),
(".//div[@class='figure']/p[@class='caption']",
'^Figure:1.2 should be Fig.1.2$', True),
(".//div[@class='figure']/p[@class='caption']",
'^Figure:1.3 should be Fig.1.3$', True),
(".//div[@class='figure']/p[@class='caption']",
'^Figure:1.4 should be Fig.1.4$', True),
(".//table/caption", '^Tab_1.1 should be Table 1.1$', True),
(".//table/caption", '^Tab_1.2 should be Table 1.2$', True),
(".//table/caption", '^Tab_1.3 should be Table 1.3$', True),
(".//table/caption", '^Tab_1.4 should be Table 1.4$', True),
(".//div[@class='code-block-caption']",
'^Code-1.1 should be List 1.1$', True),
(".//div[@class='code-block-caption']",
'^Code-1.2 should be List 1.2$', True),
(".//div[@class='code-block-caption']",
'^Code-1.3 should be List 1.3$', True),
(".//div[@class='code-block-caption']",
'^Code-1.4 should be List 1.4$', True),
],
'bar.html': [
(".//div[@class='figure']/p[@class='caption']",
'^Figure:2.1 should be Fig.2.1$', True),
(".//div[@class='figure']/p[@class='caption']",
'^Figure:2.3 should be Fig.2.3$', True),
(".//div[@class='figure']/p[@class='caption']",
'^Figure:2.4 should be Fig.2.4$', True),
(".//table/caption", '^Tab_2.1 should be Table 2.1$', True),
(".//table/caption", '^Tab_2.3 should be Table 2.3$', True),
(".//table/caption", '^Tab_2.4 should be Table 2.4$', True),
(".//div[@class='code-block-caption']",
'^Code-2.1 should be List 2.1$', True),
(".//div[@class='code-block-caption']",
'^Code-2.3 should be List 2.3$', True),
(".//div[@class='code-block-caption']",
'^Code-2.4 should be List 2.4$', True),
],
'baz.html': [
(".//div[@class='figure']/p[@class='caption']",
'^Figure:2.2 should be Fig.2.2$', True),
(".//table/caption", '^Tab_2.2 should be Table 2.2$', True),
(".//div[@class='code-block-caption']",
'^Code-2.2 should be List 2.2$', True),
],
}
for fname, paths in iteritems(expects):
parser = NslessParser()
parser.entity.update(html_entities.entitydefs)
fp = open(os.path.join(app.outdir, fname), 'rb')
try:
etree = ET.parse(fp, parser)
finally:
fp.close()
for xpath, check, be_found in paths:
yield check_xpath, etree, fname, xpath, check, be_found
@gen_with_app(buildername='html', testroot='numfig',
confoverrides={'numfig': True, 'numfig_secnum_depth': 2})
def test_numfig_with_secnum_depth(app, status, warning):
app.builder.build_all()
expects = {
'index.html': [
(".//div[@class='figure']/p[@class='caption']",
'^Fig.1 should be Fig.1$', True),
(".//div[@class='figure']/p[@class='caption']",
'^Fig.2 should be Fig.2$', True),
(".//table/caption", '^Table 1 should be Table 1$', True),
(".//table/caption", '^Table 2 should be Table 2$', True),
(".//div[@class='code-block-caption']",
'^List 1 should be List 1$', True),
(".//div[@class='code-block-caption']",
'^List 2 should be List 2$', True),
],
'foo.html': [
(".//div[@class='figure']/p[@class='caption']",
'^Fig.1.1 should be Fig.1.1$', True),
(".//div[@class='figure']/p[@class='caption']",
'^Fig.1.1.1 should be Fig.1.2$', True),
(".//div[@class='figure']/p[@class='caption']",
'^Fig.1.1.2 should be Fig.1.3$', True),
(".//div[@class='figure']/p[@class='caption']",
'^Fig.1.2.1 should be Fig.1.4$', True),
(".//table/caption", '^Table 1.1 should be Table 1.1$', True),
(".//table/caption", '^Table 1.1.1 should be Table 1.2$', True),
(".//table/caption", '^Table 1.1.2 should be Table 1.3$', True),
(".//table/caption", '^Table 1.2.1 should be Table 1.4$', True),
(".//div[@class='code-block-caption']",
'^List 1.1 should be List 1.1$', True),
(".//div[@class='code-block-caption']",
'^List 1.1.1 should be List 1.2$', True),
(".//div[@class='code-block-caption']",
'^List 1.1.2 should be List 1.3$', True),
(".//div[@class='code-block-caption']",
'^List 1.2.1 should be List 1.4$', True),
],
'bar.html': [
(".//div[@class='figure']/p[@class='caption']",
'^Fig.2.1.1 should be Fig.2.1$', True),
(".//div[@class='figure']/p[@class='caption']",
'^Fig.2.1.3 should be Fig.2.3$', True),
(".//div[@class='figure']/p[@class='caption']",
'^Fig.2.2.1 should be Fig.2.4$', True),
(".//table/caption", '^Table 2.1.1 should be Table 2.1$', True),
(".//table/caption", '^Table 2.1.3 should be Table 2.3$', True),
(".//table/caption", '^Table 2.2.1 should be Table 2.4$', True),
(".//div[@class='code-block-caption']",
'^List 2.1.1 should be List 2.1$', True),
(".//div[@class='code-block-caption']",
'^List 2.1.3 should be List 2.3$', True),
(".//div[@class='code-block-caption']",
'^List 2.2.1 should be List 2.4$', True),
],
'baz.html': [
(".//div[@class='figure']/p[@class='caption']",
'^Fig.2.1.2 should be Fig.2.2$', True),
(".//table/caption", '^Table 2.1.2 should be Table 2.2$', True),
(".//div[@class='code-block-caption']",
'^List 2.1.2 should be List 2.2$', True),
],
}
for fname, paths in iteritems(expects):
parser = NslessParser()
parser.entity.update(html_entities.entitydefs)
fp = open(os.path.join(app.outdir, fname), 'rb')
try:
etree = ET.parse(fp, parser)
finally:
fp.close()
for xpath, check, be_found in paths:
yield check_xpath, etree, fname, xpath, check, be_found

View File

@ -91,3 +91,10 @@ def test_latex(app, status, warning):
assert False, 'latex exited with return code %s' % p.returncode
finally:
os.chdir(cwd)
@with_app(buildername='latex')
def test_latex_add_latex_package(app, status, warning):
app.add_latex_package('foo')
app.builder.build_all()
assert '\\usepackage{foo}' in (app.outdir / 'SphinxTests.tex').text()