From b15b01307ea266222363b0e31709c1d94c7966ac Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Wed, 8 Apr 2020 01:32:09 +0900 Subject: [PATCH 1/2] Fix #7422: autodoc: fails with ValueError when using autodoc_mock_imports --- CHANGES | 2 ++ sphinx/util/inspect.py | 13 +++++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 212f4571fb7..5e8bcbe3328 100644 --- a/CHANGES +++ b/CHANGES @@ -16,6 +16,8 @@ Features added Bugs fixed ---------- +* #7422: autodoc: fails with ValueError when using autodoc_mock_imports + Testing -------- diff --git a/sphinx/util/inspect.py b/sphinx/util/inspect.py index 570ea9df677..64c1568f61c 100644 --- a/sphinx/util/inspect.py +++ b/sphinx/util/inspect.py @@ -17,7 +17,7 @@ import warnings from functools import partial, partialmethod from inspect import ( # NOQA - Parameter, isclass, ismethod, ismethoddescriptor, unwrap + Parameter, isclass, ismethod, ismethoddescriptor ) from io import StringIO from typing import Any, Callable, Mapping, List, Tuple @@ -116,6 +116,15 @@ def getargspec(func: Callable) -> Any: kwonlyargs, kwdefaults, annotations) +def unwrap(obj: Any) -> Any: + """Get an original object from wrapped object (wrapped functions).""" + try: + return inspect.unwrap(obj) + except ValueError: + # might be a mock object + return obj + + def unwrap_all(obj: Any) -> Any: """ Get an original object from wrapped object (unwrapping partials, wrapped @@ -217,7 +226,7 @@ def isattributedescriptor(obj: Any) -> bool: return True elif isdescriptor(obj): # non data descriptor - unwrapped = inspect.unwrap(obj) + unwrapped = unwrap(obj) if isfunction(unwrapped) or isbuiltin(unwrapped) or inspect.ismethod(unwrapped): # attribute must not be either function, builtin and method return False From 1086fd41ec131cac766955a0f2d03ef0e5de5190 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Wed, 8 Apr 2020 22:44:28 +0200 Subject: [PATCH 2/2] C++, fix merging overloaded functions in parallel builds. --- CHANGES | 1 + sphinx/domains/cpp.py | 81 ++++++++++++++++++++++++++++++++++++++----- 2 files changed, 73 insertions(+), 9 deletions(-) diff --git a/CHANGES b/CHANGES index 7d5f801863a..34e651241de 100644 --- a/CHANGES +++ b/CHANGES @@ -17,6 +17,7 @@ Bugs fixed ---------- * #7428: py domain: a reference to class ``None`` emits a nitpicky warning +* #7438: C++, fix merging overloaded functions in parallel builds. Testing -------- diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index dbb6d1a39c2..8180384dab3 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -4300,18 +4300,73 @@ def merge_with(self, other: "Symbol", docnames: List[str], Symbol.debug_indent += 1 Symbol.debug_print("merge_with:") assert other is not None + + def unconditionalAdd(self, otherChild): + # TODO: hmm, should we prune by docnames? + self._children.append(otherChild) + otherChild.parent = self + otherChild._assert_invariants() + + if Symbol.debug_lookup: + Symbol.debug_indent += 1 for otherChild in other._children: - ourChild = self._find_first_named_symbol( + if Symbol.debug_lookup: + Symbol.debug_print("otherChild:\n", otherChild.to_string(Symbol.debug_indent)) + Symbol.debug_indent += 1 + if otherChild.isRedeclaration: + unconditionalAdd(self, otherChild) + if Symbol.debug_lookup: + Symbol.debug_print("isRedeclaration") + Symbol.debug_indent -= 1 + continue + candiateIter = self._find_named_symbols( identOrOp=otherChild.identOrOp, templateParams=otherChild.templateParams, templateArgs=otherChild.templateArgs, templateShorthand=False, matchSelf=False, - recurseInAnon=False, correctPrimaryTemplateArgs=False) + recurseInAnon=False, correctPrimaryTemplateArgs=False, + searchInSiblings=False) + candidates = list(candiateIter) + + if Symbol.debug_lookup: + Symbol.debug_print("raw candidate symbols:", len(candidates)) + symbols = [s for s in candidates if not s.isRedeclaration] + if Symbol.debug_lookup: + Symbol.debug_print("non-duplicate candidate symbols:", len(symbols)) + + if len(symbols) == 0: + unconditionalAdd(self, otherChild) + if Symbol.debug_lookup: + Symbol.debug_indent -= 1 + continue + + ourChild = None + if otherChild.declaration is None: + if Symbol.debug_lookup: + Symbol.debug_print("no declaration in other child") + ourChild = symbols[0] + else: + queryId = otherChild.declaration.get_newest_id() + if Symbol.debug_lookup: + Symbol.debug_print("queryId: ", queryId) + for symbol in symbols: + if symbol.declaration is None: + if Symbol.debug_lookup: + Symbol.debug_print("empty candidate") + # if in the end we have non matching, but have an empty one, + # then just continue with that + ourChild = symbol + continue + candId = symbol.declaration.get_newest_id() + if Symbol.debug_lookup: + Symbol.debug_print("candidate:", candId) + if candId == queryId: + ourChild = symbol + break + if Symbol.debug_lookup: + Symbol.debug_indent -= 1 if ourChild is None: - # TODO: hmm, should we prune by docnames? - self._children.append(otherChild) - otherChild.parent = self - otherChild._assert_invariants() + unconditionalAdd(self, otherChild) continue if otherChild.declaration and otherChild.docname in docnames: if not ourChild.declaration: @@ -4326,10 +4381,14 @@ def merge_with(self, other: "Symbol", docnames: List[str], # Both have declarations, and in the same docname. # This can apparently happen, it should be safe to # just ignore it, right? - pass + # Hmm, only on duplicate declarations, right? + msg = "Internal C++ domain error during symbol merging.\n" + msg += "ourChild:\n" + ourChild.to_string(1) + msg += "\notherChild:\n" + otherChild.to_string(1) + logger.warning(msg, location=otherChild.docname) ourChild.merge_with(otherChild, docnames, env) if Symbol.debug_lookup: - Symbol.debug_indent -= 1 + Symbol.debug_indent -= 2 def add_name(self, nestedName: ASTNestedName, templatePrefix: ASTTemplateDeclarationPrefix = None) -> "Symbol": @@ -7116,7 +7175,6 @@ def merge_domaindata(self, docnames: List[str], otherdata: Dict) -> None: print("\tother:") print(otherdata['root_symbol'].dump(1)) print("\tother end") - print("merge_domaindata end") self.data['root_symbol'].merge_with(otherdata['root_symbol'], docnames, self.env) @@ -7130,6 +7188,11 @@ def merge_domaindata(self, docnames: List[str], otherdata: Dict) -> None: logger.warning(msg, location=docname) else: ourNames[name] = docname + if Symbol.debug_show_tree: + print("\tresult:") + print(self.data['root_symbol'].dump(1)) + print("\tresult end") + print("merge_domaindata end") def _resolve_xref_inner(self, env: BuildEnvironment, fromdocname: str, builder: Builder, typ: str, target: str, node: pending_xref,