From 7b1bc92926029058c09ac86649fb51dd7758353b Mon Sep 17 00:00:00 2001 From: Oleh Prypin Date: Fri, 23 Jun 2023 16:23:42 +0200 Subject: [PATCH] Refactor around dict key access --- docs/about/release-notes.md | 2 +- mkdocs/commands/build.py | 5 +-- mkdocs/contrib/search/__init__.py | 13 ++++--- mkdocs/structure/__init__.py | 2 +- mkdocs/structure/nav.py | 2 +- mkdocs/structure/toc.py | 59 ++++++++++++++++++----------- mkdocs/tests/config/config_tests.py | 2 +- mkdocs/tests/theme_tests.py | 7 +--- 8 files changed, 49 insertions(+), 43 deletions(-) diff --git a/docs/about/release-notes.md b/docs/about/release-notes.md index 52f66351..217868b5 100644 --- a/docs/about/release-notes.md +++ b/docs/about/release-notes.md @@ -888,7 +888,7 @@ corresponding configuration values (`config.extra_javascript` and `config.extra_css` respectively) should be used with the filter instead. ```django -{% for path in config['extra_css'] %} +{% for path in config.extra_css %} {% endfor %} ``` diff --git a/mkdocs/commands/build.py b/mkdocs/commands/build.py index a1f507f5..c118737a 100644 --- a/mkdocs/commands/build.py +++ b/mkdocs/commands/build.py @@ -212,10 +212,7 @@ def _build_page( context = get_context(nav, doc_files, config, page) # Allow 'template:' override in md source files. - if 'template' in page.meta: - template = env.get_template(page.meta['template']) - else: - template = env.get_template('main.html') + template = env.get_template(page.meta.get('template', 'main.html')) # Run `page_context` plugin events. context = config.plugins.on_page_context(context, page=page, config=config, nav=nav) diff --git a/mkdocs/contrib/search/__init__.py b/mkdocs/contrib/search/__init__.py index 8a29e8dc..03937279 100644 --- a/mkdocs/contrib/search/__init__.py +++ b/mkdocs/contrib/search/__init__.py @@ -12,6 +12,7 @@ from mkdocs.plugins import BasePlugin if TYPE_CHECKING: from mkdocs.config.defaults import MkDocsConfig + from mkdocs.structure.pages import Page from mkdocs.util.templates import TemplateContext log = logging.getLogger(__name__) @@ -62,9 +63,9 @@ class SearchPlugin(BasePlugin[_PluginConfig]): 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']: + if config.theme.get('include_search_page'): config.theme.static_templates.add('search.html') - if not ('search_index_only' in config.theme and config.theme['search_index_only']): + if not config.theme.get('search_index_only'): path = os.path.join(base_path, 'templates') config.theme.dirs.append(path) if 'search/main.js' not in config.extra_javascript: @@ -72,7 +73,7 @@ class SearchPlugin(BasePlugin[_PluginConfig]): if self.config.lang is None: # lang setting undefined. Set default based on theme locale validate = _PluginConfig.lang.run_validation - self.config.lang = validate(config.theme['locale'].language) + self.config.lang = validate(config.theme.locale.language) # The `python` method of `prebuild_index` is pending deprecation as of version 1.2. # TODO: Raise a deprecation warning in a future release (1.3?). if self.config.prebuild_index == 'python': @@ -86,9 +87,9 @@ class SearchPlugin(BasePlugin[_PluginConfig]): "Create search index instance for later use." self.search_index = SearchIndex(**self.config) - def on_page_context(self, context: TemplateContext, **kwargs) -> None: + def on_page_context(self, context: TemplateContext, page: Page, **kwargs) -> None: "Add page to search index." - self.search_index.add_entry_from_context(context['page']) + self.search_index.add_entry_from_context(page) def on_post_build(self, config: MkDocsConfig, **kwargs) -> None: "Build search index." @@ -98,7 +99,7 @@ class SearchPlugin(BasePlugin[_PluginConfig]): utils.write_file(search_index.encode('utf-8'), json_output_path) assert self.config.lang is not None - if not ('search_index_only' in config.theme and config.theme['search_index_only']): + if not config.theme.get('search_index_only'): # Include language support files in output. Copy them directly # so that only the needed files are included. files = [] diff --git a/mkdocs/structure/__init__.py b/mkdocs/structure/__init__.py index 69356405..c99b6575 100644 --- a/mkdocs/structure/__init__.py +++ b/mkdocs/structure/__init__.py @@ -32,5 +32,5 @@ class StructureItem(metaclass=abc.ABCMeta): return [] return [self.parent, *self.parent.ancestors] - def _indent_print(self, depth=0): + def _indent_print(self, depth: int = 0) -> str: return (' ' * depth) + repr(self) diff --git a/mkdocs/structure/nav.py b/mkdocs/structure/nav.py index f2aadd9f..18937cf0 100644 --- a/mkdocs/structure/nav.py +++ b/mkdocs/structure/nav.py @@ -84,7 +84,7 @@ class Section(StructureItem): is_link: bool = False """Indicates that the navigation object is a "link" object. Always `False` for section objects.""" - def _indent_print(self, depth: int = 0): + def _indent_print(self, depth: int = 0) -> str: ret = [super()._indent_print(depth)] for item in self.children: ret.append(item._indent_print(depth + 1)) diff --git a/mkdocs/structure/toc.py b/mkdocs/structure/toc.py index ef9475bb..d52a57d0 100644 --- a/mkdocs/structure/toc.py +++ b/mkdocs/structure/toc.py @@ -7,10 +7,23 @@ maintain compatibility with older versions of MkDocs. """ from __future__ import annotations -from typing import Any +import sys +from typing import Iterable, Iterator + +if sys.version_info >= (3, 8): + from typing import TypedDict +else: + from typing_extensions import TypedDict -def get_toc(toc_tokens: list) -> TableOfContents: +class _TocToken(TypedDict): + level: int + id: str + name: str + children: list[_TocToken] + + +def get_toc(toc_tokens: list[_TocToken]) -> TableOfContents: toc = [_parse_toc_token(i) for i in toc_tokens] # For the table of contents, always mark the first element as active if len(toc): @@ -18,24 +31,6 @@ def get_toc(toc_tokens: list) -> TableOfContents: return TableOfContents(toc) -class TableOfContents: - """ - Represents the table of contents for a given page. - """ - - def __init__(self, items: list) -> None: - self.items = items - - def __iter__(self): - return iter(self.items) - - def __len__(self) -> int: - return len(self.items) - - def __str__(self) -> str: - return ''.join(str(item) for item in self) - - class AnchorLink: """ A single entry in the table of contents. @@ -59,10 +54,10 @@ class AnchorLink: children: list[AnchorLink] """An iterable of any child items.""" - def __str__(self): + def __str__(self) -> str: return self.indent_print() - def indent_print(self, depth=0): + def indent_print(self, depth: int = 0) -> str: indent = ' ' * depth ret = f'{indent}{self.title} - {self.url}\n' for item in self.children: @@ -70,7 +65,25 @@ class AnchorLink: return ret -def _parse_toc_token(token: dict[str, Any]) -> AnchorLink: +class TableOfContents(Iterable[AnchorLink]): + """ + Represents the table of contents for a given page. + """ + + def __init__(self, items: list[AnchorLink]) -> None: + self.items = items + + def __iter__(self) -> Iterator[AnchorLink]: + return iter(self.items) + + def __len__(self) -> int: + return len(self.items) + + def __str__(self) -> str: + return ''.join(str(item) for item in self) + + +def _parse_toc_token(token: _TocToken) -> AnchorLink: anchor = AnchorLink(token['name'], token['id'], token['level']) for i in token['children']: anchor.children.append(_parse_toc_token(i)) diff --git a/mkdocs/tests/config/config_tests.py b/mkdocs/tests/config/config_tests.py index c43690c4..c9d691ff 100644 --- a/mkdocs/tests/config/config_tests.py +++ b/mkdocs/tests/config/config_tests.py @@ -215,7 +215,7 @@ class ConfigTests(unittest.TestCase): self.assertEqual(warnings, []) self.assertEqual(conf['theme'].dirs, result['dirs']) self.assertEqual(conf['theme'].static_templates, set(result['static_templates'])) - self.assertEqual({k: conf['theme'][k] for k in iter(conf['theme'])}, result['vars']) + self.assertEqual(dict(conf['theme']), result['vars']) def test_empty_nav(self): conf = defaults.MkDocsConfig( diff --git a/mkdocs/tests/theme_tests.py b/mkdocs/tests/theme_tests.py index bb183da1..4d123c68 100644 --- a/mkdocs/tests/theme_tests.py +++ b/mkdocs/tests/theme_tests.py @@ -13,11 +13,6 @@ mkdocs_templates_dir = os.path.join(mkdocs_dir, 'templates') theme_dir = os.path.abspath(os.path.join(mkdocs_dir, 'themes')) -def get_vars(theme): - """Return dict of theme vars.""" - return {k: theme[k] for k in iter(theme)} - - class ThemeTests(unittest.TestCase): def test_simple_theme(self): theme = Theme(name='mkdocs') @@ -27,7 +22,7 @@ class ThemeTests(unittest.TestCase): ) self.assertEqual(theme.static_templates, {'404.html', 'sitemap.xml'}) self.assertEqual( - get_vars(theme), + dict(theme), { 'name': 'mkdocs', 'locale': parse_locale('en'),