#2680: sphinx.ext.todo now emits warnings if todo_emit_warnings enabled

This commit is contained in:
Takeshi KOMIYA 2016-07-02 19:15:06 +09:00
parent 9e9eeaaf84
commit 253eef9e6a
8 changed files with 132 additions and 0 deletions

View File

@ -72,6 +72,10 @@ Features added
* math: Add hyperlink marker to each equations in HTML output
* Add new theme ``nonav`` that doesn't include any navigation links.
This is for any help generator like qthelp.
* #2680: `sphinx.ext.todo` now emits warnings if `todo_emit_warnings` enabled.
Also, it emits an additional event named `todo-defined` to handle the TODO
entries in 3rd party extensions.
Bugs fixed
----------

View File

@ -34,6 +34,13 @@ There is also an additional config value:
If this is ``True``, :rst:dir:`todo` and :rst:dir:`todolist` produce output,
else they produce nothing. The default is ``False``.
.. confval:: todo_emit_warnings
If this is ``True``, :rst:dir:`todo` emits a warning for each TODO entries.
The default is ``False``.
.. versionadded:: 1.5
.. confval:: todo_link_only
If this is ``True``, :rst:dir:`todolist` produce output without file path and line,
@ -41,3 +48,11 @@ There is also an additional config value:
.. versionadded:: 1.4
autodoc provides the following an additional event:
.. event:: todo-defined (app, node)
.. versionadded:: 1.5
Emitted when a todo is defined. *node* is the defined ``sphinx.ext.todo.todo_node``
node.

View File

@ -70,6 +70,8 @@ def process_todos(app, doctree):
if not hasattr(env, 'todo_all_todos'):
env.todo_all_todos = []
for node in doctree.traverse(todo_node):
app.emit('todo-defined', node)
try:
targetnode = node.parent[node.parent.index(node) - 1]
if not isinstance(targetnode, nodes.target):
@ -86,6 +88,9 @@ def process_todos(app, doctree):
'target': targetnode,
})
if env.config.todo_emit_warnings:
env.warn_node("TODO entry found: %s" % node[1].astext(), node)
class TodoList(Directive):
"""
@ -187,8 +192,10 @@ def depart_todo_node(self, node):
def setup(app):
app.add_event('todo-defined')
app.add_config_value('todo_include_todos', False, 'html')
app.add_config_value('todo_link_only', False, 'html')
app.add_config_value('todo_emit_warnings', False, 'html')
app.add_node(todolist)
app.add_node(todo_node,

View File

@ -0,0 +1,4 @@
bar
===
.. todo:: todo in bar

View File

@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
extensions = ['sphinx.ext.todo']
master_doc = 'index'

View File

@ -0,0 +1,4 @@
foo
===
.. todo:: todo in foo

View File

@ -0,0 +1,9 @@
test for sphinx.ext.todo
========================
.. toctree::
foo
bar
.. todolist::

85
tests/test_ext_todo.py Normal file
View File

@ -0,0 +1,85 @@
# -*- coding: utf-8 -*-
"""
test_ext_todo
~~~~~~~~~~~~~
Test sphinx.ext.todo extension.
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
import re
from util import with_app
@with_app('html', testroot='ext-todo', freshenv=True,
confoverrides={'todo_include_todos': True, 'todo_emit_warnings': True})
def test_todo(app, status, warning):
todos = []
def on_todo_defined(app, node):
todos.append(node)
app.connect('todo-defined', on_todo_defined)
app.builder.build_all()
# check todolist
content = (app.outdir / 'index.html').text()
html = ('<p class="first admonition-title">Todo</p>\n'
'<p class="last">todo in foo</p>')
assert re.search(html, content, re.S)
html = ('<p class="first admonition-title">Todo</p>\n'
'<p class="last">todo in bar</p>')
assert re.search(html, content, re.S)
# check todo
content = (app.outdir / 'foo.html').text()
html = ('<p class="first admonition-title">Todo</p>\n'
'<p class="last">todo in foo</p>')
assert re.search(html, content, re.S)
# check emitted warnings
assert 'WARNING: TODO entry found: todo in foo' in warning.getvalue()
assert 'WARNING: TODO entry found: todo in bar' in warning.getvalue()
# check handled event
assert len(todos) == 2
assert set(todo[1].astext() for todo in todos) == set(['todo in foo', 'todo in bar'])
@with_app('html', testroot='ext-todo', freshenv=True,
confoverrides={'todo_include_todos': False, 'todo_emit_warnings': True})
def test_todo_not_included(app, status, warning):
todos = []
def on_todo_defined(app, node):
todos.append(node)
app.connect('todo-defined', on_todo_defined)
app.builder.build_all()
# check todolist
content = (app.outdir / 'index.html').text()
html = ('<p class="first admonition-title">Todo</p>\n'
'<p class="last">todo in foo</p>')
assert not re.search(html, content, re.S)
html = ('<p class="first admonition-title">Todo</p>\n'
'<p class="last">todo in bar</p>')
assert not re.search(html, content, re.S)
# check todo
content = (app.outdir / 'foo.html').text()
html = ('<p class="first admonition-title">Todo</p>\n'
'<p class="last">todo in foo</p>')
assert not re.search(html, content, re.S)
# check emitted warnings
assert 'WARNING: TODO entry found: todo in foo' in warning.getvalue()
assert 'WARNING: TODO entry found: todo in bar' in warning.getvalue()
# check handled event
assert len(todos) == 2
assert set(todo[1].astext() for todo in todos) == set(['todo in foo', 'todo in bar'])