summaryrefslogtreecommitdiffstats
path: root/tests/test_builders
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--tests/test_builders/test_build.py2
-rw-r--r--tests/test_builders/test_build_dirhtml.py8
-rw-r--r--tests/test_builders/test_build_epub.py11
-rw-r--r--tests/test_builders/test_build_gettext.py51
-rw-r--r--tests/test_builders/test_build_html.py77
-rw-r--r--tests/test_builders/test_build_html_5_output.py33
-rw-r--r--tests/test_builders/test_build_html_assets.py2
-rw-r--r--tests/test_builders/test_build_html_download.py1
-rw-r--r--tests/test_builders/test_build_html_image.py5
-rw-r--r--tests/test_builders/test_build_latex.py166
-rw-r--r--tests/test_builders/test_build_linkcheck.py235
-rw-r--r--tests/test_builders/test_build_manpage.py10
-rw-r--r--tests/test_builders/test_build_texinfo.py10
13 files changed, 438 insertions, 173 deletions
diff --git a/tests/test_builders/test_build.py b/tests/test_builders/test_build.py
index 3f6d12c..0e649f7 100644
--- a/tests/test_builders/test_build.py
+++ b/tests/test_builders/test_build.py
@@ -21,7 +21,7 @@ def request_session_head(url, **kwargs):
return response
-@pytest.fixture()
+@pytest.fixture
def nonascii_srcdir(request, rootdir, sphinx_test_tempdir):
# Build in a non-ASCII source dir
test_name = '\u65e5\u672c\u8a9e'
diff --git a/tests/test_builders/test_build_dirhtml.py b/tests/test_builders/test_build_dirhtml.py
index dc5ab86..93609e3 100644
--- a/tests/test_builders/test_build_dirhtml.py
+++ b/tests/test_builders/test_build_dirhtml.py
@@ -28,13 +28,13 @@ def test_dirhtml(app, status, warning):
invdata = InventoryFile.load(f, 'path/to', posixpath.join)
assert 'index' in invdata.get('std:doc')
- assert invdata['std:doc']['index'] == ('Python', '', 'path/to/', '-')
+ assert invdata['std:doc']['index'] == ('Project name not set', '', 'path/to/', '-')
assert 'foo/index' in invdata.get('std:doc')
- assert invdata['std:doc']['foo/index'] == ('Python', '', 'path/to/foo/', '-')
+ assert invdata['std:doc']['foo/index'] == ('Project name not set', '', 'path/to/foo/', '-')
assert 'index' in invdata.get('std:label')
- assert invdata['std:label']['index'] == ('Python', '', 'path/to/#index', '-')
+ assert invdata['std:label']['index'] == ('Project name not set', '', 'path/to/#index', '-')
assert 'foo' in invdata.get('std:label')
- assert invdata['std:label']['foo'] == ('Python', '', 'path/to/foo/#foo', 'foo/index')
+ assert invdata['std:label']['foo'] == ('Project name not set', '', 'path/to/foo/#foo', 'foo/index')
diff --git a/tests/test_builders/test_build_epub.py b/tests/test_builders/test_build_epub.py
index 6829f22..691ffcc 100644
--- a/tests/test_builders/test_build_epub.py
+++ b/tests/test_builders/test_build_epub.py
@@ -67,7 +67,7 @@ def test_build_epub(app):
# toc.ncx
toc = EPUBElementTree.fromstring((app.outdir / 'toc.ncx').read_text(encoding='utf8'))
- assert toc.find("./ncx:docTitle/ncx:text").text == 'Python'
+ assert toc.find("./ncx:docTitle/ncx:text").text == 'Project name not set'
# toc.ncx / head
meta = list(toc.find("./ncx:head"))
@@ -91,11 +91,11 @@ def test_build_epub(app):
# content.opf / metadata
metadata = opf.find("./idpf:metadata")
assert metadata.find("./dc:language").text == 'en'
- assert metadata.find("./dc:title").text == 'Python'
+ assert metadata.find("./dc:title").text == 'Project name not set'
assert metadata.find("./dc:description").text == 'unknown'
- assert metadata.find("./dc:creator").text == 'unknown'
+ assert metadata.find("./dc:creator").text == 'Author name not set'
assert metadata.find("./dc:contributor").text == 'unknown'
- assert metadata.find("./dc:publisher").text == 'unknown'
+ assert metadata.find("./dc:publisher").text == 'Author name not set'
assert metadata.find("./dc:rights").text is None
assert metadata.find("./idpf:meta[@property='ibooks:version']").text is None
assert metadata.find("./idpf:meta[@property='ibooks:specified-fonts']").text == 'true'
@@ -171,7 +171,7 @@ def test_nested_toc(app):
# toc.ncx
toc = EPUBElementTree.fromstring((app.outdir / 'toc.ncx').read_bytes())
- assert toc.find("./ncx:docTitle/ncx:text").text == 'Python'
+ assert toc.find("./ncx:docTitle/ncx:text").text == 'Project name not set'
# toc.ncx / navPoint
def navinfo(elem):
@@ -409,6 +409,7 @@ def test_copy_images(app, status, warning):
images = {image.name for image in images_dir.rglob('*')}
images.discard('python-logo.png')
assert images == {
+ # 'ba30773957c3fe046897111afd65a80b81cad089.png', # epub: image from data:image/png URI in source
'img.png',
'rimg.png',
'rimg1.png',
diff --git a/tests/test_builders/test_build_gettext.py b/tests/test_builders/test_build_gettext.py
index ddc6d30..dc8f4c9 100644
--- a/tests/test_builders/test_build_gettext.py
+++ b/tests/test_builders/test_build_gettext.py
@@ -16,13 +16,12 @@ if sys.version_info[:2] >= (3, 11):
else:
from sphinx.util.osutil import _chdir as chdir
-_MSGID_PATTERN = re.compile(r'msgid "(.*)"')
+_MSGID_PATTERN = re.compile(r'msgid "((?:\n|.)*?)"\nmsgstr', re.MULTILINE)
-def msgid_getter(msgid):
- if m := _MSGID_PATTERN.search(msgid):
- return m[1]
- return None
+def get_msgids(pot):
+ matches = _MSGID_PATTERN.findall(pot)
+ return [m.replace('"\n"', '') for m in matches[1:]]
def test_Catalog_duplicated_message():
@@ -105,7 +104,7 @@ def test_gettext_index_entries(app):
app.build(filenames=[app.srcdir / 'index_entries.txt'])
pot = (app.outdir / 'index_entries.pot').read_text(encoding='utf8')
- msg_ids = list(filter(None, map(msgid_getter, pot.splitlines())))
+ msg_ids = get_msgids(pot)
assert msg_ids == [
"i18n with index entries",
@@ -134,7 +133,7 @@ def test_gettext_disable_index_entries(app):
app.build(filenames=[app.srcdir / 'index_entries.txt'])
pot = (app.outdir / 'index_entries.pot').read_text(encoding='utf8')
- msg_ids = list(filter(None, map(msgid_getter, pot.splitlines())))
+ msg_ids = get_msgids(pot)
assert msg_ids == [
"i18n with index entries",
@@ -200,7 +199,7 @@ def test_gettext_prolog_epilog_substitution(app):
assert (app.outdir / 'prolog_epilog_substitution.pot').is_file()
pot = (app.outdir / 'prolog_epilog_substitution.pot').read_text(encoding='utf8')
- msg_ids = list(filter(None, map(msgid_getter, pot.splitlines())))
+ msg_ids = get_msgids(pot)
assert msg_ids == [
"i18n with prologue and epilogue substitutions",
@@ -227,9 +226,43 @@ def test_gettext_prolog_epilog_substitution_excluded(app):
assert (app.outdir / 'prolog_epilog_substitution_excluded.pot').is_file()
pot = (app.outdir / 'prolog_epilog_substitution_excluded.pot').read_text(encoding='utf8')
- msg_ids = list(filter(None, map(msgid_getter, pot.splitlines())))
+ msg_ids = get_msgids(pot)
assert msg_ids == [
"i18n without prologue and epilogue substitutions",
"This is content that does not include prologue and epilogue substitutions.",
]
+
+
+@pytest.mark.sphinx(
+ 'gettext', srcdir='gettext',
+ confoverrides={'gettext_compact': False,
+ 'gettext_additional_targets': ['literal-block', 'doctest-block']})
+def test_gettext_literalblock_additional(app):
+ app.build(force_all=True)
+
+ assert (app.outdir / 'literalblock.pot').is_file()
+ pot = (app.outdir / 'literalblock.pot').read_text(encoding='utf8')
+ msg_ids = get_msgids(pot)
+
+ assert msg_ids == [
+ 'i18n with literal block',
+ 'Correct literal block::',
+ 'this is\\nliteral block',
+ 'Missing literal block::',
+ "That's all.",
+ 'included raw.txt',
+ '===\\nRaw\\n===\\n\\n.. raw:: html\\n\\n <iframe src=\\"https://sphinx-doc.org\\"></iframe>\\n\\n',
+ 'code blocks',
+ "def main\\n 'result'\\nend",
+ '#include <stdlib.h>\\nint main(int argc, char** argv)\\n{\\n return 0;\\n}',
+ 'example of C language',
+ '#include <stdio.h>\\nint main(int argc, char** argv)\\n{\\n return 0;\\n}',
+ 'literal-block\\nin list',
+ 'test_code_for_noqa()\\ncontinued()',
+ 'doctest blocks',
+ '>>> import sys # sys importing\\n>>> def main(): # define main '
+ "function\\n... sys.stdout.write('hello') # call write method of "
+ "stdout object\\n>>>\\n>>> if __name__ == '__main__': # if run this py "
+ 'file as python script\\n... main() # call main',
+ ]
diff --git a/tests/test_builders/test_build_html.py b/tests/test_builders/test_build_html.py
index 1fa3ba4..8db0790 100644
--- a/tests/test_builders/test_build_html.py
+++ b/tests/test_builders/test_build_html.py
@@ -1,5 +1,6 @@
"""Test the HTML builder and check output against XPath."""
+import contextlib
import os
import posixpath
import re
@@ -8,7 +9,7 @@ import pytest
from sphinx.builders.html import validate_html_extra_path, validate_html_static_path
from sphinx.deprecation import RemovedInSphinx80Warning
-from sphinx.errors import ConfigError
+from sphinx.errors import ConfigError, ThemeError
from sphinx.util.console import strip_colors
from sphinx.util.inventory import InventoryFile
@@ -16,6 +17,31 @@ from tests.test_builders.xpath_data import FIGURE_CAPTION
from tests.test_builders.xpath_util import check_xpath
+def test_html_sidebars_error(make_app, tmp_path):
+ (tmp_path / 'conf.py').touch()
+ (tmp_path / 'index.rst').touch()
+ app = make_app(
+ buildername='html',
+ srcdir=tmp_path,
+ confoverrides={'html_sidebars': {'index': 'searchbox.html'}},
+ )
+
+ # Test that the error is logged
+ warnings = app.warning.getvalue()
+ assert ("ERROR: Values in 'html_sidebars' must be a list of strings. "
+ "At least one pattern has a string value: 'index'. "
+ "Change to `html_sidebars = {'index': ['searchbox.html']}`.") in warnings
+
+ # But that the value is unchanged.
+ # (Remove this bit of the test in Sphinx 8)
+ def _html_context_hook(app, pagename, templatename, context, doctree):
+ assert context["sidebars"] == 'searchbox.html'
+ app.connect('html-page-context', _html_context_hook)
+ with contextlib.suppress(ThemeError):
+ # ignore template rendering issues (ThemeError).
+ app.build()
+
+
def test_html4_error(make_app, tmp_path):
(tmp_path / 'conf.py').write_text('', encoding='utf-8')
with pytest.raises(
@@ -131,24 +157,24 @@ def test_html_inventory(app):
'py-modindex',
'genindex',
'search'}
- assert invdata['std:label']['modindex'] == ('Python',
+ assert invdata['std:label']['modindex'] == ('Project name not set',
'',
'https://www.google.com/py-modindex.html',
'Module Index')
- assert invdata['std:label']['py-modindex'] == ('Python',
+ assert invdata['std:label']['py-modindex'] == ('Project name not set',
'',
'https://www.google.com/py-modindex.html',
'Python Module Index')
- assert invdata['std:label']['genindex'] == ('Python',
+ assert invdata['std:label']['genindex'] == ('Project name not set',
'',
'https://www.google.com/genindex.html',
'Index')
- assert invdata['std:label']['search'] == ('Python',
+ assert invdata['std:label']['search'] == ('Project name not set',
'',
'https://www.google.com/search.html',
'Search Page')
assert set(invdata['std:doc'].keys()) == {'index'}
- assert invdata['std:doc']['index'] == ('Python',
+ assert invdata['std:doc']['index'] == ('Project name not set',
'',
'https://www.google.com/index.html',
'The basic Sphinx documentation for testing')
@@ -222,8 +248,8 @@ def test_html_sidebar(app, status, warning):
app.build(force_all=True)
result = (app.outdir / 'index.html').read_text(encoding='utf8')
assert ('<div class="sphinxsidebar" role="navigation" '
- 'aria-label="main navigation">' in result)
- assert '<h1 class="logo"><a href="#">Python</a></h1>' in result
+ 'aria-label="Main">' in result)
+ assert '<h1 class="logo"><a href="#">Project name not set</a></h1>' in result
assert '<h3>Navigation</h3>' in result
assert '<h3>Related Topics</h3>' in result
assert '<h3 id="searchlabel">Quick search</h3>' in result
@@ -237,7 +263,7 @@ def test_html_sidebar(app, status, warning):
app.build(force_all=True)
result = (app.outdir / 'index.html').read_text(encoding='utf8')
assert ('<div class="sphinxsidebar" role="navigation" '
- 'aria-label="main navigation">' in result)
+ 'aria-label="Main">' in result)
assert '<h1 class="logo"><a href="#">Python</a></h1>' not in result
assert '<h3>Navigation</h3>' not in result
assert '<h3>Related Topics</h3>' in result
@@ -251,7 +277,7 @@ def test_html_sidebar(app, status, warning):
app.build(force_all=True)
result = (app.outdir / 'index.html').read_text(encoding='utf8')
assert ('<div class="sphinxsidebar" role="navigation" '
- 'aria-label="main navigation">' not in result)
+ 'aria-label="Main">' not in result)
assert '<h1 class="logo"><a href="#">Python</a></h1>' not in result
assert '<h3>Navigation</h3>' not in result
assert '<h3>Related Topics</h3>' not in result
@@ -376,3 +402,34 @@ def test_html_remove_sources_before_write_gh_issue_10786(app, warning):
file = os.fsdecode(target)
assert f'WARNING: cannot copy image file {file!r}: {file!s} does not exist' == ws[-1]
+
+
+@pytest.mark.sphinx('html', testroot='domain-py-python_maximum_signature_line_length',
+ confoverrides={'python_maximum_signature_line_length': 1})
+def test_html_pep_695_one_type_per_line(app, cached_etree_parse):
+ app.build()
+ fname = app.outdir / 'index.html'
+ etree = cached_etree_parse(fname)
+
+ class chk:
+ def __init__(self, expect):
+ self.expect = expect
+
+ def __call__(self, nodes):
+ assert len(nodes) == 1, nodes
+ objnode = ''.join(nodes[0].itertext()).replace('\n\n', '')
+ objnode = objnode.rstrip(chr(182)) # remove '¶' symbol
+ objnode = objnode.strip('\n') # remove surrounding new lines
+ assert objnode == self.expect
+
+ # each signature has a dangling ',' at the end of its parameters lists
+ check_xpath(etree, fname, r'.//dt[@id="generic_foo"][1]',
+ chk('generic_foo[\nT,\n]()'))
+ check_xpath(etree, fname, r'.//dt[@id="generic_bar"][1]',
+ chk('generic_bar[\nT,\n](\nx: list[T],\n)'))
+ check_xpath(etree, fname, r'.//dt[@id="generic_ret"][1]',
+ chk('generic_ret[\nR,\n]() → R'))
+ check_xpath(etree, fname, r'.//dt[@id="MyGenericClass"][1]',
+ chk('class MyGenericClass[\nX,\n]'))
+ check_xpath(etree, fname, r'.//dt[@id="MyList"][1]',
+ chk('class MyList[\nT,\n](list[T])'))
diff --git a/tests/test_builders/test_build_html_5_output.py b/tests/test_builders/test_build_html_5_output.py
index ece6f49..388c324 100644
--- a/tests/test_builders/test_build_html_5_output.py
+++ b/tests/test_builders/test_build_html_5_output.py
@@ -3,6 +3,7 @@
import re
import pytest
+from docutils import nodes
from tests.test_builders.xpath_util import check_xpath
@@ -25,6 +26,9 @@ def tail_check(check):
('images.html', ".//img[@src='_images/simg.png']", ''),
('images.html', ".//img[@src='_images/svgimg.svg']", ''),
('images.html', ".//a[@href='_sources/images.txt']", ''),
+ # Check svg options
+ ('images.html', ".//img[@src='_images/svgimg.svg'][@style='width: 2cm;']", ''),
+ ('images.html', ".//img[@src='_images/svgimg.svg'][@style='height: 2cm;']", ''),
('subdir/images.html', ".//img[@src='../_images/img1.png']", ''),
('subdir/images.html', ".//img[@src='../_images/rimg.png']", ''),
@@ -255,6 +259,8 @@ def tail_check(check):
('extensions.html', ".//a[@href='https://python.org/dev/']", "https://python.org/dev/"),
('extensions.html', ".//a[@href='https://bugs.python.org/issue1000']", "issue 1000"),
('extensions.html', ".//a[@href='https://bugs.python.org/issue1042']", "explicit caption"),
+ ('extensions.html', ".//a[@class='extlink-pyurl reference external']", "https://python.org/dev/"),
+ ('extensions.html', ".//a[@class='extlink-issue reference external']", "issue 1000"),
# index entries
('genindex.html', ".//a/strong", "Main"),
@@ -270,7 +276,32 @@ def tail_check(check):
])
@pytest.mark.sphinx('html', tags=['testtag'],
confoverrides={'html_context.hckey_co': 'hcval_co'})
-@pytest.mark.test_params(shared_result='test_build_html_output')
def test_html5_output(app, cached_etree_parse, fname, path, check):
app.build()
check_xpath(cached_etree_parse(app.outdir / fname), fname, path, check)
+
+
+@pytest.mark.sphinx('html', testroot='markup-rubric')
+def test_html5_rubric(app):
+ def insert_invalid_rubric_heading_level(app, doctree, docname):
+ if docname != 'index':
+ return
+ new_node = nodes.rubric('', 'INSERTED RUBRIC')
+ new_node['heading-level'] = 7
+ doctree[0].append(new_node)
+
+ app.connect('doctree-resolved', insert_invalid_rubric_heading_level)
+ app.build()
+
+ warnings = app.warning.getvalue()
+ content = (app.outdir / 'index.html').read_text(encoding='utf8')
+ assert '<p class="rubric">This is a rubric</p>' in content
+ assert '<h2 class="myclass rubric">A rubric with a heading level 2</h2>' in content
+
+ # directive warning
+ assert '"7" unknown' in warnings
+
+ # html writer warning
+ assert 'WARNING: unsupported rubric heading level: 7' in warnings
+ assert '</h7>' not in content
+ assert '<p class="rubric">INSERTED RUBRIC</p>' in content
diff --git a/tests/test_builders/test_build_html_assets.py b/tests/test_builders/test_build_html_assets.py
index fc7a987..e2c7c75 100644
--- a/tests/test_builders/test_build_html_assets.py
+++ b/tests/test_builders/test_build_html_assets.py
@@ -34,7 +34,7 @@ def test_html_assets(app):
# html_extra_path
assert (app.outdir / '.htaccess').exists()
assert not (app.outdir / '.htpasswd').exists()
- assert (app.outdir / 'API.html_t').exists()
+ assert (app.outdir / 'API.html.jinja').exists()
assert (app.outdir / 'css/style.css').exists()
assert (app.outdir / 'rimg.png').exists()
assert not (app.outdir / '_build' / 'index.html').exists()
diff --git a/tests/test_builders/test_build_html_download.py b/tests/test_builders/test_build_html_download.py
index 1201c66..14332d8 100644
--- a/tests/test_builders/test_build_html_download.py
+++ b/tests/test_builders/test_build_html_download.py
@@ -5,7 +5,6 @@ import pytest
@pytest.mark.sphinx('html')
-@pytest.mark.test_params(shared_result='test_build_html_output')
def test_html_download(app):
app.build()
diff --git a/tests/test_builders/test_build_html_image.py b/tests/test_builders/test_build_html_image.py
index 08ed618..860beb6 100644
--- a/tests/test_builders/test_build_html_image.py
+++ b/tests/test_builders/test_build_html_image.py
@@ -29,7 +29,7 @@ def test_html_remote_logo(app, status, warning):
app.build(force_all=True)
result = (app.outdir / 'index.html').read_text(encoding='utf8')
- assert ('<img class="logo" src="https://www.python.org/static/img/python-logo.png" alt="Logo"/>' in result)
+ assert ('<img class="logo" src="https://www.python.org/static/img/python-logo.png" alt="Logo of Project name not set"/>' in result)
assert ('<link rel="icon" href="https://www.python.org/static/favicon.ico"/>' in result)
assert not (app.outdir / 'python-logo.png').exists()
@@ -39,7 +39,7 @@ def test_html_local_logo(app, status, warning):
app.build(force_all=True)
result = (app.outdir / 'index.html').read_text(encoding='utf8')
- assert ('<img class="logo" src="_static/img.png" alt="Logo"/>' in result)
+ assert ('<img class="logo" src="_static/img.png" alt="Logo of Project name not set"/>' in result)
assert (app.outdir / '_static/img.png').exists()
@@ -72,6 +72,7 @@ def test_copy_images(app, status, warning):
images_dir = Path(app.outdir) / '_images'
images = {image.name for image in images_dir.rglob('*')}
assert images == {
+ # 'ba30773957c3fe046897111afd65a80b81cad089.png', # html: image from data:image/png URI in source
'img.png',
'rimg.png',
'rimg1.png',
diff --git a/tests/test_builders/test_build_latex.py b/tests/test_builders/test_build_latex.py
index 0776c74..56505b4 100644
--- a/tests/test_builders/test_build_latex.py
+++ b/tests/test_builders/test_build_latex.py
@@ -41,7 +41,7 @@ def kpsetest(*filenames):
# compile latex document with app.config.latex_engine
-def compile_latex_document(app, filename='python.tex', docclass='manual'):
+def compile_latex_document(app, filename='projectnamenotset.tex', docclass='manual'):
# now, try to run latex over it
try:
with chdir(app.outdir):
@@ -158,21 +158,21 @@ def test_writer(app, status, warning):
assert ('\\begin{wrapfigure}{r}{0pt}\n\\centering\n'
'\\noindent\\sphinxincludegraphics{{rimg}.png}\n'
- '\\caption{figure with align option}\\label{\\detokenize{markup:id9}}'
+ '\\caption{figure with align option}\\label{\\detokenize{markup:id10}}'
'\\end{wrapfigure}\n\n'
'\\mbox{}\\par\\vskip-\\dimexpr\\baselineskip+\\parskip\\relax' in result)
assert ('\\begin{wrapfigure}{r}{0.500\\linewidth}\n\\centering\n'
'\\noindent\\sphinxincludegraphics{{rimg}.png}\n'
'\\caption{figure with align \\& figwidth option}'
- '\\label{\\detokenize{markup:id10}}'
+ '\\label{\\detokenize{markup:id11}}'
'\\end{wrapfigure}\n\n'
'\\mbox{}\\par\\vskip-\\dimexpr\\baselineskip+\\parskip\\relax' in result)
assert ('\\begin{wrapfigure}{r}{3cm}\n\\centering\n'
'\\noindent\\sphinxincludegraphics[width=3cm]{{rimg}.png}\n'
'\\caption{figure with align \\& width option}'
- '\\label{\\detokenize{markup:id11}}'
+ '\\label{\\detokenize{markup:id12}}'
'\\end{wrapfigure}\n\n'
'\\mbox{}\\par\\vskip-\\dimexpr\\baselineskip+\\parskip\\relax' in result)
@@ -255,7 +255,7 @@ def test_latex_basic_howto_ja(app, status, warning):
@pytest.mark.sphinx('latex', testroot='latex-theme')
def test_latex_theme(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
print(result)
assert r'\def\sphinxdocclass{book}' in result
assert r'\documentclass[a4paper,12pt,english]{sphinxbook}' in result
@@ -266,7 +266,7 @@ def test_latex_theme(app, status, warning):
'pointsize': '9pt'}})
def test_latex_theme_papersize(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
print(result)
assert r'\def\sphinxdocclass{book}' in result
assert r'\documentclass[b5paper,9pt,english]{sphinxbook}' in result
@@ -277,7 +277,7 @@ def test_latex_theme_papersize(app, status, warning):
'pointsize': '9pt'}})
def test_latex_theme_options(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
print(result)
assert r'\def\sphinxdocclass{book}' in result
assert r'\documentclass[b5paper,9pt,english]{sphinxbook}' in result
@@ -330,7 +330,7 @@ def test_latex_release(app, status, warning):
confoverrides={'numfig': True})
def test_numref(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
print(result)
print(status.getvalue())
print(warning.getvalue())
@@ -372,7 +372,7 @@ def test_numref(app, status, warning):
'section': 'SECTION-%s'}})
def test_numref_with_prefix1(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
print(result)
print(status.getvalue())
print(warning.getvalue())
@@ -420,7 +420,7 @@ def test_numref_with_prefix1(app, status, warning):
'section': 'SECTION_%s_'}})
def test_numref_with_prefix2(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
print(result)
print(status.getvalue())
print(warning.getvalue())
@@ -460,7 +460,7 @@ def test_numref_with_prefix2(app, status, warning):
confoverrides={'numfig': True, 'language': 'ja'})
def test_numref_with_language_ja(app, status, warning):
app.build()
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
print(result)
print(status.getvalue())
print(warning.getvalue())
@@ -556,7 +556,7 @@ def test_latex_add_latex_package(app, status, warning):
@pytest.mark.sphinx('latex', testroot='latex-babel')
def test_babel_with_no_language_settings(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
print(result)
print(status.getvalue())
print(warning.getvalue())
@@ -581,7 +581,7 @@ def test_babel_with_no_language_settings(app, status, warning):
confoverrides={'language': 'de'})
def test_babel_with_language_de(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
print(result)
print(status.getvalue())
print(warning.getvalue())
@@ -606,7 +606,7 @@ def test_babel_with_language_de(app, status, warning):
confoverrides={'language': 'ru'})
def test_babel_with_language_ru(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
print(result)
print(status.getvalue())
print(warning.getvalue())
@@ -631,7 +631,7 @@ def test_babel_with_language_ru(app, status, warning):
confoverrides={'language': 'tr'})
def test_babel_with_language_tr(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
print(result)
print(status.getvalue())
print(warning.getvalue())
@@ -656,7 +656,7 @@ def test_babel_with_language_tr(app, status, warning):
confoverrides={'language': 'ja'})
def test_babel_with_language_ja(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
print(result)
print(status.getvalue())
print(warning.getvalue())
@@ -680,7 +680,7 @@ def test_babel_with_language_ja(app, status, warning):
confoverrides={'language': 'unknown'})
def test_babel_with_unknown_language(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
print(result)
print(status.getvalue())
print(warning.getvalue())
@@ -707,7 +707,7 @@ def test_babel_with_unknown_language(app, status, warning):
confoverrides={'language': 'de', 'latex_engine': 'lualatex'})
def test_polyglossia_with_language_de(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
print(result)
print(status.getvalue())
print(warning.getvalue())
@@ -733,7 +733,7 @@ def test_polyglossia_with_language_de(app, status, warning):
confoverrides={'language': 'de-1901', 'latex_engine': 'lualatex'})
def test_polyglossia_with_language_de_1901(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
print(result)
print(status.getvalue())
print(warning.getvalue())
@@ -786,7 +786,7 @@ def test_footnote(app, status, warning):
@pytest.mark.sphinx('latex', testroot='footnotes')
def test_reference_in_caption_and_codeblock_in_footnote(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
print(result)
print(status.getvalue())
print(warning.getvalue())
@@ -826,7 +826,7 @@ def test_reference_in_caption_and_codeblock_in_footnote(app, status, warning):
@pytest.mark.sphinx('latex', testroot='footnotes')
def test_footnote_referred_multiple_times(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
print(result)
print(status.getvalue())
print(warning.getvalue())
@@ -848,7 +848,7 @@ def test_footnote_referred_multiple_times(app, status, warning):
confoverrides={'latex_show_urls': 'inline'})
def test_latex_show_urls_is_inline(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
print(result)
print(status.getvalue())
print(warning.getvalue())
@@ -905,7 +905,7 @@ def test_latex_show_urls_is_inline(app, status, warning):
confoverrides={'latex_show_urls': 'footnote'})
def test_latex_show_urls_is_footnote(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
print(result)
print(status.getvalue())
print(warning.getvalue())
@@ -967,7 +967,7 @@ def test_latex_show_urls_is_footnote(app, status, warning):
confoverrides={'latex_show_urls': 'no'})
def test_latex_show_urls_is_no(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
print(result)
print(status.getvalue())
print(warning.getvalue())
@@ -1022,7 +1022,7 @@ def test_latex_show_urls_footnote_and_substitutions(app, status, warning):
@pytest.mark.sphinx('latex', testroot='image-in-section')
def test_image_in_section(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
print(result)
print(status.getvalue())
print(warning.getvalue())
@@ -1045,7 +1045,7 @@ def test_latex_logo_if_not_found(app, status, warning):
@pytest.mark.sphinx('latex', testroot='toctree-maxdepth')
def test_toctree_maxdepth_manual(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
print(result)
print(status.getvalue())
print(warning.getvalue())
@@ -1057,12 +1057,12 @@ def test_toctree_maxdepth_manual(app, status, warning):
@pytest.mark.sphinx(
'latex', testroot='toctree-maxdepth',
confoverrides={'latex_documents': [
- ('index', 'python.tex', 'Sphinx Tests Documentation',
+ ('index', 'projectnamenotset.tex', 'Sphinx Tests Documentation',
'Georg Brandl', 'howto'),
]})
def test_toctree_maxdepth_howto(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
print(result)
print(status.getvalue())
print(warning.getvalue())
@@ -1076,7 +1076,7 @@ def test_toctree_maxdepth_howto(app, status, warning):
confoverrides={'root_doc': 'foo'})
def test_toctree_not_found(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
print(result)
print(status.getvalue())
print(warning.getvalue())
@@ -1090,7 +1090,7 @@ def test_toctree_not_found(app, status, warning):
confoverrides={'root_doc': 'bar'})
def test_toctree_without_maxdepth(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
print(result)
print(status.getvalue())
print(warning.getvalue())
@@ -1103,7 +1103,7 @@ def test_toctree_without_maxdepth(app, status, warning):
confoverrides={'root_doc': 'qux'})
def test_toctree_with_deeper_maxdepth(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
print(result)
print(status.getvalue())
print(warning.getvalue())
@@ -1116,7 +1116,7 @@ def test_toctree_with_deeper_maxdepth(app, status, warning):
confoverrides={'latex_toplevel_sectioning': None})
def test_latex_toplevel_sectioning_is_None(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
print(result)
print(status.getvalue())
print(warning.getvalue())
@@ -1128,7 +1128,7 @@ def test_latex_toplevel_sectioning_is_None(app, status, warning):
confoverrides={'latex_toplevel_sectioning': 'part'})
def test_latex_toplevel_sectioning_is_part(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
print(result)
print(status.getvalue())
print(warning.getvalue())
@@ -1141,12 +1141,12 @@ def test_latex_toplevel_sectioning_is_part(app, status, warning):
'latex', testroot='toctree-maxdepth',
confoverrides={'latex_toplevel_sectioning': 'part',
'latex_documents': [
- ('index', 'python.tex', 'Sphinx Tests Documentation',
+ ('index', 'projectnamenotset.tex', 'Sphinx Tests Documentation',
'Georg Brandl', 'howto'),
]})
def test_latex_toplevel_sectioning_is_part_with_howto(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
print(result)
print(status.getvalue())
print(warning.getvalue())
@@ -1160,7 +1160,7 @@ def test_latex_toplevel_sectioning_is_part_with_howto(app, status, warning):
confoverrides={'latex_toplevel_sectioning': 'chapter'})
def test_latex_toplevel_sectioning_is_chapter(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
print(result)
print(status.getvalue())
print(warning.getvalue())
@@ -1171,12 +1171,12 @@ def test_latex_toplevel_sectioning_is_chapter(app, status, warning):
'latex', testroot='toctree-maxdepth',
confoverrides={'latex_toplevel_sectioning': 'chapter',
'latex_documents': [
- ('index', 'python.tex', 'Sphinx Tests Documentation',
+ ('index', 'projectnamenotset.tex', 'Sphinx Tests Documentation',
'Georg Brandl', 'howto'),
]})
def test_latex_toplevel_sectioning_is_chapter_with_howto(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
print(result)
print(status.getvalue())
print(warning.getvalue())
@@ -1188,7 +1188,7 @@ def test_latex_toplevel_sectioning_is_chapter_with_howto(app, status, warning):
confoverrides={'latex_toplevel_sectioning': 'section'})
def test_latex_toplevel_sectioning_is_section(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
print(result)
print(status.getvalue())
print(warning.getvalue())
@@ -1199,11 +1199,11 @@ def test_latex_toplevel_sectioning_is_section(app, status, warning):
@pytest.mark.sphinx('latex', testroot='maxlistdepth')
def test_maxlistdepth_at_ten(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
print(result)
print(status.getvalue())
print(warning.getvalue())
- compile_latex_document(app, 'python.tex')
+ compile_latex_document(app, 'projectnamenotset.tex')
@pytest.mark.sphinx('latex', testroot='latex-table',
@@ -1211,7 +1211,7 @@ def test_maxlistdepth_at_ten(app, status, warning):
@pytest.mark.test_params(shared_result='latex-table')
def test_latex_table_tabulars(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
tables = {}
for chap in re.split(r'\\(?:section|chapter){', result)[1:]:
sectname, content = chap.split('}', 1)
@@ -1282,7 +1282,7 @@ def test_latex_table_tabulars(app, status, warning):
@pytest.mark.test_params(shared_result='latex-table')
def test_latex_table_longtable(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
tables = {}
for chap in re.split(r'\\(?:section|chapter){', result)[1:]:
sectname, content = chap.split('}', 1)
@@ -1343,7 +1343,7 @@ def test_latex_table_longtable(app, status, warning):
@pytest.mark.test_params(shared_result='latex-table')
def test_latex_table_complex_tables(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
tables = {}
for chap in re.split(r'\\(?:section|renewcommand){', result)[1:]:
sectname, content = chap.split('}', 1)
@@ -1373,7 +1373,7 @@ def test_latex_table_complex_tables(app, status, warning):
@pytest.mark.sphinx('latex', testroot='latex-table')
def test_latex_table_with_booktabs_and_colorrows(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
assert r'\PassOptionsToPackage{booktabs}{sphinx}' in result
assert r'\PassOptionsToPackage{colorrows}{sphinx}' in result
# tabularcolumns
@@ -1389,15 +1389,16 @@ def test_latex_table_with_booktabs_and_colorrows(app, status, warning):
confoverrides={'templates_path': ['_mytemplates/latex']})
def test_latex_table_custom_template_caseA(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
assert 'SALUT LES COPAINS' in result
+ assert 'AU REVOIR, KANIGGETS' in result
@pytest.mark.sphinx('latex', testroot='latex-table',
confoverrides={'templates_path': ['_mytemplates']})
def test_latex_table_custom_template_caseB(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
assert 'SALUT LES COPAINS' not in result
@@ -1405,14 +1406,14 @@ def test_latex_table_custom_template_caseB(app, status, warning):
@pytest.mark.test_params(shared_result='latex-table')
def test_latex_table_custom_template_caseC(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
assert 'SALUT LES COPAINS' not in result
@pytest.mark.sphinx('latex', testroot='directives-raw')
def test_latex_raw_directive(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
# standard case
assert 'standalone raw directive (HTML)' not in result
@@ -1429,7 +1430,7 @@ def test_latex_images(app, status, warning):
with http_server(RemoteImageHandler, port=7777):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
# images are copied
assert '\\sphinxincludegraphics{{sphinx}.png}' in result
@@ -1453,7 +1454,7 @@ def test_latex_images(app, status, warning):
def test_latex_index(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
assert ('A \\index{famous@\\spxentry{famous}}famous '
'\\index{equation@\\spxentry{equation}}equation:\n' in result)
assert ('\n\\index{Einstein@\\spxentry{Einstein}}'
@@ -1467,7 +1468,7 @@ def test_latex_index(app, status, warning):
def test_latex_equations(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
expected = (app.srcdir / 'expects' / 'latex-equations.tex').read_text(encoding='utf8').strip()
assert expected in result
@@ -1477,7 +1478,7 @@ def test_latex_equations(app, status, warning):
def test_latex_image_in_parsed_literal(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
assert ('{\\sphinxunactivateextrasandspace \\raisebox{-0.5\\height}'
'{\\sphinxincludegraphics[height=2.00000cm]{{pic}.png}}'
'}AFTER') in result
@@ -1487,7 +1488,7 @@ def test_latex_image_in_parsed_literal(app, status, warning):
def test_latex_nested_enumerated_list(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
assert ('\\sphinxsetlistlabels{\\arabic}{enumi}{enumii}{}{.}%\n'
'\\setcounter{enumi}{4}\n' in result)
assert ('\\sphinxsetlistlabels{\\alph}{enumii}{enumiii}{}{.}%\n'
@@ -1504,7 +1505,7 @@ def test_latex_nested_enumerated_list(app, status, warning):
def test_latex_thebibliography(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
print(result)
assert ('\\begin{sphinxthebibliography}{AuthorYe}\n'
'\\bibitem[AuthorYear]{index:authoryear}\n\\sphinxAtStartPar\n'
@@ -1517,7 +1518,7 @@ def test_latex_thebibliography(app, status, warning):
def test_latex_glossary(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
assert (r'\sphinxlineitem{ähnlich\index{ähnlich@\spxentry{ähnlich}|spxpagem}'
r'\phantomsection'
r'\label{\detokenize{index:term-ahnlich}}}' in result)
@@ -1541,7 +1542,7 @@ def test_latex_glossary(app, status, warning):
def test_latex_labels(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
# figures
assert (r'\caption{labeled figure}'
@@ -1589,8 +1590,10 @@ def test_latex_labels(app, status, warning):
@pytest.mark.sphinx('latex', testroot='latex-figure-in-admonition')
def test_latex_figure_in_admonition(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
- assert r'\begin{figure}[H]' in result
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
+ assert 'tabulary' not in result
+ for type in ('caution', 'note', 'seealso', 'todo'):
+ assert f'{type} directive.\n\n\\begin{{figure}}[H]' in result
def test_default_latex_documents():
@@ -1619,7 +1622,7 @@ def test_includegraphics_oversized(app, status, warning):
@pytest.mark.sphinx('latex', testroot='index_on_title')
def test_index_on_title(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
assert ('\\chapter{Test for index in top level title}\n'
'\\label{\\detokenize{contents:test-for-index-in-top-level-title}}'
'\\index{index@\\spxentry{index}}\n'
@@ -1630,7 +1633,7 @@ def test_index_on_title(app, status, warning):
confoverrides={'latex_engine': 'pdflatex'})
def test_texescape_for_non_unicode_supported_engine(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
print(result)
assert 'script small e: e' in result
assert 'double struck italic small i: i' in result
@@ -1642,7 +1645,7 @@ def test_texescape_for_non_unicode_supported_engine(app, status, warning):
confoverrides={'latex_engine': 'xelatex'})
def test_texescape_for_unicode_supported_engine(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
print(result)
assert 'script small e: e' in result
assert 'double struck italic small i: i' in result
@@ -1667,7 +1670,7 @@ def test_latex_nested_tables(app, status, warning):
@pytest.mark.sphinx('latex', testroot='latex-container')
def test_latex_container(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
assert r'\begin{sphinxuseclass}{classname}' in result
assert r'\end{sphinxuseclass}' in result
@@ -1675,7 +1678,7 @@ def test_latex_container(app, status, warning):
@pytest.mark.sphinx('latex', testroot='reST-code-role')
def test_latex_code_role(app):
app.build()
- content = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ content = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
common_content = (
r'\PYG{k}{def} '
@@ -1710,6 +1713,7 @@ def test_copy_images(app, status, warning):
}
images.discard('sphinx.png')
assert images == {
+ 'ba30773957c3fe046897111afd65a80b81cad089.png', # latex: image from data:image/png URI in source
'img.pdf',
'rimg.png',
'testimäge.png',
@@ -1719,7 +1723,7 @@ def test_copy_images(app, status, warning):
@pytest.mark.sphinx('latex', testroot='latex-labels-before-module')
def test_duplicated_labels_before_module(app, status, warning):
app.build()
- content: str = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ content: str = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
def count_label(name):
text = r'\phantomsection\label{\detokenize{%s}}' % name
@@ -1750,10 +1754,40 @@ def test_duplicated_labels_before_module(app, status, warning):
confoverrides={'python_maximum_signature_line_length': 23})
def test_one_parameter_per_line(app, status, warning):
app.build(force_all=True)
- result = (app.outdir / 'python.tex').read_text(encoding='utf8')
+ result = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8')
# TODO: should these asserts check presence or absence of a final \sphinxparamcomma?
# signature of 23 characters is too short to trigger one-param-per-line mark-up
assert ('\\pysiglinewithargsret{\\sphinxbfcode{\\sphinxupquote{hello}}}' in result)
assert ('\\pysigwithonelineperarg{\\sphinxbfcode{\\sphinxupquote{foo}}}' in result)
+
+ # generic_arg[T]
+ assert ('\\pysiglinewithargsretwithtypelist{\\sphinxbfcode{\\sphinxupquote{generic\\_arg}}}'
+ '{\\sphinxtypeparam{\\DUrole{n}{T}}}{}{}' in result)
+
+ # generic_foo[T]()
+ assert ('\\pysiglinewithargsretwithtypelist{\\sphinxbfcode{\\sphinxupquote{generic\\_foo}}}' in result)
+
+ # generic_bar[T](x: list[T])
+ assert ('\\pysigwithonelineperargwithtypelist{\\sphinxbfcode{\\sphinxupquote{generic\\_bar}}}' in result)
+
+ # generic_ret[R]() -> R
+ assert ('\\pysiglinewithargsretwithtypelist{\\sphinxbfcode{\\sphinxupquote{generic\\_ret}}}'
+ '{\\sphinxtypeparam{\\DUrole{n}{R}}}{}{{ $\\rightarrow$ R}}' in result)
+
+ # MyGenericClass[X]
+ assert ('\\pysiglinewithargsretwithtypelist{\\sphinxbfcode{\\sphinxupquote{class\\DUrole{w}{ '
+ '}}}\\sphinxbfcode{\\sphinxupquote{MyGenericClass}}}' in result)
+
+ # MyList[T](list[T])
+ assert ('\\pysiglinewithargsretwithtypelist{\\sphinxbfcode{\\sphinxupquote{class\\DUrole{w}{ '
+ '}}}\\sphinxbfcode{\\sphinxupquote{MyList}}}' in result)
+
+
+@pytest.mark.sphinx('latex', testroot='markup-rubric')
+def test_latex_rubric(app):
+ app.build()
+ content = (app.outdir / 'test.tex').read_text(encoding='utf8')
+ assert r'\subsubsection*{This is a rubric}' in content
+ assert r'\subsection*{A rubric with a heading level 2}' in content
diff --git a/tests/test_builders/test_build_linkcheck.py b/tests/test_builders/test_build_linkcheck.py
index c8d8515..0787661 100644
--- a/tests/test_builders/test_build_linkcheck.py
+++ b/tests/test_builders/test_build_linkcheck.py
@@ -11,6 +11,7 @@ import wsgiref.handlers
from base64 import b64encode
from http.server import BaseHTTPRequestHandler
from queue import Queue
+from typing import TYPE_CHECKING
from unittest import mock
import docutils
@@ -20,6 +21,7 @@ from urllib3.poolmanager import PoolManager
import sphinx.util.http_date
from sphinx.builders.linkcheck import (
CheckRequest,
+ CheckResult,
Hyperlink,
HyperlinkAvailabilityCheckWorker,
RateLimit,
@@ -33,6 +35,12 @@ from tests.utils import CERT_FILE, serve_application
ts_re = re.compile(r".*\[(?P<ts>.*)\].*")
+if TYPE_CHECKING:
+ from collections.abc import Callable, Iterable
+ from io import StringIO
+
+ from sphinx.application import Sphinx
+
class DefaultsHandler(BaseHTTPRequestHandler):
protocol_version = "HTTP/1.1"
@@ -101,7 +109,7 @@ class ConnectionMeasurement:
@pytest.mark.sphinx('linkcheck', testroot='linkcheck', freshenv=True)
-def test_defaults(app):
+def test_defaults(app: Sphinx) -> None:
with serve_application(app, DefaultsHandler) as address:
with ConnectionMeasurement() as m:
app.build()
@@ -146,7 +154,7 @@ def test_defaults(app):
'info': '',
}
- def _missing_resource(filename: str, lineno: int):
+ def _missing_resource(filename: str, lineno: int) -> dict[str, str | int]:
return {
'filename': 'links.rst',
'lineno': lineno,
@@ -178,7 +186,7 @@ def test_defaults(app):
@pytest.mark.sphinx(
'linkcheck', testroot='linkcheck', freshenv=True,
confoverrides={'linkcheck_anchors': False})
-def test_check_link_response_only(app):
+def test_check_link_response_only(app: Sphinx) -> None:
with serve_application(app, DefaultsHandler) as address:
app.build()
@@ -192,7 +200,7 @@ def test_check_link_response_only(app):
@pytest.mark.sphinx('linkcheck', testroot='linkcheck-too-many-retries', freshenv=True)
-def test_too_many_retries(app):
+def test_too_many_retries(app: Sphinx) -> None:
with serve_application(app, DefaultsHandler) as address:
app.build()
@@ -221,7 +229,7 @@ def test_too_many_retries(app):
@pytest.mark.sphinx('linkcheck', testroot='linkcheck-raw-node', freshenv=True)
-def test_raw_node(app):
+def test_raw_node(app: Sphinx) -> None:
with serve_application(app, OKHandler) as address:
# write an index file that contains a link back to this webserver's root
# URL. docutils will replace the raw node with the contents retrieved..
@@ -254,7 +262,7 @@ def test_raw_node(app):
@pytest.mark.sphinx(
'linkcheck', testroot='linkcheck-anchors-ignore', freshenv=True,
confoverrides={'linkcheck_anchors_ignore': ["^!", "^top$"]})
-def test_anchors_ignored(app):
+def test_anchors_ignored(app: Sphinx) -> None:
with serve_application(app, OKHandler):
app.build()
@@ -266,6 +274,43 @@ def test_anchors_ignored(app):
class AnchorsIgnoreForUrlHandler(BaseHTTPRequestHandler):
+ protocol_version = 'HTTP/1.1'
+
+ def _chunk_content(self, content: str, *, max_chunk_size: int) -> Iterable[bytes]:
+
+ def _encode_chunk(chunk: bytes) -> Iterable[bytes]:
+ """Encode a bytestring into a format suitable for HTTP chunked-transfer.
+
+ https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Transfer-Encoding
+ """
+ yield f'{len(chunk):X}'.encode('ascii')
+ yield b'\r\n'
+ yield chunk
+ yield b'\r\n'
+
+ buffer = b''
+ for char in content:
+ buffer += char.encode('utf-8')
+ if len(buffer) >= max_chunk_size:
+ chunk, buffer = buffer[:max_chunk_size], buffer[max_chunk_size:]
+ yield from _encode_chunk(chunk)
+
+ # Flush remaining bytes, if any
+ if buffer:
+ yield from _encode_chunk(buffer)
+
+ # Emit a final empty chunk to close the stream
+ yield from _encode_chunk(b'')
+
+ def _send_chunked(self, content: str) -> bool:
+ for chunk in self._chunk_content(content, max_chunk_size=20):
+ try:
+ self.wfile.write(chunk)
+ except (BrokenPipeError, ConnectionResetError) as e:
+ self.log_message(str(e))
+ return False
+ return True
+
def do_HEAD(self):
if self.path in {'/valid', '/ignored'}:
self.send_response(200, "OK")
@@ -274,17 +319,24 @@ class AnchorsIgnoreForUrlHandler(BaseHTTPRequestHandler):
self.end_headers()
def do_GET(self):
- self.do_HEAD()
if self.path == '/valid':
- self.wfile.write(b"<h1 id='valid-anchor'>valid anchor</h1>\n")
+ self.send_response(200, 'OK')
+ content = "<h1 id='valid-anchor'>valid anchor</h1>\n"
elif self.path == '/ignored':
- self.wfile.write(b"no anchor but page exists\n")
+ self.send_response(200, 'OK')
+ content = 'no anchor but page exists\n'
+ else:
+ self.send_response(404, 'Not Found')
+ content = 'not found\n'
+ self.send_header('Transfer-Encoding', 'chunked')
+ self.end_headers()
+ self._send_chunked(content)
@pytest.mark.sphinx('linkcheck', testroot='linkcheck-anchors-ignore-for-url', freshenv=True)
-def test_anchors_ignored_for_url(app):
+def test_anchors_ignored_for_url(app: Sphinx) -> None:
with serve_application(app, AnchorsIgnoreForUrlHandler) as address:
- app.config.linkcheck_anchors_ignore_for_url = [ # type: ignore[attr-defined]
+ app.config.linkcheck_anchors_ignore_for_url = [
f'http://{address}/ignored', # existing page
f'http://{address}/invalid', # unknown page
]
@@ -295,7 +347,7 @@ def test_anchors_ignored_for_url(app):
attrs = ('filename', 'lineno', 'status', 'code', 'uri', 'info')
data = [json.loads(x) for x in content.splitlines()]
- assert len(data) == 7
+ assert len(data) == 8
assert all(all(attr in row for attr in attrs) for row in data)
# rows may be unsorted due to network latency or
@@ -304,6 +356,7 @@ def test_anchors_ignored_for_url(app):
assert rows[f'http://{address}/valid']['status'] == 'working'
assert rows[f'http://{address}/valid#valid-anchor']['status'] == 'working'
+ assert rows[f'http://{address}/valid#py:module::urllib.parse']['status'] == 'broken'
assert rows[f'http://{address}/valid#invalid-anchor'] == {
'status': 'broken',
'info': "Anchor 'invalid-anchor' not found",
@@ -323,7 +376,7 @@ def test_anchors_ignored_for_url(app):
@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver-anchor', freshenv=True)
-def test_raises_for_invalid_status(app):
+def test_raises_for_invalid_status(app: Sphinx) -> None:
class InternalServerErrorHandler(BaseHTTPRequestHandler):
protocol_version = "HTTP/1.1"
@@ -340,6 +393,50 @@ def test_raises_for_invalid_status(app):
)
+@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver-anchor', freshenv=True)
+def test_incomplete_html_anchor(app):
+ class IncompleteHTMLDocumentHandler(BaseHTTPRequestHandler):
+ protocol_version = 'HTTP/1.1'
+
+ def do_GET(self):
+ content = b'this is <div id="anchor">not</div> a valid HTML document'
+ self.send_response(200, 'OK')
+ self.send_header('Content-Length', str(len(content)))
+ self.end_headers()
+ self.wfile.write(content)
+
+ with serve_application(app, IncompleteHTMLDocumentHandler):
+ app.build()
+
+ content = (app.outdir / 'output.json').read_text(encoding='utf8')
+ assert len(content.splitlines()) == 1
+
+ row = json.loads(content)
+ assert row['status'] == 'working'
+
+
+@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver-anchor', freshenv=True)
+def test_decoding_error_anchor_ignored(app):
+ class NonASCIIHandler(BaseHTTPRequestHandler):
+ protocol_version = 'HTTP/1.1'
+
+ def do_GET(self):
+ content = b'\x80\x00\x80\x00' # non-ASCII byte-string
+ self.send_response(200, 'OK')
+ self.send_header('Content-Length', str(len(content)))
+ self.end_headers()
+ self.wfile.write(content)
+
+ with serve_application(app, NonASCIIHandler):
+ app.build()
+
+ content = (app.outdir / 'output.json').read_text(encoding='utf8')
+ assert len(content.splitlines()) == 1
+
+ row = json.loads(content)
+ assert row['status'] == 'ignored'
+
+
def custom_handler(valid_credentials=(), success_criteria=lambda _: True):
"""
Returns an HTTP request handler that authenticates the client and then determines
@@ -352,25 +449,27 @@ def custom_handler(valid_credentials=(), success_criteria=lambda _: True):
expected_token = b64encode(":".join(valid_credentials).encode()).decode("utf-8")
del valid_credentials
+ def authenticated(
+ method: Callable[[CustomHandler], None]
+ ) -> Callable[[CustomHandler], None]:
+ def method_if_authenticated(self):
+ if expected_token is None:
+ return method(self)
+ elif not self.headers["Authorization"]:
+ self.send_response(401, "Unauthorized")
+ self.end_headers()
+ elif self.headers["Authorization"] == f"Basic {expected_token}":
+ return method(self)
+ else:
+ self.send_response(403, "Forbidden")
+ self.send_header("Content-Length", "0")
+ self.end_headers()
+
+ return method_if_authenticated
+
class CustomHandler(BaseHTTPRequestHandler):
protocol_version = "HTTP/1.1"
- def authenticated(method):
- def method_if_authenticated(self):
- if expected_token is None:
- return method(self)
- elif not self.headers["Authorization"]:
- self.send_response(401, "Unauthorized")
- self.end_headers()
- elif self.headers["Authorization"] == f"Basic {expected_token}":
- return method(self)
- else:
- self.send_response(403, "Forbidden")
- self.send_header("Content-Length", "0")
- self.end_headers()
-
- return method_if_authenticated
-
@authenticated
def do_HEAD(self):
self.do_GET()
@@ -389,9 +488,9 @@ def custom_handler(valid_credentials=(), success_criteria=lambda _: True):
@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver', freshenv=True)
-def test_auth_header_uses_first_match(app):
+def test_auth_header_uses_first_match(app: Sphinx) -> None:
with serve_application(app, custom_handler(valid_credentials=("user1", "password"))) as address:
- app.config.linkcheck_auth = [ # type: ignore[attr-defined]
+ app.config.linkcheck_auth = [
(r'^$', ('no', 'match')),
(fr'^http://{re.escape(address)}/$', ('user1', 'password')),
(r'.*local.*', ('user2', 'hunter2')),
@@ -408,7 +507,7 @@ def test_auth_header_uses_first_match(app):
@pytest.mark.sphinx(
'linkcheck', testroot='linkcheck-localserver', freshenv=True,
confoverrides={'linkcheck_allow_unauthorized': False})
-def test_unauthorized_broken(app):
+def test_unauthorized_broken(app: Sphinx) -> None:
with serve_application(app, custom_handler(valid_credentials=("user1", "password"))):
app.build()
@@ -422,7 +521,7 @@ def test_unauthorized_broken(app):
@pytest.mark.sphinx(
'linkcheck', testroot='linkcheck-localserver', freshenv=True,
confoverrides={'linkcheck_auth': [(r'^$', ('user1', 'password'))]})
-def test_auth_header_no_match(app):
+def test_auth_header_no_match(app: Sphinx) -> None:
with (
serve_application(app, custom_handler(valid_credentials=("user1", "password"))),
pytest.warns(RemovedInSphinx80Warning, match='linkcheck builder encountered an HTTP 401'),
@@ -438,14 +537,14 @@ def test_auth_header_no_match(app):
@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver', freshenv=True)
-def test_linkcheck_request_headers(app):
+def test_linkcheck_request_headers(app: Sphinx) -> None:
def check_headers(self):
if "X-Secret" in self.headers:
return False
return self.headers["Accept"] == "text/html"
with serve_application(app, custom_handler(success_criteria=check_headers)) as address:
- app.config.linkcheck_request_headers = { # type: ignore[attr-defined]
+ app.config.linkcheck_request_headers = {
f"http://{address}/": {"Accept": "text/html"},
"*": {"X-Secret": "open sesami"},
}
@@ -458,14 +557,14 @@ def test_linkcheck_request_headers(app):
@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver', freshenv=True)
-def test_linkcheck_request_headers_no_slash(app):
+def test_linkcheck_request_headers_no_slash(app: Sphinx) -> None:
def check_headers(self):
if "X-Secret" in self.headers:
return False
return self.headers["Accept"] == "application/json"
with serve_application(app, custom_handler(success_criteria=check_headers)) as address:
- app.config.linkcheck_request_headers = { # type: ignore[attr-defined]
+ app.config.linkcheck_request_headers = {
f"http://{address}": {"Accept": "application/json"},
"*": {"X-Secret": "open sesami"},
}
@@ -483,7 +582,7 @@ def test_linkcheck_request_headers_no_slash(app):
"http://do.not.match.org": {"Accept": "application/json"},
"*": {"X-Secret": "open sesami"},
}})
-def test_linkcheck_request_headers_default(app):
+def test_linkcheck_request_headers_default(app: Sphinx) -> None:
def check_headers(self):
if self.headers["X-Secret"] != "open sesami":
return False
@@ -566,9 +665,9 @@ def test_follows_redirects_on_GET(app, capsys, warning):
@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver-warn-redirects')
-def test_linkcheck_allowed_redirects(app, warning):
+def test_linkcheck_allowed_redirects(app: Sphinx, warning: StringIO) -> None:
with serve_application(app, make_redirect_handler(support_head=False)) as address:
- app.config.linkcheck_allowed_redirects = {f'http://{address}/.*1': '.*'} # type: ignore[attr-defined]
+ app.config.linkcheck_allowed_redirects = {f'http://{address}/.*1': '.*'}
compile_linkcheck_allowed_redirects(app, app.config)
app.build()
@@ -626,7 +725,7 @@ def test_invalid_ssl(get_request, app):
@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver-https', freshenv=True)
-def test_connect_to_selfsigned_fails(app):
+def test_connect_to_selfsigned_fails(app: Sphinx) -> None:
with serve_application(app, OKHandler, tls_enabled=True) as address:
app.build()
@@ -639,9 +738,9 @@ def test_connect_to_selfsigned_fails(app):
assert "[SSL: CERTIFICATE_VERIFY_FAILED]" in content["info"]
-@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver-https', freshenv=True)
-def test_connect_to_selfsigned_with_tls_verify_false(app):
- app.config.tls_verify = False
+@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver-https', freshenv=True,
+ confoverrides={'tls_verify': False})
+def test_connect_to_selfsigned_with_tls_verify_false(app: Sphinx) -> None:
with serve_application(app, OKHandler, tls_enabled=True) as address:
app.build()
@@ -657,9 +756,9 @@ def test_connect_to_selfsigned_with_tls_verify_false(app):
}
-@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver-https', freshenv=True)
-def test_connect_to_selfsigned_with_tls_cacerts(app):
- app.config.tls_cacerts = CERT_FILE
+@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver-https', freshenv=True,
+ confoverrides={'tls_cacerts': CERT_FILE})
+def test_connect_to_selfsigned_with_tls_cacerts(app: Sphinx) -> None:
with serve_application(app, OKHandler, tls_enabled=True) as address:
app.build()
@@ -693,9 +792,9 @@ def test_connect_to_selfsigned_with_requests_env_var(monkeypatch, app):
}
-@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver-https', freshenv=True)
-def test_connect_to_selfsigned_nonexistent_cert_file(app):
- app.config.tls_cacerts = "does/not/exist"
+@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver-https', freshenv=True,
+ confoverrides={'tls_cacerts': "does/not/exist"})
+def test_connect_to_selfsigned_nonexistent_cert_file(app: Sphinx) -> None:
with serve_application(app, OKHandler, tls_enabled=True) as address:
app.build()
@@ -863,7 +962,7 @@ def test_too_many_requests_retry_after_without_header(app, capsys):
'linkcheck_timeout': 0.01,
}
)
-def test_requests_timeout(app):
+def test_requests_timeout(app: Sphinx) -> None:
class DelayedResponseHandler(BaseHTTPRequestHandler):
protocol_version = "HTTP/1.1"
@@ -882,9 +981,9 @@ def test_requests_timeout(app):
assert content["status"] == "timeout"
-@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver', freshenv=True)
-def test_too_many_requests_user_timeout(app):
- app.config.linkcheck_rate_limit_timeout = 0.0
+@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver', freshenv=True,
+ confoverrides={'linkcheck_rate_limit_timeout': 0.0})
+def test_too_many_requests_user_timeout(app: Sphinx) -> None:
with serve_application(app, make_retry_after_handler([(429, None)])) as address:
app.build()
content = (app.outdir / 'output.json').read_text(encoding='utf8')
@@ -903,21 +1002,21 @@ class FakeResponse:
url = "http://localhost/"
-def test_limit_rate_default_sleep(app):
+def test_limit_rate_default_sleep(app: Sphinx) -> None:
worker = HyperlinkAvailabilityCheckWorker(app.config, Queue(), Queue(), {})
with mock.patch('time.time', return_value=0.0):
next_check = worker.limit_rate(FakeResponse.url, FakeResponse.headers.get("Retry-After"))
assert next_check == 60.0
-def test_limit_rate_user_max_delay(app):
- app.config.linkcheck_rate_limit_timeout = 0.0
+@pytest.mark.sphinx(confoverrides={'linkcheck_rate_limit_timeout': 0.0})
+def test_limit_rate_user_max_delay(app: Sphinx) -> None:
worker = HyperlinkAvailabilityCheckWorker(app.config, Queue(), Queue(), {})
next_check = worker.limit_rate(FakeResponse.url, FakeResponse.headers.get("Retry-After"))
assert next_check is None
-def test_limit_rate_doubles_previous_wait_time(app):
+def test_limit_rate_doubles_previous_wait_time(app: Sphinx) -> None:
rate_limits = {"localhost": RateLimit(60.0, 0.0)}
worker = HyperlinkAvailabilityCheckWorker(app.config, Queue(), Queue(), rate_limits)
with mock.patch('time.time', return_value=0.0):
@@ -925,21 +1024,23 @@ def test_limit_rate_doubles_previous_wait_time(app):
assert next_check == 120.0
-def test_limit_rate_clips_wait_time_to_max_time(app):
- app.config.linkcheck_rate_limit_timeout = 90.0
+@pytest.mark.sphinx(confoverrides={'linkcheck_rate_limit_timeout': 90})
+def test_limit_rate_clips_wait_time_to_max_time(app: Sphinx, warning: StringIO) -> None:
rate_limits = {"localhost": RateLimit(60.0, 0.0)}
worker = HyperlinkAvailabilityCheckWorker(app.config, Queue(), Queue(), rate_limits)
with mock.patch('time.time', return_value=0.0):
next_check = worker.limit_rate(FakeResponse.url, FakeResponse.headers.get("Retry-After"))
assert next_check == 90.0
+ assert warning.getvalue() == ''
-def test_limit_rate_bails_out_after_waiting_max_time(app):
- app.config.linkcheck_rate_limit_timeout = 90.0
+@pytest.mark.sphinx(confoverrides={'linkcheck_rate_limit_timeout': 90.0})
+def test_limit_rate_bails_out_after_waiting_max_time(app: Sphinx, warning: StringIO) -> None:
rate_limits = {"localhost": RateLimit(90.0, 0.0)}
worker = HyperlinkAvailabilityCheckWorker(app.config, Queue(), Queue(), rate_limits)
next_check = worker.limit_rate(FakeResponse.url, FakeResponse.headers.get("Retry-After"))
assert next_check is None
+ assert warning.getvalue() == ''
@mock.patch('sphinx.util.requests.requests.Session.get_adapter')
@@ -957,11 +1058,13 @@ def test_connection_contention(get_adapter, app, capsys):
# Place a workload into the linkcheck queue
link_count = 10
- rqueue, wqueue = Queue(), Queue()
+ wqueue: Queue[CheckRequest] = Queue()
+ rqueue: Queue[CheckResult] = Queue()
for _ in range(link_count):
wqueue.put(CheckRequest(0, Hyperlink(f"http://{address}", "test", "test.rst", 1)))
- begin, checked = time.time(), []
+ begin = time.time()
+ checked: list[CheckResult] = []
threads = [
HyperlinkAvailabilityCheckWorker(
config=app.config,
@@ -997,7 +1100,7 @@ class ConnectionResetHandler(BaseHTTPRequestHandler):
@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver', freshenv=True)
-def test_get_after_head_raises_connection_error(app):
+def test_get_after_head_raises_connection_error(app: Sphinx) -> None:
with serve_application(app, ConnectionResetHandler) as address:
app.build()
content = (app.outdir / 'output.txt').read_text(encoding='utf8')
@@ -1014,7 +1117,7 @@ def test_get_after_head_raises_connection_error(app):
@pytest.mark.sphinx('linkcheck', testroot='linkcheck-documents_exclude', freshenv=True)
-def test_linkcheck_exclude_documents(app):
+def test_linkcheck_exclude_documents(app: Sphinx) -> None:
with serve_application(app, DefaultsHandler):
app.build()
diff --git a/tests/test_builders/test_build_manpage.py b/tests/test_builders/test_build_manpage.py
index 7172281..31d75d6 100644
--- a/tests/test_builders/test_build_manpage.py
+++ b/tests/test_builders/test_build_manpage.py
@@ -7,6 +7,8 @@ from sphinx.builders.manpage import default_man_pages
from sphinx.config import Config
+@pytest.mark.xfail(docutils.__version_info__[:2] > (0, 21),
+ reason='Docutils has removed the reference key in master')
@pytest.mark.sphinx('man')
def test_all(app, status, warning):
app.build(force_all=True)
@@ -44,13 +46,15 @@ def test_man_pages_empty_description(app, status, warning):
confoverrides={'man_make_section_directory': True})
def test_man_make_section_directory(app, status, warning):
app.build()
- assert (app.outdir / 'man1' / 'python.1').exists()
+ assert (app.outdir / 'man1' / 'projectnamenotset.1').exists()
+@pytest.mark.xfail(docutils.__version_info__[:2] > (0, 21),
+ reason='Docutils has removed the reference key in master')
@pytest.mark.sphinx('man', testroot='directive-code')
def test_captioned_code_block(app, status, warning):
app.build(force_all=True)
- content = (app.outdir / 'python.1').read_text(encoding='utf8')
+ content = (app.outdir / 'projectnamenotset.1').read_text(encoding='utf8')
if docutils.__version_info__[:2] < (0, 21):
expected = """\
@@ -100,5 +104,5 @@ def test_default_man_pages():
@pytest.mark.sphinx('man', testroot='markup-rubric')
def test_rubric(app, status, warning):
app.build()
- content = (app.outdir / 'python.1').read_text(encoding='utf8')
+ content = (app.outdir / 'projectnamenotset.1').read_text(encoding='utf8')
assert 'This is a rubric\n' in content
diff --git a/tests/test_builders/test_build_texinfo.py b/tests/test_builders/test_build_texinfo.py
index f9effb2..6abbc96 100644
--- a/tests/test_builders/test_build_texinfo.py
+++ b/tests/test_builders/test_build_texinfo.py
@@ -40,16 +40,17 @@ def test_texinfo(app, status, warning):
def test_texinfo_rubric(app, status, warning):
app.build()
- output = (app.outdir / 'python.texi').read_text(encoding='utf8')
+ output = (app.outdir / 'projectnamenotset.texi').read_text(encoding='utf8')
assert '@heading This is a rubric' in output
assert '@heading This is a multiline rubric' in output
+ assert '@heading A rubric with a heading level' in output
@pytest.mark.sphinx('texinfo', testroot='markup-citation')
def test_texinfo_citation(app, status, warning):
app.build(force_all=True)
- output = (app.outdir / 'python.texi').read_text(encoding='utf8')
+ output = (app.outdir / 'projectnamenotset.texi').read_text(encoding='utf8')
assert 'This is a citation ref; @ref{1,,[CITE1]} and @ref{2,,[CITE2]}.' in output
assert ('@anchor{index cite1}@anchor{1}@w{(CITE1)} \n'
'This is a citation\n') in output
@@ -87,7 +88,7 @@ def test_texinfo_escape_id(app, status, warning):
def test_texinfo_footnote(app, status, warning):
app.build(force_all=True)
- output = (app.outdir / 'python.texi').read_text(encoding='utf8')
+ output = (app.outdir / 'projectnamenotset.texi').read_text(encoding='utf8')
assert 'First footnote: @footnote{\nFirst\n}' in output
@@ -120,10 +121,11 @@ def test_texinfo_samp_with_variable(app, status, warning):
def test_copy_images(app, status, warning):
app.build()
- images_dir = Path(app.outdir) / 'python-figures'
+ images_dir = Path(app.outdir) / 'projectnamenotset-figures'
images = {image.name for image in images_dir.rglob('*')}
images.discard('python-logo.png')
assert images == {
+ 'ba30773957c3fe046897111afd65a80b81cad089.png', # texinfo: image from data:image/png URI in source
'img.png',
'rimg.png',
'testimäge.png',