Add Sphinx.add_enumerable_node() to add enumerable nodes for numfig feature

This commit is contained in:
Takeshi KOMIYA
2016-02-13 21:22:21 +09:00
parent 279ac7c23f
commit a391b1a1db
8 changed files with 135 additions and 0 deletions

View File

@@ -60,6 +60,7 @@ Features added
Also don't check anchors starting with ``!``. Also don't check anchors starting with ``!``.
* #2300: enhance autoclass:: to use the docstring of __new__ if __init__ method's is missing * #2300: enhance autoclass:: to use the docstring of __new__ if __init__ method's is missing
of empty of empty
* #1858: Add Sphinx.add_enumerable_node() to add enumerable nodes for numfig feature
Bugs fixed Bugs fixed
---------- ----------

View File

@@ -125,6 +125,18 @@ package.
.. versionchanged:: 0.5 .. versionchanged:: 0.5
Added the support for keyword arguments giving visit functions. Added the support for keyword arguments giving visit functions.
.. method:: Sphinx.add_enumerable_node(node, figtype, **kwds)
Register a Docutils node class as a numfig target. Sphinx treats the node as
figure, table or code-block. And then the node is numbered automatically.
*figtype* should be one of ``figure``, ``table`` or ``code-block``.
Other keyword arguments are used for node visitor functions. See the
:meth:`Sphinx.add_node` for details.
.. versionadded:: 1.4
.. method:: Sphinx.add_directive(name, func, content, arguments, **options) .. method:: Sphinx.add_directive(name, func, content, arguments, **options)
Sphinx.add_directive(name, directiveclass) Sphinx.add_directive(name, directiveclass)

View File

@@ -86,6 +86,7 @@ class Sphinx(object):
self.builderclasses = BUILTIN_BUILDERS.copy() self.builderclasses = BUILTIN_BUILDERS.copy()
self.builder = None self.builder = None
self.env = None self.env = None
self.enumerable_nodes = {}
self.srcdir = srcdir self.srcdir = srcdir
self.confdir = confdir self.confdir = confdir
@@ -193,6 +194,8 @@ class Sphinx(object):
self._init_env(freshenv) self._init_env(freshenv)
# set up the builder # set up the builder
self._init_builder(self.buildername) self._init_builder(self.buildername)
# set up the enumerable nodes
self._init_enumerable_nodes()
def _init_i18n(self): def _init_i18n(self):
"""Load translated strings from the configured localedirs if enabled in """Load translated strings from the configured localedirs if enabled in
@@ -264,6 +267,10 @@ class Sphinx(object):
self.builder = builderclass(self) self.builder = builderclass(self)
self.emit('builder-inited') self.emit('builder-inited')
def _init_enumerable_nodes(self):
for node, settings in iteritems(self.enumerable_nodes):
self.env.domains['std'].enumerable_nodes[node] = settings
# ---- main "build" method ------------------------------------------------- # ---- main "build" method -------------------------------------------------
def build(self, force_all=False, filenames=None): def build(self, force_all=False, filenames=None):
@@ -601,6 +608,10 @@ class Sphinx(object):
if depart: if depart:
setattr(translator, 'depart_'+node.__name__, depart) setattr(translator, 'depart_'+node.__name__, depart)
def add_enumerable_node(self, node, figtype, **kwds):
self.enumerable_nodes[node] = figtype
self.add_node(node, **kwds)
def _directive_helper(self, obj, content=None, arguments=None, **options): def _directive_helper(self, obj, content=None, arguments=None, **options):
if isinstance(obj, (types.FunctionType, types.MethodType)): if isinstance(obj, (types.FunctionType, types.MethodType)):
obj.content = content obj.content = content

View File

@@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
import os
import sys
sys.path.insert(0, os.path.abspath('.'))
extensions = ['test_enumerable_node']
master_doc = 'index'
numfig = True

View File

@@ -0,0 +1,38 @@
========================
test-add_enumerable_node
========================
.. toctree::
:numbered:
First section
=============
.. _first_figure:
.. figure:: rimg.png
First figure
.. _first_my_figure:
.. my-figure:: rimg.png
First my figure
Second section
==============
.. _second_my_figure:
.. my-figure:: rimg.png
Second my figure
Reference section
=================
* first_figure is :numref:`first_figure`
* first_my_figure is :numref:`first_my_figure`
* second_my_figure is :numref:`second_my_figure`

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 B

View File

@@ -0,0 +1,35 @@
# -*- coding: utf-8 -*-
from docutils import nodes
from docutils.parsers.rst import Directive
from sphinx.util.nodes import split_explicit_title
class my_figure(nodes.figure):
pass
def visit_my_figure(self, node):
self.visit_figure(node)
def depart_my_figure(self, node):
self.depart_figure(node)
class MyFigure(Directive):
required_arguments = 1
has_content = True
def run(self):
figure_node = my_figure()
figure_node += nodes.image(uri=self.arguments[0])
figure_node += nodes.caption(text=''.join(self.content))
return [figure_node]
def setup(app):
# my-figure
app.add_enumerable_node(my_figure, 'figure',
html=(visit_my_figure, depart_my_figure))
app.add_directive('my-figure', MyFigure)

View File

@@ -941,6 +941,34 @@ def test_numfig_with_secnum_depth(app, status, warning):
yield check_xpath, etree, fname, xpath, check, be_found yield check_xpath, etree, fname, xpath, check, be_found
@gen_with_app(buildername='html', testroot='add_enumerable_node')
def test_enumerable_node(app, status, warning):
app.builder.build_all()
expects = {
'index.html': [
(".//div[@class='figure']/p[@class='caption']/span[@class='caption-number']",
"Fig. 1", True),
(".//div[@class='figure']/p[@class='caption']/span[@class='caption-number']",
"Fig. 2", True),
(".//div[@class='figure']/p[@class='caption']/span[@class='caption-number']",
"Fig. 3", True),
(".//li/a/span", 'Fig. 1', True),
(".//li/a/span", 'Fig. 2', True),
(".//li/a/span", 'Fig. 3', True),
],
}
for fname, paths in iteritems(expects):
parser = NslessParser()
parser.entity.update(html_entities.entitydefs)
with (app.outdir / fname).open('rb') as fp:
etree = ET.parse(fp, parser)
for xpath, check, be_found in paths:
yield check_xpath, etree, fname, xpath, check, be_found
@with_app(buildername='html') @with_app(buildername='html')
def test_jsmath(app, status, warning): def test_jsmath(app, status, warning):
app.builder.build_all() app.builder.build_all()