Merge branch '3.x'

This commit is contained in:
Takeshi KOMIYA 2020-04-19 23:45:57 +09:00
commit 2c7d64b94c
15 changed files with 89 additions and 29 deletions

24
CHANGES
View File

@ -62,6 +62,7 @@ Features added
sidebar
* #7484: html theme: Avoid clashes between sidebar and other blocks
* #7476: html theme: Relbar breadcrumb should contain current page
* #7506: html theme: A canonical URL is not escaped
Bugs fixed
----------
@ -69,7 +70,7 @@ Bugs fixed
Testing
--------
Release 3.0.2 (in development)
Release 3.0.3 (in development)
==============================
Dependencies
@ -84,6 +85,18 @@ Deprecated
Features added
--------------
Bugs fixed
----------
Testing
--------
Release 3.0.2 (released Apr 19, 2020)
=====================================
Features added
--------------
* C, parse attributes and add :confval:`c_id_attributes`
and :confval:`c_paren_attributes` to support user-defined attributes.
@ -91,11 +104,14 @@ Bugs fixed
----------
* #7461: py domain: fails with IndexError for empty tuple in type annotation
* #7510: py domain: keyword-only arguments are documented as having a default of
None
* #7418: std domain: :rst:role:`term` role could not match case-insensitively
* #7461: autodoc: empty tuple in type annotation is not shown correctly
* #7479: autodoc: Sphinx builds has been slower since 3.0.0 on mocking
* C++, fix spacing issue in east-const declarations.
Testing
--------
* #7414: LaTeX: Xindy language options were incorrect
* sphinx crashes with ImportError on python3.5.1
Release 3.0.1 (released Apr 11, 2020)
=====================================

View File

@ -26,7 +26,7 @@ modindex_common_prefix = ['sphinx.']
html_static_path = ['_static']
html_sidebars = {'index': ['indexsidebar.html', 'searchbox.html']}
html_additional_pages = {'index': 'index.html'}
html_use_opensearch = 'http://sphinx-doc.org'
html_use_opensearch = 'https://www.sphinx-doc.org/en/master'
html_baseurl = 'https://www.sphinx-doc.org/en/master/'
htmlhelp_basename = 'Sphinxdoc'

View File

@ -52,6 +52,7 @@ if __version__.endswith('+'):
__version__ = __version__[:-1] # remove '+' for PEP-440 version spec.
try:
ret = subprocess.run(['git', 'show', '-s', '--pretty=format:%h'],
cwd=package_dir,
stdout=PIPE, stderr=PIPE, encoding='ascii')
if ret.stdout:
__display_version__ += '/' + ret.stdout.strip()

View File

@ -54,13 +54,13 @@ XINDY_LANG_OPTIONS = {
'hr': '-L croatian -C utf8 ',
'cs': '-L czech -C utf8 ',
'da': '-L danish -C utf8 ',
'nl': '-L dutch -C ij-as-ij-utf8 ',
'nl': '-L dutch-ij-as-ij -C utf8 ',
'en': '-L english -C utf8 ',
'eo': '-L esperanto -C utf8 ',
'et': '-L estonian -C utf8 ',
'fi': '-L finnish -C utf8 ',
'fr': '-L french -C utf8 ',
'de': '-L german -C din5007-utf8 ',
'de': '-L german-din5007 -C utf8 ',
'is': '-L icelandic -C utf8 ',
'it': '-L italian -C utf8 ',
'la': '-L latin -C utf8 ',
@ -73,9 +73,9 @@ XINDY_LANG_OPTIONS = {
'pl': '-L polish -C utf8 ',
'pt': '-L portuguese -C utf8 ',
'ro': '-L romanian -C utf8 ',
'sk': '-L slovak -C small-utf8 ', # there is also slovak-large
'sk': '-L slovak-small -C utf8 ', # there is also slovak-large
'sl': '-L slovenian -C utf8 ',
'es': '-L spanish -C modern-utf8 ', # there is also spanish-traditional
'es': '-L spanish-modern -C utf8 ', # there is also spanish-traditional
'sv': '-L swedish -C utf8 ',
'tr': '-L turkish -C utf8 ',
'hsb': '-L upper-sorbian -C utf8 ',
@ -86,7 +86,7 @@ XINDY_LANG_OPTIONS = {
'be': '-L belarusian -C utf8 ',
'bg': '-L bulgarian -C utf8 ',
'mk': '-L macedonian -C utf8 ',
'mn': '-L mongolian -C cyrillic-utf8 ',
'mn': '-L mongolian-cyrillic -C utf8 ',
'ru': '-L russian -C utf8 ',
'sr': '-L serbian -C utf8 ',
'sh-cyrl': '-L serbian -C utf8 ',
@ -96,7 +96,7 @@ XINDY_LANG_OPTIONS = {
# can work only with xelatex/lualatex, not supported by texindy+pdflatex
'el': '-L greek -C utf8 ',
# FIXME, not compatible with [:2] slice but does Sphinx support Greek ?
'el-polyton': '-L greek -C polytonic-utf8 ',
'el-polyton': '-L greek-polytonic -C utf8 ',
}
XINDY_CYRILLIC_SCRIPTS = [

View File

@ -29,13 +29,13 @@ class RemovedInSphinx60Warning(PendingDeprecationWarning):
RemovedInNextVersionWarning = RemovedInSphinx40Warning
def deprecated_alias(modname: str, objects: Dict, warning: Type[Warning]) -> None:
def deprecated_alias(modname: str, objects: Dict, warning: "Type[Warning]") -> None:
module = import_module(modname)
sys.modules[modname] = _ModuleWrapper(module, modname, objects, warning) # type: ignore
class _ModuleWrapper:
def __init__(self, module: Any, modname: str, objects: Dict, warning: Type[Warning]
def __init__(self, module: Any, modname: str, objects: Dict, warning: "Type[Warning]"
) -> None:
self._module = module
self._modname = modname
@ -55,7 +55,7 @@ class _ModuleWrapper:
class DeprecatedDict(dict):
"""A deprecated dict which warns on each access."""
def __init__(self, data: Dict, message: str, warning: Type[Warning]) -> None:
def __init__(self, data: Dict, message: str, warning: "Type[Warning]") -> None:
self.message = message
self.warning = warning
super().__init__(data)

View File

@ -787,6 +787,8 @@ class StandardDomain(Domain):
RemovedInSphinx40Warning)
domain = env.get_domain('citation')
return domain.resolve_xref(env, fromdocname, builder, typ, target, node, contnode)
elif typ == 'term':
resolver = self._resolve_term_xref
else:
resolver = self._resolve_obj_xref
@ -921,6 +923,28 @@ class StandardDomain(Domain):
return make_refnode(builder, fromdocname, docname,
labelid, contnode)
def _resolve_term_xref(self, env: "BuildEnvironment", fromdocname: str,
builder: "Builder", typ: str, target: str,
node: pending_xref, contnode: Element) -> Element:
result = self._resolve_obj_xref(env, fromdocname, builder, typ,
target, node, contnode)
if result:
return result
else:
for objtype, term in self.objects:
if objtype == 'term' and term.lower() == target.lower():
docname, labelid = self.objects[objtype, term]
logger.warning(__('term %s not found in case sensitive match.'
'made a reference to %s instead.'),
target, term, location=node, type='ref', subtype='term')
break
else:
docname, labelid = '', ''
if not docname:
return None
return make_refnode(builder, fromdocname, docname,
labelid, contnode)
def _resolve_obj_xref(self, env: "BuildEnvironment", fromdocname: str,
builder: "Builder", typ: str, target: str,
node: pending_xref, contnode: Element) -> Element:

View File

@ -577,7 +577,10 @@ class Documenter:
isprivate = membername.startswith('_')
keep = False
if want_all and membername.startswith('__') and \
if getattr(member, '__sphinx_mock__', False):
# mocked module or object
keep = False
elif want_all and membername.startswith('__') and \
membername.endswith('__') and len(membername) > 4:
# special __methods__
if self.options.special_members is ALL:

View File

@ -25,6 +25,7 @@ class _MockObject:
"""Used by autodoc_mock_imports."""
__display_name__ = '_MockObject'
__sphinx_mock__ = True
def __new__(cls, *args: Any, **kwargs: Any) -> Any:
if len(args) == 3 and isinstance(args[1], tuple):
@ -78,6 +79,7 @@ def _make_subclass(name: str, module: str, superclass: Any = _MockObject,
class _MockModule(ModuleType):
"""Used by autodoc_mock_imports."""
__file__ = os.devnull
__sphinx_mock__ = True
def __init__(self, name: str) -> None:
super().__init__(name)

View File

@ -79,7 +79,7 @@ class SphinxBaseReader(standalone.Reader):
self._app = app # hold application object only for compatibility
self._env = app.env
def get_transforms(self) -> List[Type[Transform]]:
def get_transforms(self) -> List["Type[Transform]"]:
transforms = super().get_transforms() + self.transforms
# remove transforms which is not needed for Sphinx

View File

@ -76,7 +76,7 @@ class XRefRole(ReferenceRole):
innernodeclass = nodes.literal # type: Type[TextElement]
def __init__(self, fix_parens: bool = False, lowercase: bool = False,
nodeclass: Type[Element] = None, innernodeclass: Type[TextElement] = None,
nodeclass: "Type[Element]" = None, innernodeclass: "Type[TextElement]" = None,
warn_dangling: bool = False) -> None:
self.fix_parens = fix_parens
self.lowercase = lowercase

View File

@ -132,7 +132,7 @@
{{- script() }}
{%- endblock %}
{%- if pageurl %}
<link rel="canonical" href="{{ pageurl }}" />
<link rel="canonical" href="{{ pageurl|e }}" />
{%- endif %}
{%- if use_opensearch %}
<link rel="search" type="application/opensearchdescription+xml"

View File

@ -527,7 +527,7 @@ def signature_from_str(signature: str) -> inspect.Signature:
annotation=annotation))
for i, arg in enumerate(args.kwonlyargs):
default = ast_unparse(args.kw_defaults[i])
default = ast_unparse(args.kw_defaults[i]) or Parameter.empty
annotation = ast_unparse(arg.annotation) or Parameter.empty
params.append(Parameter(arg.arg, Parameter.KEYWORD_ONLY, default=default,
annotation=annotation))

View File

@ -344,9 +344,7 @@ def test_pyfunction_signature_full_py38(app):
doctree = restructuredtext.parse(app, text)
assert_node(doctree[1][0][1],
[desc_parameterlist, ([desc_parameter, nodes.inline, "*"],
[desc_parameter, ([desc_sig_name, "a"],
[desc_sig_operator, "="],
[nodes.inline, "None"])])])
[desc_parameter, desc_sig_name, "a"])])
# case: separator in the middle
text = ".. py:function:: hello(a, /, b, *, c)"
@ -356,9 +354,7 @@ def test_pyfunction_signature_full_py38(app):
[desc_parameter, desc_sig_operator, "/"],
[desc_parameter, desc_sig_name, "b"],
[desc_parameter, desc_sig_operator, "*"],
[desc_parameter, ([desc_sig_name, "c"],
[desc_sig_operator, "="],
[nodes.inline, "None"])])])
[desc_parameter, desc_sig_name, "c"])])
# case: separator in the middle (2)
text = ".. py:function:: hello(a, /, *, b)"
@ -367,9 +363,7 @@ def test_pyfunction_signature_full_py38(app):
[desc_parameterlist, ([desc_parameter, desc_sig_name, "a"],
[desc_parameter, desc_sig_operator, "/"],
[desc_parameter, desc_sig_operator, "*"],
[desc_parameter, ([desc_sig_name, "b"],
[desc_sig_operator, "="],
[nodes.inline, "None"])])])
[desc_parameter, desc_sig_name, "b"])])
# case: separator at tail
text = ".. py:function:: hello(a, /)"

View File

@ -140,12 +140,23 @@ def test_glossary(app):
[nodes.definition, nodes.paragraph, "description"])
# index
objects = list(app.env.get_domain("std").get_objects())
domain = app.env.get_domain("std")
objects = list(domain.get_objects())
assert ("term1", "term1", "term", "index", "term-term1", -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
# term reference (case sensitive)
refnode = domain.resolve_xref(app.env, 'index', app.builder, 'term', 'term1',
pending_xref(), nodes.paragraph())
assert_node(refnode, nodes.reference, refid="term-term1")
# term reference (case insensitive)
refnode = domain.resolve_xref(app.env, 'index', app.builder, 'term', 'term2',
pending_xref(), nodes.paragraph())
assert_node(refnode, nodes.reference, refid="term-TERM2")
def test_glossary_warning(app, status, warning):
# empty line between terms

View File

@ -317,6 +317,15 @@ def test_signature_from_str_complex_annotations():
assert sig.return_annotation == 'Callable[[int, int], int]'
def test_signature_from_str_kwonly_args():
sig = inspect.signature_from_str('(a, *, b)')
assert list(sig.parameters.keys()) == ['a', 'b']
assert sig.parameters['a'].kind == Parameter.POSITIONAL_OR_KEYWORD
assert sig.parameters['a'].default == Parameter.empty
assert sig.parameters['b'].kind == Parameter.KEYWORD_ONLY
assert sig.parameters['b'].default == Parameter.empty
@pytest.mark.skipif(sys.version_info < (3, 8),
reason='python-3.8 or above is required')
def test_signature_from_str_positionaly_only_args():