summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/markup/misc.rst7
-rw-r--r--sphinx/builders/html.py3
-rw-r--r--sphinx/directives/other.py43
-rw-r--r--sphinx/environment.py1
-rw-r--r--sphinx/ext/autodoc.py5
-rw-r--r--sphinx/ext/graphviz.py4
-rw-r--r--sphinx/highlighting.py2
-rw-r--r--sphinx/writers/latex.py3
-rw-r--r--tests/root/contents.txt1
-rw-r--r--tests/root/only.txt203
-rw-r--r--tests/test_autodoc.py13
-rw-r--r--tests/test_env.py1
-rw-r--r--tests/test_only_directive.py61
13 files changed, 332 insertions, 15 deletions
diff --git a/doc/markup/misc.rst b/doc/markup/misc.rst
index 3a2ffa32..f5eaac9c 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
diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py
index 81840374..f5218673 100644
--- a/sphinx/builders/html.py
+++ b/sphinx/builders/html.py
@@ -610,7 +610,8 @@ class StandaloneHTMLBuilder(Builder):
"""
Builder.post_process_images(self, doctree)
for node in doctree.traverse(nodes.image):
- if not node.has_key('scale') or \
+ scale_keys = ('scale', 'width', 'height')
+ if not any((key in node) for key in scale_keys) or \
isinstance(node.parent, nodes.reference):
# docutils does unfortunately not preserve the
# ``target`` attribute on images, so we need to check
diff --git a/sphinx/directives/other.py b/sphinx/directives/other.py
index aa4142d6..506d4be9 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):
diff --git a/sphinx/environment.py b/sphinx/environment.py
index a4bbbe3b..824d9c18 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
diff --git a/sphinx/ext/autodoc.py b/sphinx/ext/autodoc.py
index 9c6575f5..c15726b4 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/sphinx/ext/graphviz.py b/sphinx/ext/graphviz.py
index 4e72761e..bacd7248 100644
--- a/sphinx/ext/graphviz.py
+++ b/sphinx/ext/graphviz.py
@@ -229,10 +229,10 @@ def render_dot_html(self, node, code, options, prefix='graphviz',
(fname, alt, imgcss))
else:
# has a map: get the name of the map and connect the parts
- mapname = mapname_re.match(imgmap[0]).group(1)
+ mapname = mapname_re.match(imgmap[0].decode('utf-8')).group(1)
self.body.append('<img src="%s" alt="%s" usemap="#%s" %s/>\n' %
(fname, alt, mapname, imgcss))
- self.body.extend(imgmap)
+ self.body.extend([item.decode('utf-8') for item in imgmap])
if node.get('caption') and not inline:
self.body.append('</p>\n<p class="caption">')
self.body.append(self.encode(node['caption']))
diff --git a/sphinx/highlighting.py b/sphinx/highlighting.py
index 2f61c1ef..63464914 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,
diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py
index f2ebad36..e5ef3a61 100644
--- a/sphinx/writers/latex.py
+++ b/sphinx/writers/latex.py
@@ -100,7 +100,8 @@ class LaTeXWriter(writers.Writer):
class ExtBabel(Babel):
def get_shorthandoff(self):
shortlang = self.language.split('_')[0]
- if shortlang in ('de', 'sl', 'pt', 'es', 'nl', 'pl', 'it'):
+ if shortlang in ('de', 'ngerman', 'sl', 'slovene', 'pt', 'portuges', 'es', 'spanish',
+ 'nl', 'dutch', 'pl', 'polish', 'it', 'italian'):
return '\\shorthandoff{"}'
return ''
diff --git a/tests/root/contents.txt b/tests/root/contents.txt
index 280953b4..ad246cb7 100644
--- a/tests/root/contents.txt
+++ b/tests/root/contents.txt
@@ -27,6 +27,7 @@ Contents:
doctest
extensions
versioning/index
+ only
Python <http://python.org/>
diff --git a/tests/root/only.txt b/tests/root/only.txt
new file mode 100644
index 00000000..4a3eb48a
--- /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_autodoc.py b/tests/test_autodoc.py
index 965064c3..6dedaad8 100644
--- a/tests/test_autodoc.py
+++ b/tests/test_autodoc.py
@@ -519,6 +519,12 @@ def test_generate():
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_env.py b/tests/test_env.py
index e62db33b..2f75187f 100644
--- a/tests/test_env.py
+++ b/tests/test_env.py
@@ -54,6 +54,7 @@ def test_images():
tree = env.get_doctree('images')
app._warning.reset()
htmlbuilder = StandaloneHTMLBuilder(app)
+ htmlbuilder.imgpath = 'dummy'
htmlbuilder.post_process_images(tree)
image_uri_message = "no matching candidate for image URI u'foo.*'"
if sys.version_info >= (3, 0):
diff --git a/tests/test_only_directive.py b/tests/test_only_directive.py
new file mode 100644
index 00000000..2396046e
--- /dev/null
+++ b/tests/test_only_directive.py
@@ -0,0 +1,61 @@
+# -*- 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]
+ 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)]
+ 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])