From 14d738c45510bb5847ac7c3e5028f3b549675d75 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Sun, 19 Aug 2012 12:13:43 +0200 Subject: [PATCH 1/6] Closes #905: work around Pygments bug returning str instead of Unicode from Latex formatter for empty input. --- sphinx/highlighting.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sphinx/highlighting.py b/sphinx/highlighting.py index 2f61c1ef1..63464914a 100644 --- a/sphinx/highlighting.py +++ b/sphinx/highlighting.py @@ -207,6 +207,8 @@ class PygmentsBridge(object): if self.dest == 'html': return hlsource else: + if not isinstance(hlsource, unicode): # Py2 / Pygments < 1.6 + hlsource = hlsource.decode() return hlsource.translate(tex_hl_escape_map_new) except ErrorToken: # this is most probably not the selected language, From c5405184ba16bfcfc9a3e0f6d85b1aae858bb1f1 Mon Sep 17 00:00:00 2001 From: Jonathan Waltman Date: Wed, 12 Sep 2012 15:34:00 -0500 Subject: [PATCH 2/6] Add failing tests for nested sections in only directives. --- tests/root/contents.txt | 1 + tests/root/only.txt | 203 +++++++++++++++++++++++++++++++++++ tests/test_only_directive.py | 63 +++++++++++ 3 files changed, 267 insertions(+) create mode 100644 tests/root/only.txt create mode 100644 tests/test_only_directive.py diff --git a/tests/root/contents.txt b/tests/root/contents.txt index 280953b46..ad246cb77 100644 --- a/tests/root/contents.txt +++ b/tests/root/contents.txt @@ -27,6 +27,7 @@ Contents: doctest extensions versioning/index + only Python diff --git a/tests/root/only.txt b/tests/root/only.txt new file mode 100644 index 000000000..4a3eb48a6 --- /dev/null +++ b/tests/root/only.txt @@ -0,0 +1,203 @@ + +1. Sections in only directives +============================== + +Testing sections in only directives. + +.. only:: nonexisting_tag + + Skipped Section + --------------- + Should not be here. + +.. only:: not nonexisting_tag + + 1.1. Section + ------------ + Should be here. + +1.2. Section +------------ + +.. only:: not nonexisting_tag + + 1.2.1. Subsection + ~~~~~~~~~~~~~~~~~ + Should be here. + +.. only:: nonexisting_tag + + Skipped Subsection + ~~~~~~~~~~~~~~~~~~ + Should not be here. + +1.3. Section +------------ + +1.3.1. Subsection +~~~~~~~~~~~~~~~~~ +Should be here. + +1.4. Section +------------ + +.. only:: not nonexisting_tag + + 1.4.1. Subsection + ~~~~~~~~~~~~~~~~~ + Should be here. + +1.5. Section +------------ + +.. only:: not nonexisting_tag + + 1.5.1. Subsection + ~~~~~~~~~~~~~~~~~ + Should be here. + +1.5.2. Subsection +~~~~~~~~~~~~~~~~~ +Should be here. + +1.6. Section +------------ + +1.6.1. Subsection +~~~~~~~~~~~~~~~~~ +Should be here. + +.. only:: not nonexisting_tag + + 1.6.2. Subsection + ~~~~~~~~~~~~~~~~~ + Should be here. + +1.6.3. Subsection +~~~~~~~~~~~~~~~~~ +Should be here. + +1.7. Section +------------ + +1.7.1. Subsection +~~~~~~~~~~~~~~~~~ +Should be here. + +.. only:: not nonexisting_tag + + 1.7.1.1. Subsubsection + ...................... + Should be here. + +1.8. Section +------------ + +1.8.1. Subsection +~~~~~~~~~~~~~~~~~ +Should be here. + +1.8.1.1. Subsubsection +...................... +Should be here. + +.. only:: not nonexisting_tag + + 1.8.1.2. Subsubsection + ...................... + Should be here. + +1.9. Section +------------ + +.. only:: nonexisting_tag + + Skipped Subsection + ~~~~~~~~~~~~~~~~~~ + +1.9.1. Subsection +~~~~~~~~~~~~~~~~~ +Should be here. + +1.9.1.1. Subsubsection +...................... +Should be here. + +.. only:: not nonexisting_tag + + 1.10. Section + ------------- + Should be here. + +1.11. Section +------------- + +Text before subsection 11.1. + +.. only:: not nonexisting_tag + + More text before subsection 11.1. + + 1.11.1. Subsection + ~~~~~~~~~~~~~~~~~~ + Should be here. + +Text after subsection 11.1. + +.. only:: not nonexisting_tag + + 1.12. Section + ------------- + Should be here. + + 1.12.1. Subsection + ~~~~~~~~~~~~~~~~~~ + Should be here. + + 1.13. Section + ------------- + Should be here. + +.. only:: not nonexisting_tag + + 1.14. Section + ------------- + Should be here. + + .. only:: not nonexisting_tag + + 1.14.1. Subsection + ~~~~~~~~~~~~~~~~~~ + Should be here. + + 1.15. Section + ------------- + Should be here. + +.. only:: nonexisting_tag + + Skipped document level heading + ============================== + Should not be here. + +.. only:: not nonexisting_tag + + 2. Included document level heading + ================================== + Should be here. + +3. Document level heading +========================= +Should be here. + +.. only:: nonexisting_tag + + Skipped document level heading + ============================== + Should not be here. + +.. only:: not nonexisting_tag + + 4. Another included document level heading + ========================================== + Should be here. diff --git a/tests/test_only_directive.py b/tests/test_only_directive.py new file mode 100644 index 000000000..10683613c --- /dev/null +++ b/tests/test_only_directive.py @@ -0,0 +1,63 @@ +# -*- coding: utf-8 -*- +""" + test_only_directive + ~~~~~~~~~~~~~~~~~~~ + + Test the only directive with the test root. + + :copyright: Copyright 2010 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" + +import re + +from docutils import nodes + +from util import * + + +def teardown_module(): + (test_root / '_build').rmtree(True) + + +@with_app(buildername='text') +def test_sectioning(app): + + def getsects(section): + if not isinstance(section, nodes.section): + return [getsects(n) for n in section.children] + title = section.next_node(nodes.title).astext().strip() + subsects = [] + children = section.children[:] + while children: + node = children.pop(0) + if isinstance(node, nodes.section): + subsects.append(node) + continue + children = list(node.children) + children + return [title, [getsects(subsect) for subsect in subsects]] + + def testsects(prefix, sects, indent=0): + title = sects[0] + sprint(' ' * indent + title) + parent_num = title.split()[0] + assert prefix == parent_num, \ + 'Section out of place: %r' % title + for i, subsect in enumerate(sects[1]): + num = subsect[0].split()[0] + assert re.match('[0-9]+[.0-9]*[.]', num), \ + 'Unnumbered section: %r' % subsect[0] + testsects(prefix + str(i+1) + '.', subsect, indent+4) + + app.builder.build(['only']) + doctree = app.env.get_doctree('only') + app.env.process_only_nodes(doctree, app.builder) + + parts = [getsects(n) + for n in filter(lambda n: isinstance(n, nodes.section), + doctree.children)] + sprint('\nChecking headings in only.txt:') + for i, s in enumerate(parts): + testsects(str(i+1) + '.', s, 4) + assert len(parts) == 4, 'Expected 4 document level headings, got:\n%s' % \ + '\n'.join([p[0] for p in parts]) From 6654687ec19a446388b7799c1e11b361921c4f7b Mon Sep 17 00:00:00 2001 From: Jonathan Waltman Date: Wed, 12 Sep 2012 15:43:27 -0500 Subject: [PATCH 3/6] Closes #886: Fix handling of section headings in "only" directives. --- sphinx/directives/other.py | 43 +++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/sphinx/directives/other.py b/sphinx/directives/other.py index aa4142d6f..506d4be91 100644 --- a/sphinx/directives/other.py +++ b/sphinx/directives/other.py @@ -338,9 +338,46 @@ class Only(Directive): node.document = self.state.document set_source_info(self, node) node['expr'] = self.arguments[0] - self.state.nested_parse(self.content, self.content_offset, node, - match_titles=1) - return [node] + + # Same as util.nested_parse_with_titles but try to handle nested + # sections which should be raised higher up the doctree. + surrounding_title_styles = self.state.memo.title_styles + surrounding_section_level = self.state.memo.section_level + self.state.memo.title_styles = [] + self.state.memo.section_level = 0 + try: + result = self.state.nested_parse(self.content, self.content_offset, + node, match_titles=1) + title_styles = self.state.memo.title_styles + if (not surrounding_title_styles + or not title_styles + or title_styles[0] not in surrounding_title_styles + or not self.state.parent): + # No nested sections so no special handling needed. + return [node] + # Calculate the depths of the current and nested sections. + current_depth = 0 + parent = self.state.parent + while parent: + current_depth += 1 + parent = parent.parent + current_depth -= 2 + title_style = title_styles[0] + nested_depth = len(surrounding_title_styles) + if title_style in surrounding_title_styles: + nested_depth = surrounding_title_styles.index(title_style) + # Use these depths to determine where the nested sections should + # be placed in the doctree. + n_sects_to_raise = current_depth - nested_depth + 1 + parent = self.state.parent + for i in xrange(n_sects_to_raise): + if parent.parent: + parent = parent.parent + parent.append(node) + return [] + finally: + self.state.memo.title_styles = surrounding_title_styles + self.state.memo.section_level = surrounding_section_level class Include(BaseInclude): From ead356e3cfa974e715ae4b9954b3ae5aee44b24c Mon Sep 17 00:00:00 2001 From: Jonathan Waltman Date: Wed, 12 Sep 2012 16:40:10 -0500 Subject: [PATCH 4/6] Remove note about sectioning limitation of the "only" directive. --- doc/markup/misc.rst | 7 ------- 1 file changed, 7 deletions(-) diff --git a/doc/markup/misc.rst b/doc/markup/misc.rst index 3a2ffa32e..f5eaac9ce 100644 --- a/doc/markup/misc.rst +++ b/doc/markup/misc.rst @@ -182,13 +182,6 @@ Including content based on tags The format of the current builder (``html``, ``latex`` or ``text``) is always set as a tag. - .. note:: - - Due to docutils' specifics of parsing of directive content, you cannot put - a section with the same level as the main document heading inside an - ``only`` directive. Such sections will appear to be ignored in the parsed - document. - .. versionadded:: 0.6 From bf362e9ccbf03988116d1c55209ae17ec8c17117 Mon Sep 17 00:00:00 2001 From: Jonathan Waltman Date: Sun, 16 Sep 2012 01:08:47 -0500 Subject: [PATCH 5/6] Closes #617: Fix docstring preparation without included signature: only ignore indentation of one line, not two. --- sphinx/ext/autodoc.py | 5 ++++- tests/test_autodoc.py | 13 +++++++++++++ tests/test_only_directive.py | 2 -- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/sphinx/ext/autodoc.py b/sphinx/ext/autodoc.py index 9c6575f52..c15726b48 100644 --- a/sphinx/ext/autodoc.py +++ b/sphinx/ext/autodoc.py @@ -862,7 +862,7 @@ class DocstringSignatureMixin(object): """ def _find_signature(self, encoding=None): - docstrings = Documenter.get_doc(self, encoding, 2) + docstrings = Documenter.get_doc(self, encoding) if len(docstrings) != 1: return doclines = docstrings[0] @@ -877,6 +877,9 @@ class DocstringSignatureMixin(object): # the base name must match ours if not self.objpath or base != self.objpath[-1]: return + # re-prepare docstring to ignore indentation after signature + docstrings = Documenter.get_doc(self, encoding, 2) + doclines = docstrings[0] # ok, now jump over remaining empty lines and set the remaining # lines as the new doclines i = 1 diff --git a/tests/test_autodoc.py b/tests/test_autodoc.py index 965064c37..6dedaad8f 100644 --- a/tests/test_autodoc.py +++ b/tests/test_autodoc.py @@ -518,6 +518,12 @@ def test_generate(): 'test_autodoc.DocstringSig.meth') assert_result_contains( ' rest of docstring', 'method', 'test_autodoc.DocstringSig.meth') + assert_result_contains( + '.. py:method:: DocstringSig.meth2()', 'method', + 'test_autodoc.DocstringSig.meth2') + assert_result_contains( + ' indented line', 'method', + 'test_autodoc.DocstringSig.meth2') assert_result_contains( '.. py:classmethod:: Class.moore(a, e, f) -> happiness', 'method', 'test_autodoc.Class.moore') @@ -660,6 +666,13 @@ First line of docstring rest of docstring """ + def meth2(self): + """First line, no signature + Second line followed by indentation:: + + indented line + """ + class StrRepr(str): def __repr__(self): return self diff --git a/tests/test_only_directive.py b/tests/test_only_directive.py index 10683613c..2396046e4 100644 --- a/tests/test_only_directive.py +++ b/tests/test_only_directive.py @@ -39,7 +39,6 @@ def test_sectioning(app): def testsects(prefix, sects, indent=0): title = sects[0] - sprint(' ' * indent + title) parent_num = title.split()[0] assert prefix == parent_num, \ 'Section out of place: %r' % title @@ -56,7 +55,6 @@ def test_sectioning(app): parts = [getsects(n) for n in filter(lambda n: isinstance(n, nodes.section), doctree.children)] - sprint('\nChecking headings in only.txt:') for i, s in enumerate(parts): testsects(str(i+1) + '.', s, 4) assert len(parts) == 4, 'Expected 4 document level headings, got:\n%s' % \ From ad6318e7f16e61ae694a5ffa87b1c7f4497c3698 Mon Sep 17 00:00:00 2001 From: Jonathan Waltman Date: Tue, 2 Oct 2012 20:53:40 -0500 Subject: [PATCH 6/6] Closes #1004: Add default value for docutils setting file_insertion_enabled. --- sphinx/environment.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sphinx/environment.py b/sphinx/environment.py index a4bbbe3b9..824d9c184 100644 --- a/sphinx/environment.py +++ b/sphinx/environment.py @@ -66,6 +66,7 @@ default_settings = { 'doctitle_xform': False, 'sectsubtitle_xform': False, 'halt_level': 5, + 'file_insertion_enabled': True, } # This is increased every time an environment attribute is added