diff --git a/mkdocs_gen_files/config_items.py b/mkdocs_gen_files/config_items.py deleted file mode 100644 index bf0d31e..0000000 --- a/mkdocs_gen_files/config_items.py +++ /dev/null @@ -1,32 +0,0 @@ -from __future__ import annotations - -from mkdocs.config.config_options import File, OptionallyRequired, ValidationError - - -class ListOfItems(OptionallyRequired): - def __init__(self, option_type, default=[], required=False): - super().__init__(default=None if required else default, required=required) - self.option_type = option_type - self.option_type.warnings = self.warnings - - def pre_validation(self, config, key_name): - self._config = config - self._key_name = key_name - - def run_validation(self, value): - if not isinstance(value, list): - raise ValidationError(f"Expected a list of items, but a {type(value)} was given.") - - result = [] - for _ in value: - self.option_type.pre_validation(self._config, self._key_name) - for item in value: - result.append(self.option_type.validate(item)) - for _ in value: - self.option_type.post_validation(self._config, self._key_name) - return result - - -class ListOfFiles(ListOfItems): - def __init__(self, required=False): - super().__init__(File(exists=True), required=required) diff --git a/mkdocs_gen_files/editor.py b/mkdocs_gen_files/editor.py index 793c508..c8c2271 100644 --- a/mkdocs_gen_files/editor.py +++ b/mkdocs_gen_files/editor.py @@ -5,21 +5,24 @@ import os.path import pathlib import shutil -from typing import IO, ClassVar, MutableMapping +from typing import IO, TYPE_CHECKING, ClassVar, MutableMapping -from mkdocs.config import Config, load_config +from mkdocs.config import load_config from mkdocs.structure.files import File, Files +if TYPE_CHECKING: + from mkdocs.config.defaults import MkDocsConfig + def file_sort_key(f: File): - parts = pathlib.PurePath(f.src_path).parts + parts = pathlib.PurePosixPath(f.src_uri).parts return tuple( chr(f.name != "index" if i == len(parts) - 1 else 2) + p for i, p in enumerate(parts) ) class FilesEditor: - config: Config + config: MkDocsConfig """The current MkDocs [config](https://www.mkdocs.org/user-guide/plugins/#config).""" directory: str """The base directory for `open()` ([docs_dir](https://www.mkdocs.org/user-guide/configuration/#docs_dir)).""" @@ -42,8 +45,8 @@ def _get_file(self, name: str, new: bool = False) -> str: new_f = File( name, src_dir=self.directory, - dest_dir=self.config["site_dir"], - use_directory_urls=self.config["use_directory_urls"], + dest_dir=self.config.site_dir, + use_directory_urls=self.config.use_directory_urls, ) new_f.generated_by = "mkdocs-gen-files" # type: ignore normname = pathlib.PurePath(name).as_posix() @@ -68,13 +71,13 @@ def set_edit_path(self, name: str, edit_name: str | None) -> None: """Choose a file path to use for the edit URI of this file.""" self.edit_paths[pathlib.PurePath(name).as_posix()] = edit_name and str(edit_name) - def __init__(self, files: Files, config: Config, directory: str | None = None): + def __init__(self, files: Files, config: MkDocsConfig, directory: str | None = None): self._files: MutableMapping[str, File] = collections.ChainMap( - {}, {pathlib.PurePath(f.src_path).as_posix(): f for f in files} + {}, {f.src_uri: f for f in files} ) self.config = config if directory is None: - directory = config["docs_dir"] + directory = config.docs_dir self.directory = directory self.edit_paths = {} @@ -97,7 +100,7 @@ def current(cls) -> FilesEditor: return cls._current if not cls._default: config = load_config("mkdocs.yml") - config["plugins"].run_event("config", config) + config.plugins.run_event("config", config) cls._default = FilesEditor(Files([]), config) return cls._default diff --git a/mkdocs_gen_files/plugin.py b/mkdocs_gen_files/plugin.py index 5623112..c4f2410 100644 --- a/mkdocs_gen_files/plugin.py +++ b/mkdocs_gen_files/plugin.py @@ -1,50 +1,39 @@ from __future__ import annotations import logging -import pathlib import runpy import tempfile import urllib.parse -from typing import Callable - -from mkdocs.plugins import BasePlugin - -try: - from mkdocs.exceptions import PluginError -except ImportError: - PluginError = SystemExit # type: ignore - from typing import TYPE_CHECKING, TypeVar -from .config_items import ListOfFiles +from mkdocs.config import Config +from mkdocs.config import config_options as opt +from mkdocs.exceptions import PluginError +from mkdocs.plugins import BasePlugin, event_priority + from .editor import FilesEditor if TYPE_CHECKING: - from mkdocs.config import Config + from mkdocs.config.defaults import MkDocsConfig from mkdocs.structure.files import Files from mkdocs.structure.pages import Page T = TypeVar("T") -try: - from mkdocs.plugins import event_priority -except ImportError: - - def event_priority(priority: float) -> Callable[[T], T]: - return lambda f: f # No-op fallback - log = logging.getLogger(f"mkdocs.plugins.{__name__}") -class GenFilesPlugin(BasePlugin): - config_scheme = (("scripts", ListOfFiles(required=True)),) +class PluginConfig(Config): + scripts = opt.ListOfItems(opt.File(exists=True)) + - def on_files(self, files: Files, config: Config) -> Files: +class GenFilesPlugin(BasePlugin[PluginConfig]): + def on_files(self, files: Files, config: MkDocsConfig) -> Files: self._dir = tempfile.TemporaryDirectory(prefix="mkdocs_gen_files_") with FilesEditor(files, config, self._dir.name) as ed: - for file_name in self.config["scripts"]: + for file_name in self.config.scripts: try: runpy.run_path(file_name) except SystemExit as e: @@ -54,11 +43,11 @@ def on_files(self, files: Files, config: Config) -> Files: self._edit_paths = dict(ed.edit_paths) return ed.files - def on_page_content(self, html, page: Page, config: Config, files: Files): - repo_url = config.get("repo_url", None) - edit_uri = config.get("edit_uri", None) + def on_page_content(self, html, page: Page, config: MkDocsConfig, files: Files): + repo_url = config.repo_url + edit_uri = config.edit_uri - src_path = pathlib.PurePath(page.file.src_path).as_posix() + src_path = page.file.src_uri if src_path in self._edit_paths: path = self._edit_paths.pop(src_path) if repo_url and edit_uri: @@ -73,7 +62,7 @@ def on_page_content(self, html, page: Page, config: Config, files: Files): return html @event_priority(-100) - def on_post_build(self, config: Config): + def on_post_build(self, config: MkDocsConfig): self._dir.cleanup() unused_edit_paths = {k: str(v) for k, v in self._edit_paths.items() if v} diff --git a/pyproject.toml b/pyproject.toml index c7c58ea..63846ff 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,7 +32,7 @@ classifiers = [ dynamic = ["version"] requires-python = ">=3.7" dependencies = [ - "mkdocs >=1.0.3", + "mkdocs >=1.4.1", #min "jinja2 >=2.10.1", #min "markupsafe >=2.0.1", ] diff --git a/tests/test_editor.py b/tests/test_editor.py index 8d625a6..6949568 100644 --- a/tests/test_editor.py +++ b/tests/test_editor.py @@ -1,4 +1,5 @@ import pytest +from mkdocs.config.defaults import MkDocsConfig from mkdocs.structure.files import File from mkdocs_gen_files import editor @@ -16,11 +17,13 @@ def test_file_sort_key(use_directory_urls, names): files = [ File(name, src_dir="", dest_dir="", use_directory_urls=use_directory_urls) for name in names ] - sorted_names = [f.src_path.replace("\\", "/") for f in sorted(files, key=editor.file_sort_key)] + sorted_names = [f.src_uri for f in sorted(files, key=editor.file_sort_key)] assert sorted_names == names def test_edit_paths_consistency(): - ed = editor.FilesEditor([], {"docs_dir": "."}) + conf = MkDocsConfig() + conf["docs_dir"] = "." + ed = editor.FilesEditor([], conf) ed.set_edit_path("foo//bar", "zzz//xxx") assert ed.edit_paths == {"foo/bar": "zzz//xxx"}