From 82345f5c11cab5fac0378af80b690795cf78451f Mon Sep 17 00:00:00 2001 From: Lukas Prokop Date: Sun, 22 Mar 2015 11:28:25 +0100 Subject: [PATCH 1/5] speicifer -> specifier --- doc/domains.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/domains.rst b/doc/domains.rst index 2e85841e6..a29481638 100644 --- a/doc/domains.rst +++ b/doc/domains.rst @@ -524,7 +524,7 @@ The C++ domain (name **cpp**) supports documenting C++ projects. The following directives are available. All declarations can start with a visibility statement (``public``, ``private`` or ``protected``). -.. rst:directive:: .. cpp:class:: class speicifer +.. rst:directive:: .. cpp:class:: class specifier Describe a class/struct, possibly with specification of inheritance, e.g.,:: From 0215b1fb108ab3a78af41375c69eac84722022c1 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 29 Mar 2015 10:31:26 +0900 Subject: [PATCH 2/5] Fix #1789 `:pyobject:` option of `literalinclude` directive includes following lines after definitions --- CHANGES | 3 +++ sphinx/pycode/__init__.py | 17 ++++++++++++++--- tests/roots/test-directive-code/literal.inc | 1 + tests/test_directive_code.py | 9 ++++++--- 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/CHANGES b/CHANGES index 546e06a74..1dddeff0f 100644 --- a/CHANGES +++ b/CHANGES @@ -10,6 +10,9 @@ Features added Bugs fixed ---------- +* #1789: ``:pyobject:`` option of ``literalinclude`` directive includes following + lines after class definitions + Documentation ------------- diff --git a/sphinx/pycode/__init__.py b/sphinx/pycode/__init__.py index ec05c7bf7..57707e9d0 100644 --- a/sphinx/pycode/__init__.py +++ b/sphinx/pycode/__init__.py @@ -10,6 +10,7 @@ """ from __future__ import print_function +import re import sys from os import path @@ -45,6 +46,8 @@ number2name.update(token.tok_name) _eq = nodes.Leaf(token.EQUAL, '=') +emptyline_re = re.compile('^\s*(#.*)?$') + class AttrDocVisitor(nodes.NodeVisitor): """ @@ -289,8 +292,9 @@ class ModuleAnalyzer(object): indent = 0 defline = False expect_indent = False + emptylines = 0 - def tokeniter(ignore = (token.COMMENT, token.NL)): + def tokeniter(ignore = (token.COMMENT,)): for tokentup in self.tokens: if tokentup[0] not in ignore: yield tokentup @@ -303,7 +307,7 @@ class ModuleAnalyzer(object): dtype, fullname, startline, _ = stack.pop() endline = epos[0] namespace.pop() - result[fullname] = (dtype, startline, endline) + result[fullname] = (dtype, startline, endline - emptylines) expect_indent = False if tok in ('def', 'class'): name = next(tokeniter)[1] @@ -322,7 +326,7 @@ class ModuleAnalyzer(object): dtype, fullname, startline, _ = stack.pop() endline = spos[0] namespace.pop() - result[fullname] = (dtype, startline, endline) + result[fullname] = (dtype, startline, endline - emptylines) elif type == token.NEWLINE: # if this line contained a definition, expect an INDENT # to start the suite; if there is no such INDENT @@ -330,6 +334,13 @@ class ModuleAnalyzer(object): if defline: defline = False expect_indent = True + emptylines = 0 + elif type == token.NL: + # count up if line is empty or comment only + if emptyline_re.match(line): + emptylines += 1 + else: + emptylines = 0 self.tags = result return result diff --git a/tests/roots/test-directive-code/literal.inc b/tests/roots/test-directive-code/literal.inc index 694f15ed9..a590f557b 100644 --- a/tests/roots/test-directive-code/literal.inc +++ b/tests/roots/test-directive-code/literal.inc @@ -10,4 +10,5 @@ class Bar: def baz(): pass +# comment after Bar class definition def bar(): pass diff --git a/tests/test_directive_code.py b/tests/test_directive_code.py index ba4687cc0..c09f97986 100644 --- a/tests/test_directive_code.py +++ b/tests/test_directive_code.py @@ -116,7 +116,8 @@ def test_literal_include_linenos(app, status, warning): '10\n' '11\n' '12\n' - '13') + '13\n' + '14') assert linenos in html @@ -138,7 +139,8 @@ def test_literal_include_lineno_start(app, status, warning): '209\n' '210\n' '211\n' - '212') + '212\n' + '213') assert linenos in html @@ -168,7 +170,8 @@ def test_literal_include_lineno_match(app, status, warning): '10\n' '11\n' '12\n' - '13') + '13\n' + '14') assert start_after in html From 0b60eafe0ec690c8844bc881810b2728b627a343 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 30 Mar 2015 20:34:00 +0900 Subject: [PATCH 3/5] Fix #1790 literalinclude strips empty lines at the head and tail --- CHANGES | 1 + sphinx/directives/code.py | 9 --------- sphinx/highlighting.py | 12 ++++++------ sphinx/writers/latex.py | 3 +-- tests/roots/test-directive-code/empty.inc | 3 +++ tests/roots/test-directive-code/lineno_match.rst | 3 +++ tests/test_directive_code.py | 15 +++++++++++++++ 7 files changed, 29 insertions(+), 17 deletions(-) create mode 100644 tests/roots/test-directive-code/empty.inc diff --git a/CHANGES b/CHANGES index 1dddeff0f..c35d002e8 100644 --- a/CHANGES +++ b/CHANGES @@ -12,6 +12,7 @@ Bugs fixed * #1789: ``:pyobject:`` option of ``literalinclude`` directive includes following lines after class definitions +* #1790: ``literalinclude`` strips empty lines at the head and tail Documentation ------------- diff --git a/sphinx/directives/code.py b/sphinx/directives/code.py index 5043a31e4..f31ba7a99 100644 --- a/sphinx/directives/code.py +++ b/sphinx/directives/code.py @@ -302,15 +302,6 @@ class LiteralInclude(Directive): res.append(line) lines = res - if 'lineno-match' in self.options: - # handle that docutils remove preceding lines which only contains - # line separation. - for line in lines: - # check if line contains anything else than line separation. - if line and line.splitlines()[0]: - break - linenostart += 1 - prepend = self.options.get('prepend') if prepend: lines.insert(0, prepend + '\n') diff --git a/sphinx/highlighting.py b/sphinx/highlighting.py index 57a841899..dd40bc308 100644 --- a/sphinx/highlighting.py +++ b/sphinx/highlighting.py @@ -35,12 +35,12 @@ from pygments.util import ClassNotFound from sphinx.pygments_styles import SphinxStyle, NoneStyle lexers = dict( - none = TextLexer(), - python = PythonLexer(), - pycon = PythonConsoleLexer(), - pycon3 = PythonConsoleLexer(python3=True), - rest = RstLexer(), - c = CLexer(), + none = TextLexer(stripnl=False), + python = PythonLexer(stripnl=False), + pycon = PythonConsoleLexer(stripnl=False), + pycon3 = PythonConsoleLexer(python3=True, stripnl=False), + rest = RstLexer(stripnl=False), + c = CLexer(stripnl=False), ) for _lexer in lexers.values(): _lexer.add_filter('raiseonerror') diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index 2940e4eb1..ffa8ae874 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -1542,7 +1542,7 @@ class LaTeXTranslator(nodes.NodeVisitor): # most probably a parsed-literal block -- don't highlight self.body.append('\\begin{alltt}\n') else: - code = node.astext().rstrip('\n') + code = node.astext() lang = self.hlsettingstack[-1][0] linenos = code.count('\n') >= self.hlsettingstack[-1][1] - 1 highlight_args = node.get('highlight_args', {}) @@ -1573,7 +1573,6 @@ class LaTeXTranslator(nodes.NodeVisitor): self.table.has_verbatim = True # get consistent trailer hlcode = hlcode.rstrip()[:-14] # strip \end{Verbatim} - hlcode = hlcode.rstrip() + '\n' self.body.append('\n' + hlcode + '\\end{%sVerbatim}\n' % (self.table and 'Original' or '')) raise nodes.SkipNode diff --git a/tests/roots/test-directive-code/empty.inc b/tests/roots/test-directive-code/empty.inc new file mode 100644 index 000000000..b28b04f64 --- /dev/null +++ b/tests/roots/test-directive-code/empty.inc @@ -0,0 +1,3 @@ + + + diff --git a/tests/roots/test-directive-code/lineno_match.rst b/tests/roots/test-directive-code/lineno_match.rst index 4e3b38357..1015c8df7 100644 --- a/tests/roots/test-directive-code/lineno_match.rst +++ b/tests/roots/test-directive-code/lineno_match.rst @@ -15,3 +15,6 @@ Literal Includes with Line Numbers Matching :language: python :start-after: pass :lineno-match: + +.. literalinclude:: empty.inc + :lineno-match: diff --git a/tests/test_directive_code.py b/tests/test_directive_code.py index c09f97986..d75a29454 100644 --- a/tests/test_directive_code.py +++ b/tests/test_directive_code.py @@ -158,6 +158,7 @@ def test_literal_include_lineno_match(app, status, warning): lines = ( '
'
+        '5\n'
         '6\n'
         '7\n'
         '8\n'
@@ -166,6 +167,7 @@ def test_literal_include_lineno_match(app, status, warning):
 
     start_after = (
         '
'
+        ' 8\n'
         ' 9\n'
         '10\n'
         '11\n'
@@ -175,6 +177,19 @@ def test_literal_include_lineno_match(app, status, warning):
     assert start_after in html
 
 
+@with_app('latex', testroot='directive-code')
+def test_literalinclude_file_whole_of_emptyline(app, status, warning):
+    app.builder.build_all()
+    latex = (app.outdir / 'Python.tex').text()
+    includes = (
+        '\\begin{Verbatim}[commandchars=\\\\\\{\\},numbers=left,firstnumber=1,stepnumber=1]\n'
+        '\n'
+        '\n'
+        '\n'
+        '\\end{Verbatim}\n')
+    assert includes in latex
+
+
 @with_app('html', testroot='directive-code')
 def test_literalinclude_caption_html(app, status, warning):
     app.builder.build('index')

From 80eb821ec81840b79ed517cb5f73aff7df0c79d0 Mon Sep 17 00:00:00 2001
From: Rob Ruana 
Date: Fri, 3 Apr 2015 21:32:05 -0400
Subject: [PATCH 4/5] Closes #1831: [Napoleon] If name is not found in NumPy
 Doc Returns section, regard the whole line as the type

---
 sphinx/ext/napoleon/docstring.py     |  2 +
 tests/test_ext_napoleon_docstring.py | 61 ++++++++++++++++++++++++++++
 2 files changed, 63 insertions(+)

diff --git a/sphinx/ext/napoleon/docstring.py b/sphinx/ext/napoleon/docstring.py
index fa3c65bf5..e893226dc 100644
--- a/sphinx/ext/napoleon/docstring.py
+++ b/sphinx/ext/napoleon/docstring.py
@@ -720,6 +720,8 @@ class NumpyDocstring(GoogleDocstring):
         line = next(self._line_iter)
         if parse_type:
             _name, _, _type = line.partition(':')
+            if not _name:
+                _type = line
         else:
             _name, _type = line, ''
         _name, _type = _name.strip(), _type.strip()
diff --git a/tests/test_ext_napoleon_docstring.py b/tests/test_ext_napoleon_docstring.py
index 0271391a5..20852e6e4 100644
--- a/tests/test_ext_napoleon_docstring.py
+++ b/tests/test_ext_napoleon_docstring.py
@@ -326,6 +326,24 @@ Attributes:
 """
         self.assertEqual(expected, actual)
 
+    def test_code_block_in_returns_section(self):
+        docstring = """
+Returns:
+    foobar: foo::
+
+        codecode
+        codecode
+"""
+        expected = """
+:returns: foo::
+
+              codecode
+              codecode
+:rtype: foobar
+"""
+        actual = str(GoogleDocstring(docstring))
+        self.assertEqual(expected, actual)
+
 
 class NumpyDocstringTest(BaseDocstringTest):
     docstrings = [(
@@ -588,3 +606,46 @@ numpy.multivariate_normal(mean, cov, shape=None, spam=None)
        relationship
 """
         self.assertEqual(expected, actual)
+
+    def test_colon_in_return_type(self):
+        docstring = """
+Summary
+
+Returns
+-------
+:py:class:`~my_mod.my_class`
+    an instance of :py:class:`~my_mod.my_class`
+"""
+
+        expected = """
+Summary
+
+:returns: an instance of :py:class:`~my_mod.my_class`
+:rtype: :py:class:`~my_mod.my_class`
+"""
+
+        config = Config()
+        app = mock.Mock()
+        actual = str(NumpyDocstring(docstring, config, app, "method"))
+
+        self.assertEqual(expected, actual)
+
+    def test_underscore_in_attribute(self):
+        docstring = """
+Attributes
+----------
+
+arg_ : type
+    some description
+"""
+
+        expected = """
+:ivar arg_: some description
+:vartype arg_: type
+"""
+
+        config = Config(napoleon_use_ivar=True)
+        app = mock.Mock()
+        actual = str(NumpyDocstring(docstring, config, app, "class"))
+
+        self.assertEqual(expected, actual)

From 42f2b305791507e6bfe9507832daefc5071969cd Mon Sep 17 00:00:00 2001
From: Rob Ruana 
Date: Sun, 3 May 2015 16:28:39 -0700
Subject: [PATCH 5/5] Closes #1831: [Napoleon] Makes google type regex greedy
 to consume entire type, even if it contains colons

---
 sphinx/ext/napoleon/docstring.py     | 24 +++++++-------
 tests/test_ext_napoleon_docstring.py | 47 ++++++++++++++++++++++++++++
 2 files changed, 59 insertions(+), 12 deletions(-)

diff --git a/sphinx/ext/napoleon/docstring.py b/sphinx/ext/napoleon/docstring.py
index e893226dc..1ac7d869f 100644
--- a/sphinx/ext/napoleon/docstring.py
+++ b/sphinx/ext/napoleon/docstring.py
@@ -23,8 +23,8 @@ from sphinx.util.pycompat import UnicodeMixin
 
 
 _directive_regex = re.compile(r'\.\. \S+::')
-_google_untyped_arg_regex = re.compile(r'\s*(.+?)\s*:\s*(.*)')
-_google_typed_arg_regex = re.compile(r'\s*(.+?)\s*\(\s*(.+?)\s*\)\s*:\s*(.*)')
+_google_untyped_arg_regex = re.compile(r'(.+)\s*(?