diff --git a/CHANGES b/CHANGES
index 06f732b8c..d31973321 100644
--- a/CHANGES
+++ b/CHANGES
@@ -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)
=====================================
diff --git a/doc/conf.py b/doc/conf.py
index 681fdc449..f62e02a34 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -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'
diff --git a/sphinx/__init__.py b/sphinx/__init__.py
index 3f4dab272..574ede346 100644
--- a/sphinx/__init__.py
+++ b/sphinx/__init__.py
@@ -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()
diff --git a/sphinx/builders/latex/__init__.py b/sphinx/builders/latex/__init__.py
index 390a5d9c7..183708520 100644
--- a/sphinx/builders/latex/__init__.py
+++ b/sphinx/builders/latex/__init__.py
@@ -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 = [
diff --git a/sphinx/deprecation.py b/sphinx/deprecation.py
index a1b024c09..3a6e6aa0c 100644
--- a/sphinx/deprecation.py
+++ b/sphinx/deprecation.py
@@ -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)
diff --git a/sphinx/domains/std.py b/sphinx/domains/std.py
index cae250b2a..8663b97b2 100644
--- a/sphinx/domains/std.py
+++ b/sphinx/domains/std.py
@@ -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:
diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py
index a0d1f6e32..4202bd51b 100644
--- a/sphinx/ext/autodoc/__init__.py
+++ b/sphinx/ext/autodoc/__init__.py
@@ -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:
diff --git a/sphinx/ext/autodoc/mock.py b/sphinx/ext/autodoc/mock.py
index 25f50d27e..98a3a3a96 100644
--- a/sphinx/ext/autodoc/mock.py
+++ b/sphinx/ext/autodoc/mock.py
@@ -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)
diff --git a/sphinx/io.py b/sphinx/io.py
index c8dba1fed..fc3544cb6 100644
--- a/sphinx/io.py
+++ b/sphinx/io.py
@@ -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
diff --git a/sphinx/roles.py b/sphinx/roles.py
index 3a925056a..922f2e02c 100644
--- a/sphinx/roles.py
+++ b/sphinx/roles.py
@@ -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
diff --git a/sphinx/themes/basic/layout.html b/sphinx/themes/basic/layout.html
index f5961e389..d10f183e1 100644
--- a/sphinx/themes/basic/layout.html
+++ b/sphinx/themes/basic/layout.html
@@ -132,7 +132,7 @@
{{- script() }}
{%- endblock %}
{%- if pageurl %}
-
+
{%- endif %}
{%- if use_opensearch %}
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))
diff --git a/tests/test_domain_py.py b/tests/test_domain_py.py
index e330ba634..d9d61db14 100644
--- a/tests/test_domain_py.py
+++ b/tests/test_domain_py.py
@@ -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, /)"
diff --git a/tests/test_domain_std.py b/tests/test_domain_std.py
index c16bd861d..66253b89a 100644
--- a/tests/test_domain_std.py
+++ b/tests/test_domain_std.py
@@ -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
diff --git a/tests/test_util_inspect.py b/tests/test_util_inspect.py
index 627d20f54..ff1074702 100644
--- a/tests/test_util_inspect.py
+++ b/tests/test_util_inspect.py
@@ -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():