mirror of
https://github.com/mkdocs/mkdocs.git
synced 2026-03-27 09:58:31 +07:00
Move forward with some deprecations (#3425)
This commit is contained in:
@@ -18,7 +18,6 @@ import threading
|
||||
import time
|
||||
import traceback
|
||||
import urllib.parse
|
||||
import warnings
|
||||
import wsgiref.simple_server
|
||||
import wsgiref.util
|
||||
from typing import Any, BinaryIO, Callable, Iterable
|
||||
@@ -119,10 +118,8 @@ class LiveReloadServer(socketserver.ThreadingMixIn, wsgiref.simple_server.WSGISe
|
||||
self._visible_epoch = self._wanted_epoch # Latest fully built version of the site.
|
||||
self._epoch_cond = threading.Condition() # Must be held when accessing _visible_epoch.
|
||||
|
||||
self._to_rebuild: dict[
|
||||
Callable[[], None], bool
|
||||
] = {} # Used as an ordered set of functions to call.
|
||||
self._rebuild_cond = threading.Condition() # Must be held when accessing _to_rebuild.
|
||||
self._want_rebuild: bool = False
|
||||
self._rebuild_cond = threading.Condition() # Must be held when accessing _want_rebuild.
|
||||
|
||||
self._shutdown = False
|
||||
self.serve_thread = threading.Thread(target=lambda: self.serve_forever(shutdown_delay))
|
||||
@@ -131,21 +128,11 @@ class LiveReloadServer(socketserver.ThreadingMixIn, wsgiref.simple_server.WSGISe
|
||||
self._watched_paths: dict[str, int] = {}
|
||||
self._watch_refs: dict[str, Any] = {}
|
||||
|
||||
def watch(
|
||||
self, path: str, func: Callable[[], None] | None = None, recursive: bool = True
|
||||
) -> None:
|
||||
def watch(self, path: str, func: None = None, *, recursive: bool = True) -> None:
|
||||
"""Add the 'path' to watched paths, call the function and reload when any file changes under it."""
|
||||
path = os.path.abspath(path)
|
||||
if func is None or func is self.builder:
|
||||
funct = self.builder
|
||||
else:
|
||||
funct = func
|
||||
warnings.warn(
|
||||
"Plugins should not pass the 'func' parameter of watch(). "
|
||||
"The ability to execute custom callbacks will be removed soon.",
|
||||
DeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
if not (func is None or func is self.builder): # type: ignore[unreachable]
|
||||
raise TypeError("Plugins can no longer pass a 'func' parameter to watch().")
|
||||
|
||||
if path in self._watched_paths:
|
||||
self._watched_paths[path] += 1
|
||||
@@ -157,7 +144,7 @@ class LiveReloadServer(socketserver.ThreadingMixIn, wsgiref.simple_server.WSGISe
|
||||
return
|
||||
log.debug(str(event))
|
||||
with self._rebuild_cond:
|
||||
self._to_rebuild[funct] = True
|
||||
self._want_rebuild = True
|
||||
self._rebuild_cond.notify_all()
|
||||
|
||||
handler = watchdog.events.FileSystemEventHandler()
|
||||
@@ -193,7 +180,7 @@ class LiveReloadServer(socketserver.ThreadingMixIn, wsgiref.simple_server.WSGISe
|
||||
while True:
|
||||
with self._rebuild_cond:
|
||||
while not self._rebuild_cond.wait_for(
|
||||
lambda: self._to_rebuild or self._shutdown, timeout=self.shutdown_delay
|
||||
lambda: self._want_rebuild or self._shutdown, timeout=self.shutdown_delay
|
||||
):
|
||||
# We could have used just one wait instead of a loop + timeout, but we need
|
||||
# occasional breaks, otherwise on Windows we can't receive KeyboardInterrupt.
|
||||
@@ -205,12 +192,10 @@ class LiveReloadServer(socketserver.ThreadingMixIn, wsgiref.simple_server.WSGISe
|
||||
log.debug("Waiting for file changes to stop happening")
|
||||
|
||||
self._wanted_epoch = _timestamp()
|
||||
funcs = list(self._to_rebuild)
|
||||
self._to_rebuild.clear()
|
||||
self._want_rebuild = False
|
||||
|
||||
try:
|
||||
for func in funcs:
|
||||
func()
|
||||
self.builder()
|
||||
except Exception as e:
|
||||
if isinstance(e, SystemExit):
|
||||
print(e, file=sys.stderr) # noqa: T201
|
||||
|
||||
@@ -181,28 +181,6 @@ class BuildTests(unittest.TestCase):
|
||||
with self.assertRaises(KeyError):
|
||||
server.unwatch(site_dir)
|
||||
|
||||
@tempdir({"foo.docs": "a"})
|
||||
@tempdir({"foo.site": "original"})
|
||||
def test_custom_action_warns(self, site_dir, docs_dir):
|
||||
started_building = threading.Event()
|
||||
|
||||
def rebuild():
|
||||
started_building.set()
|
||||
content = Path(docs_dir, "foo.docs").read_text()
|
||||
Path(site_dir, "foo.site").write_text(content * 5)
|
||||
|
||||
with testing_server(site_dir) as server:
|
||||
with self.assertWarnsRegex(DeprecationWarning, "func") as cm:
|
||||
server.watch(docs_dir, rebuild)
|
||||
time.sleep(0.01)
|
||||
self.assertIn("livereload_tests.py", cm.filename)
|
||||
|
||||
Path(docs_dir, "foo.docs").write_text("b")
|
||||
self.assertTrue(started_building.wait(timeout=10))
|
||||
|
||||
_, output = do_request(server, "GET /foo.site")
|
||||
self.assertEqual(output, "bbbbb")
|
||||
|
||||
@tempdir({"foo.docs": "docs1"})
|
||||
@tempdir({"foo.extra": "extra1"})
|
||||
@tempdir({"foo.site": "original"})
|
||||
|
||||
@@ -2,6 +2,7 @@ from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import os
|
||||
import warnings
|
||||
from typing import Any, Collection, MutableMapping
|
||||
|
||||
import jinja2
|
||||
@@ -37,8 +38,7 @@ class Theme(MutableMapping[str, Any]):
|
||||
self.name = name
|
||||
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)
|
||||
self.__vars = _vars
|
||||
|
||||
# MkDocs provided static templates are always included
|
||||
package_dir = os.path.abspath(os.path.dirname(__file__))
|
||||
@@ -62,9 +62,9 @@ class Theme(MutableMapping[str, Any]):
|
||||
_vars.update(user_config)
|
||||
|
||||
# Validate locale and convert to Locale object
|
||||
_vars['locale'] = localization.parse_locale(
|
||||
locale if locale is not None else _vars['locale']
|
||||
)
|
||||
if locale is None:
|
||||
locale = _vars['locale']
|
||||
_vars['locale'] = localization.parse_locale(locale)
|
||||
|
||||
name: str | None
|
||||
|
||||
@@ -76,6 +76,14 @@ class Theme(MutableMapping[str, Any]):
|
||||
def custom_dir(self) -> str | None:
|
||||
return self._custom_dir
|
||||
|
||||
@property
|
||||
def _vars(self) -> dict[str, Any]:
|
||||
warnings.warn(
|
||||
"Do not access Theme._vars, instead access the keys of Theme directly.",
|
||||
DeprecationWarning,
|
||||
)
|
||||
return self.__vars
|
||||
|
||||
dirs: list[str]
|
||||
|
||||
static_templates: set[str]
|
||||
@@ -90,22 +98,22 @@ class Theme(MutableMapping[str, Any]):
|
||||
)
|
||||
|
||||
def __getitem__(self, key: str) -> Any:
|
||||
return self._vars[key] # type: ignore[attr-defined]
|
||||
return self.__vars[key]
|
||||
|
||||
def __setitem__(self, key: str, value):
|
||||
self._vars[key] = value # type: ignore[attr-defined]
|
||||
self.__vars[key] = value
|
||||
|
||||
def __delitem__(self, key: str):
|
||||
del self._vars[key] # type: ignore[attr-defined]
|
||||
del self.__vars[key]
|
||||
|
||||
def __contains__(self, item: object) -> bool:
|
||||
return item in self._vars # type: ignore[attr-defined]
|
||||
return item in self.__vars
|
||||
|
||||
def __len__(self):
|
||||
return len(self._vars) # type: ignore[attr-defined]
|
||||
return len(self.__vars)
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self._vars) # type: ignore[attr-defined]
|
||||
return iter(self.__vars)
|
||||
|
||||
def _load_theme_config(self, name: str) -> None:
|
||||
"""Recursively load theme and any parent themes."""
|
||||
@@ -137,7 +145,7 @@ class Theme(MutableMapping[str, Any]):
|
||||
self._load_theme_config(parent_theme)
|
||||
|
||||
self.static_templates.update(theme_config.pop('static_templates', []))
|
||||
self._vars.update(theme_config) # type: ignore[attr-defined]
|
||||
self.__vars.update(theme_config)
|
||||
|
||||
def get_env(self) -> jinja2.Environment:
|
||||
"""Return a Jinja environment for the theme."""
|
||||
|
||||
@@ -44,16 +44,6 @@ markdown_extensions = (
|
||||
)
|
||||
|
||||
|
||||
def modified_time(file_path):
|
||||
warnings.warn(
|
||||
"modified_time is never used in MkDocs and will be removed soon.", DeprecationWarning
|
||||
)
|
||||
if os.path.exists(file_path):
|
||||
return os.path.getmtime(file_path)
|
||||
else:
|
||||
return 0.0
|
||||
|
||||
|
||||
def get_build_timestamp() -> int:
|
||||
"""
|
||||
Returns the number of seconds since the epoch.
|
||||
@@ -162,27 +152,6 @@ def clean_directory(directory: str) -> None:
|
||||
os.unlink(path)
|
||||
|
||||
|
||||
def get_html_path(path):
|
||||
warnings.warn(
|
||||
"get_html_path is never used in MkDocs and will be removed soon.", DeprecationWarning
|
||||
)
|
||||
path = os.path.splitext(path)[0]
|
||||
if os.path.basename(path) == 'index':
|
||||
return path + '.html'
|
||||
return "/".join((path, 'index.html'))
|
||||
|
||||
|
||||
def get_url_path(path, use_directory_urls=True):
|
||||
warnings.warn(
|
||||
"get_url_path is never used in MkDocs and will be removed soon.", DeprecationWarning
|
||||
)
|
||||
path = get_html_path(path)
|
||||
url = '/' + path.replace(os.sep, '/')
|
||||
if use_directory_urls:
|
||||
return url[: -len('index.html')]
|
||||
return url
|
||||
|
||||
|
||||
def is_markdown_file(path: str) -> bool:
|
||||
"""
|
||||
Return True if the given file path is a Markdown file.
|
||||
@@ -192,20 +161,6 @@ def is_markdown_file(path: str) -> bool:
|
||||
return path.endswith(markdown_extensions)
|
||||
|
||||
|
||||
def is_html_file(path):
|
||||
warnings.warn(
|
||||
"is_html_file is never used in MkDocs and will be removed soon.", DeprecationWarning
|
||||
)
|
||||
return path.lower().endswith(('.html', '.htm'))
|
||||
|
||||
|
||||
def is_template_file(path):
|
||||
warnings.warn(
|
||||
"is_template_file is never used in MkDocs and will be removed soon.", DeprecationWarning
|
||||
)
|
||||
return path.lower().endswith(('.html', '.htm', '.xml'))
|
||||
|
||||
|
||||
_ERROR_TEMPLATE_RE = re.compile(r'^\d{3}\.html?$')
|
||||
|
||||
|
||||
@@ -297,7 +252,9 @@ def create_media_urls(
|
||||
|
||||
|
||||
def path_to_url(path):
|
||||
"""Soft-deprecated, do not use."""
|
||||
warnings.warn(
|
||||
"path_to_url is never used in MkDocs and will be removed soon.", DeprecationWarning
|
||||
)
|
||||
return path.replace('\\', '/')
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user