mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2026-09-03 20:52:55 -05:00
Merge branch '2.0' into refactor_autosummary3
This commit is contained in:
@@ -41,12 +41,13 @@ Bugs fixed
|
||||
* #5502: linkcheck: Consider HTTP 503 response as not an error
|
||||
* #6439: Make generated download links reproducible
|
||||
* #6486: UnboundLocalError is raised if broken extension installed
|
||||
* #6498: autosummary: crashed with wrong autosummary_generate setting
|
||||
* #6507: autosummary: crashes without no autosummary_generate setting
|
||||
|
||||
Testing
|
||||
--------
|
||||
|
||||
Release 2.1.2 (in development)
|
||||
Release 2.1.3 (in development)
|
||||
==============================
|
||||
|
||||
Dependencies
|
||||
@@ -67,6 +68,15 @@ Bugs fixed
|
||||
Testing
|
||||
--------
|
||||
|
||||
Release 2.1.2 (released Jun 19, 2019)
|
||||
=====================================
|
||||
|
||||
Bugs fixed
|
||||
----------
|
||||
|
||||
* #6497: custom lexers fails highlighting when syntax error
|
||||
* #6478, #6488: info field lists are incorrectly recognized
|
||||
|
||||
Release 2.1.1 (released Jun 10, 2019)
|
||||
=====================================
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ extras_require = {
|
||||
'html5lib',
|
||||
'flake8>=3.5.0',
|
||||
'flake8-import-order',
|
||||
'mypy>=0.590',
|
||||
'mypy>=0.710',
|
||||
'docutils-stubs',
|
||||
],
|
||||
}
|
||||
|
||||
@@ -73,6 +73,7 @@ class ObjectDescription(SphinxDirective):
|
||||
|
||||
def get_field_type_map(self) -> Dict[str, Tuple[Field, bool]]:
|
||||
if self._doc_field_type_map == {}:
|
||||
self._doc_field_type_map = {}
|
||||
for field in self.doc_field_types:
|
||||
for name in field.names:
|
||||
self._doc_field_type_map[name] = (field, False)
|
||||
|
||||
@@ -910,12 +910,13 @@ class StandardDomain(Domain):
|
||||
# type: (nodes.Node) -> str
|
||||
"""Get the title of enumerable nodes to refer them using its title"""
|
||||
if self.is_enumerable_node(node):
|
||||
_, title_getter = self.enumerable_nodes.get(node.__class__, (None, None))
|
||||
elem = cast(nodes.Element, node)
|
||||
_, title_getter = self.enumerable_nodes.get(elem.__class__, (None, None))
|
||||
if title_getter:
|
||||
return title_getter(node)
|
||||
return title_getter(elem)
|
||||
else:
|
||||
for subnode in node:
|
||||
if subnode.tagname in ('caption', 'title'):
|
||||
for subnode in elem:
|
||||
if isinstance(subnode, (nodes.caption, nodes.title)):
|
||||
return clean_astext(subnode)
|
||||
|
||||
return None
|
||||
|
||||
@@ -58,6 +58,7 @@ import posixpath
|
||||
import re
|
||||
import sys
|
||||
import warnings
|
||||
from os import path
|
||||
from types import ModuleType
|
||||
from typing import List, cast
|
||||
|
||||
@@ -738,26 +739,31 @@ def process_generate_options(app):
|
||||
# type: (Sphinx) -> None
|
||||
genfiles = app.config.autosummary_generate
|
||||
|
||||
if genfiles and not hasattr(genfiles, '__len__'):
|
||||
if genfiles is True:
|
||||
env = app.builder.env
|
||||
genfiles = [env.doc2path(x, base=None) for x in env.found_docs
|
||||
if os.path.isfile(env.doc2path(x))]
|
||||
else:
|
||||
ext = list(app.config.source_suffix)
|
||||
genfiles = [genfile + (not genfile.endswith(tuple(ext)) and ext[0] or '')
|
||||
for genfile in genfiles]
|
||||
|
||||
for entry in genfiles[:]:
|
||||
if not path.isfile(path.join(app.srcdir, entry)):
|
||||
logger.warning(__('autosummary_generate: file not found: %s'), entry)
|
||||
genfiles.remove(entry)
|
||||
|
||||
if not genfiles:
|
||||
return
|
||||
|
||||
from sphinx.ext.autosummary.generate import generate_autosummary_docs
|
||||
|
||||
ext = list(app.config.source_suffix)
|
||||
genfiles = [genfile + (not genfile.endswith(tuple(ext)) and ext[0] or '')
|
||||
for genfile in genfiles]
|
||||
|
||||
suffix = get_rst_suffix(app)
|
||||
if suffix is None:
|
||||
logger.warning(__('autosummary generats .rst files internally. '
|
||||
'But your source_suffix does not contain .rst. Skipped.'))
|
||||
return
|
||||
|
||||
from sphinx.ext.autosummary.generate import generate_autosummary_docs
|
||||
|
||||
imported_members = app.config.autosummary_imported_members
|
||||
with mock(app.config.autosummary_mock_imports):
|
||||
generate_autosummary_docs(genfiles, builder=app.builder,
|
||||
|
||||
@@ -208,23 +208,25 @@ def generate_autosummary_docs(sources, output_dir=None, suffix='.rst',
|
||||
if info:
|
||||
warnings.warn('info argument for generate_autosummary_docs() is deprecated.',
|
||||
RemovedInSphinx40Warning)
|
||||
_info = info
|
||||
else:
|
||||
info = logger.info
|
||||
_info = logger.info
|
||||
|
||||
if warn:
|
||||
warnings.warn('warn argument for generate_autosummary_docs() is deprecated.',
|
||||
RemovedInSphinx40Warning)
|
||||
_warn = warn
|
||||
else:
|
||||
warn = logger.warning
|
||||
_warn = logger.warning
|
||||
|
||||
showed_sources = list(sorted(sources))
|
||||
if len(showed_sources) > 20:
|
||||
showed_sources = showed_sources[:10] + ['...'] + showed_sources[-10:]
|
||||
info(__('[autosummary] generating autosummary for: %s') %
|
||||
', '.join(showed_sources))
|
||||
_info(__('[autosummary] generating autosummary for: %s') %
|
||||
', '.join(showed_sources))
|
||||
|
||||
if output_dir:
|
||||
info(__('[autosummary] writing to %s') % output_dir)
|
||||
_info(__('[autosummary] writing to %s') % output_dir)
|
||||
|
||||
if base_path is not None:
|
||||
sources = [os.path.join(base_path, filename) for filename in sources]
|
||||
@@ -250,7 +252,7 @@ def generate_autosummary_docs(sources, output_dir=None, suffix='.rst',
|
||||
try:
|
||||
name, obj, parent, mod_name = import_by_name(name)
|
||||
except ImportError as e:
|
||||
warn('[autosummary] failed to import %r: %s' % (name, e))
|
||||
_warn('[autosummary] failed to import %r: %s' % (name, e))
|
||||
continue
|
||||
|
||||
fn = os.path.join(path, name + suffix)
|
||||
|
||||
@@ -139,7 +139,8 @@ class PygmentsBridge:
|
||||
lexer = lexers['none']
|
||||
|
||||
if lang in lexers:
|
||||
lexer = lexers[lang]
|
||||
# just return custom lexers here (without installing raiseonerror filter)
|
||||
return lexers[lang]
|
||||
elif lang in lexer_classes:
|
||||
lexer = lexer_classes[lang](**opts)
|
||||
else:
|
||||
|
||||
@@ -123,7 +123,7 @@ def isenumattribute(x: Any) -> bool:
|
||||
|
||||
def ispartial(obj: Any) -> bool:
|
||||
"""Check if the object is partial."""
|
||||
return isinstance(obj, (partial, partialmethod))
|
||||
return isinstance(obj, (partial, partialmethod)) # type: ignore
|
||||
|
||||
|
||||
def isclassmethod(obj: Any) -> bool:
|
||||
|
||||
@@ -30,7 +30,7 @@ class PyStemmer(BaseStemmer):
|
||||
return self.stemmer.stemWord(word)
|
||||
|
||||
|
||||
class StandardStemmer(PorterStemmer, BaseStemmer): # type: ignore
|
||||
class StandardStemmer(PorterStemmer, BaseStemmer):
|
||||
"""All those porter stemmer implementations look hideous;
|
||||
make at least the stem method nicer.
|
||||
"""
|
||||
|
||||
@@ -2598,7 +2598,7 @@ class LaTeXTranslator(SphinxTranslator):
|
||||
RemovedInSphinx30Warning)
|
||||
|
||||
def visit_admonition(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
# type: (LaTeXTranslator, nodes.Element) -> None
|
||||
self.body.append('\n\\begin{sphinxadmonition}{%s}{%s:}' %
|
||||
(name, admonitionlabels[name]))
|
||||
return visit_admonition
|
||||
|
||||
@@ -1752,6 +1752,6 @@ class TexinfoTranslator(SphinxTranslator):
|
||||
RemovedInSphinx30Warning)
|
||||
|
||||
def visit(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
# type: (TexinfoTranslator, nodes.Element) -> None
|
||||
self.visit_admonition(node, admonitionlabels[name])
|
||||
return visit
|
||||
|
||||
@@ -1375,6 +1375,6 @@ class TextTranslator(SphinxTranslator):
|
||||
RemovedInSphinx30Warning)
|
||||
|
||||
def depart_admonition(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
# type: (TextTranslator, nodes.Element) -> None
|
||||
self.end_state(first=admonitionlabels[name] + ': ')
|
||||
return depart_admonition
|
||||
|
||||
@@ -26,4 +26,4 @@ test-image
|
||||
.. image:: https://www.python.org/static/img/python-logo.png
|
||||
|
||||
.. non-exist remote image
|
||||
.. image:: http://example.com/NOT_EXIST.PNG
|
||||
.. image:: https://www.google.com/NOT_EXIST.PNG
|
||||
|
||||
@@ -23,8 +23,8 @@ link to external1_ and external2_.
|
||||
|
||||
link to `Sphinx Site <http://sphinx-doc.org>`_ and `Python Site <http://python.org>`_.
|
||||
|
||||
.. _external1: http://example.com/external1
|
||||
.. _external2: http://example.com/external2
|
||||
.. _external1: https://www.google.com/external1
|
||||
.. _external2: https://www.google.com/external2
|
||||
|
||||
|
||||
Multiple references in the same line
|
||||
|
||||
@@ -6,11 +6,11 @@ This is from CPython documentation.
|
||||
|
||||
Some additional anchors to exercise ignore code
|
||||
|
||||
* `Example Bar invalid <http://example.com/#!bar>`_
|
||||
* `Example Bar invalid <http://example.com#!bar>`_ tests that default ignore anchor of #! does not need to be prefixed with /
|
||||
* `Example Bar invalid <http://example.com/#top>`_
|
||||
* `Example Bar invalid <https://www.google.com/#!bar>`_
|
||||
* `Example Bar invalid <https://www.google.com#!bar>`_ tests that default ignore anchor of #! does not need to be prefixed with /
|
||||
* `Example Bar invalid <https://www.google.com/#top>`_
|
||||
* `Example anchor invalid <http://www.sphinx-doc.org/en/1.7/intro.html#does-not-exist>`_
|
||||
* `Complete nonsense <https://localhost:7777/doesnotexist>`_
|
||||
|
||||
.. image:: http://example.com/image.png
|
||||
.. figure:: http://example.com/image2.png
|
||||
.. image:: https://www.google.com/image.png
|
||||
.. figure:: https://www.google.com/image2.png
|
||||
|
||||
@@ -1240,25 +1240,25 @@ def test_html_entity(app):
|
||||
def test_html_inventory(app):
|
||||
app.builder.build_all()
|
||||
with open(app.outdir / 'objects.inv', 'rb') as f:
|
||||
invdata = InventoryFile.load(f, 'http://example.com', os.path.join)
|
||||
invdata = InventoryFile.load(f, 'https://www.google.com', os.path.join)
|
||||
assert set(invdata.keys()) == {'std:label', 'std:doc'}
|
||||
assert set(invdata['std:label'].keys()) == {'modindex', 'genindex', 'search'}
|
||||
assert invdata['std:label']['modindex'] == ('Python',
|
||||
'',
|
||||
'http://example.com/py-modindex.html',
|
||||
'https://www.google.com/py-modindex.html',
|
||||
'Module Index')
|
||||
assert invdata['std:label']['genindex'] == ('Python',
|
||||
'',
|
||||
'http://example.com/genindex.html',
|
||||
'https://www.google.com/genindex.html',
|
||||
'Index')
|
||||
assert invdata['std:label']['search'] == ('Python',
|
||||
'',
|
||||
'http://example.com/search.html',
|
||||
'https://www.google.com/search.html',
|
||||
'Search Page')
|
||||
assert set(invdata['std:doc'].keys()) == {'index'}
|
||||
assert invdata['std:doc']['index'] == ('Python',
|
||||
'',
|
||||
'http://example.com/index.html',
|
||||
'https://www.google.com/index.html',
|
||||
'The basic Sphinx documentation for testing')
|
||||
|
||||
|
||||
|
||||
@@ -1242,7 +1242,7 @@ def test_latex_images(app, status, warning):
|
||||
# not found images
|
||||
assert '\\sphinxincludegraphics{{NOT_EXIST}.PNG}' not in result
|
||||
assert ('WARNING: Could not fetch remote image: '
|
||||
'http://example.com/NOT_EXIST.PNG [404]' in warning.getvalue())
|
||||
'https://www.google.com/NOT_EXIST.PNG [404]' in warning.getvalue())
|
||||
|
||||
# an image having target
|
||||
assert ('\\sphinxhref{https://www.sphinx-doc.org/}'
|
||||
|
||||
@@ -25,8 +25,8 @@ def test_defaults(app, status, warning):
|
||||
# looking for non-existent URL should fail
|
||||
assert " Max retries exceeded with url: /doesnotexist" in content
|
||||
# images should fail
|
||||
assert "Not Found for url: http://example.com/image.png" in content
|
||||
assert "Not Found for url: http://example.com/image2.png" in content
|
||||
assert "Not Found for url: https://www.google.com/image.png" in content
|
||||
assert "Not Found for url: https://www.google.com/image2.png" in content
|
||||
assert len(content.splitlines()) == 5
|
||||
|
||||
|
||||
@@ -36,8 +36,8 @@ def test_defaults(app, status, warning):
|
||||
'linkcheck_ignore': [
|
||||
'https://localhost:7777/doesnotexist',
|
||||
'http://www.sphinx-doc.org/en/1.7/intro.html#',
|
||||
'http://example.com/image.png',
|
||||
'http://example.com/image2.png']
|
||||
'https://www.google.com/image.png',
|
||||
'https://www.google.com/image2.png']
|
||||
})
|
||||
def test_anchors_ignored(app, status, warning):
|
||||
app.builder.build_all()
|
||||
|
||||
@@ -310,3 +310,9 @@ def test_empty_autosummary_generate(app, status, warning):
|
||||
app.build()
|
||||
assert ("WARNING: autosummary: stub file not found 'autosummary_importfail'"
|
||||
in warning.getvalue())
|
||||
|
||||
|
||||
@pytest.mark.sphinx('dummy', testroot='ext-autosummary',
|
||||
confoverrides={'autosummary_generate': ['unknown']})
|
||||
def test_invalid_autosummary_generate(app, status, warning):
|
||||
assert 'WARNING: autosummary_generate: file not found: unknown.rst' in warning.getvalue()
|
||||
+2
-2
@@ -885,8 +885,8 @@ def test_xml_keep_external_links(app):
|
||||
assert_elem(
|
||||
para1[0],
|
||||
['LINK TO', 'external2', 'AND', 'external1', '.'],
|
||||
['http://example.com/external2',
|
||||
'http://example.com/external1'])
|
||||
['https://www.google.com/external2',
|
||||
'https://www.google.com/external1'])
|
||||
assert_elem(
|
||||
para1[1],
|
||||
['LINK TO', 'THE PYTHON SITE', 'AND', 'THE SPHINX SITE', '.'],
|
||||
|
||||
@@ -279,9 +279,9 @@ def get_verifier(verify, verify_re):
|
||||
(
|
||||
# in URIs
|
||||
'verify_re',
|
||||
'`test <http://example.com/~me/>`_',
|
||||
'`test <https://www.google.com/~me/>`_',
|
||||
None,
|
||||
r'\\sphinxhref{http://example.com/~me/}{test}.*',
|
||||
r'\\sphinxhref{https://www.google.com/~me/}{test}.*',
|
||||
),
|
||||
(
|
||||
# description list: simple
|
||||
|
||||
Reference in New Issue
Block a user