diff --git a/pyproject.toml b/pyproject.toml index 78af6bff..7077ccf8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,7 +32,7 @@ dependencies = [ "Jinja2>=2.11.1", "Markdown>=3.3", "MarkupSafe>=1.1", - "mkdocs>=1.2", + "mkdocs>=1.4", "mkdocs-autorefs>=0.3.1", "pymdown-extensions>=6.3", "importlib-metadata>=4.6; python_version < '3.10'", diff --git a/src/mkdocstrings/extension.py b/src/mkdocstrings/extension.py index 8e83c62e..a819f14b 100644 --- a/src/mkdocstrings/extension.py +++ b/src/mkdocstrings/extension.py @@ -72,8 +72,7 @@ def __init__( Arguments: parser: A `markdown.blockparser.BlockParser` instance. md: A `markdown.Markdown` instance. - config: The [configuration][mkdocstrings.plugin.MkdocstringsPlugin.config_scheme] - of the `mkdocstrings` plugin. + config: The [configuration][mkdocstrings.plugin.PluginConfig] of the `mkdocstrings` plugin. handlers: The handlers container. autorefs: The autorefs plugin instance. """ diff --git a/src/mkdocstrings/plugin.py b/src/mkdocstrings/plugin.py index 682310cc..c694ad4e 100644 --- a/src/mkdocstrings/plugin.py +++ b/src/mkdocstrings/plugin.py @@ -22,8 +22,8 @@ from typing import TYPE_CHECKING, Any, BinaryIO, Callable, Iterable, List, Mapping, Tuple, TypeVar from urllib import request -from mkdocs.config.config_options import Type as MkType -from mkdocs.config.config_options import Dir, Optional +from mkdocs.config import Config +from mkdocs.config import config_options as opt from mkdocs.plugins import BasePlugin from mkdocs.utils import write_file from mkdocs_autorefs.plugin import AutorefsPlugin @@ -34,7 +34,6 @@ if TYPE_CHECKING: from jinja2.environment import Environment - from mkdocs.config import Config from mkdocs.config.defaults import MkDocsConfig if sys.version_info < (3, 10): @@ -63,38 +62,13 @@ def wrapper(*args: P.args, **kwargs: P.kwargs) -> R: return wrapper -class MkdocstringsPlugin(BasePlugin): - """An `mkdocs` plugin. - - This plugin defines the following event hooks: - - - `on_config` - - `on_env` - - `on_post_build` +class PluginConfig(Config): + """The configuration options of `mkdocstrings`, written in `mkdocs.yml`.""" - Check the [Developing Plugins](https://www.mkdocs.org/user-guide/plugins/#developing-plugins) page of `mkdocs` - for more information about its plugin system. - """ - - config_scheme: tuple[tuple[str, MkType]] = ( # type: ignore[assignment] - ("handlers", MkType(dict, default={})), - ("default_handler", MkType(str, default="python")), - ("custom_templates", Optional(Dir(exists=True))), - ("enable_inventory", MkType(bool, default=None)), - ("enabled", MkType(bool, default=True)), - ) + handlers = opt.Type(dict, default={}) """ - The configuration options of `mkdocstrings`, written in `mkdocs.yml`. - - Available options are: - - - **`handlers`**: Global configuration of handlers. You can set global configuration per handler, applied everywhere, - but overridable in each "autodoc" instruction. Example: - - **`default_handler`**: The default handler to use. The value is the name of the handler module. Default is "python". - - **`custom_templates`**: Location of custom templates to use when rendering API objects. Value should be the path of - a directory relative to the MkDocs configuration file. - - **`enable_inventory`**: Whether to enable object inventory creation. - - **`enabled`**: Whether to enable the plugin. Default is true. If false, *mkdocstrings* will not collect or render anything. + Global configuration of handlers. You can set global configuration per handler, applied everywhere, + but overridable in each "autodoc" instruction. Example: ```yaml plugins: @@ -110,6 +84,30 @@ class MkdocstringsPlugin(BasePlugin): ``` """ + default_handler = opt.Type(str, default="python") + """The default handler to use. The value is the name of the handler module. Default is "python".""" + custom_templates = opt.Optional(opt.Dir(exists=True)), + """Location of custom templates to use when rendering API objects. Value should be the path of + a directory relative to the MkDocs configuration file.""" + enable_inventory = opt.Optional(opt.Type(bool)) + """Whether to enable object inventory creation.""" + enabled = opt.Type(bool, default=True) + """Whether to enable the plugin. Default is true. If false, *mkdocstrings* will not collect or render anything.""" + + +class MkdocstringsPlugin(BasePlugin[PluginConfig]): + """An `mkdocs` plugin. + + This plugin defines the following event hooks: + + - `on_config` + - `on_env` + - `on_post_build` + + Check the [Developing Plugins](https://www.mkdocs.org/user-guide/plugins/#developing-plugins) page of `mkdocs` + for more information about its plugin system. + """ + css_filename = "assets/_mkdocstrings.css" def __init__(self) -> None: @@ -152,10 +150,10 @@ def on_config(self, config: MkDocsConfig) -> MkDocsConfig | None: return config log.debug("Adding extension to the list") - theme_name = config["theme"].name or os.path.dirname(config["theme"].dirs[0]) + theme_name = config.theme.name or os.path.dirname(config.theme.dirs[0]) to_import: InventoryImportType = [] - for handler_name, conf in self.config["handlers"].items(): + for handler_name, conf in self.config.handlers.items(): for import_item in conf.pop("import", ()): if isinstance(import_item, str): import_item = {"url": import_item} # noqa: PLW2901 @@ -163,8 +161,8 @@ def on_config(self, config: MkDocsConfig) -> MkDocsConfig | None: extension_config = { "theme_name": theme_name, - "mdx": config["markdown_extensions"], - "mdx_configs": config["mdx_configs"], + "mdx": config.markdown_extensions, + "mdx_configs": config.mdx_configs, "mkdocstrings": self.config, "mkdocs": config, } @@ -172,21 +170,21 @@ def on_config(self, config: MkDocsConfig) -> MkDocsConfig | None: try: # If autorefs plugin is explicitly enabled, just use it. - autorefs = config["plugins"]["autorefs"] + autorefs = config.plugins["autorefs"] log.debug(f"Picked up existing autorefs instance {autorefs!r}") except KeyError: # Otherwise, add a limited instance of it that acts only on what's added through `register_anchor`. autorefs = AutorefsPlugin() autorefs.scan_toc = False - config["plugins"]["autorefs"] = autorefs + config.plugins["autorefs"] = autorefs log.debug(f"Added a subdued autorefs instance {autorefs!r}") # Add collector-based fallback in either case. autorefs.get_fallback_anchor = self.handlers.get_anchors mkdocstrings_extension = MkdocstringsExtension(extension_config, self.handlers, autorefs) - config["markdown_extensions"].append(mkdocstrings_extension) + config.markdown_extensions.append(mkdocstrings_extension) - config["extra_css"].insert(0, self.css_filename) # So that it has lower priority than user files. + config.extra_css.insert(0, self.css_filename) # So that it has lower priority than user files. self._inv_futures = {} if to_import: @@ -210,7 +208,7 @@ def inventory_enabled(self) -> bool: Returns: Whether the inventory is enabled. """ - inventory_enabled = self.config["enable_inventory"] + inventory_enabled = self.config.enable_inventory if inventory_enabled is None: inventory_enabled = any(handler.enable_inventory for handler in self.handlers.seen_handlers) return inventory_enabled @@ -222,9 +220,9 @@ def plugin_enabled(self) -> bool: Returns: Whether the plugin is enabled. """ - return self.config["enabled"] + return self.config.enabled - def on_env(self, env: Environment, config: Config, *args: Any, **kwargs: Any) -> None: # noqa: ARG002 + def on_env(self, env: Environment, config: MkDocsConfig, *args: Any, **kwargs: Any) -> None: # noqa: ARG002 """Extra actions that need to happen after all Markdown rendering and before HTML rendering. Hook for the [`on_env` event](https://www.mkdocs.org/user-guide/plugins/#on_env). @@ -236,12 +234,12 @@ def on_env(self, env: Environment, config: Config, *args: Any, **kwargs: Any) -> return if self._handlers: css_content = "\n".join(handler.extra_css for handler in self.handlers.seen_handlers) - write_file(css_content.encode("utf-8"), os.path.join(config["site_dir"], self.css_filename)) + write_file(css_content.encode("utf-8"), os.path.join(config.site_dir, self.css_filename)) if self.inventory_enabled: log.debug("Creating inventory file objects.inv") inv_contents = self.handlers.inventory.format_sphinx() - write_file(inv_contents, os.path.join(config["site_dir"], "objects.inv")) + write_file(inv_contents, os.path.join(config.site_dir, "objects.inv")) if self._inv_futures: log.debug(f"Waiting for {len(self._inv_futures)} inventory download(s)") @@ -256,12 +254,12 @@ def on_env(self, env: Environment, config: Config, *args: Any, **kwargs: Any) -> loader_name = loader.__func__.__qualname__ log.error(f"Couldn't load inventory {import_item} through {loader_name}: {error}") # noqa: TRY400 for page, identifier in results.items(): - config["plugins"]["autorefs"].register_url(page, identifier) + config.plugins["autorefs"].register_url(page, identifier) self._inv_futures = {} def on_post_build( self, - config: Config, # noqa: ARG002 + config: MkDocsConfig, # noqa: ARG002 **kwargs: Any, # noqa: ARG002 ) -> None: """Teardown the handlers. diff --git a/tests/conftest.py b/tests/conftest.py index 2119d1f3..59bac65a 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -8,7 +8,7 @@ import pytest from markdown.core import Markdown from mkdocs import config -from mkdocs.config.defaults import get_schema +from mkdocs.config.defaults import MkDocsConfig if TYPE_CHECKING: from pathlib import Path @@ -19,7 +19,7 @@ @pytest.fixture(name="mkdocs_conf") def fixture_mkdocs_conf(request: pytest.FixtureRequest, tmp_path: Path) -> Iterator[config.Config]: """Yield a MkDocs configuration object.""" - conf = config.Config(schema=get_schema()) # type: ignore[call-arg] + conf = MkDocsConfig() while hasattr(request, "_parent_request") and hasattr(request._parent_request, "_parent_request"): request = request._parent_request @@ -53,6 +53,6 @@ def fixture_plugin(mkdocs_conf: config.Config) -> MkdocstringsPlugin: @pytest.fixture(name="ext_markdown") -def fixture_ext_markdown(mkdocs_conf: config.Config) -> Markdown: +def fixture_ext_markdown(mkdocs_conf: MkDocsConfig) -> Markdown: """Return a Markdown instance with MkdocstringsExtension.""" return Markdown(extensions=mkdocs_conf["markdown_extensions"], extension_configs=mkdocs_conf["mdx_configs"])