diff --git a/doc/ext/autosummary.rst b/doc/ext/autosummary.rst index 8548fbd5e..d2e94e7da 100644 --- a/doc/ext/autosummary.rst +++ b/doc/ext/autosummary.rst @@ -158,7 +158,7 @@ is not supported.) may indicate that it's a better idea to write custom narrative documentation instead. -Autosummary uses the following template files: +Autosummary uses the following Jinja template files: - :file:`autosummary/base.rst` -- fallback template - :file:`autosummary/module.rst` -- template for modules @@ -194,7 +194,8 @@ The following variables available in the templates: .. data:: underline - A string containing ``len(full_name) * '='``. + A string containing ``len(full_name) * '='``. Use the ``underline`` filter + instead. .. data:: members @@ -227,7 +228,25 @@ The following variables available in the templates: List containing names of "public" attributes in the class. Only available for classes. + +Additionally, the following filters are available + +.. function:: escape(s) + + Escape any special characters in the text to be used in formatting RST + contexts. For instance, this prevents asterisks making things bolt. This + replaces the builtin Jinja `escape filter`_ that does html-escaping. + +.. function:: underline(s, line='=') + + Add a title underline to a piece of text. + +For instance, ``{{ fullname | escape | underline }}`` should be used to produce +the title of a page. + .. note:: You can use the :rst:dir:`autosummary` directive in the stub pages. Stub pages are generated also based on these directives. + +.. _`escape filter`: http://jinja.pocoo.org/docs/2.9/templates/#escape diff --git a/sphinx/ext/autosummary/generate.py b/sphinx/ext/autosummary/generate.py index 173c9ab08..b68846711 100644 --- a/sphinx/ext/autosummary/generate.py +++ b/sphinx/ext/autosummary/generate.py @@ -34,6 +34,7 @@ from sphinx.ext.autosummary import import_by_name, get_documenter from sphinx.jinja2glue import BuiltinTemplateLoader from sphinx.util.osutil import ensuredir from sphinx.util.inspect import safe_getattr +from sphinx.util.rst import escape as rst_escape # Add documenters to AutoDirective registry from sphinx.ext.autodoc import add_documenter, \ @@ -80,6 +81,12 @@ def _simple_warn(msg): print('WARNING: ' + msg, file=sys.stderr) +def _underline(title, line='='): + if '\n' in title: + raise ValueError('Can only underline single lines') + return title + '\n' + line * len(title) + + # -- Generating output --------------------------------------------------------- def generate_autosummary_docs(sources, output_dir=None, suffix='.rst', @@ -110,6 +117,11 @@ def generate_autosummary_docs(sources, output_dir=None, suffix='.rst', template_dirs.insert(0, template_dir) template_loader = FileSystemLoader(template_dirs) template_env = SandboxedEnvironment(loader=template_loader) + template_env.filters['underline'] = _underline + + # replace the builtin html filters + template_env.filters['escape'] = rst_escape + template_env.filters['e'] = rst_escape # read items = find_autosummary_in_files(sources) diff --git a/sphinx/ext/autosummary/templates/autosummary/base.rst b/sphinx/ext/autosummary/templates/autosummary/base.rst index 21a0ccd83..b7556ebf7 100644 --- a/sphinx/ext/autosummary/templates/autosummary/base.rst +++ b/sphinx/ext/autosummary/templates/autosummary/base.rst @@ -1,5 +1,4 @@ -{{ fullname }} -{{ underline }} +{{ fullname | escape | underline}} .. currentmodule:: {{ module }} diff --git a/sphinx/ext/autosummary/templates/autosummary/class.rst b/sphinx/ext/autosummary/templates/autosummary/class.rst index 40494dadb..8861b79a9 100644 --- a/sphinx/ext/autosummary/templates/autosummary/class.rst +++ b/sphinx/ext/autosummary/templates/autosummary/class.rst @@ -1,5 +1,4 @@ -{{ fullname }} -{{ underline }} +{{ fullname | escape | underline}} .. currentmodule:: {{ module }} diff --git a/sphinx/ext/autosummary/templates/autosummary/module.rst b/sphinx/ext/autosummary/templates/autosummary/module.rst index c14456ba1..6ec89e05e 100644 --- a/sphinx/ext/autosummary/templates/autosummary/module.rst +++ b/sphinx/ext/autosummary/templates/autosummary/module.rst @@ -1,5 +1,4 @@ -{{ fullname }} -{{ underline }} +{{ fullname | escape | underline}} .. automodule:: {{ fullname }} diff --git a/tests/roots/test-autosummary/contents.rst b/tests/roots/test-autosummary/contents.rst index 0355c95b2..5ddc4bd40 100644 --- a/tests/roots/test-autosummary/contents.rst +++ b/tests/roots/test-autosummary/contents.rst @@ -4,4 +4,5 @@ :toctree: dummy_module + underscore_module_ sphinx diff --git a/tests/roots/test-autosummary/underscore_module_.py b/tests/roots/test-autosummary/underscore_module_.py new file mode 100644 index 000000000..c3da50542 --- /dev/null +++ b/tests/roots/test-autosummary/underscore_module_.py @@ -0,0 +1,12 @@ +""" +module with trailing underscores everywhere +""" +class class_(object): + """ Class """ + def method_(_arg): + """ Method """ + pass + +def function_(_arg): + """ Function """ + pass diff --git a/tests/test_ext_autosummary.py b/tests/test_ext_autosummary.py index 434664928..146acb8eb 100644 --- a/tests/test_ext_autosummary.py +++ b/tests/test_ext_autosummary.py @@ -13,6 +13,8 @@ from six import iteritems, StringIO from sphinx.ext.autosummary import mangle_signature +from util import etree_parse + import pytest html_warnfile = StringIO() @@ -103,3 +105,24 @@ def test_get_items_summary(app, status, warning): 'Test function take an argument ended with underscore.', 'dummy_module.func') assert autosummary_items['func'] == func_attrs + +def str_content(elem): + if elem.text is not None: + return elem.text + else: + return ''.join(str_content(e) for e in elem) + +@pytest.mark.sphinx('xml', **default_kw) +def test_escaping(app, status, warning): + from xml.etree import ElementTree + + app.builder.build_all() + + outdir = app.builder.outdir + + docpage = outdir / 'underscore_module_.xml' + assert docpage.exists() + + title = etree_parse(docpage).find('section/title') + + assert str_content(title) == 'underscore_module_'