diff --git a/CHANGES b/CHANGES index 57583accf..13a4ac151 100644 --- a/CHANGES +++ b/CHANGES @@ -173,6 +173,12 @@ Bugs fixed mocked module * #4973: latex: glossary directive adds whitespace to each item * #4980: latex: Explicit labels on code blocks are duplicated +* #4919: node.asdom() crashes if toctree has :numbered: option +* #4914: autodoc: Parsing error when using dataclasses without default values +* #4931: autodoc: crashed when handler for autodoc-skip-member raises an error +* #4931: autodoc: crashed when subclass of mocked class are processed by + napoleon module +* #5007: sphinx-build crashes when error log contains a "%" character Testing -------- diff --git a/sphinx/environment/collectors/toctree.py b/sphinx/environment/collectors/toctree.py index dcbee07f7..3d8c89f43 100644 --- a/sphinx/environment/collectors/toctree.py +++ b/sphinx/environment/collectors/toctree.py @@ -172,10 +172,10 @@ class TocTreeCollector(EnvironmentCollector): number = tuple(numstack) else: number = None - secnums[subnode[0]['anchorname']] = \ - subnode[0]['secnumber'] = number + secnums[subnode[0]['anchorname']] = number + subnode[0]['secnumber'] = list(number) if titlenode: - titlenode['secnumber'] = number + titlenode['secnumber'] = list(number) titlenode = None elif isinstance(subnode, addnodes.toctree): _walk_toctree(subnode, depth) diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index 353188aaf..62143fda4 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -643,11 +643,17 @@ class Documenter(object): # should be skipped if self.env.app: # let extensions preprocess docstrings - skip_user = self.env.app.emit_firstresult( - 'autodoc-skip-member', self.objtype, membername, member, - not keep, self.options) - if skip_user is not None: - keep = not skip_user + try: + skip_user = self.env.app.emit_firstresult( + 'autodoc-skip-member', self.objtype, membername, member, + not keep, self.options) + if skip_user is not None: + keep = not skip_user + except Exception as exc: + logger.warning(__('autodoc: failed to determine %r to be documented.' + 'the following exception was raised:\n%s'), + member, exc) + keep = False if keep: ret.append((membername, member, isattr)) diff --git a/sphinx/ext/autodoc/importer.py b/sphinx/ext/autodoc/importer.py index 789cfc1c1..bf6bfc03d 100644 --- a/sphinx/ext/autodoc/importer.py +++ b/sphinx/ext/autodoc/importer.py @@ -23,7 +23,7 @@ from sphinx.util.inspect import isenumclass, safe_getattr if False: # For type annotation - from typing import Any, Callable, Dict, Generator, List, Optional, Tuple # NOQA + from typing import Any, Callable, Dict, Generator, Iterator, List, Optional, Tuple # NOQA logger = logging.getLogger(__name__) @@ -41,7 +41,7 @@ class _MockObject(object): def __init__(self, *args, **kwargs): # type: (Any, Any) -> None - pass + self.__qualname__ = '' def __len__(self): # type: () -> int @@ -52,8 +52,8 @@ class _MockObject(object): return False def __iter__(self): - # type: () -> None - pass + # type: () -> Iterator + return iter([]) def __mro_entries__(self, bases): # type: (Tuple) -> Tuple diff --git a/sphinx/pycode/parser.py b/sphinx/pycode/parser.py index f943b7985..31d2c465a 100644 --- a/sphinx/pycode/parser.py +++ b/sphinx/pycode/parser.py @@ -225,12 +225,13 @@ class AfterCommentParser(TokenProcessor): def parse(self): # type: () -> None """Parse the code and obtain comment after assignment.""" - # skip lvalue (until '=' operator) - while self.fetch_token() != [OP, '=']: + # skip lvalue (or whole of AnnAssign) + while not self.fetch_token().match([OP, '='], NEWLINE, COMMENT): assert self.current - # skip rvalue - self.fetch_rvalue() + # skip rvalue (if exists) + if self.current == [OP, '=']: + self.fetch_rvalue() if self.current == COMMENT: self.comment = self.current.value diff --git a/sphinx/util/logging.py b/sphinx/util/logging.py index 5034c007d..d2f6cafbe 100644 --- a/sphinx/util/logging.py +++ b/sphinx/util/logging.py @@ -392,7 +392,7 @@ class WarningIsErrorFilter(logging.Filter): location = getattr(record, 'location', '') try: message = record.msg % record.args - except TypeError: + except (TypeError, ValueError): message = record.msg # use record.msg itself if location: diff --git a/tests/test_environment_toctree.py b/tests/test_environment_toctree.py index 1bebbaa3e..3fbb21856 100644 --- a/tests/test_environment_toctree.py +++ b/tests/test_environment_toctree.py @@ -227,11 +227,11 @@ def test_get_toctree_for(app): [list_item, compact_paragraph, reference, "foo.1"], [list_item, compact_paragraph, reference, "foo.2"])) - assert_node(toctree[1][0][0][0], reference, refuri="foo", secnumber=(1,)) - assert_node(toctree[1][0][1][0][0][0], reference, refuri="quux", secnumber=(1, 1)) - assert_node(toctree[1][0][1][1][0][0], reference, refuri="foo#foo-1", secnumber=(1, 2)) - assert_node(toctree[1][0][1][2][0][0], reference, refuri="foo#foo-2", secnumber=(1, 3)) - assert_node(toctree[1][1][0][0], reference, refuri="bar", secnumber=(2,)) + assert_node(toctree[1][0][0][0], reference, refuri="foo", secnumber=[1]) + assert_node(toctree[1][0][1][0][0][0], reference, refuri="quux", secnumber=[1, 1]) + assert_node(toctree[1][0][1][1][0][0], reference, refuri="foo#foo-1", secnumber=[1, 2]) + assert_node(toctree[1][0][1][2][0][0], reference, refuri="foo#foo-2", secnumber=[1, 3]) + assert_node(toctree[1][1][0][0], reference, refuri="bar", secnumber=[2]) assert_node(toctree[1][2][0][0], reference, refuri="http://sphinx-doc.org/") assert_node(toctree[2], @@ -258,8 +258,8 @@ def test_get_toctree_for_collapse(app): ([list_item, compact_paragraph, reference, "foo"], [list_item, compact_paragraph, reference, "bar"], [list_item, compact_paragraph, reference, "http://sphinx-doc.org/"])) - assert_node(toctree[1][0][0][0], reference, refuri="foo", secnumber=(1,)) - assert_node(toctree[1][1][0][0], reference, refuri="bar", secnumber=(2,)) + assert_node(toctree[1][0][0][0], reference, refuri="foo", secnumber=[1]) + assert_node(toctree[1][1][0][0], reference, refuri="bar", secnumber=[2]) assert_node(toctree[1][2][0][0], reference, refuri="http://sphinx-doc.org/") assert_node(toctree[2], @@ -296,13 +296,13 @@ def test_get_toctree_for_maxdepth(app): assert_node(toctree[1][0][1][1][1], [bullet_list, list_item, compact_paragraph, reference, "foo.1-1"]) - assert_node(toctree[1][0][0][0], reference, refuri="foo", secnumber=(1,)) - assert_node(toctree[1][0][1][0][0][0], reference, refuri="quux", secnumber=(1, 1)) - assert_node(toctree[1][0][1][1][0][0], reference, refuri="foo#foo-1", secnumber=(1, 2)) + assert_node(toctree[1][0][0][0], reference, refuri="foo", secnumber=[1]) + assert_node(toctree[1][0][1][0][0][0], reference, refuri="quux", secnumber=[1, 1]) + assert_node(toctree[1][0][1][1][0][0], reference, refuri="foo#foo-1", secnumber=[1, 2]) assert_node(toctree[1][0][1][1][1][0][0][0], - reference, refuri="foo#foo-1-1", secnumber=(1, 2, 1)) - assert_node(toctree[1][0][1][2][0][0], reference, refuri="foo#foo-2", secnumber=(1, 3)) - assert_node(toctree[1][1][0][0], reference, refuri="bar", secnumber=(2,)) + reference, refuri="foo#foo-1-1", secnumber=[1, 2, 1]) + assert_node(toctree[1][0][1][2][0][0], reference, refuri="foo#foo-2", secnumber=[1, 3]) + assert_node(toctree[1][1][0][0], reference, refuri="bar", secnumber=[2]) assert_node(toctree[1][2][0][0], reference, refuri="http://sphinx-doc.org/") assert_node(toctree[2], @@ -335,11 +335,11 @@ def test_get_toctree_for_includehidden(app): [list_item, compact_paragraph, reference, "foo.1"], [list_item, compact_paragraph, reference, "foo.2"])) - assert_node(toctree[1][0][0][0], reference, refuri="foo", secnumber=(1,)) - assert_node(toctree[1][0][1][0][0][0], reference, refuri="quux", secnumber=(1, 1)) - assert_node(toctree[1][0][1][1][0][0], reference, refuri="foo#foo-1", secnumber=(1, 2)) - assert_node(toctree[1][0][1][2][0][0], reference, refuri="foo#foo-2", secnumber=(1, 3)) - assert_node(toctree[1][1][0][0], reference, refuri="bar", secnumber=(2,)) + assert_node(toctree[1][0][0][0], reference, refuri="foo", secnumber=[1]) + assert_node(toctree[1][0][1][0][0][0], reference, refuri="quux", secnumber=[1, 1]) + assert_node(toctree[1][0][1][1][0][0], reference, refuri="foo#foo-1", secnumber=[1, 2]) + assert_node(toctree[1][0][1][2][0][0], reference, refuri="foo#foo-2", secnumber=[1, 3]) + assert_node(toctree[1][1][0][0], reference, refuri="bar", secnumber=[2]) assert_node(toctree[1][2][0][0], reference, refuri="http://sphinx-doc.org/") assert_node(toctree[2], diff --git a/tests/test_pycode_parser.py b/tests/test_pycode_parser.py index 09f1f41f5..29363e17e 100644 --- a/tests/test_pycode_parser.py +++ b/tests/test_pycode_parser.py @@ -100,11 +100,13 @@ def test_comment_picker_location(): def test_annotated_assignment_py36(): source = ('a: str = "Sphinx" #: comment\n' 'b: int = 1\n' - '"""string on next line"""') + '"""string on next line"""\n' + 'c: int #: comment') parser = Parser(source) parser.parse() assert parser.comments == {('', 'a'): 'comment', - ('', 'b'): 'string on next line'} + ('', 'b'): 'string on next line', + ('', 'c'): 'comment'} assert parser.definitions == {}