Merge branch '3.x'

This commit is contained in:
Takeshi KOMIYA 2020-11-02 22:25:10 +09:00
commit 449a567732
14 changed files with 375 additions and 158 deletions

75
CHANGES
View File

@ -46,7 +46,7 @@ Bugs fixed
Testing
--------
Release 3.3.0 (in development)
Release 3.4.0 (in development)
==============================
Dependencies
@ -58,6 +58,42 @@ Incompatible changes
Deprecated
----------
Features added
--------------
Bugs fixed
----------
Testing
--------
Release 3.3.1 (in development)
==============================
Dependencies
------------
Incompatible changes
--------------------
Deprecated
----------
Features added
--------------
Bugs fixed
----------
Testing
--------
Release 3.3.0 (released Nov 02, 2020)
=====================================
Deprecated
----------
* ``sphinx.builders.latex.LaTeXBuilder.usepackages``
* ``sphinx.builders.latex.LaTeXBuilder.usepackages_afger_hyperref``
* ``sphinx.ext.autodoc.SingledispatchFunctionDocumenter``
@ -78,6 +114,11 @@ Features added
builder using :confval:`suppress_warnings`.
* #8298: sphinx-quickstart: Add :option:`sphinx-quickstart --no-sep` option
* #8304: sphinx.testing: Register public markers in sphinx.testing.fixtures
* #8051: napoleon: use the obj role for all See Also items
* #8050: napoleon: Apply :confval:`napoleon_preprocess_types` to every field
* C and C++, show line numbers for previous declarations when duplicates are
detected.
* #8183: Remove substitution_reference nodes from doctree only on LaTeX builds
Bugs fixed
----------
@ -96,6 +137,7 @@ Bugs fixed
* #8200: autodoc: type aliases break type formatting of autoattribute
* #7786: autodoc: can't detect overloaded methods defined in other file
* #8294: autodoc: single-string __slots__ is not handled correctly
* #7785: autodoc: autodoc_typehints='none' does not effect to overloaded functions
* #8192: napoleon: description is disappeared when it contains inline literals
* #8142: napoleon: Potential of regex denial of service in google style docs
* #8169: LaTeX: pxjahyper loaded even when latex_engine is not platex
@ -118,32 +160,6 @@ Bugs fixed
* #8321: linkcheck: ``tel:`` schema hyperlinks are detected as errors
* #8323: linkcheck: An exit status is incorrect when links having unsupported
schema found
* #6914: figure numbers are unexpectedly assigned to uncaptioned items
* #8320: make "inline" line numbers un-selectable
Testing
--------
* #8257: Support parallel build in sphinx.testing
Release 3.2.2 (in development)
==============================
Dependencies
------------
Incompatible changes
--------------------
Deprecated
----------
Features added
--------------
Bugs fixed
----------
* #8188: C, add missing items to internal object types dictionary,
e.g., preventing intersphinx from resolving them.
* C, fix anon objects in intersphinx.
@ -151,11 +167,14 @@ Bugs fixed
non-function declaration of the same name already exists.
* C, fix references to function parameters.
Link to the function instead of a non-existing anchor.
* #6914: figure numbers are unexpectedly assigned to uncaptioned items
* #8320: make "inline" line numbers un-selectable
Testing
--------
* #8257: Support parallel build in sphinx.testing
Release 3.2.1 (released Aug 14, 2020)
=====================================

View File

@ -13,6 +13,7 @@ from typing import cast
from docutils import nodes
from docutils.nodes import Element, Node
from docutils.transforms.references import Substitutions
from sphinx import addnodes
from sphinx.application import Sphinx
@ -38,6 +39,18 @@ class FootnoteDocnameUpdater(SphinxTransform):
node['docname'] = self.env.docname
class SubstitutionDefinitionsRemover(SphinxPostTransform):
"""Remove ``substitution_definition node from doctrees."""
# should be invoked after Substitutions process
default_priority = Substitutions.default_priority + 1
builders = ('latex',)
def apply(self, **kwargs: Any) -> None:
for node in self.document.traverse(nodes.substitution_definition):
node.parent.remove(node)
class ShowUrlsTransform(SphinxPostTransform):
"""Expand references to inline text or footnotes.
@ -602,6 +615,7 @@ class IndexInSectionTitleTransform(SphinxTransform):
def setup(app: Sphinx) -> Dict[str, Any]:
app.add_transform(FootnoteDocnameUpdater)
app.add_post_transform(SubstitutionDefinitionsRemover)
app.add_post_transform(BibliographyTransform)
app.add_post_transform(CitationReferenceTransform)
app.add_post_transform(DocumentTargetTransform)

View File

@ -227,6 +227,7 @@ class CheckExternalLinksBuilder(Builder):
if rex.match(uri):
return 'ignored', '', 0
else:
self.broken[uri] = ''
return 'broken', '', 0
elif uri in self.good:
return 'working', 'old', 0

View File

@ -1475,7 +1475,7 @@ class Symbol:
assert False # shouldn't happen
else:
# the domain base class makes a copy of the initial data, which is fine
return Symbol(None, None, None, None)
return Symbol(None, None, None, None, None)
@staticmethod
def debug_print(*args: Any) -> None:
@ -1498,7 +1498,7 @@ class Symbol:
return super().__setattr__(key, value)
def __init__(self, parent: "Symbol", ident: ASTIdentifier,
declaration: ASTDeclaration, docname: str) -> None:
declaration: ASTDeclaration, docname: str, line: int) -> None:
self.parent = parent
# declarations in a single directive are linked together
self.siblingAbove = None # type: Symbol
@ -1506,6 +1506,7 @@ class Symbol:
self.ident = ident
self.declaration = declaration
self.docname = docname
self.line = line
self.isRedeclaration = False
self._assert_invariants()
@ -1521,12 +1522,14 @@ class Symbol:
# Do symbol addition after self._children has been initialised.
self._add_function_params()
def _fill_empty(self, declaration: ASTDeclaration, docname: str) -> None:
def _fill_empty(self, declaration: ASTDeclaration, docname: str, line: int) -> None:
self._assert_invariants()
assert not self.declaration
assert not self.docname
assert declaration
assert docname
assert self.declaration is None
assert self.docname is None
assert self.line is None
assert declaration is not None
assert docname is not None
assert line is not None
self.declaration = declaration
self.declaration.symbol = self
self.docname = docname
@ -1553,7 +1556,7 @@ class Symbol:
decl = ASTDeclaration('functionParam', None, p)
assert not nn.rooted
assert len(nn.names) == 1
self._add_symbols(nn, decl, self.docname)
self._add_symbols(nn, decl, self.docname, self.line)
if Symbol.debug_lookup:
Symbol.debug_indent -= 1
@ -1570,6 +1573,7 @@ class Symbol:
if sChild.declaration and sChild.docname == docname:
sChild.declaration = None
sChild.docname = None
sChild.line = None
if sChild.siblingAbove is not None:
sChild.siblingAbove.siblingBelow = sChild.siblingBelow
if sChild.siblingBelow is not None:
@ -1763,7 +1767,7 @@ class Symbol:
return SymbolLookupResult(symbols, parentSymbol, ident)
def _add_symbols(self, nestedName: ASTNestedName,
declaration: ASTDeclaration, docname: str) -> "Symbol":
declaration: ASTDeclaration, docname: str, line: int) -> "Symbol":
# TODO: further simplification from C++ to C
# Used for adding a whole path of symbols, where the last may or may not
# be an actual declaration.
@ -1772,9 +1776,9 @@ class Symbol:
Symbol.debug_indent += 1
Symbol.debug_print("_add_symbols:")
Symbol.debug_indent += 1
Symbol.debug_print("nn: ", nestedName)
Symbol.debug_print("decl: ", declaration)
Symbol.debug_print("doc: ", docname)
Symbol.debug_print("nn: ", nestedName)
Symbol.debug_print("decl: ", declaration)
Symbol.debug_print("location: {}:{}".format(docname, line))
def onMissingQualifiedSymbol(parentSymbol: "Symbol", ident: ASTIdentifier) -> "Symbol":
if Symbol.debug_lookup:
@ -1784,7 +1788,7 @@ class Symbol:
Symbol.debug_print("ident: ", ident)
Symbol.debug_indent -= 2
return Symbol(parent=parentSymbol, ident=ident,
declaration=None, docname=None)
declaration=None, docname=None, line=None)
lookupResult = self._symbol_lookup(nestedName,
onMissingQualifiedSymbol,
@ -1800,12 +1804,12 @@ class Symbol:
Symbol.debug_indent += 1
Symbol.debug_print("ident: ", lookupResult.ident)
Symbol.debug_print("declaration: ", declaration)
Symbol.debug_print("docname: ", docname)
Symbol.debug_print("location: {}:{}".format(docname, line))
Symbol.debug_indent -= 1
symbol = Symbol(parent=lookupResult.parentSymbol,
ident=lookupResult.ident,
declaration=declaration,
docname=docname)
docname=docname, line=line)
if Symbol.debug_lookup:
Symbol.debug_indent -= 2
return symbol
@ -1853,7 +1857,7 @@ class Symbol:
symbol = Symbol(parent=lookupResult.parentSymbol,
ident=lookupResult.ident,
declaration=declaration,
docname=docname)
docname=docname, line=line)
if Symbol.debug_lookup:
Symbol.debug_print("end: creating candidate symbol")
return symbol
@ -1919,7 +1923,7 @@ class Symbol:
# .. namespace:: Test
# .. namespace:: nullptr
# .. class:: Test
symbol._fill_empty(declaration, docname)
symbol._fill_empty(declaration, docname, line)
return symbol
def merge_with(self, other: "Symbol", docnames: List[str],
@ -1940,13 +1944,15 @@ class Symbol:
continue
if otherChild.declaration and otherChild.docname in docnames:
if not ourChild.declaration:
ourChild._fill_empty(otherChild.declaration, otherChild.docname)
ourChild._fill_empty(otherChild.declaration,
otherChild.docname, otherChild.line)
elif ourChild.docname != otherChild.docname:
name = str(ourChild.declaration)
msg = __("Duplicate C declaration, also defined in '%s'.\n"
"Declaration is '%s'.")
msg = msg % (ourChild.docname, name)
logger.warning(msg, location=otherChild.docname)
msg = __("Duplicate C declaration, also defined at %s:%s.\n"
"Declaration is '.. c:%s:: %s'.")
msg = msg % (ourChild.docname, ourChild.line,
ourChild.declaration.directiveType, name)
logger.warning(msg, location=(otherChild.docname, otherChild.line))
else:
# Both have declarations, and in the same docname.
# This can apparently happen, it should be safe to
@ -1960,19 +1966,21 @@ class Symbol:
if Symbol.debug_lookup:
Symbol.debug_indent += 1
Symbol.debug_print("add_name:")
res = self._add_symbols(nestedName, declaration=None, docname=None)
res = self._add_symbols(nestedName, declaration=None, docname=None, line=None)
if Symbol.debug_lookup:
Symbol.debug_indent -= 1
return res
def add_declaration(self, declaration: ASTDeclaration, docname: str) -> "Symbol":
def add_declaration(self, declaration: ASTDeclaration,
docname: str, line: int) -> "Symbol":
if Symbol.debug_lookup:
Symbol.debug_indent += 1
Symbol.debug_print("add_declaration:")
assert declaration
assert docname
assert declaration is not None
assert docname is not None
assert line is not None
nestedName = declaration.name
res = self._add_symbols(nestedName, declaration, docname)
res = self._add_symbols(nestedName, declaration, docname, line)
if Symbol.debug_lookup:
Symbol.debug_indent -= 1
return res
@ -3149,7 +3157,7 @@ class CObject(ObjectDescription):
declClone.enumeratorScopedSymbol = symbol
Symbol(parent=targetSymbol, ident=symbol.ident,
declaration=declClone,
docname=self.env.docname)
docname=self.env.docname, line=self.get_source_info()[1])
def add_target_and_index(self, ast: ASTDeclaration, sig: str,
signode: TextElement) -> None:
@ -3252,7 +3260,8 @@ class CObject(ObjectDescription):
raise ValueError from e
try:
symbol = parentSymbol.add_declaration(ast, docname=self.env.docname)
symbol = parentSymbol.add_declaration(
ast, docname=self.env.docname, line=self.get_source_info()[1])
# append the new declaration to the sibling list
assert symbol.siblingAbove is None
assert symbol.siblingBelow is None
@ -3265,9 +3274,9 @@ class CObject(ObjectDescription):
# Assume we are actually in the old symbol,
# instead of the newly created duplicate.
self.env.temp_data['c:last_symbol'] = e.symbol
msg = __("Duplicate C declaration, also defined in '%s'.\n"
"Declaration is '%s'.")
msg = msg % (e.symbol.docname, sig)
msg = __("Duplicate C declaration, also defined at %s:%s.\n"
"Declaration is '.. c:%s:: %s'.")
msg = msg % (e.symbol.docname, e.symbol.line, self.display_object_type, sig)
logger.warning(msg, location=signode)
if ast.objectType == 'enumerator':
@ -3694,7 +3703,7 @@ class CDomain(Domain):
'texpr': CExprRole(asCode=False)
}
initial_data = {
'root_symbol': Symbol(None, None, None, None),
'root_symbol': Symbol(None, None, None, None, None),
'objects': {}, # fullname -> docname, node_id, objtype
} # type: Dict[str, Union[Symbol, Dict[str, Tuple[str, str, str]]]]

View File

@ -3798,7 +3798,7 @@ class Symbol:
assert False # shouldn't happen
else:
# the domain base class makes a copy of the initial data, which is fine
return Symbol(None, None, None, None, None, None)
return Symbol(None, None, None, None, None, None, None)
@staticmethod
def debug_print(*args: Any) -> None:
@ -3825,7 +3825,8 @@ class Symbol:
def __init__(self, parent: "Symbol", identOrOp: Union[ASTIdentifier, ASTOperator],
templateParams: Union[ASTTemplateParams, ASTTemplateIntroduction],
templateArgs: Any, declaration: ASTDeclaration, docname: str) -> None:
templateArgs: Any, declaration: ASTDeclaration,
docname: str, line: int) -> None:
self.parent = parent
# declarations in a single directive are linked together
self.siblingAbove = None # type: Symbol
@ -3835,6 +3836,7 @@ class Symbol:
self.templateArgs = templateArgs # identifier<templateArgs>
self.declaration = declaration
self.docname = docname
self.line = line
self.isRedeclaration = False
self._assert_invariants()
@ -3850,15 +3852,18 @@ class Symbol:
# Do symbol addition after self._children has been initialised.
self._add_template_and_function_params()
def _fill_empty(self, declaration: ASTDeclaration, docname: str) -> None:
def _fill_empty(self, declaration: ASTDeclaration, docname: str, line: int) -> None:
self._assert_invariants()
assert not self.declaration
assert not self.docname
assert declaration
assert docname
assert self.declaration is None
assert self.docname is None
assert self.line is None
assert declaration is not None
assert docname is not None
assert line is not None
self.declaration = declaration
self.declaration.symbol = self
self.docname = docname
self.line = line
self._assert_invariants()
# and symbol addition should be done as well
self._add_template_and_function_params()
@ -3882,7 +3887,7 @@ class Symbol:
decl = None
nne = ASTNestedNameElement(tp.get_identifier(), None)
nn = ASTNestedName([nne], [False], rooted=False)
self._add_symbols(nn, [], decl, self.docname)
self._add_symbols(nn, [], decl, self.docname, self.line)
# add symbols for function parameters, if any
if self.declaration is not None and self.declaration.function_params is not None:
for fp in self.declaration.function_params:
@ -3895,7 +3900,7 @@ class Symbol:
decl = ASTDeclaration('functionParam', None, None, None, None, fp, None)
assert not nn.rooted
assert len(nn.names) == 1
self._add_symbols(nn, [], decl, self.docname)
self._add_symbols(nn, [], decl, self.docname, self.line)
if Symbol.debug_lookup:
Symbol.debug_indent -= 1
@ -3913,6 +3918,7 @@ class Symbol:
if sChild.declaration and sChild.docname == docname:
sChild.declaration = None
sChild.docname = None
sChild.line = None
if sChild.siblingAbove is not None:
sChild.siblingAbove.siblingBelow = sChild.siblingBelow
if sChild.siblingBelow is not None:
@ -4223,7 +4229,7 @@ class Symbol:
identOrOp, templateParams, templateArgs)
def _add_symbols(self, nestedName: ASTNestedName, templateDecls: List[Any],
declaration: ASTDeclaration, docname: str) -> "Symbol":
declaration: ASTDeclaration, docname: str, line: int) -> "Symbol":
# Used for adding a whole path of symbols, where the last may or may not
# be an actual declaration.
@ -4232,9 +4238,9 @@ class Symbol:
Symbol.debug_print("_add_symbols:")
Symbol.debug_indent += 1
Symbol.debug_print("tdecls:", ",".join(str(t) for t in templateDecls))
Symbol.debug_print("nn: ", nestedName)
Symbol.debug_print("decl: ", declaration)
Symbol.debug_print("doc: ", docname)
Symbol.debug_print("nn: ", nestedName)
Symbol.debug_print("decl: ", declaration)
Symbol.debug_print("location: {}:{}".format(docname, line))
def onMissingQualifiedSymbol(parentSymbol: "Symbol",
identOrOp: Union[ASTIdentifier, ASTOperator],
@ -4251,7 +4257,7 @@ class Symbol:
return Symbol(parent=parentSymbol, identOrOp=identOrOp,
templateParams=templateParams,
templateArgs=templateArgs, declaration=None,
docname=None)
docname=None, line=None)
lookupResult = self._symbol_lookup(nestedName, templateDecls,
onMissingQualifiedSymbol,
@ -4272,14 +4278,14 @@ class Symbol:
Symbol.debug_print("identOrOp: ", lookupResult.identOrOp)
Symbol.debug_print("templateArgs: ", lookupResult.templateArgs)
Symbol.debug_print("declaration: ", declaration)
Symbol.debug_print("docname: ", docname)
Symbol.debug_print("location: {}:{}".format(docname, line))
Symbol.debug_indent -= 1
symbol = Symbol(parent=lookupResult.parentSymbol,
identOrOp=lookupResult.identOrOp,
templateParams=lookupResult.templateParams,
templateArgs=lookupResult.templateArgs,
declaration=declaration,
docname=docname)
docname=docname, line=line)
if Symbol.debug_lookup:
Symbol.debug_indent -= 2
return symbol
@ -4328,7 +4334,7 @@ class Symbol:
templateParams=lookupResult.templateParams,
templateArgs=lookupResult.templateArgs,
declaration=declaration,
docname=docname)
docname=docname, line=line)
if Symbol.debug_lookup:
Symbol.debug_print("end: creating candidate symbol")
return symbol
@ -4400,7 +4406,7 @@ class Symbol:
# .. namespace:: Test
# .. namespace:: nullptr
# .. class:: Test
symbol._fill_empty(declaration, docname)
symbol._fill_empty(declaration, docname, line)
return symbol
def merge_with(self, other: "Symbol", docnames: List[str],
@ -4479,13 +4485,15 @@ class Symbol:
continue
if otherChild.declaration and otherChild.docname in docnames:
if not ourChild.declaration:
ourChild._fill_empty(otherChild.declaration, otherChild.docname)
ourChild._fill_empty(otherChild.declaration,
otherChild.docname, otherChild.line)
elif ourChild.docname != otherChild.docname:
name = str(ourChild.declaration)
msg = __("Duplicate C++ declaration, also defined in '%s'.\n"
"Declaration is '%s'.")
msg = msg % (ourChild.docname, name)
logger.warning(msg, location=otherChild.docname)
msg = __("Duplicate C++ declaration, also defined at %s:%s.\n"
"Declaration is '.. cpp:%s:: %s'.")
msg = msg % (ourChild.docname, ourChild.line,
ourChild.declaration.directiveType, name)
logger.warning(msg, location=(otherChild.docname, otherChild.line))
else:
# Both have declarations, and in the same docname.
# This can apparently happen, it should be safe to
@ -4509,23 +4517,25 @@ class Symbol:
else:
templateDecls = []
res = self._add_symbols(nestedName, templateDecls,
declaration=None, docname=None)
declaration=None, docname=None, line=None)
if Symbol.debug_lookup:
Symbol.debug_indent -= 1
return res
def add_declaration(self, declaration: ASTDeclaration, docname: str) -> "Symbol":
def add_declaration(self, declaration: ASTDeclaration,
docname: str, line: int) -> "Symbol":
if Symbol.debug_lookup:
Symbol.debug_indent += 1
Symbol.debug_print("add_declaration:")
assert declaration
assert docname
assert declaration is not None
assert docname is not None
assert line is not None
nestedName = declaration.name
if declaration.templatePrefix:
templateDecls = declaration.templatePrefix.templates
else:
templateDecls = []
res = self._add_symbols(nestedName, templateDecls, declaration, docname)
res = self._add_symbols(nestedName, templateDecls, declaration, docname, line)
if Symbol.debug_lookup:
Symbol.debug_indent -= 1
return res
@ -4720,7 +4730,8 @@ class Symbol:
templateParams=lookupResult.templateParams,
templateArgs=lookupResult.templateArgs,
declaration=declaration,
docname='fakeDocnameForQuery')
docname='fakeDocnameForQuery',
line=42)
queryId = declaration.get_newest_id()
for symbol in symbols:
if symbol.declaration is None:
@ -6726,7 +6737,7 @@ class CPPObject(ObjectDescription):
Symbol(parent=targetSymbol, identOrOp=symbol.identOrOp,
templateParams=None, templateArgs=None,
declaration=declClone,
docname=self.env.docname)
docname=self.env.docname, line=self.get_source_info()[1])
def add_target_and_index(self, ast: ASTDeclaration, sig: str,
signode: TextElement) -> None:
@ -6840,7 +6851,7 @@ class CPPObject(ObjectDescription):
return super().run()
def handle_signature(self, sig: str, signode: desc_signature) -> ASTDeclaration:
parentSymbol = self.env.temp_data['cpp:parent_symbol']
parentSymbol = self.env.temp_data['cpp:parent_symbol'] # type: Symbol
parser = DefinitionParser(sig, location=signode, config=self.env.config)
try:
@ -6856,7 +6867,8 @@ class CPPObject(ObjectDescription):
raise ValueError from e
try:
symbol = parentSymbol.add_declaration(ast, docname=self.env.docname)
symbol = parentSymbol.add_declaration(
ast, docname=self.env.docname, line=self.get_source_info()[1])
# append the new declaration to the sibling list
assert symbol.siblingAbove is None
assert symbol.siblingBelow is None
@ -6869,9 +6881,10 @@ class CPPObject(ObjectDescription):
# Assume we are actually in the old symbol,
# instead of the newly created duplicate.
self.env.temp_data['cpp:last_symbol'] = e.symbol
msg = __("Duplicate C++ declaration, also defined in '%s'.\n"
"Declaration is '%s'.")
msg = msg % (e.symbol.docname, sig)
msg = __("Duplicate C++ declaration, also defined at %s:%s.\n"
"Declaration is '.. cpp:%s:: %s'.")
msg = msg % (e.symbol.docname, e.symbol.line,
self.display_object_type, sig)
logger.warning(msg, location=signode)
if ast.objectType == 'enumerator':
@ -7290,7 +7303,7 @@ class CPPDomain(Domain):
'texpr': CPPExprRole(asCode=False)
}
initial_data = {
'root_symbol': Symbol(None, None, None, None, None, None),
'root_symbol': Symbol(None, None, None, None, None, None, None),
'names': {} # full name for indexing -> docname
}

View File

@ -1225,7 +1225,9 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ
def format_signature(self, **kwargs: Any) -> str:
sigs = []
if self.analyzer and '.'.join(self.objpath) in self.analyzer.overloads:
if (self.analyzer and
'.'.join(self.objpath) in self.analyzer.overloads and
self.env.config.autodoc_typehints == 'signature'):
# Use signatures for overloaded functions instead of the implementation function.
overloaded = True
else:
@ -1459,7 +1461,7 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
sigs = []
overloads = self.get_overloaded_signatures()
if overloads:
if overloads and self.env.config.autodoc_typehints == 'signature':
# Use signatures for overloaded methods instead of the implementation method.
method = safe_getattr(self._signature_class, self._signature_method_name, None)
__globals__ = safe_getattr(method, '__globals__', {})
@ -1860,7 +1862,9 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
def format_signature(self, **kwargs: Any) -> str:
sigs = []
if self.analyzer and '.'.join(self.objpath) in self.analyzer.overloads:
if (self.analyzer and
'.'.join(self.objpath) in self.analyzer.overloads and
self.env.config.autodoc_typehints == 'signature'):
# Use signatures for overloaded methods instead of the implementation method.
overloaded = True
else:

View File

@ -695,6 +695,9 @@ class GoogleDocstring:
m = self._name_rgx.match(_type)
if m and m.group('name'):
_type = m.group('name')
elif _xref_regex.match(_type):
pos = _type.find('`')
_type = _type[pos + 1:-1]
_type = ' ' + _type if _type else ''
_desc = self._strip_empty(_desc)
_descs = ' ' + '\n '.join(_desc) if any(_desc) else ''
@ -1100,6 +1103,10 @@ class NumpyDocstring(GoogleDocstring):
_name, _type = line, ''
_name, _type = _name.strip(), _type.strip()
_name = self._escape_args_and_kwargs(_name)
if prefer_type and not _type:
_type, _name = _name, _type
if self._config.napoleon_preprocess_types:
_type = _convert_numpy_type_spec(
_type,
@ -1107,8 +1114,6 @@ class NumpyDocstring(GoogleDocstring):
translations=self._config.napoleon_type_aliases or {},
)
if prefer_type and not _type:
_type, _name = _name, _type
indent = self._get_indent(line) + 1
_desc = self._dedent(self._consume_indented_block(indent))
_desc = self.__class__(_desc, self._config).lines()
@ -1184,6 +1189,22 @@ class NumpyDocstring(GoogleDocstring):
items.append((name, list(rest), role))
del rest[:]
def translate(func, description, role):
translations = self._config.napoleon_type_aliases
if role is not None or not translations:
return func, description, role
translated = translations.get(func, func)
match = self._name_rgx.match(translated)
if not match:
return translated, description, role
groups = match.groupdict()
role = groups["role"]
new_func = groups["name"] or groups["name2"]
return new_func, description, role
current_func = None
rest = [] # type: List[str]
@ -1214,37 +1235,19 @@ class NumpyDocstring(GoogleDocstring):
if not items:
return []
roles = {
'method': 'meth',
'meth': 'meth',
'function': 'func',
'func': 'func',
'class': 'class',
'exception': 'exc',
'exc': 'exc',
'object': 'obj',
'obj': 'obj',
'module': 'mod',
'mod': 'mod',
'data': 'data',
'constant': 'const',
'const': 'const',
'attribute': 'attr',
'attr': 'attr'
}
if self._what is None:
func_role = 'obj'
else:
func_role = roles.get(self._what, '')
# apply type aliases
items = [
translate(func, description, role)
for func, description, role in items
]
lines = [] # type: List[str]
last_had_desc = True
for func, desc, role in items:
for name, desc, role in items:
if role:
link = ':%s:`%s`' % (role, func)
elif func_role:
link = ':%s:`%s`' % (func_role, func)
link = ':%s:`%s`' % (role, name)
else:
link = "`%s`_" % func
link = ':obj:`%s`' % name
if desc or last_had_desc:
lines += ['']
lines += [link]

View File

@ -11,8 +11,7 @@
from typing import Any, Dict
from typing import TYPE_CHECKING
from docutils import nodes
from docutils.transforms.references import DanglingReferences, Substitutions
from docutils.transforms.references import DanglingReferences
from sphinx.transforms import SphinxTransform
@ -20,17 +19,6 @@ if TYPE_CHECKING:
from sphinx.application import Sphinx
class SubstitutionDefinitionsRemover(SphinxTransform):
"""Remove ``substitution_definition node from doctrees."""
# should be invoked after Substitutions process
default_priority = Substitutions.default_priority + 1
def apply(self, **kwargs: Any) -> None:
for node in self.document.traverse(nodes.substitution_definition):
node.parent.remove(node)
class SphinxDanglingReferences(DanglingReferences):
"""DanglingReferences transform which does not output info messages."""
@ -56,7 +44,6 @@ class SphinxDomains(SphinxTransform):
def setup(app: "Sphinx") -> Dict[str, Any]:
app.add_transform(SubstitutionDefinitionsRemover)
app.add_transform(SphinxDanglingReferences)
app.add_transform(SphinxDomains)

View File

@ -1241,6 +1241,15 @@ class TexinfoTranslator(SphinxTranslator):
def depart_legend(self, node: Element) -> None:
pass
def visit_substitution_reference(self, node: Element) -> None:
pass
def depart_substitution_reference(self, node: Element) -> None:
pass
def visit_substitution_definition(self, node: Element) -> None:
raise nodes.SkipNode
def visit_system_message(self, node: Element) -> None:
self.body.append('\n@verbatim\n'
'<SYSTEM MESSAGE: %s>\n'

View File

@ -1012,6 +1012,9 @@ class TextTranslator(SphinxTranslator):
def visit_toctree(self, node: Element) -> None:
raise nodes.SkipNode
def visit_substitution_definition(self, node: Element) -> None:
raise nodes.SkipNode
def visit_pending_xref(self, node: Element) -> None:
pass

View File

@ -54,8 +54,8 @@ def _check(name, input, idDict, output, key, asTextOutput):
print("Result: ", res)
print("Expected: ", outputAst)
raise DefinitionError("")
rootSymbol = Symbol(None, None, None, None)
symbol = rootSymbol.add_declaration(ast, docname="TestDoc")
rootSymbol = Symbol(None, None, None, None, None)
symbol = rootSymbol.add_declaration(ast, docname="TestDoc", line=42)
parentNode = addnodes.desc()
signode = addnodes.desc_signature(input, '')
parentNode += signode

View File

@ -59,8 +59,8 @@ def _check(name, input, idDict, output, key, asTextOutput):
print("Result: ", res)
print("Expected: ", outputAst)
raise DefinitionError("")
rootSymbol = Symbol(None, None, None, None, None, None)
symbol = rootSymbol.add_declaration(ast, docname="TestDoc")
rootSymbol = Symbol(None, None, None, None, None, None, None)
symbol = rootSymbol.add_declaration(ast, docname="TestDoc", line=42)
parentNode = addnodes.desc()
signode = addnodes.desc_signature(input, '')
parentNode += signode
@ -1241,8 +1241,8 @@ def test_mix_decl_duplicate(app, warning):
restructuredtext.parse(app, text)
ws = warning.getvalue().split("\n")
assert len(ws) == 5
assert "index.rst:2: WARNING: Duplicate C++ declaration, also defined in 'index'." in ws[0]
assert "Declaration is 'void A()'." in ws[1]
assert "index.rst:3: WARNING: Duplicate C++ declaration, also defined in 'index'." in ws[2]
assert "Declaration is 'A'." in ws[3]
assert "index.rst:2: WARNING: Duplicate C++ declaration, also defined at index:1." in ws[0]
assert "Declaration is '.. cpp:function:: void A()'." in ws[1]
assert "index.rst:3: WARNING: Duplicate C++ declaration, also defined at index:1." in ws[2]
assert "Declaration is '.. cpp:struct:: A'." in ws[3]
assert ws[4] == ""

View File

@ -610,6 +610,54 @@ def test_autodoc_typehints_none(app):
]
@pytest.mark.sphinx('html', testroot='ext-autodoc',
confoverrides={'autodoc_typehints': 'none'})
def test_autodoc_typehints_none_for_overload(app):
options = {"members": None}
actual = do_autodoc(app, 'module', 'target.overload', options)
assert list(actual) == [
'',
'.. py:module:: target.overload',
'',
'',
'.. py:class:: Bar(x, y)',
' :module: target.overload',
'',
' docstring',
'',
'',
'.. py:class:: Baz(x, y)',
' :module: target.overload',
'',
' docstring',
'',
'',
'.. py:class:: Foo(x, y)',
' :module: target.overload',
'',
' docstring',
'',
'',
'.. py:class:: Math()',
' :module: target.overload',
'',
' docstring',
'',
'',
' .. py:method:: Math.sum(x, y)',
' :module: target.overload',
'',
' docstring',
'',
'',
'.. py:function:: sum(x, y)',
' :module: target.overload',
'',
' docstring',
'',
]
@pytest.mark.sphinx('text', testroot='ext-autodoc',
confoverrides={'autodoc_typehints': "description"})
def test_autodoc_typehints_description(app):

View File

@ -1177,7 +1177,7 @@ class NumpyDocstringTest(BaseDocstringTest):
"""
Single line summary
:returns: *str* -- Extended
:returns: :class:`str` -- Extended
description of return value
"""
), (
@ -1193,7 +1193,7 @@ class NumpyDocstringTest(BaseDocstringTest):
"""
Single line summary
:returns: *str* -- Extended
:returns: :class:`str` -- Extended
description of return value
"""
), (
@ -1246,7 +1246,7 @@ class NumpyDocstringTest(BaseDocstringTest):
"""
Single line summary
:Yields: *str* -- Extended
:Yields: :class:`str` -- Extended
description of yielded value
"""
), (
@ -1262,7 +1262,7 @@ class NumpyDocstringTest(BaseDocstringTest):
"""
Single line summary
:Yields: *str* -- Extended
:Yields: :class:`str` -- Extended
description of yielded value
"""
)]
@ -1455,9 +1455,38 @@ numpy.multivariate_normal(mean, cov, shape=None, spam=None)
.. seealso::
:meth:`some`, :meth:`other`, :meth:`funcs`
:obj:`some`, :obj:`other`, :obj:`funcs`
\n\
:meth:`otherfunc`
:obj:`otherfunc`
relationship
"""
self.assertEqual(expected, actual)
docstring = """\
numpy.multivariate_normal(mean, cov, shape=None, spam=None)
See Also
--------
some, other, :func:`funcs`
otherfunc : relationship
"""
translations = {
"other": "MyClass.other",
"otherfunc": ":func:`~my_package.otherfunc`",
}
config = Config(napoleon_type_aliases=translations)
app = mock.Mock()
actual = str(NumpyDocstring(docstring, config, app, "method"))
expected = """\
numpy.multivariate_normal(mean, cov, shape=None, spam=None)
.. seealso::
:obj:`some`, :obj:`MyClass.other`, :func:`funcs`
\n\
:func:`~my_package.otherfunc`
relationship
"""
self.assertEqual(expected, actual)
@ -1526,6 +1555,52 @@ arg_ : type
self.assertEqual(expected, actual)
def test_return_types(self):
docstring = dedent("""
Returns
-------
DataFrame
a dataframe
""")
expected = dedent("""
:returns: a dataframe
:rtype: :class:`~pandas.DataFrame`
""")
translations = {
"DataFrame": "~pandas.DataFrame",
}
config = Config(
napoleon_use_param=True,
napoleon_use_rtype=True,
napoleon_preprocess_types=True,
napoleon_type_aliases=translations,
)
actual = str(NumpyDocstring(docstring, config))
self.assertEqual(expected, actual)
def test_yield_types(self):
docstring = dedent("""
Example Function
Yields
------
scalar or array-like
The result of the computation
""")
expected = dedent("""
Example Function
:Yields: :term:`scalar` or :class:`array-like <numpy.ndarray>` -- The result of the computation
""")
translations = {
"scalar": ":term:`scalar`",
"array-like": ":class:`array-like <numpy.ndarray>`",
}
config = Config(napoleon_type_aliases=translations, napoleon_preprocess_types=True)
app = mock.Mock()
actual = str(NumpyDocstring(docstring, config, app, "method"))
self.assertEqual(expected, actual)
def test_raises_types(self):
docstrings = [("""
Example Function
@ -1690,6 +1765,34 @@ Example Function
("""
Example Function
Raises
------
CustomError
If the dimensions couldn't be parsed.
""", """
Example Function
:raises package.CustomError: If the dimensions couldn't be parsed.
"""),
################################
("""
Example Function
Raises
------
AnotherError
If the dimensions couldn't be parsed.
""", """
Example Function
:raises ~package.AnotherError: If the dimensions couldn't be parsed.
"""),
################################
("""
Example Function
Raises
------
:class:`exc.InvalidDimensionsError`
@ -1702,7 +1805,11 @@ Example Function
:raises exc.InvalidArgumentsError:
""")]
for docstring, expected in docstrings:
config = Config()
translations = {
"CustomError": "package.CustomError",
"AnotherError": ":py:exc:`~package.AnotherError`",
}
config = Config(napoleon_type_aliases=translations, napoleon_preprocess_types=True)
app = mock.Mock()
actual = str(NumpyDocstring(docstring, config, app, "method"))
self.assertEqual(expected, actual)