mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Use read-only test roots (#13285)
This commit is contained in:
parent
d24ffe2949
commit
0d4425ce07
4
.github/workflows/main.yml
vendored
4
.github/workflows/main.yml
vendored
@ -49,6 +49,10 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Mount the test roots as read-only
|
||||
run: |
|
||||
mkdir -p ./tests/roots-read-only
|
||||
sudo mount -v --bind --read-only ./tests/roots ./tests/roots-read-only
|
||||
- name: Set up Python ${{ matrix.python }}
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
|
@ -104,12 +104,16 @@ def app_params(
|
||||
|
||||
test_root = kwargs.pop('testroot', 'root')
|
||||
kwargs['srcdir'] = srcdir = sphinx_test_tempdir / kwargs.get('srcdir', test_root)
|
||||
copy_test_root = not {'srcdir', 'copy_test_root'}.isdisjoint(kwargs)
|
||||
|
||||
# special support for sphinx/tests
|
||||
if rootdir is not None:
|
||||
test_root_path = rootdir / f'test-{test_root}'
|
||||
if test_root_path.is_dir() and not srcdir.exists():
|
||||
shutil.copytree(test_root_path, srcdir)
|
||||
if copy_test_root:
|
||||
if test_root_path.is_dir():
|
||||
shutil.copytree(test_root_path, srcdir, dirs_exist_ok=True)
|
||||
else:
|
||||
kwargs['srcdir'] = test_root_path
|
||||
|
||||
# always write to the temporary directory
|
||||
kwargs.setdefault('builddir', srcdir / '_build')
|
||||
|
@ -223,7 +223,11 @@ class SphinxTestApp(sphinx.application.Sphinx):
|
||||
def cleanup(self, doctrees: bool = False) -> None:
|
||||
sys.path[:] = self._saved_path
|
||||
_clean_up_global_state()
|
||||
self.docutils_conf_path.unlink(missing_ok=True)
|
||||
try:
|
||||
self.docutils_conf_path.unlink(missing_ok=True)
|
||||
except OSError as exc:
|
||||
if exc.errno != 30: # Ignore "read-only file system" errors
|
||||
raise
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f'<{self.__class__.__name__} buildername={self._builder_name!r}>'
|
||||
|
@ -19,7 +19,10 @@ if TYPE_CHECKING:
|
||||
from collections.abc import Iterator
|
||||
|
||||
_TESTS_ROOT = Path(__file__).resolve().parent
|
||||
_ROOTS_DIR = _TESTS_ROOT / 'roots'
|
||||
if 'CI' in os.environ and (_TESTS_ROOT / 'roots-read-only').is_dir():
|
||||
_ROOTS_DIR = _TESTS_ROOT / 'roots-read-only'
|
||||
else:
|
||||
_ROOTS_DIR = _TESTS_ROOT / 'roots'
|
||||
|
||||
|
||||
def _init_console(
|
||||
|
@ -257,6 +257,7 @@ def test_too_many_retries(app: SphinxTestApp) -> None:
|
||||
'linkcheck',
|
||||
testroot='linkcheck-raw-node',
|
||||
freshenv=True,
|
||||
copy_test_root=True,
|
||||
)
|
||||
def test_raw_node(app: SphinxTestApp) -> None:
|
||||
with serve_application(app, OKHandler) as address:
|
||||
|
@ -20,7 +20,7 @@ from sphinx.environment import (
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.sphinx('dummy', testroot='basic')
|
||||
@pytest.mark.sphinx('dummy', testroot='basic', copy_test_root=True)
|
||||
def test_config_status(make_app, app_params):
|
||||
args, kwargs = app_params
|
||||
|
||||
|
@ -1033,6 +1033,7 @@ def test_autodoc_typehints_description(app):
|
||||
'autodoc_typehints': 'description',
|
||||
'autodoc_typehints_description_target': 'documented',
|
||||
},
|
||||
copy_test_root=True,
|
||||
)
|
||||
def test_autodoc_typehints_description_no_undoc(app):
|
||||
# No :type: or :rtype: will be injected for `incr`, which does not have
|
||||
@ -1085,6 +1086,7 @@ def test_autodoc_typehints_description_no_undoc(app):
|
||||
'autodoc_typehints': 'description',
|
||||
'autodoc_typehints_description_target': 'documented_params',
|
||||
},
|
||||
copy_test_root=True,
|
||||
)
|
||||
def test_autodoc_typehints_description_no_undoc_doc_rtype(app):
|
||||
# No :type: will be injected for `incr`, which does not have a description
|
||||
@ -1154,6 +1156,7 @@ def test_autodoc_typehints_description_no_undoc_doc_rtype(app):
|
||||
'text',
|
||||
testroot='ext-autodoc',
|
||||
confoverrides={'autodoc_typehints': 'description'},
|
||||
copy_test_root=True,
|
||||
)
|
||||
def test_autodoc_typehints_description_with_documented_init(app):
|
||||
with overwrite_file(
|
||||
@ -1198,6 +1201,7 @@ def test_autodoc_typehints_description_with_documented_init(app):
|
||||
'autodoc_typehints': 'description',
|
||||
'autodoc_typehints_description_target': 'documented',
|
||||
},
|
||||
copy_test_root=True,
|
||||
)
|
||||
def test_autodoc_typehints_description_with_documented_init_no_undoc(app):
|
||||
with overwrite_file(
|
||||
@ -1232,6 +1236,7 @@ def test_autodoc_typehints_description_with_documented_init_no_undoc(app):
|
||||
'autodoc_typehints': 'description',
|
||||
'autodoc_typehints_description_target': 'documented_params',
|
||||
},
|
||||
copy_test_root=True,
|
||||
)
|
||||
def test_autodoc_typehints_description_with_documented_init_no_undoc_doc_rtype(app):
|
||||
# see test_autodoc_typehints_description_with_documented_init_no_undoc
|
||||
@ -1276,6 +1281,7 @@ def test_autodoc_typehints_description_for_invalid_node(app):
|
||||
'text',
|
||||
testroot='ext-autodoc',
|
||||
confoverrides={'autodoc_typehints': 'both'},
|
||||
copy_test_root=True,
|
||||
)
|
||||
def test_autodoc_typehints_both(app):
|
||||
with overwrite_file(
|
||||
|
@ -151,6 +151,7 @@ def test_extract_summary(capsys):
|
||||
'dummy',
|
||||
testroot='ext-autosummary-ext',
|
||||
confoverrides=defaults.copy(),
|
||||
copy_test_root=True,
|
||||
)
|
||||
def test_get_items_summary(make_app, app_params):
|
||||
import sphinx.ext.autosummary
|
||||
@ -227,6 +228,7 @@ def str_content(elem: Element) -> str:
|
||||
'xml',
|
||||
testroot='ext-autosummary-ext',
|
||||
confoverrides=defaults.copy(),
|
||||
copy_test_root=True,
|
||||
)
|
||||
def test_escaping(app):
|
||||
app.build(force_all=True)
|
||||
@ -238,7 +240,7 @@ def test_escaping(app):
|
||||
assert str_content(title) == 'underscore_module_'
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='ext-autosummary')
|
||||
@pytest.mark.sphinx('html', testroot='ext-autosummary', copy_test_root=True)
|
||||
def test_autosummary_generate_content_for_module(app):
|
||||
import autosummary_dummy_module # type: ignore[import-not-found]
|
||||
|
||||
@ -298,7 +300,7 @@ def test_autosummary_generate_content_for_module(app):
|
||||
assert context['objtype'] == 'module'
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='ext-autosummary')
|
||||
@pytest.mark.sphinx('html', testroot='ext-autosummary', copy_test_root=True)
|
||||
def test_autosummary_generate_content_for_module___all__(app):
|
||||
import autosummary_dummy_module
|
||||
|
||||
@ -343,7 +345,7 @@ def test_autosummary_generate_content_for_module___all__(app):
|
||||
assert context['objtype'] == 'module'
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='ext-autosummary')
|
||||
@pytest.mark.sphinx('html', testroot='ext-autosummary', copy_test_root=True)
|
||||
def test_autosummary_generate_content_for_module_skipped(app):
|
||||
import autosummary_dummy_module
|
||||
|
||||
@ -389,7 +391,7 @@ def test_autosummary_generate_content_for_module_skipped(app):
|
||||
assert context['exceptions'] == []
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='ext-autosummary')
|
||||
@pytest.mark.sphinx('html', testroot='ext-autosummary', copy_test_root=True)
|
||||
def test_autosummary_generate_content_for_module_imported_members(app):
|
||||
import autosummary_dummy_module
|
||||
|
||||
@ -455,7 +457,7 @@ def test_autosummary_generate_content_for_module_imported_members(app):
|
||||
assert context['objtype'] == 'module'
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='ext-autosummary')
|
||||
@pytest.mark.sphinx('html', testroot='ext-autosummary', copy_test_root=True)
|
||||
def test_autosummary_generate_content_for_module_imported_members_inherited_module(app):
|
||||
import autosummary_dummy_inherited_module # type: ignore[import-not-found]
|
||||
|
||||
@ -501,7 +503,7 @@ def test_autosummary_generate_content_for_module_imported_members_inherited_modu
|
||||
assert context['objtype'] == 'module'
|
||||
|
||||
|
||||
@pytest.mark.sphinx('dummy', testroot='ext-autosummary')
|
||||
@pytest.mark.sphinx('dummy', testroot='ext-autosummary', copy_test_root=True)
|
||||
def test_autosummary_generate(app):
|
||||
app.build(force_all=True)
|
||||
|
||||
@ -650,6 +652,7 @@ def test_autosummary_generate(app):
|
||||
'dummy',
|
||||
testroot='ext-autosummary',
|
||||
confoverrides={'autosummary_generate_overwrite': False},
|
||||
copy_test_root=True,
|
||||
)
|
||||
def test_autosummary_generate_overwrite1(app_params, make_app):
|
||||
args, kwargs = app_params
|
||||
@ -669,6 +672,7 @@ def test_autosummary_generate_overwrite1(app_params, make_app):
|
||||
'dummy',
|
||||
testroot='ext-autosummary',
|
||||
confoverrides={'autosummary_generate_overwrite': True},
|
||||
copy_test_root=True,
|
||||
)
|
||||
def test_autosummary_generate_overwrite2(app_params, make_app):
|
||||
args, kwargs = app_params
|
||||
@ -684,7 +688,7 @@ def test_autosummary_generate_overwrite2(app_params, make_app):
|
||||
assert 'autosummary_dummy_module.rst' not in app._warning.getvalue()
|
||||
|
||||
|
||||
@pytest.mark.sphinx('dummy', testroot='ext-autosummary-recursive')
|
||||
@pytest.mark.sphinx('dummy', testroot='ext-autosummary-recursive', copy_test_root=True)
|
||||
@pytest.mark.usefixtures('rollback_sysmodules')
|
||||
def test_autosummary_recursive(app):
|
||||
sys.modules.pop('package', None) # unload target module to clear the module cache
|
||||
@ -738,7 +742,11 @@ def test_autosummary_recursive_skips_mocked_modules(app):
|
||||
assert not (app.srcdir / 'generated' / 'package.package.module.rst').exists()
|
||||
|
||||
|
||||
@pytest.mark.sphinx('dummy', testroot='ext-autosummary-filename-map')
|
||||
@pytest.mark.sphinx(
|
||||
'dummy',
|
||||
testroot='ext-autosummary-filename-map',
|
||||
copy_test_root=True,
|
||||
)
|
||||
def test_autosummary_filename_map(app):
|
||||
app.build()
|
||||
|
||||
@ -756,6 +764,7 @@ def test_autosummary_filename_map(app):
|
||||
'latex',
|
||||
testroot='ext-autosummary-ext',
|
||||
confoverrides=defaults.copy(),
|
||||
copy_test_root=True,
|
||||
)
|
||||
def test_autosummary_latex_table_colspec(app):
|
||||
app.build(force_all=True)
|
||||
@ -793,7 +802,11 @@ def test_import_by_name():
|
||||
assert modname == 'sphinx.ext.autosummary'
|
||||
|
||||
|
||||
@pytest.mark.sphinx('dummy', testroot='ext-autosummary-mock_imports')
|
||||
@pytest.mark.sphinx(
|
||||
'dummy',
|
||||
testroot='ext-autosummary-mock_imports',
|
||||
copy_test_root=True,
|
||||
)
|
||||
def test_autosummary_mock_imports(app):
|
||||
try:
|
||||
app.build()
|
||||
@ -805,7 +818,11 @@ def test_autosummary_mock_imports(app):
|
||||
sys.modules.pop('foo', None) # unload foo module
|
||||
|
||||
|
||||
@pytest.mark.sphinx('dummy', testroot='ext-autosummary-imported_members')
|
||||
@pytest.mark.sphinx(
|
||||
'dummy',
|
||||
testroot='ext-autosummary-imported_members',
|
||||
copy_test_root=True,
|
||||
)
|
||||
def test_autosummary_imported_members(app):
|
||||
try:
|
||||
app.build()
|
||||
@ -820,7 +837,11 @@ def test_autosummary_imported_members(app):
|
||||
sys.modules.pop('autosummary_dummy_package', None)
|
||||
|
||||
|
||||
@pytest.mark.sphinx('dummy', testroot='ext-autosummary-module_all')
|
||||
@pytest.mark.sphinx(
|
||||
'dummy',
|
||||
testroot='ext-autosummary-module_all',
|
||||
copy_test_root=True,
|
||||
)
|
||||
def test_autosummary_module_all(app):
|
||||
try:
|
||||
app.build()
|
||||
@ -839,7 +860,11 @@ def test_autosummary_module_all(app):
|
||||
sys.modules.pop('autosummary_dummy_package_all', None)
|
||||
|
||||
|
||||
@pytest.mark.sphinx('dummy', testroot='ext-autosummary-module_empty_all')
|
||||
@pytest.mark.sphinx(
|
||||
'dummy',
|
||||
testroot='ext-autosummary-module_empty_all',
|
||||
copy_test_root=True,
|
||||
)
|
||||
def test_autosummary_module_empty_all(app):
|
||||
try:
|
||||
app.build()
|
||||
@ -867,6 +892,7 @@ def test_autosummary_module_empty_all(app):
|
||||
'html',
|
||||
testroot='ext-autodoc',
|
||||
confoverrides={'extensions': ['sphinx.ext.autosummary']},
|
||||
copy_test_root=True,
|
||||
)
|
||||
def test_generate_autosummary_docs_property(app):
|
||||
with patch('sphinx.ext.autosummary.generate.find_autosummary_in_files') as mock:
|
||||
@ -886,7 +912,11 @@ def test_generate_autosummary_docs_property(app):
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='ext-autosummary-skip-member')
|
||||
@pytest.mark.sphinx(
|
||||
'html',
|
||||
testroot='ext-autosummary-skip-member',
|
||||
copy_test_root=True,
|
||||
)
|
||||
def test_autosummary_skip_member(app):
|
||||
app.build()
|
||||
|
||||
@ -895,7 +925,7 @@ def test_autosummary_skip_member(app):
|
||||
assert 'Foo._privatemeth' in content
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='ext-autosummary-template')
|
||||
@pytest.mark.sphinx('html', testroot='ext-autosummary-template', copy_test_root=True)
|
||||
def test_autosummary_template(app):
|
||||
app.build()
|
||||
|
||||
|
@ -59,7 +59,11 @@ def test_autosummary_import_cycle(app):
|
||||
assert expected in app.warning.getvalue()
|
||||
|
||||
|
||||
@pytest.mark.sphinx('dummy', testroot='ext-autosummary-module_prefix')
|
||||
@pytest.mark.sphinx(
|
||||
'dummy',
|
||||
testroot='ext-autosummary-module_prefix',
|
||||
copy_test_root=True,
|
||||
)
|
||||
@pytest.mark.usefixtures('rollback_sysmodules')
|
||||
def test_autosummary_generate_prefixes(app):
|
||||
app.build()
|
||||
|
@ -696,7 +696,7 @@ def test_inspect_main_url(capsys):
|
||||
assert stderr == ''
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='ext-intersphinx-role')
|
||||
@pytest.mark.sphinx('html', testroot='ext-intersphinx-role', copy_test_root=True)
|
||||
def test_intersphinx_role(app):
|
||||
inv_file = app.srcdir / 'inventory'
|
||||
inv_file.write_bytes(INVENTORY_V2)
|
||||
|
@ -699,7 +699,7 @@ def test_gettext_buildr_ignores_only_directive(app):
|
||||
|
||||
|
||||
@sphinx_intl
|
||||
@pytest.mark.sphinx('html', testroot='intl')
|
||||
@pytest.mark.sphinx('html', testroot='intl', copy_test_root=True)
|
||||
def test_node_translated_attribute(app):
|
||||
app.build(filenames=[app.srcdir / 'translation_progress.txt'])
|
||||
|
||||
@ -713,7 +713,7 @@ def test_node_translated_attribute(app):
|
||||
|
||||
|
||||
@sphinx_intl
|
||||
@pytest.mark.sphinx('html', testroot='intl')
|
||||
@pytest.mark.sphinx('html', testroot='intl', copy_test_root=True)
|
||||
def test_translation_progress_substitution(app):
|
||||
app.build(filenames=[app.srcdir / 'translation_progress.txt'])
|
||||
|
||||
@ -732,6 +732,7 @@ def test_translation_progress_substitution(app):
|
||||
'gettext_compact': False,
|
||||
'translation_progress_classes': True,
|
||||
},
|
||||
copy_test_root=True,
|
||||
)
|
||||
def test_translation_progress_classes_true(app):
|
||||
app.build(filenames=[app.srcdir / 'translation_progress.txt'])
|
||||
@ -862,6 +863,7 @@ def mock_time_and_i18n() -> Iterator[tuple[pytest.MonkeyPatch, _MockClock]]:
|
||||
'dummy',
|
||||
testroot='builder-gettext-dont-rebuild-mo',
|
||||
freshenv=True,
|
||||
copy_test_root=True,
|
||||
)
|
||||
def test_dummy_should_rebuild_mo(mock_time_and_i18n, make_app, app_params):
|
||||
mock, clock = mock_time_and_i18n
|
||||
@ -924,6 +926,7 @@ def test_dummy_should_rebuild_mo(mock_time_and_i18n, make_app, app_params):
|
||||
'gettext',
|
||||
testroot='builder-gettext-dont-rebuild-mo',
|
||||
freshenv=True,
|
||||
copy_test_root=True,
|
||||
)
|
||||
def test_gettext_dont_rebuild_mo(mock_time_and_i18n, app):
|
||||
mock, clock = mock_time_and_i18n
|
||||
@ -1677,6 +1680,7 @@ def test_additional_targets_should_be_translated(app):
|
||||
'image',
|
||||
],
|
||||
},
|
||||
copy_test_root=True,
|
||||
)
|
||||
def test_additional_targets_should_be_translated_substitution_definitions(app):
|
||||
app.build(force_all=True)
|
||||
@ -1713,6 +1717,7 @@ def test_text_references(app):
|
||||
'locale_dirs': ['.'],
|
||||
'gettext_compact': False,
|
||||
},
|
||||
copy_test_root=True,
|
||||
)
|
||||
def test_text_prolog_epilog_substitution(app):
|
||||
app.build()
|
||||
@ -1946,6 +1951,7 @@ def test_gettext_disallow_fuzzy_translations(app):
|
||||
'html',
|
||||
testroot='basic',
|
||||
confoverrides={'language': 'de', 'html_sidebars': {'**': ['searchbox.html']}},
|
||||
copy_test_root=True,
|
||||
)
|
||||
def test_customize_system_message(make_app, app_params):
|
||||
try:
|
||||
|
@ -7,7 +7,7 @@ import pytest
|
||||
from sphinx.ext.autosummary.generate import setup_documenters
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='templating')
|
||||
@pytest.mark.sphinx('html', testroot='templating', copy_test_root=True)
|
||||
def test_layout_overloading(make_app, app_params):
|
||||
args, kwargs = app_params
|
||||
app = make_app(*args, **kwargs)
|
||||
@ -18,7 +18,7 @@ def test_layout_overloading(make_app, app_params):
|
||||
assert '<!-- layout overloading -->' in result
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='templating')
|
||||
@pytest.mark.sphinx('html', testroot='templating', copy_test_root=True)
|
||||
def test_autosummary_class_template_overloading(make_app, app_params):
|
||||
args, kwargs = app_params
|
||||
app = make_app(*args, **kwargs)
|
||||
@ -36,6 +36,7 @@ def test_autosummary_class_template_overloading(make_app, app_params):
|
||||
'html',
|
||||
testroot='templating',
|
||||
confoverrides={'autosummary_context': {'sentence': 'foobar'}},
|
||||
copy_test_root=True,
|
||||
)
|
||||
def test_autosummary_context(make_app, app_params):
|
||||
args, kwargs = app_params
|
||||
|
@ -29,6 +29,7 @@ def test_html_with_default_docutilsconf(app):
|
||||
testroot='docutilsconf',
|
||||
freshenv=True,
|
||||
docutils_conf='[restructuredtext parser]\ntrim_footnote_reference_space: true\n',
|
||||
copy_test_root=True,
|
||||
)
|
||||
def test_html_with_docutilsconf(app):
|
||||
with patch_docutils(app.confdir):
|
||||
|
Loading…
Reference in New Issue
Block a user