summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakeshi KOMIYA <i.tkomiya@gmail.com>2020-09-21 00:49:23 +0900
committerGitHub <noreply@github.com>2020-09-21 00:49:23 +0900
commitb454d4e4b0801105ad1517289c972ca2030cedd7 (patch)
treecb715a3a29d8c7cf0ebf11f2b70abb4b5a4eeb80
parentfd3d654c17874d4cbffbd8e9379728f83a31b30b (diff)
parent3c017dcdee6b9f4b7f5e46b3b0ba2cebced4d4dc (diff)
downloadsphinx-git-b454d4e4b0801105ad1517289c972ca2030cedd7.tar.gz
Merge branch '3.x' into 8190_autodoc-process-docstring-without_ending_blankline
-rw-r--r--CHANGES12
-rw-r--r--doc/usage/restructuredtext/domains.rst12
-rw-r--r--package-lock.json22
-rw-r--r--sphinx/builders/html/__init__.py13
-rw-r--r--sphinx/builders/latex/__init__.py2
-rw-r--r--sphinx/directives/code.py2
-rw-r--r--sphinx/domains/c.py76
-rw-r--r--sphinx/domains/cpp.py2
-rw-r--r--sphinx/ext/inheritance_diagram.py5
-rw-r--r--sphinx/ext/napoleon/docstring.py2
-rw-r--r--sphinx/util/fileutil.py18
-rw-r--r--sphinx/util/inspect.py5
-rw-r--r--tests/roots/test-ext-autodoc/target/cached_property.py7
-rw-r--r--tests/test_build_html.py8
-rw-r--r--tests/test_ext_autodoc.py20
15 files changed, 163 insertions, 43 deletions
diff --git a/CHANGES b/CHANGES
index c8de2d7e6..39eafd713 100644
--- a/CHANGES
+++ b/CHANGES
@@ -13,14 +13,22 @@ Deprecated
Features added
--------------
+* #8100: html: Show a better error message for failures on copying
+ html_static_files
+* #8141: C: added a ``maxdepth`` option to :rst:dir:`c:alias` to insert
+ nested declarations.
+
Bugs fixed
----------
* #8085: i18n: Add support for having single text domain
* #8143: autodoc: AttributeError is raised when False value is passed to
autodoc_default_options
+* #8103: autodoc: functools.cached_property is not considered as a property
* #8190: autodoc: parsing error is raised if some extension replaces docstring
by string not ending with blank lines
+* #8192: napoleon: description is disappeared when it contains inline literals
+* #8169: LaTeX: pxjahyper loaded even when latex_engine is not platex
* #8093: The highlight warning has wrong location in some builders (LaTeX,
singlehtml and so on)
@@ -45,6 +53,10 @@ Features added
Bugs fixed
----------
+* #8188: C, add missing items to internal object types dictionary,
+ e.g., preventing intersphinx from resolving them.
+
+
Testing
--------
diff --git a/doc/usage/restructuredtext/domains.rst b/doc/usage/restructuredtext/domains.rst
index 311b03d66..f3754ab7c 100644
--- a/doc/usage/restructuredtext/domains.rst
+++ b/doc/usage/restructuredtext/domains.rst
@@ -744,6 +744,18 @@ The following directive can be used for this purpose.
.. versionadded:: 3.2
+
+ .. rubric:: Options
+
+ .. rst:directive:option:: maxdepth: int
+
+ Insert nested declarations as well, up to the total depth given.
+ Use 0 for infinite depth and 1 for just the mentioned declaration.
+ Defaults to 1.
+
+ .. versionadded:: 3.3
+
+
.. c:namespace-pop::
diff --git a/package-lock.json b/package-lock.json
index e3fb91e21..087afcf3e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -385,12 +385,6 @@
"integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=",
"dev": true
},
- "eventemitter3": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz",
- "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==",
- "dev": true
- },
"extend": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
@@ -535,14 +529,22 @@
}
},
"http-proxy": {
- "version": "1.17.0",
- "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz",
- "integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==",
+ "version": "1.18.1",
+ "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz",
+ "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==",
"dev": true,
"requires": {
- "eventemitter3": "^3.0.0",
+ "eventemitter3": "^4.0.0",
"follow-redirects": "^1.0.0",
"requires-port": "^1.0.0"
+ },
+ "dependencies": {
+ "eventemitter3": {
+ "version": "4.0.7",
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
+ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==",
+ "dev": true
+ }
}
},
"iconv-lite": {
diff --git a/sphinx/builders/html/__init__.py b/sphinx/builders/html/__init__.py
index 923212a99..c30aa9cfd 100644
--- a/sphinx/builders/html/__init__.py
+++ b/sphinx/builders/html/__init__.py
@@ -751,18 +751,27 @@ class StandaloneHTMLBuilder(Builder):
copyfile(jsfile, path.join(self.outdir, '_static', '_stemmer.js'))
def copy_theme_static_files(self, context: Dict) -> None:
+ def onerror(filename: str, error: Exception) -> None:
+ logger.warning(__('Failed to copy a file in html_static_file: %s: %r'),
+ filename, error)
+
if self.theme:
for entry in self.theme.get_theme_dirs()[::-1]:
copy_asset(path.join(entry, 'static'),
path.join(self.outdir, '_static'),
- excluded=DOTFILES, context=context, renderer=self.templates)
+ excluded=DOTFILES, context=context,
+ renderer=self.templates, onerror=onerror)
def copy_html_static_files(self, context: Dict) -> None:
+ def onerror(filename: str, error: Exception) -> None:
+ logger.warning(__('Failed to copy a file in html_static_file: %s: %r'),
+ filename, error)
+
excluded = Matcher(self.config.exclude_patterns + ["**/.*"])
for entry in self.config.html_static_path:
copy_asset(path.join(self.confdir, entry),
path.join(self.outdir, '_static'),
- excluded, context=context, renderer=self.templates)
+ excluded, context=context, renderer=self.templates, onerror=onerror)
def copy_html_logo(self) -> None:
if self.config.html_logo:
diff --git a/sphinx/builders/latex/__init__.py b/sphinx/builders/latex/__init__.py
index 88c471675..ffb17d2eb 100644
--- a/sphinx/builders/latex/__init__.py
+++ b/sphinx/builders/latex/__init__.py
@@ -505,7 +505,7 @@ def validate_latex_theme_options(app: Sphinx, config: Config) -> None:
def install_pakcages_for_ja(app: Sphinx) -> None:
"""Install packages for Japanese."""
- if app.config.language == 'ja':
+ if app.config.language == 'ja' and app.config.latex_engine in ('platex', 'uplatex'):
app.add_latex_package('pxjahyper', after_hyperref=True)
diff --git a/sphinx/directives/code.py b/sphinx/directives/code.py
index f1f4a341a..4ca849cf0 100644
--- a/sphinx/directives/code.py
+++ b/sphinx/directives/code.py
@@ -72,7 +72,7 @@ def dedent_lines(lines: List[str], dedent: int, location: Tuple[str, int] = None
return lines
if any(s[:dedent].strip() for s in lines):
- logger.warning(__('Over dedent has detected'), location=location)
+ logger.warning(__('non-whitespace stripped by dedent'), location=location)
new_lines = []
for line in lines:
diff --git a/sphinx/domains/c.py b/sphinx/domains/c.py
index d8ccc2e3d..304c871ea 100644
--- a/sphinx/domains/c.py
+++ b/sphinx/domains/c.py
@@ -136,8 +136,8 @@ class ASTIdentifier(ASTBaseBase):
reftype='identifier',
reftarget=targetText, modname=None,
classname=None)
- # key = symbol.get_lookup_key()
- # pnode['c:parent_key'] = key
+ key = symbol.get_lookup_key()
+ pnode['c:parent_key'] = key
if self.is_anon():
pnode += nodes.strong(text="[anonymous]")
else:
@@ -1563,6 +1563,11 @@ class Symbol:
yield s
@property
+ def children(self) -> Iterator["Symbol"]:
+ for c in self._children:
+ yield c
+
+ @property
def children_recurse_anon(self) -> Iterator["Symbol"]:
for c in self._children:
yield c
@@ -1792,7 +1797,7 @@ class Symbol:
if not declaration:
if Symbol.debug_lookup:
- Symbol.debug_print("no delcaration")
+ Symbol.debug_print("no declaration")
Symbol.debug_indent -= 2
# good, just a scope creation
# TODO: what if we have more than one symbol?
@@ -3408,10 +3413,13 @@ class CNamespacePopObject(SphinxDirective):
class AliasNode(nodes.Element):
- def __init__(self, sig: str, env: "BuildEnvironment" = None,
+ def __init__(self, sig: str, maxdepth: int, document: Any, env: "BuildEnvironment" = None,
parentKey: LookupKey = None) -> None:
super().__init__()
self.sig = sig
+ self.maxdepth = maxdepth
+ assert maxdepth >= 0
+ self.document = document
if env is not None:
if 'c:parent_symbol' not in env.temp_data:
root = env.domaindata['c']['root_symbol']
@@ -3428,6 +3436,37 @@ class AliasNode(nodes.Element):
class AliasTransform(SphinxTransform):
default_priority = ReferencesResolver.default_priority - 1
+ def _render_symbol(self, s: Symbol, maxdepth: int, document: Any) -> List[Node]:
+ nodes = [] # type: List[Node]
+ options = dict() # type: ignore
+ signode = addnodes.desc_signature('', '')
+ nodes.append(signode)
+ s.declaration.describe_signature(signode, 'markName', self.env, options)
+ if maxdepth == 0:
+ recurse = True
+ elif maxdepth == 1:
+ recurse = False
+ else:
+ maxdepth -= 1
+ recurse = True
+ if recurse:
+ content = addnodes.desc_content()
+ desc = addnodes.desc()
+ content.append(desc)
+ desc.document = document
+ desc['domain'] = 'c'
+ # 'desctype' is a backwards compatible attribute
+ desc['objtype'] = desc['desctype'] = 'alias'
+ desc['noindex'] = True
+
+ for sChild in s.children:
+ childNodes = self._render_symbol(sChild, maxdepth, document)
+ desc.extend(childNodes)
+
+ if len(desc.children) != 0:
+ nodes.append(content)
+ return nodes
+
def apply(self, **kwargs: Any) -> None:
for node in self.document.traverse(AliasNode):
sig = node.sig
@@ -3468,17 +3507,16 @@ class AliasTransform(SphinxTransform):
logger.warning("Could not find C declaration for alias '%s'." % name,
location=node)
node.replace_self(signode)
- else:
- nodes = []
- options = dict() # type: ignore
- signode = addnodes.desc_signature(sig, '')
- nodes.append(signode)
- s.declaration.describe_signature(signode, 'markName', self.env, options)
- node.replace_self(nodes)
+ continue
+
+ nodes = self._render_symbol(s, maxdepth=node.maxdepth, document=node.document)
+ node.replace_self(nodes)
class CAliasObject(ObjectDescription):
- option_spec = {} # type: Dict
+ option_spec = {
+ 'maxdepth': directives.nonnegative_int
+ } # type: Dict
def run(self) -> List[Node]:
if ':' in self.name:
@@ -3494,16 +3532,10 @@ class CAliasObject(ObjectDescription):
node['noindex'] = True
self.names = [] # type: List[str]
+ maxdepth = self.options.get('maxdepth', 1)
signatures = self.get_signatures()
for i, sig in enumerate(signatures):
- node.append(AliasNode(sig, env=self.env))
-
- contentnode = addnodes.desc_content()
- node.append(contentnode)
- self.before_content()
- self.state.nested_parse(self.content, self.content_offset, contentnode)
- self.env.temp_data['object'] = None
- self.after_content()
+ node.append(AliasNode(sig, maxdepth, self.state.document, env=self.env))
return [node]
@@ -3607,6 +3639,10 @@ class CDomain(Domain):
'macro': ObjType(_('macro'), 'macro'),
'type': ObjType(_('type'), 'type'),
'var': ObjType(_('variable'), 'data'),
+ 'enum': ObjType(_('enum'), 'enum'),
+ 'enumerator': ObjType(_('enumerator'), 'enumerator'),
+ 'struct': ObjType(_('struct'), 'struct'),
+ 'union': ObjType(_('union'), 'union'),
}
directives = {
diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py
index 92d578427..7b10f8166 100644
--- a/sphinx/domains/cpp.py
+++ b/sphinx/domains/cpp.py
@@ -4292,7 +4292,7 @@ class Symbol:
if not declaration:
if Symbol.debug_lookup:
- Symbol.debug_print("no delcaration")
+ Symbol.debug_print("no declaration")
Symbol.debug_indent -= 2
# good, just a scope creation
# TODO: what if we have more than one symbol?
diff --git a/sphinx/ext/inheritance_diagram.py b/sphinx/ext/inheritance_diagram.py
index 7b2383fca..71a123b15 100644
--- a/sphinx/ext/inheritance_diagram.py
+++ b/sphinx/ext/inheritance_diagram.py
@@ -66,6 +66,10 @@ module_sig_re = re.compile(r'''^(?:([\w.]*)\.)? # module names
''', re.VERBOSE)
+py_builtins = [obj for obj in vars(builtins).values()
+ if inspect.isclass(obj)]
+
+
def try_import(objname: str) -> Any:
"""Import a object or module using *name* and *currentmodule*.
*name* should be a relative name from *currentmodule* or
@@ -178,7 +182,6 @@ class InheritanceGraph:
traverse to. Multiple names can be specified separated by comma.
"""
all_classes = {}
- py_builtins = vars(builtins).values()
def recurse(cls: Any) -> None:
if not show_builtins and cls in py_builtins:
diff --git a/sphinx/ext/napoleon/docstring.py b/sphinx/ext/napoleon/docstring.py
index 4397d0e41..97eaa0fd6 100644
--- a/sphinx/ext/napoleon/docstring.py
+++ b/sphinx/ext/napoleon/docstring.py
@@ -36,7 +36,7 @@ _numpy_section_regex = re.compile(r'^[=\-`:\'"~^_*+#<>]{2,}\s*$')
_single_colon_regex = re.compile(r'(?<!:):(?!:)')
_xref_or_code_regex = re.compile(
r'((?::(?:[a-zA-Z0-9]+[\-_+:.])*[a-zA-Z0-9]+:`.+?`)|'
- r'(?:``.+``))')
+ r'(?:``.+?``))')
_xref_regex = re.compile(
r'(?:(?::(?:[a-zA-Z0-9]+[\-_+:.])*[a-zA-Z0-9]+:)?`.+?`)'
)
diff --git a/sphinx/util/fileutil.py b/sphinx/util/fileutil.py
index d8e896d48..eec1ae463 100644
--- a/sphinx/util/fileutil.py
+++ b/sphinx/util/fileutil.py
@@ -10,7 +10,7 @@
import os
import posixpath
-from typing import Dict
+from typing import Callable, Dict
from docutils.utils import relative_path
@@ -56,7 +56,8 @@ def copy_asset_file(source: str, destination: str,
def copy_asset(source: str, destination: str, excluded: PathMatcher = lambda path: False,
- context: Dict = None, renderer: "BaseRenderer" = None) -> None:
+ context: Dict = None, renderer: "BaseRenderer" = None,
+ onerror: Callable[[str, Exception], None] = None) -> None:
"""Copy asset files to destination recursively.
On copying, it expands the template variables if context argument is given and
@@ -67,6 +68,7 @@ def copy_asset(source: str, destination: str, excluded: PathMatcher = lambda pat
:param excluded: The matcher to determine the given path should be copied or not
:param context: The template variables. If not given, template files are simply copied
:param renderer: The template engine. If not given, SphinxRenderer is used by default
+ :param onerror: The error handler.
"""
if not os.path.exists(source):
return
@@ -90,6 +92,12 @@ def copy_asset(source: str, destination: str, excluded: PathMatcher = lambda pat
for filename in files:
if not excluded(posixpath.join(reldir, filename)):
- copy_asset_file(posixpath.join(root, filename),
- posixpath.join(destination, reldir),
- context, renderer)
+ try:
+ copy_asset_file(posixpath.join(root, filename),
+ posixpath.join(destination, reldir),
+ context, renderer)
+ except Exception as exc:
+ if onerror:
+ onerror(posixpath.join(root, filename), exc)
+ else:
+ raise
diff --git a/sphinx/util/inspect.py b/sphinx/util/inspect.py
index a5c64f882..37997e6b2 100644
--- a/sphinx/util/inspect.py
+++ b/sphinx/util/inspect.py
@@ -304,6 +304,11 @@ def iscoroutinefunction(obj: Any) -> bool:
def isproperty(obj: Any) -> bool:
"""Check if the object is property."""
+ if sys.version_info > (3, 8):
+ from functools import cached_property # cached_property is available since py3.8
+ if isinstance(obj, cached_property):
+ return True
+
return isinstance(obj, property)
diff --git a/tests/roots/test-ext-autodoc/target/cached_property.py b/tests/roots/test-ext-autodoc/target/cached_property.py
new file mode 100644
index 000000000..63ec09f8e
--- /dev/null
+++ b/tests/roots/test-ext-autodoc/target/cached_property.py
@@ -0,0 +1,7 @@
+from functools import cached_property
+
+
+class Foo:
+ @cached_property
+ def prop(self) -> int:
+ return 1
diff --git a/tests/test_build_html.py b/tests/test_build_html.py
index e949f1157..1efc6c14a 100644
--- a/tests/test_build_html.py
+++ b/tests/test_build_html.py
@@ -10,8 +10,10 @@
import os
import re
+from distutils.version import LooseVersion
from itertools import cycle, chain
+import pygments
import pytest
from html5lib import HTMLParser
@@ -1591,4 +1593,8 @@ def test_html_codeblock_linenos_style_inline(app):
app.build()
content = (app.outdir / 'index.html').read_text()
- assert '<span class="lineno">1 </span>' in content
+ pygments_version = tuple(LooseVersion(pygments.__version__).version)
+ if pygments_version > (2, 7):
+ assert '<span class="linenos">1</span>' in content
+ else:
+ assert '<span class="lineno">1 </span>' in content
diff --git a/tests/test_ext_autodoc.py b/tests/test_ext_autodoc.py
index 90a2ec95a..1ba64a0a7 100644
--- a/tests/test_ext_autodoc.py
+++ b/tests/test_ext_autodoc.py
@@ -881,6 +881,26 @@ def test_autodoc_descriptor(app):
]
+@pytest.mark.skipif(sys.version_info < (3, 8),
+ reason='cached_property is available since python3.8.')
+@pytest.mark.sphinx('html', testroot='ext-autodoc')
+def test_autodoc_cached_property(app):
+ options = {"members": None,
+ "undoc-members": True}
+ actual = do_autodoc(app, 'class', 'target.cached_property.Foo', options)
+ assert list(actual) == [
+ '',
+ '.. py:class:: Foo()',
+ ' :module: target.cached_property',
+ '',
+ '',
+ ' .. py:method:: Foo.prop',
+ ' :module: target.cached_property',
+ ' :property:',
+ '',
+ ]
+
+
@pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_autodoc_member_order(app):
# case member-order='bysource'