mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Replace deprecation tooling with module level `__getattr__
` (#11054)
This commit is contained in:
parent
f022db3e8a
commit
67291f414e
@ -7,21 +7,25 @@ from typing import TYPE_CHECKING, Any, Sequence
|
||||
from docutils import nodes
|
||||
from docutils.nodes import Element
|
||||
|
||||
from sphinx.deprecation import RemovedInSphinx70Warning, deprecated_alias
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from sphinx.application import Sphinx
|
||||
|
||||
deprecated_alias('sphinx.addnodes',
|
||||
{
|
||||
'meta': nodes.meta, # type: ignore
|
||||
'docutils_meta': nodes.meta, # type: ignore
|
||||
},
|
||||
RemovedInSphinx70Warning,
|
||||
{
|
||||
'meta': 'docutils.nodes.meta',
|
||||
'docutils_meta': 'docutils.nodes.meta',
|
||||
})
|
||||
# deprecated name -> (object to return, canonical path or empty string)
|
||||
_DEPRECATED_OBJECTS = {
|
||||
'meta': (nodes.meta, 'docutils.nodes.meta'), # type: ignore[attr-defined]
|
||||
'docutils_meta': (nodes.meta, 'docutils.nodes.meta'), # type: ignore[attr-defined]
|
||||
}
|
||||
|
||||
|
||||
def __getattr__(name):
|
||||
if name not in _DEPRECATED_OBJECTS:
|
||||
raise AttributeError(f'module {__name__!r} has no attribute {name!r}')
|
||||
|
||||
from sphinx.deprecation import _deprecation_warning
|
||||
|
||||
deprecated_object, canonical_name = _DEPRECATED_OBJECTS[name]
|
||||
_deprecation_warning(__name__, name, canonical_name, remove=(7, 0))
|
||||
return deprecated_object
|
||||
|
||||
|
||||
class document(nodes.document):
|
||||
|
@ -26,7 +26,6 @@ from sphinx import version_info as sphinx_version
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.builders import Builder
|
||||
from sphinx.config import ENUM, Config
|
||||
from sphinx.deprecation import RemovedInSphinx70Warning, deprecated_alias
|
||||
from sphinx.domains import Domain, Index, IndexEntry
|
||||
from sphinx.environment import BuildEnvironment
|
||||
from sphinx.environment.adapters.asset import ImageAdapter
|
||||
@ -1329,16 +1328,6 @@ import sphinxcontrib.serializinghtml # noqa: E402,F401
|
||||
import sphinx.builders.dirhtml # noqa: E402,F401,RUF100
|
||||
import sphinx.builders.singlehtml # noqa: E402,F401
|
||||
|
||||
deprecated_alias('sphinx.builders.html',
|
||||
{
|
||||
'html5_ready': True,
|
||||
'HTMLTranslator': HTML4Translator,
|
||||
},
|
||||
RemovedInSphinx70Warning,
|
||||
{
|
||||
'HTMLTranslator': 'sphinx.writers.html.HTML5Translator',
|
||||
})
|
||||
|
||||
|
||||
def setup(app: Sphinx) -> dict[str, Any]:
|
||||
# builders
|
||||
@ -1418,3 +1407,21 @@ def setup(app: Sphinx) -> dict[str, Any]:
|
||||
'parallel_read_safe': True,
|
||||
'parallel_write_safe': True,
|
||||
}
|
||||
|
||||
|
||||
# deprecated name -> (object to return, canonical path or empty string)
|
||||
_DEPRECATED_OBJECTS = {
|
||||
'html5_ready': (True, ''),
|
||||
'HTMLTranslator': (HTML4Translator, 'sphinx.writers.html.HTML5Translator'),
|
||||
}
|
||||
|
||||
|
||||
def __getattr__(name):
|
||||
if name not in _DEPRECATED_OBJECTS:
|
||||
raise AttributeError(f'module {__name__!r} has no attribute {name!r}')
|
||||
|
||||
from sphinx.deprecation import _deprecation_warning
|
||||
|
||||
deprecated_object, canonical_name = _DEPRECATED_OBJECTS[name]
|
||||
_deprecation_warning(__name__, name, canonical_name, remove=(7, 0))
|
||||
return deprecated_object
|
||||
|
@ -2,10 +2,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
import warnings
|
||||
from importlib import import_module
|
||||
from typing import Any, Dict
|
||||
|
||||
|
||||
class RemovedInSphinx70Warning(DeprecationWarning):
|
||||
@ -19,65 +16,49 @@ class RemovedInSphinx80Warning(PendingDeprecationWarning):
|
||||
RemovedInNextVersionWarning = RemovedInSphinx70Warning
|
||||
|
||||
|
||||
def deprecated_alias(modname: str, objects: dict[str, object],
|
||||
warning: type[Warning], names: dict[str, str] = {}) -> None:
|
||||
module = import_module(modname)
|
||||
sys.modules[modname] = _ModuleWrapper( # type: ignore
|
||||
module, modname, objects, warning, names)
|
||||
def _deprecation_warning(
|
||||
module: str,
|
||||
attribute: str,
|
||||
canonical_name: str,
|
||||
*,
|
||||
remove: tuple[int, int]
|
||||
) -> None:
|
||||
"""Helper function for module-level deprecations using __getattr__
|
||||
|
||||
Exemplar usage:
|
||||
|
||||
.. code:: python
|
||||
|
||||
# deprecated name -> (object to return, canonical path or empty string)
|
||||
_DEPRECATED_OBJECTS = {
|
||||
'deprecated_name': (object_to_return, 'fully_qualified_replacement_name'),
|
||||
}
|
||||
|
||||
|
||||
class _ModuleWrapper:
|
||||
def __init__(self, module: Any, modname: str,
|
||||
objects: dict[str, object],
|
||||
warning: type[Warning],
|
||||
names: dict[str, str]) -> None:
|
||||
self._module = module
|
||||
self._modname = modname
|
||||
self._objects = objects
|
||||
self._warning = warning
|
||||
self._names = names
|
||||
def __getattr__(name):
|
||||
if name not in _DEPRECATED_OBJECTS:
|
||||
raise AttributeError(f'module {__name__!r} has no attribute {name!r}')
|
||||
|
||||
def __getattr__(self, name: str) -> Any:
|
||||
if name not in self._objects:
|
||||
return getattr(self._module, name)
|
||||
from sphinx.deprecation import _deprecation_warning
|
||||
|
||||
canonical_name = self._names.get(name, None)
|
||||
if canonical_name is not None:
|
||||
warnings.warn(f"The alias '{self._modname}.{name}' is deprecated, "
|
||||
f"use '{canonical_name}' instead. "
|
||||
"Check CHANGES for Sphinx API modifications.",
|
||||
self._warning, stacklevel=3)
|
||||
else:
|
||||
warnings.warn(f"{self._modname}.{name} is deprecated. "
|
||||
"Check CHANGES for Sphinx API modifications.",
|
||||
self._warning, stacklevel=3)
|
||||
return self._objects[name]
|
||||
deprecated_object, canonical_name = _DEPRECATED_OBJECTS[name]
|
||||
_deprecation_warning(__name__, name, canonical_name, remove=(7, 0))
|
||||
return deprecated_object
|
||||
"""
|
||||
|
||||
if remove == (7, 0):
|
||||
warning_class: type[Warning] = RemovedInSphinx70Warning
|
||||
elif remove == (8, 0):
|
||||
warning_class = RemovedInSphinx80Warning
|
||||
else:
|
||||
raise RuntimeError(f'removal version {remove!r} is invalid!')
|
||||
|
||||
class DeprecatedDict(Dict[str, Any]):
|
||||
"""A deprecated dict which warns on each access."""
|
||||
qualified_name = f'{module}.{attribute}'
|
||||
if canonical_name:
|
||||
message = (f'The alias {qualified_name!r} is deprecated, '
|
||||
f'use {canonical_name!r} instead.')
|
||||
else:
|
||||
message = f'{qualified_name!r} is deprecated.'
|
||||
|
||||
def __init__(self, data: dict[str, Any], message: str, warning: type[Warning]) -> None:
|
||||
self.message = message
|
||||
self.warning = warning
|
||||
super().__init__(data)
|
||||
|
||||
def __setitem__(self, key: str, value: Any) -> None:
|
||||
warnings.warn(self.message, self.warning, stacklevel=2)
|
||||
super().__setitem__(key, value)
|
||||
|
||||
def setdefault(self, key: str, default: Any = None) -> Any:
|
||||
warnings.warn(self.message, self.warning, stacklevel=2)
|
||||
return super().setdefault(key, default)
|
||||
|
||||
def __getitem__(self, key: str) -> Any:
|
||||
warnings.warn(self.message, self.warning, stacklevel=2)
|
||||
return super().__getitem__(key)
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
warnings.warn(self.message, self.warning, stacklevel=2)
|
||||
return super().get(key, default)
|
||||
|
||||
def update(self, other: dict[str, Any]) -> None: # type: ignore
|
||||
warnings.warn(self.message, self.warning, stacklevel=2)
|
||||
super().update(other)
|
||||
warnings.warn(message + " Check CHANGES for Sphinx API modifications.",
|
||||
warning_class, stacklevel=3)
|
||||
|
@ -13,11 +13,7 @@ from os import path
|
||||
from typing import IO, Any, Iterable
|
||||
from urllib.parse import parse_qsl, quote_plus, urlencode, urlsplit, urlunsplit
|
||||
|
||||
from sphinx.deprecation import (
|
||||
RemovedInSphinx70Warning,
|
||||
RemovedInSphinx80Warning,
|
||||
deprecated_alias,
|
||||
)
|
||||
from sphinx.deprecation import RemovedInSphinx70Warning
|
||||
from sphinx.errors import ExtensionError, FiletypeNotFoundError
|
||||
from sphinx.locale import __
|
||||
from sphinx.util import display as _display
|
||||
@ -388,29 +384,29 @@ def _xml_name_checker():
|
||||
return _XML_NAME_PATTERN
|
||||
|
||||
|
||||
deprecated_alias('sphinx.util',
|
||||
{
|
||||
'path_stabilize': _osutil.path_stabilize,
|
||||
'display_chunk': _display.display_chunk,
|
||||
'status_iterator': _display.status_iterator,
|
||||
'SkipProgressMessage': _display.SkipProgressMessage,
|
||||
'progress_message': _display.progress_message,
|
||||
'epoch_to_rfc1123': _http_date.epoch_to_rfc1123,
|
||||
'rfc1123_to_epoch': _http_date.rfc1123_to_epoch,
|
||||
'save_traceback': _exceptions.save_traceback,
|
||||
'format_exception_cut_frames': _exceptions.format_exception_cut_frames,
|
||||
'xmlname_checker': _xml_name_checker,
|
||||
},
|
||||
RemovedInSphinx80Warning,
|
||||
{
|
||||
'path_stabilize': 'sphinx.util.osutil.path_stabilize',
|
||||
'display_chunk': 'sphinx.util.display.display_chunk',
|
||||
'status_iterator': 'sphinx.util.display.status_iterator',
|
||||
'SkipProgressMessage': 'sphinx.util.display.SkipProgressMessage',
|
||||
'progress_message': 'sphinx.util.display.progress_message',
|
||||
'epoch_to_rfc1123': 'sphinx.http_date.epoch_to_rfc1123',
|
||||
'rfc1123_to_epoch': 'sphinx.http_date.rfc1123_to_epoch',
|
||||
'save_traceback': 'sphinx.exceptions.save_traceback',
|
||||
'format_exception_cut_frames': 'sphinx.exceptions.format_exception_cut_frames', # NoQA: E501
|
||||
'xmlname_checker': 'sphinx.builders.epub3._XML_NAME_PATTERN',
|
||||
})
|
||||
# deprecated name -> (object to return, canonical path or empty string)
|
||||
_DEPRECATED_OBJECTS = {
|
||||
'path_stabilize': (_osutil.path_stabilize, 'sphinx.util.osutil.path_stabilize'),
|
||||
'display_chunk': (_display.display_chunk, 'sphinx.util.display.display_chunk'),
|
||||
'status_iterator': (_display.status_iterator, 'sphinx.util.display.status_iterator'),
|
||||
'SkipProgressMessage': (_display.SkipProgressMessage,
|
||||
'sphinx.util.display.SkipProgressMessage'),
|
||||
'progress_message': (_display.progress_message, 'sphinx.http_date.epoch_to_rfc1123'),
|
||||
'epoch_to_rfc1123': (_http_date.epoch_to_rfc1123, 'sphinx.http_date.rfc1123_to_epoch'),
|
||||
'rfc1123_to_epoch': (_http_date.rfc1123_to_epoch, 'sphinx.http_date.rfc1123_to_epoch'),
|
||||
'save_traceback': (_exceptions.save_traceback, 'sphinx.exceptions.save_traceback'),
|
||||
'format_exception_cut_frames': (_exceptions.format_exception_cut_frames,
|
||||
'sphinx.exceptions.format_exception_cut_frames'),
|
||||
'xmlname_checker': (_xml_name_checker, 'sphinx.builders.epub3._XML_NAME_PATTERN'),
|
||||
}
|
||||
|
||||
|
||||
def __getattr__(name):
|
||||
if name not in _DEPRECATED_OBJECTS:
|
||||
raise AttributeError(f'module {__name__!r} has no attribute {name!r}')
|
||||
|
||||
from sphinx.deprecation import _deprecation_warning
|
||||
|
||||
deprecated_object, canonical_name = _DEPRECATED_OBJECTS[name]
|
||||
_deprecation_warning(__name__, name, canonical_name, remove=(8, 0))
|
||||
return deprecated_object
|
||||
|
@ -21,7 +21,6 @@ from docutils.statemachine import State, StateMachine, StringList
|
||||
from docutils.utils import Reporter, unescape
|
||||
from docutils.writers._html_base import HTMLTranslator
|
||||
|
||||
from sphinx.deprecation import RemovedInSphinx70Warning, deprecated_alias
|
||||
from sphinx.errors import SphinxError
|
||||
from sphinx.locale import _, __
|
||||
from sphinx.util import logging
|
||||
@ -37,14 +36,23 @@ if TYPE_CHECKING:
|
||||
from sphinx.config import Config
|
||||
from sphinx.environment import BuildEnvironment
|
||||
|
||||
deprecated_alias('sphinx.util.docutils',
|
||||
{
|
||||
'__version_info__': docutils.__version_info__,
|
||||
},
|
||||
RemovedInSphinx70Warning,
|
||||
{
|
||||
'__version_info__': 'docutils.__version_info__',
|
||||
})
|
||||
# deprecated name -> (object to return, canonical path or empty string)
|
||||
_DEPRECATED_OBJECTS = {
|
||||
'__version_info__': (docutils.__version_info__, 'docutils.__version_info__'),
|
||||
}
|
||||
|
||||
|
||||
def __getattr__(name):
|
||||
if name not in _DEPRECATED_OBJECTS:
|
||||
raise AttributeError(f'module {__name__!r} has no attribute {name!r}')
|
||||
|
||||
from sphinx.deprecation import _deprecation_warning
|
||||
|
||||
deprecated_object, canonical_name = _DEPRECATED_OBJECTS[name]
|
||||
_deprecation_warning(__name__, name, canonical_name, remove=(7, 0))
|
||||
return deprecated_object
|
||||
|
||||
|
||||
additional_nodes: set[type[Element]] = set()
|
||||
|
||||
|
||||
@ -361,6 +369,8 @@ class NullReporter(Reporter):
|
||||
|
||||
|
||||
def is_html5_writer_available() -> bool:
|
||||
from sphinx.deprecation import RemovedInSphinx70Warning
|
||||
|
||||
warnings.warn('is_html5_writer_available() is deprecated.',
|
||||
RemovedInSphinx70Warning)
|
||||
return True
|
||||
|
@ -11,8 +11,6 @@ from typing import Any, Callable, Dict, ForwardRef, List, Tuple, TypeVar, Union
|
||||
from docutils import nodes
|
||||
from docutils.parsers.rst.states import Inliner
|
||||
|
||||
from sphinx.deprecation import RemovedInSphinx80Warning, deprecated_alias
|
||||
|
||||
try:
|
||||
from types import UnionType # type: ignore # python 3.10 or above
|
||||
except ImportError:
|
||||
@ -342,11 +340,18 @@ def stringify_annotation(
|
||||
return module_prefix + qualname
|
||||
|
||||
|
||||
deprecated_alias(__name__,
|
||||
{
|
||||
'stringify': stringify_annotation,
|
||||
},
|
||||
RemovedInSphinx80Warning,
|
||||
{
|
||||
'stringify': 'sphinx.util.typing.stringify_annotation',
|
||||
})
|
||||
# deprecated name -> (object to return, canonical path or empty string)
|
||||
_DEPRECATED_OBJECTS = {
|
||||
'stringify': (stringify_annotation, 'sphinx.util.typing.stringify_annotation'),
|
||||
}
|
||||
|
||||
|
||||
def __getattr__(name):
|
||||
if name not in _DEPRECATED_OBJECTS:
|
||||
raise AttributeError(f'module {__name__!r} has no attribute {name!r}')
|
||||
|
||||
from sphinx.deprecation import _deprecation_warning
|
||||
|
||||
deprecated_object, canonical_name = _DEPRECATED_OBJECTS[name]
|
||||
_deprecation_warning(__name__, name, canonical_name, remove=(8, 0))
|
||||
return deprecated_object
|
||||
|
Loading…
Reference in New Issue
Block a user