From c7bee16c8a8d874bfa145bd37b0ba6a7a670546f Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Fri, 24 Jul 2015 16:30:48 +0200 Subject: [PATCH 1/6] Closes #1871: fix for latex writer with multirow and 1-column tables. --- sphinx/writers/latex.py | 1 + tests/root/markup.txt | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index 62f8a5284..c1ba04cab 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -874,6 +874,7 @@ class LaTeXTranslator(nodes.NodeVisitor): self.body.append('\\\\\n') if any(self.remember_multirow.values()): linestart = 1 + col = self.table.colcount for col in range(1, self.table.col + 1): if self.remember_multirow.get(col): if linestart != col: diff --git a/tests/root/markup.txt b/tests/root/markup.txt index de1bcaecb..9e8c6bc86 100644 --- a/tests/root/markup.txt +++ b/tests/root/markup.txt @@ -187,7 +187,7 @@ Tables | 2 | Empty cells: | | +----+----------------+----+ -Table with multirow and multicol: +Tables with multirow and multicol: .. only:: latex @@ -199,6 +199,12 @@ Table with multirow and multicol: | x | multi-column cell | x | +----+---------------------+----+ + +----+ + | 1 | + + + + | | + +----+ + Figures ------- From 1b8afbb34348327ffd8b5d8dec400da6803fb81b Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Fri, 24 Jul 2015 16:34:11 +0200 Subject: [PATCH 2/6] some changelog entries --- CHANGES | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index da6050cbc..16767c362 100644 --- a/CHANGES +++ b/CHANGES @@ -26,7 +26,10 @@ Bugs fixed * #1822, #1892: Fix regression for #1061. autosummary can't generate doc for imported members since sphinx-1.3b3. Thanks to Eric Larson. * #1793, #1819: "see also" misses a linebreak in text output. Thanks to Takayuki Hirai. -* #1780, #1866: "make text" shows "class" keyword twice. Thanks to Takayuki Hirai. +* #1780, #1866: "make text" shows "class" keyword twice. Thanks to Takayuki + Hirai. +* #1871: Fix for LaTeX output of tables with one column and multirows. +* Work around the lack of the HTMLParserError exception in Python 3.5. Release 1.3.1 (released Mar 17, 2015) From 6b6d3dbea9f37602aefed545e6487a5fe87f677b Mon Sep 17 00:00:00 2001 From: Rob Ruana Date: Fri, 24 Jul 2015 11:30:35 -0700 Subject: [PATCH 3/6] Closes #1840: [Napoleon] Fixes Google style parsing to only match section headers ending with exactly one colon --- sphinx/ext/napoleon/docstring.py | 8 +- tests/test_ext_napoleon_docstring.py | 126 +++++++++++++++++++++++++++ 2 files changed, 131 insertions(+), 3 deletions(-) diff --git a/sphinx/ext/napoleon/docstring.py b/sphinx/ext/napoleon/docstring.py index ae0ab31db..0cc1f96f1 100644 --- a/sphinx/ext/napoleon/docstring.py +++ b/sphinx/ext/napoleon/docstring.py @@ -23,7 +23,9 @@ from sphinx.util.pycompat import UnicodeMixin _directive_regex = re.compile(r'\.\. \S+::') +_google_section_regex = re.compile(r'^(\s|\w)+:\s*$') _google_typed_arg_regex = re.compile(r'\s*(.+?)\s*\(\s*(.+?)\s*\)') +_numpy_section_regex = re.compile(r'^[=\-`:\'"~^_*+#<>]{2,}\s*$') _xref_regex = re.compile(r'(:\w+:\S+:`.+?`|:\S+:`.+?`|`.+?`)') @@ -381,7 +383,8 @@ class GoogleDocstring(UnicodeMixin): def _is_section_header(self): section = self._line_iter.peek().lower() - if section.strip(':') in self._sections: + match = _google_section_regex.match(section) + if match and section.strip(':') in self._sections: header_indent = self._get_indent(section) section_indent = self._get_current_indent(peek_ahead=1) return section_indent > header_indent @@ -769,8 +772,7 @@ class NumpyDocstring(GoogleDocstring): section, underline = self._line_iter.peek(2) section = section.lower() if section in self._sections and isinstance(underline, string_types): - pattern = r'[=\-`:\'"~^_*+#<>]{' + str(len(section)) + r'}$' - return bool(re.match(pattern, underline)) + return bool(_numpy_section_regex.match(underline)) elif self._directive_sections: if _directive_regex.match(section): for directive_section in self._directive_sections: diff --git a/tests/test_ext_napoleon_docstring.py b/tests/test_ext_napoleon_docstring.py index 0543d0846..81707c2e1 100644 --- a/tests/test_ext_napoleon_docstring.py +++ b/tests/test_ext_napoleon_docstring.py @@ -576,6 +576,60 @@ Code sample for usage:: actual = str(GoogleDocstring(docstring)) self.assertEqual(expected, actual) + def test_section_header_formatting(self): + docstrings = [(""" +Summary line + +Example: + Multiline reStructuredText + literal code block + +""", """ +Summary line + +.. rubric:: Example + +Multiline reStructuredText +literal code block +"""), + ################################ + (""" +Summary line + +Example:: + + Multiline reStructuredText + literal code block + +""", """ +Summary line + +Example:: + + Multiline reStructuredText + literal code block +"""), + ################################ + (""" +Summary line + +:Example: + + Multiline reStructuredText + literal code block + +""", """ +Summary line + +:Example: + + Multiline reStructuredText + literal code block +""")] + for docstring, expected in docstrings: + actual = str(GoogleDocstring(docstring)) + self.assertEqual(expected, actual) + class NumpyDocstringTest(BaseDocstringTest): docstrings = [( @@ -1095,3 +1149,75 @@ Example Function app = mock.Mock() actual = str(NumpyDocstring(docstring, config, app, "method")) self.assertEqual(expected, actual) + + def test_section_header_underline_length(self): + docstrings = [(""" +Summary line + +Example +- +Multiline example +body + +""", """ +Summary line + +Example +- +Multiline example +body +"""), + ################################ + (""" +Summary line + +Example +-- +Multiline example +body + +""", """ +Summary line + +.. rubric:: Example + +Multiline example +body +"""), + ################################ + (""" +Summary line + +Example +------- +Multiline example +body + +""", """ +Summary line + +.. rubric:: Example + +Multiline example +body +"""), + ################################ + (""" +Summary line + +Example +------------ +Multiline example +body + +""", """ +Summary line + +.. rubric:: Example + +Multiline example +body +""")] + for docstring, expected in docstrings: + actual = str(NumpyDocstring(docstring)) + self.assertEqual(expected, actual) From 21188120cc86e51654230988cfc39847d910a27a Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Fri, 24 Jul 2015 16:37:18 +0200 Subject: [PATCH 4/6] fix message when calling sphinx-build without arguments --- sphinx/cmdline.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/sphinx/cmdline.py b/sphinx/cmdline.py index e5335f47d..e411836c3 100644 --- a/sphinx/cmdline.py +++ b/sphinx/cmdline.py @@ -27,11 +27,6 @@ from sphinx.util.osutil import abspath, fs_encoding from sphinx.util.pycompat import terminal_safe -def usage(argv, msg=None): - if msg: - print(msg, file=sys.stderr) - print(file=sys.stderr) - USAGE = """\ Sphinx v%s Usage: %%prog [options] sourcedir outdir [filenames...] @@ -150,7 +145,7 @@ def main(argv): return 1 outdir = abspath(args[1]) except IndexError: - usage(argv, 'Error: Insufficient arguments.') + parser.print_help() return 1 except UnicodeError: print( From ae7e3afb4faaf616aa8042e86c1da3a8aebea3af Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Sat, 25 Jul 2015 09:32:52 +0200 Subject: [PATCH 5/6] Closes #1949: Use ``safe_getattr`` in the coverage builder to avoid aborting with descriptors that have custom behavior. --- CHANGES | 2 ++ sphinx/ext/coverage.py | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 16767c362..eae6d5059 100644 --- a/CHANGES +++ b/CHANGES @@ -30,6 +30,8 @@ Bugs fixed Hirai. * #1871: Fix for LaTeX output of tables with one column and multirows. * Work around the lack of the HTMLParserError exception in Python 3.5. +* #1949: Use ``safe_getattr`` in the coverage builder to avoid aborting with + descriptors that have custom behavior. Release 1.3.1 (released Mar 17, 2015) diff --git a/sphinx/ext/coverage.py b/sphinx/ext/coverage.py index 8e3ac1ae3..c564aeedd 100644 --- a/sphinx/ext/coverage.py +++ b/sphinx/ext/coverage.py @@ -20,6 +20,7 @@ from six.moves import cPickle as pickle import sphinx from sphinx.builders import Builder +from sphinx.util.inspect import safe_getattr # utility @@ -187,7 +188,10 @@ class CoverageBuilder(Builder): for attr_name in dir(obj): if attr_name not in obj.__dict__: continue - attr = getattr(obj, attr_name) + try: + attr = safe_getattr(obj, attr_name) + except AttributeError: + continue if not (inspect.ismethod(attr) or inspect.isfunction(attr)): continue From 657f6b16f00649842f57a9f6f4bd92190cea3d07 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Sat, 25 Jul 2015 12:35:52 +0200 Subject: [PATCH 6/6] Fixes #1915: Do not generate smart quotes in doc field type annotations. --- CHANGES | 1 + sphinx/util/docfields.py | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index eae6d5059..269401f96 100644 --- a/CHANGES +++ b/CHANGES @@ -32,6 +32,7 @@ Bugs fixed * Work around the lack of the HTMLParserError exception in Python 3.5. * #1949: Use ``safe_getattr`` in the coverage builder to avoid aborting with descriptors that have custom behavior. +* #1915: Do not generate smart quotes in doc field type annotations. Release 1.3.1 (released Mar 17, 2015) diff --git a/sphinx/util/docfields.py b/sphinx/util/docfields.py index c654fed32..d503ac58b 100644 --- a/sphinx/util/docfields.py +++ b/sphinx/util/docfields.py @@ -53,8 +53,8 @@ class Field(object): self.rolename = rolename self.bodyrolename = bodyrolename - def make_xref(self, rolename, domain, target, innernode=nodes.emphasis, - contnode=None): + def make_xref(self, rolename, domain, target, + innernode=addnodes.literal_emphasis, contnode=None): if not rolename: return contnode or innernode(target, target) refnode = addnodes.pending_xref('', refdomain=domain, refexplicit=False, @@ -159,7 +159,8 @@ class TypedField(GroupedField): fieldtype = types.pop(fieldarg) if len(fieldtype) == 1 and isinstance(fieldtype[0], nodes.Text): typename = u''.join(n.astext() for n in fieldtype) - par += self.make_xref(self.typerolename, domain, typename) + par += self.make_xref(self.typerolename, domain, typename, + addnodes.literal_emphasis) else: par += fieldtype par += nodes.Text(')')