mirror of
https://github.com/zensical/zensical.git
synced 2026-09-23 23:05:34 +00:00
refactor: relax all plugins validation
Signed-off-by: Timothée Mazzucotelli <dev@pawamoy.fr>
This commit is contained in:
+35
-24
@@ -31,6 +31,7 @@ from typing import TYPE_CHECKING, Any
|
||||
import pytest
|
||||
|
||||
import zensical
|
||||
from zensical.config import ConfigurationError, parse_config
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from pathlib import Path
|
||||
@@ -549,37 +550,47 @@ def test_leading_hierarchy_separator_keeps_identity_and_listing_link(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("option", "replacement"),
|
||||
"option",
|
||||
[
|
||||
("tags_compare", "tags_sort_by"),
|
||||
("tags_compare_reverse", "tags_sort_reverse"),
|
||||
("tags_pages_compare", "listings_sort_by"),
|
||||
("tags_pages_compare_reverse", "listings_sort_reverse"),
|
||||
("tags_file", "material/tags"),
|
||||
("tags_extra_files", "material/tags"),
|
||||
"tags_compare",
|
||||
"tags_compare_reverse",
|
||||
"tags_pages_compare",
|
||||
"tags_pages_compare_reverse",
|
||||
"tags_file",
|
||||
"tags_extra_files",
|
||||
"export",
|
||||
"export_file",
|
||||
"export_only",
|
||||
],
|
||||
)
|
||||
def test_rust_rejects_deprecated_tags_options(
|
||||
tmp_path: Path, option: str, replacement: str
|
||||
) -> None:
|
||||
"""The native configuration boundary owns deprecated-option errors."""
|
||||
config = _write_project(tmp_path, plugin=f" {option}: value\n")
|
||||
|
||||
with pytest.raises(ValueError, match=option) as error:
|
||||
zensical.build(str(config), _BUILD_OPTIONS)
|
||||
|
||||
assert replacement in str(error.value)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("option", ["export_only", "tags_hierachy"])
|
||||
def test_rust_rejects_unsupported_tags_options(
|
||||
def test_ignores_unimplemented_tags_options(
|
||||
tmp_path: Path, option: str
|
||||
) -> None:
|
||||
"""Unsupported behavior and misspellings cannot silently disappear."""
|
||||
"""Legacy options never reach Rust and do not suppress native listings."""
|
||||
config = _write_project(tmp_path, plugin=f" {option}: true\n")
|
||||
|
||||
with pytest.raises(ValueError, match=option):
|
||||
zensical.build(str(config), _BUILD_OPTIONS)
|
||||
zensical.build(str(config), _BUILD_OPTIONS)
|
||||
|
||||
listing = (tmp_path / "site" / "index.html").read_text()
|
||||
assert '<h2 id="tag:guide">' in listing
|
||||
assert "Rust page" in listing
|
||||
assert not (tmp_path / "site" / "tags.json").exists()
|
||||
assert not (tmp_path / "site" / "ignored-tags.json").exists()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("option", ["unknown", "tags_hierachy"])
|
||||
def test_config_rejects_unknown_tags_options(
|
||||
tmp_path: Path, option: str
|
||||
) -> None:
|
||||
"""Unknown options fail even when known legacy options are ignored."""
|
||||
config = _write_project(
|
||||
tmp_path, plugin=f" export_only: true\n {option}: true\n"
|
||||
)
|
||||
|
||||
with pytest.raises(
|
||||
ConfigurationError, match=rf"unknown tags option: {option}"
|
||||
):
|
||||
parse_config(str(config))
|
||||
|
||||
|
||||
def test_scalar_configuration_and_metadata_match_python_names(
|
||||
|
||||
Vendored
+44
-2
@@ -275,6 +275,45 @@ class TestPluginShimming:
|
||||
config = self._parse_yaml(tmp_path, plugins={"glightbox": {}})
|
||||
assert GlightboxExtension.name in config["markdown_extensions"]
|
||||
|
||||
def test_ignored_plugin_settings_do_not_affect_hashes_or_shims(
|
||||
self, tmp_path: Path
|
||||
) -> None:
|
||||
plugins: dict[str, dict[str, Any]] = {
|
||||
"autorefs": {},
|
||||
"glightbox": {"auto": False},
|
||||
"macros": {"render_by_default": False},
|
||||
"mike": {"version_selector": False},
|
||||
"mkdocstrings": {"enabled": False},
|
||||
"search": {"separator": r"\s+"},
|
||||
"material/tags": {"enabled": False},
|
||||
}
|
||||
baseline = self._parse_yaml(tmp_path, plugins=plugins)
|
||||
for name, options in {
|
||||
"autorefs": {"link_titles": "external"},
|
||||
"glightbox": {"slide_effect": "fade"},
|
||||
"macros": {"force_render_paths": "guides/**"},
|
||||
"mike": {"javascript_dir": "scripts"},
|
||||
"mkdocstrings": {"enable_inventory": False, "watch": ["src"]},
|
||||
"search": {"lang": ["en", "fr"]},
|
||||
"material/tags": {"tags_file": "tags.md", "export_only": True},
|
||||
}.items():
|
||||
plugins[name].update(options)
|
||||
plugins["external"] = {"enabled": ["not", "a", "boolean"]}
|
||||
config_file = tmp_path / "mkdocs.yml"
|
||||
config_file.write_text(_minimal_yaml(plugins=plugins))
|
||||
|
||||
configured = parse_config(str(config_file))
|
||||
|
||||
for key in (
|
||||
"plugins",
|
||||
"plugins_hash",
|
||||
"markdown_extensions",
|
||||
"mdx_configs",
|
||||
"mdx_configs_hash",
|
||||
"watched_files",
|
||||
):
|
||||
assert configured[key] == baseline[key]
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"entry",
|
||||
["meta", {"meta": None}, "material/meta", {"material/meta": None}],
|
||||
@@ -540,10 +579,13 @@ class TestPluginShimming:
|
||||
self, tmp_path: Path
|
||||
) -> None:
|
||||
config = self._parse_yaml(
|
||||
tmp_path, plugins={"glightbox": {"loop": True}}
|
||||
tmp_path,
|
||||
plugins={"glightbox": {"width": "80%", "slide_effect": "fade"}},
|
||||
)
|
||||
assert GlightboxExtension.name in config["markdown_extensions"]
|
||||
assert config["mdx_configs"][GlightboxExtension.name] == {"loop": True}
|
||||
assert config["mdx_configs"][GlightboxExtension.name] == {
|
||||
"width": "80%"
|
||||
}
|
||||
|
||||
def test_macros_plugin_shimmed(self, tmp_path: Path) -> None:
|
||||
config = self._parse_yaml(tmp_path, plugins={"macros": {}})
|
||||
|
||||
+124
-12
@@ -118,6 +118,27 @@ def test_preserves_plugin_presence_semantics() -> None:
|
||||
assert not set(SHIM_PLUGINS) & set(plugins)
|
||||
|
||||
|
||||
def test_preserves_zensical_plugin_options() -> None:
|
||||
plugins = _convert_plugins(
|
||||
{
|
||||
"minify": {
|
||||
"enabled": False,
|
||||
"minify_inline_js": True,
|
||||
"minify_inline_css": True,
|
||||
},
|
||||
"glightbox": {"auto": False, "slide_effect": "fade"},
|
||||
"macros": {"include_yaml": {"data": "data.yml"}},
|
||||
}
|
||||
)
|
||||
|
||||
minify = plugins["minify"]["config"]
|
||||
assert minify["enabled"] is False
|
||||
assert minify["minify_inline_js"] is True
|
||||
assert minify["minify_inline_css"] is True
|
||||
assert plugins["glightbox"]["config"] == {"auto": False}
|
||||
assert plugins["macros"]["config"]["include_yaml"] == {"data": "data.yml"}
|
||||
|
||||
|
||||
def test_normalizes_mike_defaults() -> None:
|
||||
plugins = _convert_plugins({"mike": {}})
|
||||
assert plugins["mike"]["config"] == {
|
||||
@@ -158,7 +179,7 @@ def test_silently_discards_unsupported_mike_options(
|
||||
assert capsys.readouterr().err == ""
|
||||
|
||||
|
||||
@pytest.mark.parametrize("name", [*PYTHON_PLUGINS, "tags", "external"])
|
||||
@pytest.mark.parametrize("name", [*PYTHON_PLUGINS, "tags"])
|
||||
def test_plugin_configuration_must_be_a_mapping(name: str) -> None:
|
||||
with pytest.raises(
|
||||
ConfigurationError,
|
||||
@@ -167,7 +188,88 @@ def test_plugin_configuration_must_be_a_mapping(name: str) -> None:
|
||||
_convert_plugins({name: []})
|
||||
|
||||
|
||||
@pytest.mark.parametrize("name", PYTHON_PLUGINS)
|
||||
@pytest.mark.parametrize(
|
||||
"name",
|
||||
[
|
||||
"external", # does not exist
|
||||
"material/blog", # exists but isn't supported yet
|
||||
"literate_nav", # misspelling (`_` instead of `-`)
|
||||
],
|
||||
)
|
||||
@pytest.mark.parametrize("data", [None, True, 42, "config", [], {42: object()}])
|
||||
@pytest.mark.parametrize("as_list", [False, True])
|
||||
def test_ignores_unsupported_plugins(
|
||||
name: str, data: Any, as_list: bool, capsys: pytest.CaptureFixture[str]
|
||||
) -> None:
|
||||
value = {name: data}
|
||||
plugins = _convert_plugins([value] if as_list else value)
|
||||
|
||||
assert plugins == _convert_plugins([])
|
||||
assert capsys.readouterr().err == ""
|
||||
|
||||
|
||||
@pytest.mark.parametrize("name", ["external", "material/blog", "literate_nav"])
|
||||
def test_ignores_unsupported_plugin_names(name: str) -> None:
|
||||
assert _convert_plugins([name]) == _convert_plugins([])
|
||||
|
||||
|
||||
@pytest.mark.parametrize("prefix", ["", "material/"])
|
||||
@pytest.mark.parametrize("value", [True, False, "auto", 42, [], {}, None])
|
||||
@pytest.mark.parametrize(
|
||||
("plugin", "option"),
|
||||
[
|
||||
("autorefs", "resolve_closest"),
|
||||
("autorefs", "link_titles"),
|
||||
("autorefs", "strip_title_tags"),
|
||||
("glightbox", "touchNavigation"),
|
||||
("glightbox", "loop"),
|
||||
("glightbox", "effect"),
|
||||
("glightbox", "slide_effect"),
|
||||
("glightbox", "zoomable"),
|
||||
("glightbox", "draggable"),
|
||||
("glightbox", "background"),
|
||||
("glightbox", "shadow"),
|
||||
("macros", "force_render_paths"),
|
||||
("macros", "verbose"),
|
||||
("mike", "css_dir"),
|
||||
("mike", "javascript_dir"),
|
||||
("mkdocstrings", "enable_inventory"),
|
||||
("mkdocstrings", "watch"),
|
||||
("search", "fields"),
|
||||
("search", "indexing"),
|
||||
("search", "jieba_dict"),
|
||||
("search", "jieba_dict_user"),
|
||||
("search", "lang"),
|
||||
("search", "min_search_length"),
|
||||
("search", "pipeline"),
|
||||
("search", "prebuild_index"),
|
||||
("tags", "tags_compare"),
|
||||
("tags", "tags_compare_reverse"),
|
||||
("tags", "tags_pages_compare"),
|
||||
("tags", "tags_pages_compare_reverse"),
|
||||
("tags", "tags_file"),
|
||||
("tags", "tags_extra_files"),
|
||||
("tags", "export"),
|
||||
("tags", "export_file"),
|
||||
("tags", "export_only"),
|
||||
],
|
||||
)
|
||||
def test_silently_discards_unimplemented_options(
|
||||
plugin: str,
|
||||
option: str,
|
||||
value: Any,
|
||||
prefix: str,
|
||||
capsys: pytest.CaptureFixture[str],
|
||||
) -> None:
|
||||
data = {"enabled": False, option: value}
|
||||
plugins = _convert_plugins({prefix + plugin: data})
|
||||
|
||||
assert plugins == _convert_plugins({plugin: {"enabled": False}})
|
||||
assert data == {"enabled": False, option: value}
|
||||
assert capsys.readouterr().err == ""
|
||||
|
||||
|
||||
@pytest.mark.parametrize("name", [*PYTHON_PLUGINS, "tags"])
|
||||
def test_rejects_unknown_python_plugin_options(name: str) -> None:
|
||||
with pytest.raises(
|
||||
ConfigurationError,
|
||||
@@ -176,6 +278,21 @@ def test_rejects_unknown_python_plugin_options(name: str) -> None:
|
||||
_convert_plugins({name: {"unknown": True}})
|
||||
|
||||
|
||||
@pytest.mark.parametrize("plugin", ["table-reader", "material/table-reader"])
|
||||
@pytest.mark.parametrize(
|
||||
("option", "value"),
|
||||
[("base_path", "docs_dir"), ("search_page_directory", False)],
|
||||
)
|
||||
def test_rejects_removed_table_reader_options(
|
||||
plugin: str, option: str, value: Any
|
||||
) -> None:
|
||||
with pytest.raises(
|
||||
ConfigurationError,
|
||||
match=rf"unknown table-reader option: {option}",
|
||||
):
|
||||
_convert_plugins({plugin: {option: value}})
|
||||
|
||||
|
||||
@pytest.mark.parametrize("plugin", ["search", "material/search"])
|
||||
def test_silently_discards_unsupported_search_options(
|
||||
plugin: str, capsys: pytest.CaptureFixture[str]
|
||||
@@ -226,7 +343,6 @@ def test_normalizes_null_shim_configuration(name: str) -> None:
|
||||
"enabled": False,
|
||||
"handlers": {"python": {"options": {}}},
|
||||
"custom_templates": None,
|
||||
"enable_inventory": None,
|
||||
"default_handler": "python",
|
||||
"locale": "fr",
|
||||
},
|
||||
@@ -243,13 +359,6 @@ def test_normalizes_null_shim_configuration(name: str) -> None:
|
||||
"auto_themed": True,
|
||||
"auto_caption": True,
|
||||
"caption_position": "top",
|
||||
"touchNavigation": False,
|
||||
"loop": True,
|
||||
"effect": "fade",
|
||||
"zoomable": False,
|
||||
"draggable": False,
|
||||
"background": "black",
|
||||
"shadow": False,
|
||||
"manual": None,
|
||||
},
|
||||
id="glightbox",
|
||||
@@ -265,7 +374,6 @@ def test_normalizes_null_shim_configuration(name: str) -> None:
|
||||
"render_by_default": False,
|
||||
"on_error_fail": True,
|
||||
"on_undefined": "strict",
|
||||
"verbose": True,
|
||||
"j2_block_start_string": "<%",
|
||||
"j2_block_end_string": "%>",
|
||||
"j2_variable_start_string": "<@",
|
||||
@@ -371,7 +479,11 @@ def test_silently_discards_unsupported_autorefs_options(
|
||||
"languages must be a list of supported language names",
|
||||
),
|
||||
("mkdocstrings", {"handlers": []}, "handlers must be a mapping"),
|
||||
("glightbox", {"effect": "slide"}, "effect must be"),
|
||||
(
|
||||
"glightbox",
|
||||
{"caption_position": "center"},
|
||||
"caption_position must be",
|
||||
),
|
||||
("macros", {"include_yaml": [42]}, "include_yaml must be a list"),
|
||||
("macros", {"on_undefined": "silent"}, "on_undefined must be"),
|
||||
(
|
||||
|
||||
+116
-65
@@ -109,6 +109,104 @@ DEFAULT_MARKDOWN_EXTENSIONS = {
|
||||
"pymdownx.tilde": {},
|
||||
}
|
||||
|
||||
# Supported MkDocs plugins and their recognized but unimplemented options.
|
||||
# Discard these before validation, hashing and forwarding to native modules or
|
||||
# Markdown extensions. Empty tuples mark plugins with no ignored options.
|
||||
_PLUGIN_UNSUPPORTED_OPTIONS = {
|
||||
"autorefs": (
|
||||
# TODO: Configure native URL selection and link title rendering.
|
||||
"resolve_closest",
|
||||
"link_titles",
|
||||
"strip_title_tags",
|
||||
),
|
||||
"awesome-nav": (),
|
||||
"glightbox": (
|
||||
"touchNavigation",
|
||||
"loop",
|
||||
"effect",
|
||||
"slide_effect",
|
||||
"zoomable",
|
||||
"draggable",
|
||||
"background",
|
||||
"shadow",
|
||||
),
|
||||
"literate-nav": (),
|
||||
"macros": (
|
||||
# TODO: Match page paths before deciding whether to render macros.
|
||||
"force_render_paths",
|
||||
# TODO: Add diagnostics for module loading and macro rendering.
|
||||
"verbose",
|
||||
),
|
||||
"markdown-exec": (),
|
||||
"meta": (),
|
||||
"mike": (
|
||||
"css_dir",
|
||||
"javascript_dir",
|
||||
),
|
||||
"minify": (),
|
||||
"mkdocstrings": (
|
||||
# TODO: Gate native objects.inv generation on this setting.
|
||||
"enable_inventory",
|
||||
"watch",
|
||||
),
|
||||
"offline": (),
|
||||
"redirects": (),
|
||||
"search": (
|
||||
"fields",
|
||||
"indexing",
|
||||
"jieba_dict",
|
||||
"jieba_dict_user",
|
||||
"lang",
|
||||
"min_search_length",
|
||||
"pipeline",
|
||||
"prebuild_index",
|
||||
),
|
||||
"table-reader": (),
|
||||
"tags": (
|
||||
"tags_compare",
|
||||
"tags_compare_reverse",
|
||||
"tags_pages_compare",
|
||||
"tags_pages_compare_reverse",
|
||||
"tags_file",
|
||||
"tags_extra_files",
|
||||
"export",
|
||||
"export_file",
|
||||
"export_only",
|
||||
),
|
||||
}
|
||||
|
||||
# Tags options forwarded to the native configuration after Python removes
|
||||
# recognized but unimplemented options.
|
||||
_TAGS_SUPPORTED_OPTIONS = {
|
||||
"enabled",
|
||||
"filters",
|
||||
"tags",
|
||||
"tags_slugify",
|
||||
"tags_slugify_separator",
|
||||
"tags_slugify_format",
|
||||
"tags_hierarchy",
|
||||
"tags_hierarchy_separator",
|
||||
"tags_sort_by",
|
||||
"tags_sort_reverse",
|
||||
"tags_name_property",
|
||||
"tags_name_variable",
|
||||
"tags_allowed",
|
||||
"listings",
|
||||
"listings_map",
|
||||
"listings_sort_by",
|
||||
"listings_sort_reverse",
|
||||
"listings_tags_sort_by",
|
||||
"listings_tags_sort_reverse",
|
||||
"listings_directive",
|
||||
"listings_layout",
|
||||
"listings_toc",
|
||||
"shadow",
|
||||
"shadow_on_serve",
|
||||
"shadow_tags",
|
||||
"shadow_tags_prefix",
|
||||
"shadow_tags_suffix",
|
||||
}
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Classes
|
||||
@@ -709,11 +807,8 @@ def _apply_defaults(config: dict, path: str) -> dict:
|
||||
# Hash all templates, so we rebuild if something changes
|
||||
config["template_hash"] = _hash(theme_files)
|
||||
|
||||
# Hash the entire plugins configuration.
|
||||
# This is a special case for plugins because we currently only source
|
||||
# the plugin configuration that we support in Rust,
|
||||
# which means config on other plugins doesn't contribute to the hash,
|
||||
# in turn not triggering full rebuilds.
|
||||
# Include Python-only plugin settings in rebuilds. Unsupported plugins and
|
||||
# ignored legacy options have already been discarded during normalization.
|
||||
config["plugins_hash"] = _hash(config["plugins"])
|
||||
|
||||
return config
|
||||
@@ -1411,13 +1506,18 @@ def _convert_plugins(value: Any, config: dict) -> dict:
|
||||
if not isinstance(name, str):
|
||||
raise ConfigurationError("Plugin names must be strings")
|
||||
name = name.removeprefix("material/")
|
||||
if name not in _PLUGIN_UNSUPPORTED_OPTIONS:
|
||||
return
|
||||
if data is None:
|
||||
data = {}
|
||||
elif not isinstance(data, dict):
|
||||
raise ConfigurationError(f"{name} configuration must be a mapping")
|
||||
else:
|
||||
data = dict(data)
|
||||
for option in _PLUGIN_UNSUPPORTED_OPTIONS[name]:
|
||||
data.pop(option, None)
|
||||
if name == "tags":
|
||||
_reject_unknown_options("tags", data, _TAGS_SUPPORTED_OPTIONS)
|
||||
tags.append({"name": name, "config": data})
|
||||
else:
|
||||
plugins[name] = data
|
||||
@@ -1443,29 +1543,13 @@ def _convert_plugins(value: Any, config: dict) -> dict:
|
||||
else:
|
||||
raise ConfigurationError("plugins must be a list or mapping")
|
||||
|
||||
# Rust owns all tags defaults, validation, scalar coercion and callable
|
||||
# lowering. Python only preserves ordered plugin instances and their raw
|
||||
# configuration, as it does for future native compatibility modules.
|
||||
# Rust owns tags defaults, value validation, scalar coercion and callable
|
||||
# lowering. Python validates option names and preserves ordered instances.
|
||||
plugins["tags"] = tags
|
||||
|
||||
# Search is enabled by default, even when it isn't explicitly configured.
|
||||
search = plugins.pop("search", {})
|
||||
supported = {"enabled", "separator"}
|
||||
# Keep recognized upstream options non-fatal during migration, but discard
|
||||
# them before extracting the typed native search configuration in Rust.
|
||||
unsupported = {
|
||||
"fields",
|
||||
"indexing",
|
||||
"jieba_dict",
|
||||
"jieba_dict_user",
|
||||
"lang",
|
||||
"min_search_length",
|
||||
"pipeline",
|
||||
"prebuild_index",
|
||||
}
|
||||
_reject_unknown_options("search", search, supported | unsupported)
|
||||
for name in sorted(unsupported & search.keys()):
|
||||
search.pop(name)
|
||||
_reject_unknown_options("search", search, {"enabled", "separator"})
|
||||
set_default(search, "enabled", True)
|
||||
set_default(search, "separator", '[\\s\\-_,:!=\\[\\]()\\\\"`/]+|\\.(?!\\d)')
|
||||
_validate_boolean_options("search", search, ("enabled",))
|
||||
@@ -1678,17 +1762,16 @@ def _convert_plugins(value: Any, config: dict) -> dict:
|
||||
"deploy_prefix": "",
|
||||
}
|
||||
nullable_strings = ("redirect_template", "canonical_version")
|
||||
# Zensical bundles its own version selector assets, so accept and
|
||||
# discard Mike's asset directory options for compatibility.
|
||||
unsupported = {"css_dir", "javascript_dir"}
|
||||
_reject_unknown_options(
|
||||
"mike",
|
||||
mike,
|
||||
{"enabled", "version_selector", *string_defaults, *nullable_strings}
|
||||
| unsupported,
|
||||
{
|
||||
"enabled",
|
||||
"version_selector",
|
||||
*string_defaults,
|
||||
*nullable_strings,
|
||||
},
|
||||
)
|
||||
for name in sorted(unsupported & mike.keys()):
|
||||
mike.pop(name)
|
||||
_validate_boolean_options("mike", mike, ("enabled", "version_selector"))
|
||||
for name, default in string_defaults.items():
|
||||
set_default(mike, name, default)
|
||||
@@ -1704,16 +1787,8 @@ def _convert_plugins(value: Any, config: dict) -> dict:
|
||||
# Validate settings forwarded by the plugin-to-extension shims.
|
||||
if "autorefs" in plugins:
|
||||
autorefs = plugins["autorefs"]
|
||||
_reject_unknown_options(
|
||||
"autorefs",
|
||||
autorefs,
|
||||
{"enabled", "resolve_closest", "link_titles", "strip_title_tags"},
|
||||
)
|
||||
_reject_unknown_options("autorefs", autorefs, {"enabled"})
|
||||
_validate_boolean_options("autorefs", autorefs, ("enabled",))
|
||||
# Ignore these upstream settings: the Rust resolver currently uses
|
||||
# fixed resolution and title behavior.
|
||||
for name in ("resolve_closest", "link_titles", "strip_title_tags"):
|
||||
autorefs.pop(name, None)
|
||||
|
||||
if "markdown-exec" in plugins:
|
||||
markdown_exec = plugins["markdown-exec"]
|
||||
@@ -1769,7 +1844,6 @@ def _convert_plugins(value: Any, config: dict) -> dict:
|
||||
"enabled",
|
||||
"handlers",
|
||||
"custom_templates",
|
||||
"enable_inventory",
|
||||
},
|
||||
)
|
||||
_validate_boolean_options("mkdocstrings", mkdocstrings, ("enabled",))
|
||||
@@ -1789,29 +1863,16 @@ def _convert_plugins(value: Any, config: dict) -> dict:
|
||||
raise ConfigurationError(
|
||||
"mkdocstrings custom_templates must be a string or null"
|
||||
)
|
||||
if (
|
||||
"enable_inventory" in mkdocstrings
|
||||
and mkdocstrings["enable_inventory"] is not None
|
||||
and not isinstance(mkdocstrings["enable_inventory"], bool)
|
||||
):
|
||||
raise ConfigurationError(
|
||||
"mkdocstrings enable_inventory must be a boolean or null"
|
||||
)
|
||||
_validate_string_options("mkdocstrings", mkdocstrings, string_options)
|
||||
|
||||
if "glightbox" in plugins:
|
||||
glightbox = plugins["glightbox"]
|
||||
string_options = {"width", "height", "background"}
|
||||
string_options = {"width", "height"}
|
||||
boolean_options = {
|
||||
"enabled",
|
||||
"auto",
|
||||
"auto_themed",
|
||||
"auto_caption",
|
||||
"touchNavigation",
|
||||
"loop",
|
||||
"zoomable",
|
||||
"draggable",
|
||||
"shadow",
|
||||
}
|
||||
_reject_unknown_options(
|
||||
"glightbox",
|
||||
@@ -1821,7 +1882,6 @@ def _convert_plugins(value: Any, config: dict) -> dict:
|
||||
| {
|
||||
"skip_classes",
|
||||
"caption_position",
|
||||
"effect",
|
||||
"manual",
|
||||
},
|
||||
)
|
||||
@@ -1843,14 +1903,6 @@ def _convert_plugins(value: Any, config: dict) -> dict:
|
||||
"glightbox caption_position must be 'bottom', 'top', 'left' "
|
||||
"or 'right'"
|
||||
)
|
||||
if "effect" in glightbox and glightbox["effect"] not in {
|
||||
"zoom",
|
||||
"fade",
|
||||
"none",
|
||||
}:
|
||||
raise ConfigurationError(
|
||||
"glightbox effect must be 'zoom', 'fade' or 'none'"
|
||||
)
|
||||
if (
|
||||
"manual" in glightbox
|
||||
and glightbox["manual"] is not None
|
||||
@@ -1877,7 +1929,6 @@ def _convert_plugins(value: Any, config: dict) -> dict:
|
||||
"enabled",
|
||||
"render_by_default",
|
||||
"on_error_fail",
|
||||
"verbose",
|
||||
}
|
||||
_reject_unknown_options(
|
||||
"macros",
|
||||
|
||||
Reference in New Issue
Block a user