mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge branch '3.x' into 8190_autodoc-process-docstring-without_ending_blankline
This commit is contained in:
12
CHANGES
12
CHANGES
@@ -13,14 +13,22 @@ Deprecated
|
|||||||
Features added
|
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
|
Bugs fixed
|
||||||
----------
|
----------
|
||||||
|
|
||||||
* #8085: i18n: Add support for having single text domain
|
* #8085: i18n: Add support for having single text domain
|
||||||
* #8143: autodoc: AttributeError is raised when False value is passed to
|
* #8143: autodoc: AttributeError is raised when False value is passed to
|
||||||
autodoc_default_options
|
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
|
* #8190: autodoc: parsing error is raised if some extension replaces docstring
|
||||||
by string not ending with blank lines
|
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,
|
* #8093: The highlight warning has wrong location in some builders (LaTeX,
|
||||||
singlehtml and so on)
|
singlehtml and so on)
|
||||||
|
|
||||||
@@ -45,6 +53,10 @@ Features added
|
|||||||
Bugs fixed
|
Bugs fixed
|
||||||
----------
|
----------
|
||||||
|
|
||||||
|
* #8188: C, add missing items to internal object types dictionary,
|
||||||
|
e.g., preventing intersphinx from resolving them.
|
||||||
|
|
||||||
|
|
||||||
Testing
|
Testing
|
||||||
--------
|
--------
|
||||||
|
|
||||||
|
|||||||
@@ -744,6 +744,18 @@ The following directive can be used for this purpose.
|
|||||||
|
|
||||||
.. versionadded:: 3.2
|
.. 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::
|
.. c:namespace-pop::
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
22
package-lock.json
generated
22
package-lock.json
generated
@@ -385,12 +385,6 @@
|
|||||||
"integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=",
|
"integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=",
|
||||||
"dev": true
|
"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": {
|
"extend": {
|
||||||
"version": "3.0.2",
|
"version": "3.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
|
||||||
@@ -535,14 +529,22 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"http-proxy": {
|
"http-proxy": {
|
||||||
"version": "1.17.0",
|
"version": "1.18.1",
|
||||||
"resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz",
|
"resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz",
|
||||||
"integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==",
|
"integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"eventemitter3": "^3.0.0",
|
"eventemitter3": "^4.0.0",
|
||||||
"follow-redirects": "^1.0.0",
|
"follow-redirects": "^1.0.0",
|
||||||
"requires-port": "^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": {
|
"iconv-lite": {
|
||||||
|
|||||||
@@ -751,18 +751,27 @@ class StandaloneHTMLBuilder(Builder):
|
|||||||
copyfile(jsfile, path.join(self.outdir, '_static', '_stemmer.js'))
|
copyfile(jsfile, path.join(self.outdir, '_static', '_stemmer.js'))
|
||||||
|
|
||||||
def copy_theme_static_files(self, context: Dict) -> None:
|
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:
|
if self.theme:
|
||||||
for entry in self.theme.get_theme_dirs()[::-1]:
|
for entry in self.theme.get_theme_dirs()[::-1]:
|
||||||
copy_asset(path.join(entry, 'static'),
|
copy_asset(path.join(entry, 'static'),
|
||||||
path.join(self.outdir, '_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 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 + ["**/.*"])
|
excluded = Matcher(self.config.exclude_patterns + ["**/.*"])
|
||||||
for entry in self.config.html_static_path:
|
for entry in self.config.html_static_path:
|
||||||
copy_asset(path.join(self.confdir, entry),
|
copy_asset(path.join(self.confdir, entry),
|
||||||
path.join(self.outdir, '_static'),
|
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:
|
def copy_html_logo(self) -> None:
|
||||||
if self.config.html_logo:
|
if self.config.html_logo:
|
||||||
|
|||||||
@@ -505,7 +505,7 @@ def validate_latex_theme_options(app: Sphinx, config: Config) -> None:
|
|||||||
|
|
||||||
def install_pakcages_for_ja(app: Sphinx) -> None:
|
def install_pakcages_for_ja(app: Sphinx) -> None:
|
||||||
"""Install packages for Japanese."""
|
"""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)
|
app.add_latex_package('pxjahyper', after_hyperref=True)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ def dedent_lines(lines: List[str], dedent: int, location: Tuple[str, int] = None
|
|||||||
return lines
|
return lines
|
||||||
|
|
||||||
if any(s[:dedent].strip() for s in 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 = []
|
new_lines = []
|
||||||
for line in lines:
|
for line in lines:
|
||||||
|
|||||||
@@ -136,8 +136,8 @@ class ASTIdentifier(ASTBaseBase):
|
|||||||
reftype='identifier',
|
reftype='identifier',
|
||||||
reftarget=targetText, modname=None,
|
reftarget=targetText, modname=None,
|
||||||
classname=None)
|
classname=None)
|
||||||
# key = symbol.get_lookup_key()
|
key = symbol.get_lookup_key()
|
||||||
# pnode['c:parent_key'] = key
|
pnode['c:parent_key'] = key
|
||||||
if self.is_anon():
|
if self.is_anon():
|
||||||
pnode += nodes.strong(text="[anonymous]")
|
pnode += nodes.strong(text="[anonymous]")
|
||||||
else:
|
else:
|
||||||
@@ -1562,6 +1562,11 @@ class Symbol:
|
|||||||
for s in sChild.get_all_symbols():
|
for s in sChild.get_all_symbols():
|
||||||
yield s
|
yield s
|
||||||
|
|
||||||
|
@property
|
||||||
|
def children(self) -> Iterator["Symbol"]:
|
||||||
|
for c in self._children:
|
||||||
|
yield c
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def children_recurse_anon(self) -> Iterator["Symbol"]:
|
def children_recurse_anon(self) -> Iterator["Symbol"]:
|
||||||
for c in self._children:
|
for c in self._children:
|
||||||
@@ -1792,7 +1797,7 @@ class Symbol:
|
|||||||
|
|
||||||
if not declaration:
|
if not declaration:
|
||||||
if Symbol.debug_lookup:
|
if Symbol.debug_lookup:
|
||||||
Symbol.debug_print("no delcaration")
|
Symbol.debug_print("no declaration")
|
||||||
Symbol.debug_indent -= 2
|
Symbol.debug_indent -= 2
|
||||||
# good, just a scope creation
|
# good, just a scope creation
|
||||||
# TODO: what if we have more than one symbol?
|
# TODO: what if we have more than one symbol?
|
||||||
@@ -3408,10 +3413,13 @@ class CNamespacePopObject(SphinxDirective):
|
|||||||
|
|
||||||
|
|
||||||
class AliasNode(nodes.Element):
|
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:
|
parentKey: LookupKey = None) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.sig = sig
|
self.sig = sig
|
||||||
|
self.maxdepth = maxdepth
|
||||||
|
assert maxdepth >= 0
|
||||||
|
self.document = document
|
||||||
if env is not None:
|
if env is not None:
|
||||||
if 'c:parent_symbol' not in env.temp_data:
|
if 'c:parent_symbol' not in env.temp_data:
|
||||||
root = env.domaindata['c']['root_symbol']
|
root = env.domaindata['c']['root_symbol']
|
||||||
@@ -3428,6 +3436,37 @@ class AliasNode(nodes.Element):
|
|||||||
class AliasTransform(SphinxTransform):
|
class AliasTransform(SphinxTransform):
|
||||||
default_priority = ReferencesResolver.default_priority - 1
|
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:
|
def apply(self, **kwargs: Any) -> None:
|
||||||
for node in self.document.traverse(AliasNode):
|
for node in self.document.traverse(AliasNode):
|
||||||
sig = node.sig
|
sig = node.sig
|
||||||
@@ -3468,17 +3507,16 @@ class AliasTransform(SphinxTransform):
|
|||||||
logger.warning("Could not find C declaration for alias '%s'." % name,
|
logger.warning("Could not find C declaration for alias '%s'." % name,
|
||||||
location=node)
|
location=node)
|
||||||
node.replace_self(signode)
|
node.replace_self(signode)
|
||||||
else:
|
continue
|
||||||
nodes = []
|
|
||||||
options = dict() # type: ignore
|
nodes = self._render_symbol(s, maxdepth=node.maxdepth, document=node.document)
|
||||||
signode = addnodes.desc_signature(sig, '')
|
|
||||||
nodes.append(signode)
|
|
||||||
s.declaration.describe_signature(signode, 'markName', self.env, options)
|
|
||||||
node.replace_self(nodes)
|
node.replace_self(nodes)
|
||||||
|
|
||||||
|
|
||||||
class CAliasObject(ObjectDescription):
|
class CAliasObject(ObjectDescription):
|
||||||
option_spec = {} # type: Dict
|
option_spec = {
|
||||||
|
'maxdepth': directives.nonnegative_int
|
||||||
|
} # type: Dict
|
||||||
|
|
||||||
def run(self) -> List[Node]:
|
def run(self) -> List[Node]:
|
||||||
if ':' in self.name:
|
if ':' in self.name:
|
||||||
@@ -3494,16 +3532,10 @@ class CAliasObject(ObjectDescription):
|
|||||||
node['noindex'] = True
|
node['noindex'] = True
|
||||||
|
|
||||||
self.names = [] # type: List[str]
|
self.names = [] # type: List[str]
|
||||||
|
maxdepth = self.options.get('maxdepth', 1)
|
||||||
signatures = self.get_signatures()
|
signatures = self.get_signatures()
|
||||||
for i, sig in enumerate(signatures):
|
for i, sig in enumerate(signatures):
|
||||||
node.append(AliasNode(sig, env=self.env))
|
node.append(AliasNode(sig, maxdepth, self.state.document, 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()
|
|
||||||
return [node]
|
return [node]
|
||||||
|
|
||||||
|
|
||||||
@@ -3607,6 +3639,10 @@ class CDomain(Domain):
|
|||||||
'macro': ObjType(_('macro'), 'macro'),
|
'macro': ObjType(_('macro'), 'macro'),
|
||||||
'type': ObjType(_('type'), 'type'),
|
'type': ObjType(_('type'), 'type'),
|
||||||
'var': ObjType(_('variable'), 'data'),
|
'var': ObjType(_('variable'), 'data'),
|
||||||
|
'enum': ObjType(_('enum'), 'enum'),
|
||||||
|
'enumerator': ObjType(_('enumerator'), 'enumerator'),
|
||||||
|
'struct': ObjType(_('struct'), 'struct'),
|
||||||
|
'union': ObjType(_('union'), 'union'),
|
||||||
}
|
}
|
||||||
|
|
||||||
directives = {
|
directives = {
|
||||||
|
|||||||
@@ -4292,7 +4292,7 @@ class Symbol:
|
|||||||
|
|
||||||
if not declaration:
|
if not declaration:
|
||||||
if Symbol.debug_lookup:
|
if Symbol.debug_lookup:
|
||||||
Symbol.debug_print("no delcaration")
|
Symbol.debug_print("no declaration")
|
||||||
Symbol.debug_indent -= 2
|
Symbol.debug_indent -= 2
|
||||||
# good, just a scope creation
|
# good, just a scope creation
|
||||||
# TODO: what if we have more than one symbol?
|
# TODO: what if we have more than one symbol?
|
||||||
|
|||||||
@@ -66,6 +66,10 @@ module_sig_re = re.compile(r'''^(?:([\w.]*)\.)? # module names
|
|||||||
''', re.VERBOSE)
|
''', re.VERBOSE)
|
||||||
|
|
||||||
|
|
||||||
|
py_builtins = [obj for obj in vars(builtins).values()
|
||||||
|
if inspect.isclass(obj)]
|
||||||
|
|
||||||
|
|
||||||
def try_import(objname: str) -> Any:
|
def try_import(objname: str) -> Any:
|
||||||
"""Import a object or module using *name* and *currentmodule*.
|
"""Import a object or module using *name* and *currentmodule*.
|
||||||
*name* should be a relative name from *currentmodule* or
|
*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.
|
traverse to. Multiple names can be specified separated by comma.
|
||||||
"""
|
"""
|
||||||
all_classes = {}
|
all_classes = {}
|
||||||
py_builtins = vars(builtins).values()
|
|
||||||
|
|
||||||
def recurse(cls: Any) -> None:
|
def recurse(cls: Any) -> None:
|
||||||
if not show_builtins and cls in py_builtins:
|
if not show_builtins and cls in py_builtins:
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ _numpy_section_regex = re.compile(r'^[=\-`:\'"~^_*+#<>]{2,}\s*$')
|
|||||||
_single_colon_regex = re.compile(r'(?<!:):(?!:)')
|
_single_colon_regex = re.compile(r'(?<!:):(?!:)')
|
||||||
_xref_or_code_regex = re.compile(
|
_xref_or_code_regex = re.compile(
|
||||||
r'((?::(?:[a-zA-Z0-9]+[\-_+:.])*[a-zA-Z0-9]+:`.+?`)|'
|
r'((?::(?:[a-zA-Z0-9]+[\-_+:.])*[a-zA-Z0-9]+:`.+?`)|'
|
||||||
r'(?:``.+``))')
|
r'(?:``.+?``))')
|
||||||
_xref_regex = re.compile(
|
_xref_regex = re.compile(
|
||||||
r'(?:(?::(?:[a-zA-Z0-9]+[\-_+:.])*[a-zA-Z0-9]+:)?`.+?`)'
|
r'(?:(?::(?:[a-zA-Z0-9]+[\-_+:.])*[a-zA-Z0-9]+:)?`.+?`)'
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import posixpath
|
import posixpath
|
||||||
from typing import Dict
|
from typing import Callable, Dict
|
||||||
|
|
||||||
from docutils.utils import relative_path
|
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,
|
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.
|
"""Copy asset files to destination recursively.
|
||||||
|
|
||||||
On copying, it expands the template variables if context argument is given and
|
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 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 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 renderer: The template engine. If not given, SphinxRenderer is used by default
|
||||||
|
:param onerror: The error handler.
|
||||||
"""
|
"""
|
||||||
if not os.path.exists(source):
|
if not os.path.exists(source):
|
||||||
return
|
return
|
||||||
@@ -90,6 +92,12 @@ def copy_asset(source: str, destination: str, excluded: PathMatcher = lambda pat
|
|||||||
|
|
||||||
for filename in files:
|
for filename in files:
|
||||||
if not excluded(posixpath.join(reldir, filename)):
|
if not excluded(posixpath.join(reldir, filename)):
|
||||||
|
try:
|
||||||
copy_asset_file(posixpath.join(root, filename),
|
copy_asset_file(posixpath.join(root, filename),
|
||||||
posixpath.join(destination, reldir),
|
posixpath.join(destination, reldir),
|
||||||
context, renderer)
|
context, renderer)
|
||||||
|
except Exception as exc:
|
||||||
|
if onerror:
|
||||||
|
onerror(posixpath.join(root, filename), exc)
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
|||||||
@@ -304,6 +304,11 @@ def iscoroutinefunction(obj: Any) -> bool:
|
|||||||
|
|
||||||
def isproperty(obj: Any) -> bool:
|
def isproperty(obj: Any) -> bool:
|
||||||
"""Check if the object is property."""
|
"""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)
|
return isinstance(obj, property)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
7
tests/roots/test-ext-autodoc/target/cached_property.py
Normal file
7
tests/roots/test-ext-autodoc/target/cached_property.py
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
from functools import cached_property
|
||||||
|
|
||||||
|
|
||||||
|
class Foo:
|
||||||
|
@cached_property
|
||||||
|
def prop(self) -> int:
|
||||||
|
return 1
|
||||||
@@ -10,8 +10,10 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
from distutils.version import LooseVersion
|
||||||
from itertools import cycle, chain
|
from itertools import cycle, chain
|
||||||
|
|
||||||
|
import pygments
|
||||||
import pytest
|
import pytest
|
||||||
from html5lib import HTMLParser
|
from html5lib import HTMLParser
|
||||||
|
|
||||||
@@ -1591,4 +1593,8 @@ def test_html_codeblock_linenos_style_inline(app):
|
|||||||
app.build()
|
app.build()
|
||||||
content = (app.outdir / 'index.html').read_text()
|
content = (app.outdir / 'index.html').read_text()
|
||||||
|
|
||||||
|
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
|
assert '<span class="lineno">1 </span>' in content
|
||||||
|
|||||||
@@ -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')
|
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||||
def test_autodoc_member_order(app):
|
def test_autodoc_member_order(app):
|
||||||
# case member-order='bysource'
|
# case member-order='bysource'
|
||||||
|
|||||||
Reference in New Issue
Block a user