diff --git a/CHANGES b/CHANGES index 546e06a74..c35d002e8 100644 --- a/CHANGES +++ b/CHANGES @@ -10,6 +10,10 @@ Features added 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/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.,:: 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/ext/napoleon/docstring.py b/sphinx/ext/napoleon/docstring.py index fa3c65bf5..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*(?= 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/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..d75a29454 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 @@ -156,6 +158,7 @@ def test_literal_include_lineno_match(app, status, warning): lines = ( '
'
+        '5\n'
         '6\n'
         '7\n'
         '8\n'
@@ -164,14 +167,29 @@ def test_literal_include_lineno_match(app, status, warning):
 
     start_after = (
         '
'
+        ' 8\n'
         ' 9\n'
         '10\n'
         '11\n'
         '12\n'
-        '13
') + '13\n' + '14
') 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') diff --git a/tests/test_ext_napoleon_docstring.py b/tests/test_ext_napoleon_docstring.py index 0271391a5..bfd067ade 100644 --- a/tests/test_ext_napoleon_docstring.py +++ b/tests/test_ext_napoleon_docstring.py @@ -326,6 +326,71 @@ 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) + + def test_colon_in_return_type(self): + docstring = """Example property. + +Returns: + :py:class:`~.module.submodule.SomeClass`: an example instance + if available, None if not available. +""" + expected = """Example property. + +:returns: an example instance + if available, None if not available. +:rtype: :py:class:`~.module.submodule.SomeClass` +""" + actual = str(GoogleDocstring(docstring)) + self.assertEqual(expected, actual) + + def test_kwargs_in_arguments(self): + docstring = """Allows to create attributes binded to this device. + +Some other paragraph. + +Code sample for usage:: + + dev.bind(loopback=Loopback) + dev.loopback.configure() + +Arguments: + **kwargs: name/class pairs that will create resource-managers + bound as instance attributes to this instance. See code + example above. +""" + expected = """Allows to create attributes binded to this device. + +Some other paragraph. + +Code sample for usage:: + + dev.bind(loopback=Loopback) + dev.loopback.configure() + +:param \\*\\*kwargs: name/class pairs that will create resource-managers + bound as instance attributes to this instance. See code + example above. +""" + actual = str(GoogleDocstring(docstring)) + self.assertEqual(expected, actual) + class NumpyDocstringTest(BaseDocstringTest): docstrings = [( @@ -588,3 +653,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)