diff --git a/mkdocs/commands/build.py b/mkdocs/commands/build.py index 940624c3..a1bc9b9f 100644 --- a/mkdocs/commands/build.py +++ b/mkdocs/commands/build.py @@ -12,7 +12,7 @@ from jinja2.exceptions import TemplateNotFound import mkdocs from mkdocs import utils -from mkdocs.config.base import Config +from mkdocs.config.defaults import MkDocsConfig from mkdocs.exceptions import Abort, BuildError from mkdocs.structure.files import File, Files, get_files from mkdocs.structure.nav import Navigation, get_navigation @@ -38,7 +38,7 @@ log.addFilter(DuplicateFilter()) def get_context( nav: Navigation, files: Union[Sequence[File], Files], - config: Config, + config: MkDocsConfig, page: Optional[Page] = None, base_url: str = '', ) -> Dict[str, Any]: @@ -69,7 +69,7 @@ def get_context( def _build_template( - name: str, template: jinja2.Template, files: Files, config: Config, nav: Navigation + name: str, template: jinja2.Template, files: Files, config: MkDocsConfig, nav: Navigation ) -> str: """ Return rendered output for given template as a string. @@ -105,7 +105,7 @@ def _build_template( def _build_theme_template( - template_name: str, env: jinja2.Environment, files: Files, config: Config, nav: Navigation + template_name: str, env: jinja2.Environment, files: Files, config: MkDocsConfig, nav: Navigation ) -> None: """Build a template using the theme environment.""" @@ -136,7 +136,7 @@ def _build_theme_template( log.info(f"Template skipped: '{template_name}' generated empty output.") -def _build_extra_template(template_name: str, files: Files, config: Config, nav: Navigation): +def _build_extra_template(template_name: str, files: Files, config: MkDocsConfig, nav: Navigation): """Build user templates which are not part of the theme.""" log.debug(f"Building extra template: {template_name}") @@ -161,7 +161,7 @@ def _build_extra_template(template_name: str, files: Files, config: Config, nav: log.info(f"Template skipped: '{template_name}' generated empty output.") -def _populate_page(page: Page, config: Config, files: Files, dirty: bool = False) -> None: +def _populate_page(page: Page, config: MkDocsConfig, files: Files, dirty: bool = False) -> None: """Read page content from docs_dir and render Markdown.""" try: @@ -197,7 +197,7 @@ def _populate_page(page: Page, config: Config, files: Files, dirty: bool = False def _build_page( page: Page, - config: Config, + config: MkDocsConfig, doc_files: Sequence[File], nav: Navigation, env: jinja2.Environment, @@ -254,7 +254,7 @@ def _build_page( raise -def build(config: Config, live_server: bool = False, dirty: bool = False) -> None: +def build(config: MkDocsConfig, live_server: bool = False, dirty: bool = False) -> None: """Perform a full site build.""" logger = logging.getLogger('mkdocs') diff --git a/mkdocs/commands/gh_deploy.py b/mkdocs/commands/gh_deploy.py index bf5d8845..f8070468 100644 --- a/mkdocs/commands/gh_deploy.py +++ b/mkdocs/commands/gh_deploy.py @@ -9,6 +9,7 @@ import ghp_import from packaging import version import mkdocs +from mkdocs.config.defaults import MkDocsConfig from mkdocs.exceptions import Abort log = logging.getLogger(__name__) @@ -95,7 +96,12 @@ def _check_version(branch): def gh_deploy( - config, message=None, force=False, no_history=False, ignore_version=False, shell=False + config: MkDocsConfig, + message=None, + force=False, + no_history=False, + ignore_version=False, + shell=False, ): if not _is_cwd_git_repo(): log.error('Cannot deploy - this directory does not appear to be a git repository') diff --git a/mkdocs/commands/serve.py b/mkdocs/commands/serve.py index 75f72e54..9577f19a 100644 --- a/mkdocs/commands/serve.py +++ b/mkdocs/commands/serve.py @@ -11,6 +11,7 @@ import jinja2.exceptions from mkdocs.commands.build import build from mkdocs.config import load_config +from mkdocs.config.defaults import MkDocsConfig from mkdocs.exceptions import Abort from mkdocs.livereload import LiveReloadServer @@ -40,7 +41,7 @@ def serve( # string is returned. And it makes MkDocs temp dirs easier to identify. site_dir = tempfile.mkdtemp(prefix='mkdocs_') - def mount_path(config): + def mount_path(config: MkDocsConfig): return urlsplit(config['site_url'] or '/').path get_config = functools.partial( diff --git a/mkdocs/config/base.py b/mkdocs/config/base.py index 9fac7349..d1510aff 100644 --- a/mkdocs/config/base.py +++ b/mkdocs/config/base.py @@ -6,12 +6,28 @@ import os import sys from collections import UserDict from contextlib import contextmanager -from typing import IO, Generic, Iterator, List, Optional, Sequence, Tuple, TypeVar, Union, overload +from typing import ( + IO, + TYPE_CHECKING, + Generic, + Iterator, + List, + Optional, + Sequence, + Tuple, + TypeVar, + Union, + overload, +) from yaml import YAMLError from mkdocs import exceptions, utils +if TYPE_CHECKING: + from mkdocs.config.defaults import MkDocsConfig + + log = logging.getLogger('mkdocs.config') @@ -306,7 +322,7 @@ def _open_config_file(config_file: Optional[Union[str, IO]]) -> Iterator[IO]: result_config_file.close() -def load_config(config_file: Optional[Union[str, IO]] = None, **kwargs) -> Config: +def load_config(config_file: Optional[Union[str, IO]] = None, **kwargs) -> MkDocsConfig: """ Load the configuration for a given file object or name diff --git a/mkdocs/contrib/search/__init__.py b/mkdocs/contrib/search/__init__.py index f24fc596..b24d48a7 100644 --- a/mkdocs/contrib/search/__init__.py +++ b/mkdocs/contrib/search/__init__.py @@ -7,7 +7,7 @@ from typing import Any, Dict, List from mkdocs import utils from mkdocs.config import base from mkdocs.config import config_options as c -from mkdocs.config.base import Config +from mkdocs.config.defaults import MkDocsConfig from mkdocs.contrib.search.search_index import SearchIndex from mkdocs.plugins import BasePlugin @@ -59,7 +59,7 @@ class SearchPlugin(BasePlugin[_PluginConfig]): config_class = _PluginConfig - def on_config(self, config: Config, **kwargs) -> Config: + def on_config(self, config: MkDocsConfig, **kwargs) -> MkDocsConfig: "Add plugin templates and scripts to config." if 'include_search_page' in config['theme'] and config['theme']['include_search_page']: config['theme'].static_templates.add('search.html') @@ -81,7 +81,7 @@ class SearchPlugin(BasePlugin[_PluginConfig]): ) return config - def on_pre_build(self, config: Config, **kwargs) -> None: + def on_pre_build(self, config: MkDocsConfig, **kwargs) -> None: "Create search index instance for later use." self.search_index = SearchIndex(**self.config) @@ -89,7 +89,7 @@ class SearchPlugin(BasePlugin[_PluginConfig]): "Add page to search index." self.search_index.add_entry_from_context(context['page']) - def on_post_build(self, config: Config, **kwargs) -> None: + def on_post_build(self, config: MkDocsConfig, **kwargs) -> None: "Build search index." output_base_path = os.path.join(config['site_dir'], 'search') search_index = self.search_index.generate_search_index() diff --git a/mkdocs/plugins.py b/mkdocs/plugins.py index 927ea98b..8cb76403 100644 --- a/mkdocs/plugins.py +++ b/mkdocs/plugins.py @@ -7,7 +7,19 @@ from __future__ import annotations import logging import sys from collections import OrderedDict -from typing import Any, Callable, Dict, Generic, List, Optional, Tuple, Type, TypeVar, overload +from typing import ( + TYPE_CHECKING, + Any, + Callable, + Dict, + Generic, + List, + Optional, + Tuple, + Type, + TypeVar, + overload, +) if sys.version_info >= (3, 10): from importlib.metadata import EntryPoint, entry_points @@ -28,6 +40,10 @@ from mkdocs.structure.files import Files from mkdocs.structure.nav import Navigation from mkdocs.structure.pages import Page +if TYPE_CHECKING: + from mkdocs.config.defaults import MkDocsConfig + + log = logging.getLogger('mkdocs.plugins') @@ -120,7 +136,7 @@ class BasePlugin(Generic[SomeConfig]): """ def on_serve( - self, server: LiveReloadServer, *, config: Config, builder: Callable + self, server: LiveReloadServer, *, config: MkDocsConfig, builder: Callable ) -> Optional[LiveReloadServer]: """ The `serve` event is only called when the `serve` command is used during @@ -141,7 +157,7 @@ class BasePlugin(Generic[SomeConfig]): # Global events - def on_config(self, config: Config) -> Optional[Config]: + def on_config(self, config: MkDocsConfig) -> Optional[Config]: """ The `config` event is the first event called on build and is run immediately after the user configuration is loaded and validated. Any alterations to the @@ -155,7 +171,7 @@ class BasePlugin(Generic[SomeConfig]): """ return config - def on_pre_build(self, *, config: Config) -> None: + def on_pre_build(self, *, config: MkDocsConfig) -> None: """ The `pre_build` event does not alter any variables. Use this event to call pre-build scripts. @@ -164,7 +180,7 @@ class BasePlugin(Generic[SomeConfig]): config: global configuration object """ - def on_files(self, files: Files, *, config: Config) -> Optional[Files]: + def on_files(self, files: Files, *, config: MkDocsConfig) -> Optional[Files]: """ The `files` event is called after the files collection is populated from the `docs_dir`. Use this event to add, remove, or alter files in the @@ -181,7 +197,9 @@ class BasePlugin(Generic[SomeConfig]): """ return files - def on_nav(self, nav: Navigation, *, config: Config, files: Files) -> Optional[Navigation]: + def on_nav( + self, nav: Navigation, *, config: MkDocsConfig, files: Files + ) -> Optional[Navigation]: """ The `nav` event is called after the site navigation is created and can be used to alter the site navigation. @@ -197,7 +215,7 @@ class BasePlugin(Generic[SomeConfig]): return nav def on_env( - self, env: jinja2.Environment, *, config: Config, files: Files + self, env: jinja2.Environment, *, config: MkDocsConfig, files: Files ) -> Optional[jinja2.Environment]: """ The `env` event is called after the Jinja template environment is created @@ -214,7 +232,7 @@ class BasePlugin(Generic[SomeConfig]): """ return env - def on_post_build(self, *, config: Config) -> None: + def on_post_build(self, *, config: MkDocsConfig) -> None: """ The `post_build` event does not alter any variables. Use this event to call post-build scripts. @@ -238,7 +256,7 @@ class BasePlugin(Generic[SomeConfig]): # Template events def on_pre_template( - self, template: jinja2.Template, *, template_name: str, config: Config + self, template: jinja2.Template, *, template_name: str, config: MkDocsConfig ) -> Optional[jinja2.Template]: """ The `pre_template` event is called immediately after the subject template is @@ -255,7 +273,7 @@ class BasePlugin(Generic[SomeConfig]): return template def on_template_context( - self, context: Dict[str, Any], *, template_name: str, config: Config + self, context: Dict[str, Any], *, template_name: str, config: MkDocsConfig ) -> Optional[Dict[str, Any]]: """ The `template_context` event is called immediately after the context is created @@ -273,7 +291,7 @@ class BasePlugin(Generic[SomeConfig]): return context def on_post_template( - self, output_content: str, *, template_name: str, config: Config + self, output_content: str, *, template_name: str, config: MkDocsConfig ) -> Optional[str]: """ The `post_template` event is called after the template is rendered, but before @@ -293,7 +311,7 @@ class BasePlugin(Generic[SomeConfig]): # Page events - def on_pre_page(self, page: Page, *, config: Config, files: Files) -> Optional[Page]: + def on_pre_page(self, page: Page, *, config: MkDocsConfig, files: Files) -> Optional[Page]: """ The `pre_page` event is called before any actions are taken on the subject page and can be used to alter the `Page` instance. @@ -308,7 +326,7 @@ class BasePlugin(Generic[SomeConfig]): """ return page - def on_page_read_source(self, *, page: Page, config: Config) -> Optional[str]: + def on_page_read_source(self, *, page: Page, config: MkDocsConfig) -> Optional[str]: """ The `on_page_read_source` event can replace the default mechanism to read the contents of a page's source from the filesystem. @@ -324,7 +342,7 @@ class BasePlugin(Generic[SomeConfig]): return None def on_page_markdown( - self, markdown: str, *, page: Page, config: Config, files: Files + self, markdown: str, *, page: Page, config: MkDocsConfig, files: Files ) -> Optional[str]: """ The `page_markdown` event is called after the page's markdown is loaded @@ -343,7 +361,7 @@ class BasePlugin(Generic[SomeConfig]): return markdown def on_page_content( - self, html: str, *, page: Page, config: Config, files: Files + self, html: str, *, page: Page, config: MkDocsConfig, files: Files ) -> Optional[str]: """ The `page_content` event is called after the Markdown text is rendered to @@ -362,7 +380,7 @@ class BasePlugin(Generic[SomeConfig]): return html def on_page_context( - self, context: Dict[str, Any], *, page: Page, config: Config, nav: Navigation + self, context: Dict[str, Any], *, page: Page, config: MkDocsConfig, nav: Navigation ) -> Optional[Dict[str, Any]]: """ The `page_context` event is called after the context for a page is created @@ -379,7 +397,7 @@ class BasePlugin(Generic[SomeConfig]): """ return context - def on_post_page(self, output: str, *, page: Page, config: Config) -> Optional[str]: + def on_post_page(self, output: str, *, page: Page, config: MkDocsConfig) -> Optional[str]: """ The `post_page` event is called after the template is rendered, but before it is written to disc and can be used to alter the output of the diff --git a/mkdocs/structure/files.py b/mkdocs/structure/files.py index b9331376..131590d3 100644 --- a/mkdocs/structure/files.py +++ b/mkdocs/structure/files.py @@ -23,11 +23,12 @@ from urllib.parse import quote as urlquote import jinja2.environment from mkdocs import utils -from mkdocs.config.base import Config if TYPE_CHECKING: + from mkdocs.config.defaults import MkDocsConfig from mkdocs.structure.pages import Page + log = logging.getLogger(__name__) @@ -103,7 +104,7 @@ class Files: """Return iterable of all CSS file objects.""" return [file for file in self if file.is_css()] - def add_files_from_theme(self, env: jinja2.Environment, config: Config) -> None: + def add_files_from_theme(self, env: jinja2.Environment, config: MkDocsConfig) -> None: """Retrieve static files from Jinja environment and add to collection.""" def filter(name): @@ -278,7 +279,7 @@ class File: return self.src_uri.endswith('.css') -def get_files(config: Union[Config, Mapping[str, Any]]) -> Files: +def get_files(config: Union[MkDocsConfig, Mapping[str, Any]]) -> Files: """Walk the `docs_dir` and return a Files collection.""" files = [] exclude = ['.*', '/templates'] diff --git a/mkdocs/structure/nav.py b/mkdocs/structure/nav.py index 489ce395..1fff69c8 100644 --- a/mkdocs/structure/nav.py +++ b/mkdocs/structure/nav.py @@ -1,14 +1,17 @@ from __future__ import annotations import logging -from typing import Any, Iterator, List, Mapping, Optional, Type, TypeVar, Union +from typing import TYPE_CHECKING, Any, Iterator, List, Mapping, Optional, Type, TypeVar, Union from urllib.parse import urlsplit -from mkdocs.config.base import Config from mkdocs.structure.files import Files from mkdocs.structure.pages import Page from mkdocs.utils import nest_paths +if TYPE_CHECKING: + from mkdocs.config.defaults import MkDocsConfig + + log = logging.getLogger(__name__) @@ -142,7 +145,7 @@ class Link: return '{}{}'.format(' ' * depth, repr(self)) -def get_navigation(files: Files, config: Union[Config, Mapping[str, Any]]) -> Navigation: +def get_navigation(files: Files, config: Union[MkDocsConfig, Mapping[str, Any]]) -> Navigation: """Build site navigation from config and files.""" nav_config = config['nav'] or nest_paths(f.src_uri for f in files.documentation_pages()) items = _data_to_navigation(nav_config, files, config) @@ -189,7 +192,7 @@ def get_navigation(files: Files, config: Union[Config, Mapping[str, Any]]) -> Na return Navigation(items, pages) -def _data_to_navigation(data, files: Files, config: Union[Config, Mapping[str, Any]]): +def _data_to_navigation(data, files: Files, config: Union[MkDocsConfig, Mapping[str, Any]]): if isinstance(data, dict): return [ _data_to_navigation((key, value), files, config) diff --git a/mkdocs/structure/pages.py b/mkdocs/structure/pages.py index ffe74d98..f24ad967 100644 --- a/mkdocs/structure/pages.py +++ b/mkdocs/structure/pages.py @@ -13,21 +13,22 @@ from markdown.extensions import Extension from markdown.treeprocessors import Treeprocessor from markdown.util import AMP_SUBSTITUTE -from mkdocs.config.base import Config from mkdocs.structure.files import File, Files from mkdocs.structure.toc import get_toc from mkdocs.utils import get_build_date, get_markdown_title, meta if TYPE_CHECKING: + from mkdocs.config.defaults import MkDocsConfig from mkdocs.structure.nav import Section from mkdocs.structure.toc import TableOfContents + log = logging.getLogger(__name__) class Page: def __init__( - self, title: Optional[str], file: File, config: Union[Config, Mapping[str, Any]] + self, title: Optional[str], file: File, config: Union[MkDocsConfig, Mapping[str, Any]] ) -> None: file.page = self self.file = file @@ -208,7 +209,7 @@ class Page: else: self.edit_url = None - def read_source(self, config: Config) -> None: + def read_source(self, config: MkDocsConfig) -> None: source = config['plugins'].run_event('page_read_source', page=self, config=config) if source is None: try: @@ -255,7 +256,7 @@ class Page: self.title = title - def render(self, config: Config, files: Files) -> None: + def render(self, config: MkDocsConfig, files: Files) -> None: """ Convert the Markdown source file to HTML as per the config. """ diff --git a/mkdocs/tests/base.py b/mkdocs/tests/base.py index b6eee458..0c838ebd 100644 --- a/mkdocs/tests/base.py +++ b/mkdocs/tests/base.py @@ -21,7 +21,7 @@ def get_markdown_toc(markdown_source): return md.toc_tokens -def load_config(**cfg): +def load_config(**cfg) -> MkDocsConfig: """Helper to build a simple config for testing.""" path_base = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'integration', 'minimal') cfg = cfg or {}