Merge pull request #3249 from mkdocs/userc

Deprecate Theme-related fields that were accidentally available
This commit is contained in:
Oleh Prypin
2023-06-18 17:53:01 +02:00
committed by GitHub
5 changed files with 84 additions and 30 deletions

View File

@@ -4,13 +4,27 @@ import functools
import logging
import os
import sys
import warnings
from collections import UserDict
from contextlib import contextmanager
from typing import IO, TYPE_CHECKING, Generic, Iterator, List, Sequence, Tuple, TypeVar, overload
from typing import (
IO,
TYPE_CHECKING,
Any,
Generic,
Iterator,
List,
Mapping,
Sequence,
Tuple,
TypeVar,
overload,
)
from yaml import YAMLError
from mkdocs import exceptions, utils
from mkdocs.utils import weak_property
if TYPE_CHECKING:
from mkdocs.config.defaults import MkDocsConfig
@@ -143,7 +157,7 @@ class Config(UserDict):
def __init__(self, config_file_path: str | bytes | None = None):
super().__init__()
self.user_configs: list[dict] = []
self.__user_configs: list[dict] = []
self.set_defaults()
self._schema_keys = {k for k, v in self._schema}
@@ -237,7 +251,7 @@ class Config(UserDict):
f"{type(patch)}"
)
self.user_configs.append(patch)
self.__user_configs.append(patch)
self.update(patch)
def load_file(self, config_file: IO) -> None:
@@ -250,6 +264,13 @@ class Config(UserDict):
f"MkDocs encountered an error parsing the configuration file: {e}"
)
@weak_property
def user_configs(self) -> Sequence[Mapping[str, Any]]:
warnings.warn(
"user_configs is never used in MkDocs and will be removed soon.", DeprecationWarning
)
return self.__user_configs
@functools.lru_cache(maxsize=None)
def get_schema(cls: type) -> PlainConfigSchema:

View File

@@ -33,7 +33,7 @@ class NoBabelExtension(InternationalizationExtension): # pragma: no cover
)
def parse_locale(locale) -> Locale:
def parse_locale(locale: str) -> Locale:
try:
return Locale.parse(locale, sep='_')
except (ValueError, UnknownLocaleError, TypeError) as e:

View File

@@ -1,4 +1,7 @@
import logging
import unittest.util
unittest.util._MAX_LENGTH = 100000
class DisallowLogsHandler(logging.Handler):

View File

@@ -1104,6 +1104,7 @@ class ThemeTest(TestCase):
conf = self.get_config(Schema, {'option': config})
self.assertEqual(conf.option.name, 'mkdocs')
self.assertEqual(conf.option.custom_dir, custom_dir)
self.assertIn(custom_dir, conf.option.dirs)
self.assertEqual(
conf.option.static_templates,
@@ -1228,7 +1229,7 @@ class ThemeTest(TestCase):
theme = c.Theme()
conf = self.get_config(Schema, config)
self.assertEqual(conf.theme['locale'].language, 'fr')
self.assertEqual(conf.theme.locale.language, 'fr')
class NavTest(TestCase):

View File

@@ -2,7 +2,7 @@ from __future__ import annotations
import logging
import os
from typing import Any
from typing import Any, Collection, MutableMapping
import jinja2
@@ -13,25 +13,32 @@ from mkdocs.utils import filters
log = logging.getLogger(__name__)
class Theme:
class Theme(MutableMapping[str, Any]):
"""
A Theme object.
Keywords:
Parameters:
name: The name of the theme as defined by its entrypoint.
custom_dir: User defined directory for custom templates.
static_templates: A list of templates to render as static pages.
All other keywords are passed as-is and made available as a key/value mapping.
"""
def __init__(self, name: str | None = None, **user_config) -> None:
def __init__(
self,
name: str | None = None,
*,
custom_dir: str | None = None,
static_templates: Collection[str] = (),
locale: str | None = None,
**user_config,
) -> None:
self.name = name
self._vars = {'name': name, 'locale': 'en'}
self._custom_dir = custom_dir
_vars: dict[str, Any] = {'name': name, 'locale': 'en'}
# _vars is soft-deprecated, intentionally hide it from mypy.
setattr(self, '_vars', _vars)
# MkDocs provided static templates are always included
package_dir = os.path.abspath(os.path.dirname(__file__))
@@ -41,8 +48,8 @@ class Theme:
# Build self.dirs from various sources in order of precedence
self.dirs = []
if 'custom_dir' in user_config:
self.dirs.append(user_config.pop('custom_dir'))
if custom_dir is not None:
self.dirs.append(custom_dir)
if name:
self._load_theme_config(name)
@@ -51,32 +58,54 @@ class Theme:
self.dirs.append(mkdocs_templates)
# Handle remaining user configs. Override theme configs (if set)
self.static_templates.update(user_config.pop('static_templates', []))
self._vars.update(user_config)
self.static_templates.update(static_templates)
_vars.update(user_config)
# Validate locale and convert to Locale object
self._vars['locale'] = localization.parse_locale(self._vars['locale'])
_vars['locale'] = localization.parse_locale(
locale if locale is not None else _vars['locale']
)
name: str | None
@property
def locale(self) -> localization.Locale:
return self['locale']
@property
def custom_dir(self) -> str | None:
return self._custom_dir
dirs: list[str]
static_templates: set[str]
def __repr__(self) -> str:
return "{}(name='{}', dirs={}, static_templates={}, {})".format(
return "{}(name={!r}, dirs={!r}, static_templates={!r}, {})".format(
self.__class__.__name__,
self.name,
self.dirs,
list(self.static_templates),
', '.join(f'{k}={v!r}' for k, v in self._vars.items()),
self.static_templates,
', '.join(f'{k}={v!r}' for k, v in self.items()),
)
def __getitem__(self, key: str) -> Any:
return self._vars[key]
return self._vars[key] # type: ignore[attr-defined]
def __setitem__(self, key, value):
self._vars[key] = value
def __setitem__(self, key: str, value):
self._vars[key] = value # type: ignore[attr-defined]
def __contains__(self, item: str) -> bool:
return item in self._vars
def __delitem__(self, key: str):
del self._vars[key] # type: ignore[attr-defined]
def __contains__(self, item: object) -> bool:
return item in self._vars # type: ignore[attr-defined]
def __len__(self):
return len(self._vars) # type: ignore[attr-defined]
def __iter__(self):
return iter(self._vars)
return iter(self._vars) # type: ignore[attr-defined]
def _load_theme_config(self, name: str) -> None:
"""Recursively load theme and any parent themes."""
@@ -108,7 +137,7 @@ class Theme:
self._load_theme_config(parent_theme)
self.static_templates.update(theme_config.pop('static_templates', []))
self._vars.update(theme_config)
self._vars.update(theme_config) # type: ignore[attr-defined]
def get_env(self) -> jinja2.Environment:
"""Return a Jinja environment for the theme."""
@@ -117,5 +146,5 @@ class Theme:
# No autoreload because editing a template in the middle of a build is not useful.
env = jinja2.Environment(loader=loader, auto_reload=False)
env.filters['url'] = filters.url_filter
localization.install_translations(env, self._vars['locale'], self.dirs)
localization.install_translations(env, self.locale, self.dirs)
return env