Skip to content

Commit

Permalink
Merge branch '3.0.x' into 7435_typehints_not_suppressed_for_class
Browse files Browse the repository at this point in the history
  • Loading branch information
tk0miya committed Apr 9, 2020
2 parents 0525c39 + 9002b6c commit a6dcbc7
Show file tree
Hide file tree
Showing 8 changed files with 105 additions and 19 deletions.
6 changes: 6 additions & 0 deletions CHANGES
Expand Up @@ -7,6 +7,8 @@ Dependencies
Incompatible changes
--------------------

* #7418: std domain: :rst:dir:`term` role becomes case sensitive

Deprecated
----------

Expand All @@ -17,8 +19,12 @@ Bugs fixed
----------

* #7428: py domain: a reference to class ``None`` emits a nitpicky warning
* #7418: std domain: duplication warning for glossary terms is case insensitive
* #7438: C++, fix merging overloaded functions in parallel builds.
* #7422: autodoc: fails with ValueError when using autodoc_mock_imports
* #7435: autodoc: ``autodoc_typehints='description'`` doesn't suppress typehints
in signature for classes/methods
* #7423: crashed when giving a non-string object to logger

Testing
--------
Expand Down
2 changes: 1 addition & 1 deletion doc/extdev/index.rst
Expand Up @@ -27,7 +27,7 @@ Discovery of builders by entry point

.. versionadded:: 1.6

:term:`Builder` extensions can be discovered by means of `entry points`_ so
:term:`builder` extensions can be discovered by means of `entry points`_ so
that they do not have to be listed in the :confval:`extensions` configuration
value.

Expand Down
81 changes: 72 additions & 9 deletions sphinx/domains/cpp.py
Expand Up @@ -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:
Expand All @@ -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":
Expand Down Expand Up @@ -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)
Expand All @@ -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,
Expand Down
4 changes: 2 additions & 2 deletions sphinx/domains/std.py
Expand Up @@ -305,7 +305,7 @@ def make_glossary_term(env: "BuildEnvironment", textnodes: Iterable[Node], index
term['ids'].append(node_id)

std = cast(StandardDomain, env.get_domain('std'))
std.note_object('term', termtext.lower(), node_id, location=term)
std.note_object('term', termtext, node_id, location=term)

# add an index entry too
indexnode = addnodes.index()
Expand Down Expand Up @@ -565,7 +565,7 @@ class StandardDomain(Domain):
# links to tokens in grammar productions
'token': TokenXRefRole(),
# links to terms in glossary
'term': XRefRole(lowercase=True, innernodeclass=nodes.inline,
'term': XRefRole(innernodeclass=nodes.inline,
warn_dangling=True),
# links to headings or arbitrary labels
'ref': XRefRole(lowercase=True, innernodeclass=nodes.inline,
Expand Down
13 changes: 11 additions & 2 deletions sphinx/util/inspect.py
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion sphinx/util/logging.py
Expand Up @@ -412,7 +412,7 @@ def filter(self, record: logging.LogRecord) -> bool:
message = record.msg # use record.msg itself

if location:
raise SphinxWarning(location + ":" + message)
raise SphinxWarning(location + ":" + str(message))
else:
raise SphinxWarning(message)
else:
Expand Down
8 changes: 4 additions & 4 deletions tests/test_domain_std.py
Expand Up @@ -99,7 +99,7 @@ def test_glossary(app):
text = (".. glossary::\n"
"\n"
" term1\n"
" term2\n"
" TERM2\n"
" description\n"
"\n"
" term3 : classifier\n"
Expand All @@ -114,7 +114,7 @@ def test_glossary(app):
assert_node(doctree, (
[glossary, definition_list, ([definition_list_item, ([term, ("term1",
index)],
[term, ("term2",
[term, ("TERM2",
index)],
definition)],
[definition_list_item, ([term, ("term3",
Expand All @@ -127,7 +127,7 @@ def test_glossary(app):
assert_node(doctree[0][0][0][0][1],
entries=[("single", "term1", "term-term1", "main", None)])
assert_node(doctree[0][0][0][1][1],
entries=[("single", "term2", "term-term2", "main", None)])
entries=[("single", "TERM2", "term-TERM2", "main", None)])
assert_node(doctree[0][0][0][2],
[definition, nodes.paragraph, "description"])
assert_node(doctree[0][0][1][0][1],
Expand All @@ -143,7 +143,7 @@ def test_glossary(app):
# index
objects = list(app.env.get_domain("std").get_objects())
assert ("term1", "term1", "term", "index", "term-term1", -1) in objects
assert ("term2", "term2", "term", "index", "term-term2", -1) in objects
assert ("TERM2", "TERM2", "term", "index", "term-TERM2", -1) in objects
assert ("term3", "term3", "term", "index", "term-term3", -1) in objects
assert ("term4", "term4", "term", "index", "term-term4", -1) in objects

Expand Down
8 changes: 8 additions & 0 deletions tests/test_util_logging.py
Expand Up @@ -48,6 +48,14 @@ def test_info_and_warning(app, status, warning):
assert 'message5' in warning.getvalue()


def test_Exception(app, status, warning):
logging.setup(app, status, warning)
logger = logging.getLogger(__name__)

logger.info(Exception)
assert "<class 'Exception'>" in status.getvalue()


def test_verbosity_filter(app, status, warning):
# verbosity = 0: INFO
app.verbosity = 0
Expand Down

0 comments on commit a6dcbc7

Please sign in to comment.