mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
c0bc64f9fe
4
CHANGES
4
CHANGES
@ -10,6 +10,10 @@ Features added
|
|||||||
Bugs fixed
|
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
|
Documentation
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
|
@ -524,7 +524,7 @@ The C++ domain (name **cpp**) supports documenting C++ projects.
|
|||||||
The following directives are available. All declarations can start with
|
The following directives are available. All declarations can start with
|
||||||
a visibility statement (``public``, ``private`` or ``protected``).
|
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.,::
|
Describe a class/struct, possibly with specification of inheritance, e.g.,::
|
||||||
|
|
||||||
|
@ -302,15 +302,6 @@ class LiteralInclude(Directive):
|
|||||||
res.append(line)
|
res.append(line)
|
||||||
lines = res
|
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')
|
prepend = self.options.get('prepend')
|
||||||
if prepend:
|
if prepend:
|
||||||
lines.insert(0, prepend + '\n')
|
lines.insert(0, prepend + '\n')
|
||||||
|
@ -23,8 +23,8 @@ from sphinx.util.pycompat import UnicodeMixin
|
|||||||
|
|
||||||
|
|
||||||
_directive_regex = re.compile(r'\.\. \S+::')
|
_directive_regex = re.compile(r'\.\. \S+::')
|
||||||
_google_untyped_arg_regex = re.compile(r'\s*(.+?)\s*:\s*(.*)')
|
_google_untyped_arg_regex = re.compile(r'(.+)\s*(?<!:):(?!:)\s*(.*)')
|
||||||
_google_typed_arg_regex = re.compile(r'\s*(.+?)\s*\(\s*(.+?)\s*\)\s*:\s*(.*)')
|
_google_typed_arg_regex = re.compile(r'(.+)\((.+)\)\s*(?<!:):(?!:)\s*(.*)')
|
||||||
|
|
||||||
|
|
||||||
class GoogleDocstring(UnicodeMixin):
|
class GoogleDocstring(UnicodeMixin):
|
||||||
@ -207,15 +207,15 @@ class GoogleDocstring(UnicodeMixin):
|
|||||||
if parse_type:
|
if parse_type:
|
||||||
match = _google_typed_arg_regex.match(line)
|
match = _google_typed_arg_regex.match(line)
|
||||||
if match:
|
if match:
|
||||||
_name = match.group(1)
|
_name = match.group(1).strip()
|
||||||
_type = match.group(2)
|
_type = match.group(2).strip()
|
||||||
_desc = match.group(3)
|
_desc = match.group(3).strip()
|
||||||
|
|
||||||
if not match:
|
if not match:
|
||||||
match = _google_untyped_arg_regex.match(line)
|
match = _google_untyped_arg_regex.match(line)
|
||||||
if match:
|
if match:
|
||||||
_name = match.group(1)
|
_name = match.group(1).strip()
|
||||||
_desc = match.group(2)
|
_desc = match.group(2).strip()
|
||||||
|
|
||||||
if _name[:2] == '**':
|
if _name[:2] == '**':
|
||||||
_name = r'\*\*'+_name[2:]
|
_name = r'\*\*'+_name[2:]
|
||||||
@ -244,14 +244,14 @@ class GoogleDocstring(UnicodeMixin):
|
|||||||
_name, _type, _desc = '', '', lines
|
_name, _type, _desc = '', '', lines
|
||||||
match = _google_typed_arg_regex.match(lines[0])
|
match = _google_typed_arg_regex.match(lines[0])
|
||||||
if match:
|
if match:
|
||||||
_name = match.group(1)
|
_name = match.group(1).strip()
|
||||||
_type = match.group(2)
|
_type = match.group(2).strip()
|
||||||
_desc = match.group(3)
|
_desc = match.group(3).strip()
|
||||||
else:
|
else:
|
||||||
match = _google_untyped_arg_regex.match(lines[0])
|
match = _google_untyped_arg_regex.match(lines[0])
|
||||||
if match:
|
if match:
|
||||||
_type = match.group(1)
|
_type = match.group(1).strip()
|
||||||
_desc = match.group(2)
|
_desc = match.group(2).strip()
|
||||||
if match:
|
if match:
|
||||||
lines[0] = _desc
|
lines[0] = _desc
|
||||||
_desc = lines
|
_desc = lines
|
||||||
@ -720,6 +720,8 @@ class NumpyDocstring(GoogleDocstring):
|
|||||||
line = next(self._line_iter)
|
line = next(self._line_iter)
|
||||||
if parse_type:
|
if parse_type:
|
||||||
_name, _, _type = line.partition(':')
|
_name, _, _type = line.partition(':')
|
||||||
|
if not _name:
|
||||||
|
_type = line
|
||||||
else:
|
else:
|
||||||
_name, _type = line, ''
|
_name, _type = line, ''
|
||||||
_name, _type = _name.strip(), _type.strip()
|
_name, _type = _name.strip(), _type.strip()
|
||||||
|
@ -35,12 +35,12 @@ from pygments.util import ClassNotFound
|
|||||||
from sphinx.pygments_styles import SphinxStyle, NoneStyle
|
from sphinx.pygments_styles import SphinxStyle, NoneStyle
|
||||||
|
|
||||||
lexers = dict(
|
lexers = dict(
|
||||||
none = TextLexer(),
|
none = TextLexer(stripnl=False),
|
||||||
python = PythonLexer(),
|
python = PythonLexer(stripnl=False),
|
||||||
pycon = PythonConsoleLexer(),
|
pycon = PythonConsoleLexer(stripnl=False),
|
||||||
pycon3 = PythonConsoleLexer(python3=True),
|
pycon3 = PythonConsoleLexer(python3=True, stripnl=False),
|
||||||
rest = RstLexer(),
|
rest = RstLexer(stripnl=False),
|
||||||
c = CLexer(),
|
c = CLexer(stripnl=False),
|
||||||
)
|
)
|
||||||
for _lexer in lexers.values():
|
for _lexer in lexers.values():
|
||||||
_lexer.add_filter('raiseonerror')
|
_lexer.add_filter('raiseonerror')
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
"""
|
"""
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
|
import re
|
||||||
import sys
|
import sys
|
||||||
from os import path
|
from os import path
|
||||||
|
|
||||||
@ -45,6 +46,8 @@ number2name.update(token.tok_name)
|
|||||||
|
|
||||||
_eq = nodes.Leaf(token.EQUAL, '=')
|
_eq = nodes.Leaf(token.EQUAL, '=')
|
||||||
|
|
||||||
|
emptyline_re = re.compile('^\s*(#.*)?$')
|
||||||
|
|
||||||
|
|
||||||
class AttrDocVisitor(nodes.NodeVisitor):
|
class AttrDocVisitor(nodes.NodeVisitor):
|
||||||
"""
|
"""
|
||||||
@ -289,8 +292,9 @@ class ModuleAnalyzer(object):
|
|||||||
indent = 0
|
indent = 0
|
||||||
defline = False
|
defline = False
|
||||||
expect_indent = False
|
expect_indent = False
|
||||||
|
emptylines = 0
|
||||||
|
|
||||||
def tokeniter(ignore = (token.COMMENT, token.NL)):
|
def tokeniter(ignore = (token.COMMENT,)):
|
||||||
for tokentup in self.tokens:
|
for tokentup in self.tokens:
|
||||||
if tokentup[0] not in ignore:
|
if tokentup[0] not in ignore:
|
||||||
yield tokentup
|
yield tokentup
|
||||||
@ -303,7 +307,7 @@ class ModuleAnalyzer(object):
|
|||||||
dtype, fullname, startline, _ = stack.pop()
|
dtype, fullname, startline, _ = stack.pop()
|
||||||
endline = epos[0]
|
endline = epos[0]
|
||||||
namespace.pop()
|
namespace.pop()
|
||||||
result[fullname] = (dtype, startline, endline)
|
result[fullname] = (dtype, startline, endline - emptylines)
|
||||||
expect_indent = False
|
expect_indent = False
|
||||||
if tok in ('def', 'class'):
|
if tok in ('def', 'class'):
|
||||||
name = next(tokeniter)[1]
|
name = next(tokeniter)[1]
|
||||||
@ -322,7 +326,7 @@ class ModuleAnalyzer(object):
|
|||||||
dtype, fullname, startline, _ = stack.pop()
|
dtype, fullname, startline, _ = stack.pop()
|
||||||
endline = spos[0]
|
endline = spos[0]
|
||||||
namespace.pop()
|
namespace.pop()
|
||||||
result[fullname] = (dtype, startline, endline)
|
result[fullname] = (dtype, startline, endline - emptylines)
|
||||||
elif type == token.NEWLINE:
|
elif type == token.NEWLINE:
|
||||||
# if this line contained a definition, expect an INDENT
|
# if this line contained a definition, expect an INDENT
|
||||||
# to start the suite; if there is no such INDENT
|
# to start the suite; if there is no such INDENT
|
||||||
@ -330,6 +334,13 @@ class ModuleAnalyzer(object):
|
|||||||
if defline:
|
if defline:
|
||||||
defline = False
|
defline = False
|
||||||
expect_indent = True
|
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
|
self.tags = result
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
@ -1542,7 +1542,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
|||||||
# most probably a parsed-literal block -- don't highlight
|
# most probably a parsed-literal block -- don't highlight
|
||||||
self.body.append('\\begin{alltt}\n')
|
self.body.append('\\begin{alltt}\n')
|
||||||
else:
|
else:
|
||||||
code = node.astext().rstrip('\n')
|
code = node.astext()
|
||||||
lang = self.hlsettingstack[-1][0]
|
lang = self.hlsettingstack[-1][0]
|
||||||
linenos = code.count('\n') >= self.hlsettingstack[-1][1] - 1
|
linenos = code.count('\n') >= self.hlsettingstack[-1][1] - 1
|
||||||
highlight_args = node.get('highlight_args', {})
|
highlight_args = node.get('highlight_args', {})
|
||||||
@ -1573,7 +1573,6 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
|||||||
self.table.has_verbatim = True
|
self.table.has_verbatim = True
|
||||||
# get consistent trailer
|
# get consistent trailer
|
||||||
hlcode = hlcode.rstrip()[:-14] # strip \end{Verbatim}
|
hlcode = hlcode.rstrip()[:-14] # strip \end{Verbatim}
|
||||||
hlcode = hlcode.rstrip() + '\n'
|
|
||||||
self.body.append('\n' + hlcode + '\\end{%sVerbatim}\n' %
|
self.body.append('\n' + hlcode + '\\end{%sVerbatim}\n' %
|
||||||
(self.table and 'Original' or ''))
|
(self.table and 'Original' or ''))
|
||||||
raise nodes.SkipNode
|
raise nodes.SkipNode
|
||||||
|
3
tests/roots/test-directive-code/empty.inc
Normal file
3
tests/roots/test-directive-code/empty.inc
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
@ -15,3 +15,6 @@ Literal Includes with Line Numbers Matching
|
|||||||
:language: python
|
:language: python
|
||||||
:start-after: pass
|
:start-after: pass
|
||||||
:lineno-match:
|
:lineno-match:
|
||||||
|
|
||||||
|
.. literalinclude:: empty.inc
|
||||||
|
:lineno-match:
|
||||||
|
@ -10,4 +10,5 @@ class Bar:
|
|||||||
def baz():
|
def baz():
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# comment after Bar class definition
|
||||||
def bar(): pass
|
def bar(): pass
|
||||||
|
@ -116,7 +116,8 @@ def test_literal_include_linenos(app, status, warning):
|
|||||||
'10\n'
|
'10\n'
|
||||||
'11\n'
|
'11\n'
|
||||||
'12\n'
|
'12\n'
|
||||||
'13</pre></div></td>')
|
'13\n'
|
||||||
|
'14</pre></div></td>')
|
||||||
assert linenos in html
|
assert linenos in html
|
||||||
|
|
||||||
|
|
||||||
@ -138,7 +139,8 @@ def test_literal_include_lineno_start(app, status, warning):
|
|||||||
'209\n'
|
'209\n'
|
||||||
'210\n'
|
'210\n'
|
||||||
'211\n'
|
'211\n'
|
||||||
'212</pre></div></td>')
|
'212\n'
|
||||||
|
'213</pre></div></td>')
|
||||||
assert linenos in html
|
assert linenos in html
|
||||||
|
|
||||||
|
|
||||||
@ -156,6 +158,7 @@ def test_literal_include_lineno_match(app, status, warning):
|
|||||||
|
|
||||||
lines = (
|
lines = (
|
||||||
'<td class="linenos"><div class="linenodiv"><pre>'
|
'<td class="linenos"><div class="linenodiv"><pre>'
|
||||||
|
'5\n'
|
||||||
'6\n'
|
'6\n'
|
||||||
'7\n'
|
'7\n'
|
||||||
'8\n'
|
'8\n'
|
||||||
@ -164,14 +167,29 @@ def test_literal_include_lineno_match(app, status, warning):
|
|||||||
|
|
||||||
start_after = (
|
start_after = (
|
||||||
'<td class="linenos"><div class="linenodiv"><pre>'
|
'<td class="linenos"><div class="linenodiv"><pre>'
|
||||||
|
' 8\n'
|
||||||
' 9\n'
|
' 9\n'
|
||||||
'10\n'
|
'10\n'
|
||||||
'11\n'
|
'11\n'
|
||||||
'12\n'
|
'12\n'
|
||||||
'13</pre></div></td>')
|
'13\n'
|
||||||
|
'14</pre></div></td>')
|
||||||
assert start_after in html
|
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')
|
@with_app('html', testroot='directive-code')
|
||||||
def test_literalinclude_caption_html(app, status, warning):
|
def test_literalinclude_caption_html(app, status, warning):
|
||||||
app.builder.build('index')
|
app.builder.build('index')
|
||||||
|
@ -326,6 +326,71 @@ Attributes:
|
|||||||
"""
|
"""
|
||||||
self.assertEqual(expected, actual)
|
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):
|
class NumpyDocstringTest(BaseDocstringTest):
|
||||||
docstrings = [(
|
docstrings = [(
|
||||||
@ -588,3 +653,46 @@ numpy.multivariate_normal(mean, cov, shape=None, spam=None)
|
|||||||
relationship
|
relationship
|
||||||
"""
|
"""
|
||||||
self.assertEqual(expected, actual)
|
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)
|
||||||
|
Loading…
Reference in New Issue
Block a user