mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Move `sphinx.util
re-exports to module
__getattr__
`
This commit is contained in:
parent
b52ac5c71b
commit
cc8161a066
@ -2,49 +2,23 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import os
|
||||
import posixpath
|
||||
import re
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sphinx.errors import ExtensionError as _ExtensionError
|
||||
from sphinx.errors import FiletypeNotFoundError
|
||||
from sphinx.util import _files, _importer, logging
|
||||
from sphinx.util import index_entries as _index_entries
|
||||
from sphinx.util._lines import parse_line_num_spec as parselinenos # NoQA: F401
|
||||
from sphinx.util._uri import encode_uri # NoQA: F401
|
||||
from sphinx.util._uri import is_url as isurl # NoQA: F401
|
||||
from sphinx.util.console import strip_colors # NoQA: F401
|
||||
from sphinx.util.matching import patfilter # NoQA: F401
|
||||
from sphinx.util.nodes import ( # NoQA: F401
|
||||
caption_ref_re,
|
||||
explicit_title_re,
|
||||
nested_parse_with_titles,
|
||||
split_explicit_title,
|
||||
)
|
||||
|
||||
# import other utilities; partly for backwards compatibility, so don't
|
||||
# prune unused ones indiscriminately
|
||||
from sphinx.util.osutil import ( # NoQA: F401
|
||||
SEP,
|
||||
copyfile,
|
||||
ensuredir,
|
||||
make_filename,
|
||||
os_path,
|
||||
relative_uri,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import hashlib
|
||||
from collections.abc import Callable
|
||||
from types import ModuleType
|
||||
from typing import Any
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Generally useful regular expressions.
|
||||
ws_re: re.Pattern[str] = re.compile(r'\s+')
|
||||
url_re: re.Pattern[str] = re.compile(r'(?P<schema>.+)://.*')
|
||||
|
||||
|
||||
# High-level utility functions.
|
||||
|
||||
|
||||
@ -67,6 +41,8 @@ def _md5(data: bytes = b'', **_kw: Any) -> hashlib._Hash:
|
||||
|
||||
To be removed in Sphinx 9.0
|
||||
"""
|
||||
import hashlib
|
||||
|
||||
return hashlib.md5(data, usedforsecurity=False)
|
||||
|
||||
|
||||
@ -75,37 +51,108 @@ def _sha1(data: bytes = b'', **_kw: Any) -> hashlib._Hash:
|
||||
|
||||
To be removed in Sphinx 9.0
|
||||
"""
|
||||
import hashlib
|
||||
|
||||
return hashlib.sha1(data, usedforsecurity=False)
|
||||
|
||||
|
||||
# deprecated name -> (object to return, canonical path or empty string)
|
||||
_DEPRECATED_OBJECTS: dict[str, tuple[Any, str, tuple[int, int]]] = {
|
||||
'split_index_msg': (
|
||||
_index_entries.split_index_msg,
|
||||
'sphinx.util.index_entries.split_index_msg',
|
||||
(9, 0),
|
||||
),
|
||||
'split_into': (
|
||||
_index_entries.split_index_msg,
|
||||
'sphinx.util.index_entries.split_into',
|
||||
(9, 0),
|
||||
),
|
||||
'ExtensionError': (_ExtensionError, 'sphinx.errors.ExtensionError', (9, 0)),
|
||||
'md5': (_md5, '', (9, 0)),
|
||||
'sha1': (_sha1, '', (9, 0)),
|
||||
'import_object': (_importer.import_object, '', (10, 0)),
|
||||
'FilenameUniqDict': (_files.FilenameUniqDict, '', (10, 0)),
|
||||
'DownloadFiles': (_files.DownloadFiles, '', (10, 0)),
|
||||
}
|
||||
|
||||
|
||||
def __getattr__(name: str) -> Any:
|
||||
if name not in _DEPRECATED_OBJECTS:
|
||||
msg = f'module {__name__!r} has no attribute {name!r}'
|
||||
raise AttributeError(msg)
|
||||
|
||||
from sphinx.deprecation import _deprecation_warning
|
||||
|
||||
deprecated_object, canonical_name, remove = _DEPRECATED_OBJECTS[name]
|
||||
_deprecation_warning(__name__, name, canonical_name, remove=remove)
|
||||
return deprecated_object
|
||||
obj: Callable[..., Any]
|
||||
mod: ModuleType
|
||||
|
||||
# RemovedInSphinx90Warning
|
||||
if name == 'split_index_msg':
|
||||
from sphinx.util.index_entries import split_index_msg as obj
|
||||
|
||||
canonical_name = f'{obj.__module__}.{obj.__qualname__}'
|
||||
_deprecation_warning(__name__, name, canonical_name, remove=(9, 0))
|
||||
return obj
|
||||
|
||||
if name == 'split_into':
|
||||
from sphinx.util.index_entries import _split_into as obj
|
||||
|
||||
_deprecation_warning(__name__, name, '', remove=(9, 0))
|
||||
return obj
|
||||
|
||||
if name == 'ExtensionError':
|
||||
from sphinx.errors import ExtensionError as obj
|
||||
|
||||
canonical_name = f'{obj.__module__}.{obj.__qualname__}'
|
||||
_deprecation_warning(__name__, name, canonical_name, remove=(9, 0))
|
||||
return obj
|
||||
|
||||
if name in {'md5', 'sha1'}:
|
||||
obj = globals()[f'_{name}']
|
||||
canonical_name = f'hashlib.{name}'
|
||||
_deprecation_warning(__name__, name, canonical_name, remove=(9, 0))
|
||||
return obj
|
||||
|
||||
# RemovedInSphinx10Warning
|
||||
|
||||
if name in {'DownloadFiles', 'FilenameUniqDict'}:
|
||||
from sphinx.util import _files as mod
|
||||
|
||||
obj = getattr(mod, name)
|
||||
_deprecation_warning(__name__, name, '', remove=(10, 0))
|
||||
return obj
|
||||
|
||||
if name == 'import_object':
|
||||
from sphinx.util._importer import import_object
|
||||
|
||||
_deprecation_warning(__name__, name, '', remove=(10, 0))
|
||||
return import_object
|
||||
|
||||
# Re-exported for backwards compatibility,
|
||||
# but not currently deprecated
|
||||
|
||||
if name == 'encode_uri':
|
||||
from sphinx.util._uri import encode_uri
|
||||
|
||||
return encode_uri
|
||||
|
||||
if name == 'isurl':
|
||||
from sphinx.util._uri import is_url
|
||||
|
||||
return is_url
|
||||
|
||||
if name == 'parselinenos':
|
||||
from sphinx.util._lines import parse_line_num_spec
|
||||
|
||||
return parse_line_num_spec
|
||||
|
||||
if name == 'patfilter':
|
||||
from sphinx.util.matching import patfilter
|
||||
|
||||
return patfilter
|
||||
|
||||
if name == 'strip_colors':
|
||||
from sphinx.util.console import strip_colors
|
||||
|
||||
return strip_colors
|
||||
|
||||
if name in {
|
||||
'caption_ref_re',
|
||||
'explicit_title_re',
|
||||
'nested_parse_with_titles',
|
||||
'split_explicit_title',
|
||||
}:
|
||||
from sphinx.util import nodes as mod
|
||||
|
||||
return getattr(mod, name)
|
||||
|
||||
if name in {
|
||||
'SEP',
|
||||
'copyfile',
|
||||
'ensuredir',
|
||||
'make_filename',
|
||||
'os_path',
|
||||
'relative_uri',
|
||||
}:
|
||||
from sphinx.util import osutil as mod
|
||||
|
||||
return getattr(mod, name)
|
||||
|
||||
msg = f'module {__name__!r} has no attribute {name!r}'
|
||||
raise AttributeError(msg)
|
||||
|
@ -140,22 +140,26 @@ def test_file_checksum(app):
|
||||
|
||||
def test_file_checksum_query_string():
|
||||
with pytest.raises(
|
||||
ThemeError, match='Local asset file paths must not contain query strings'
|
||||
ThemeError,
|
||||
match='Local asset file paths must not contain query strings',
|
||||
):
|
||||
_file_checksum(Path(), 'with_query_string.css?dead_parrots=1')
|
||||
|
||||
with pytest.raises(
|
||||
ThemeError, match='Local asset file paths must not contain query strings'
|
||||
ThemeError,
|
||||
match='Local asset file paths must not contain query strings',
|
||||
):
|
||||
_file_checksum(Path(), 'with_query_string.js?dead_parrots=1')
|
||||
|
||||
with pytest.raises(
|
||||
ThemeError, match='Local asset file paths must not contain query strings'
|
||||
ThemeError,
|
||||
match='Local asset file paths must not contain query strings',
|
||||
):
|
||||
_file_checksum(Path.cwd(), '_static/with_query_string.css?dead_parrots=1')
|
||||
|
||||
with pytest.raises(
|
||||
ThemeError, match='Local asset file paths must not contain query strings'
|
||||
ThemeError,
|
||||
match='Local asset file paths must not contain query strings',
|
||||
):
|
||||
_file_checksum(Path.cwd(), '_static/with_query_string.js?dead_parrots=1')
|
||||
|
||||
|
@ -107,7 +107,8 @@ def test_LiteralIncludeReader_lines_and_lineno_match2(literal_inc_path, app):
|
||||
options = {'lines': '0,3,5', 'lineno-match': True}
|
||||
reader = LiteralIncludeReader(literal_inc_path, options, DUMMY_CONFIG)
|
||||
with pytest.raises(
|
||||
ValueError, match='Cannot use "lineno-match" with a disjoint set of "lines"'
|
||||
ValueError,
|
||||
match='Cannot use "lineno-match" with a disjoint set of "lines"',
|
||||
):
|
||||
reader.read()
|
||||
|
||||
@ -117,7 +118,8 @@ def test_LiteralIncludeReader_lines_and_lineno_match3(literal_inc_path, app):
|
||||
options = {'lines': '100-', 'lineno-match': True}
|
||||
reader = LiteralIncludeReader(literal_inc_path, options, DUMMY_CONFIG)
|
||||
with pytest.raises(
|
||||
ValueError, match="Line spec '100-': no lines pulled from include file"
|
||||
ValueError,
|
||||
match="Line spec '100-': no lines pulled from include file",
|
||||
):
|
||||
reader.read()
|
||||
|
||||
|
@ -2,7 +2,32 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from sphinx.util.osutil import ensuredir
|
||||
import pytest
|
||||
|
||||
import sphinx.util
|
||||
from sphinx.deprecation import RemovedInSphinx10Warning, RemovedInSphinx90Warning
|
||||
from sphinx.errors import ExtensionError
|
||||
from sphinx.util._files import DownloadFiles, FilenameUniqDict
|
||||
from sphinx.util._importer import import_object
|
||||
from sphinx.util._lines import parse_line_num_spec
|
||||
from sphinx.util._uri import encode_uri, is_url
|
||||
from sphinx.util.console import strip_colors
|
||||
from sphinx.util.index_entries import _split_into, split_index_msg
|
||||
from sphinx.util.matching import patfilter
|
||||
from sphinx.util.nodes import (
|
||||
caption_ref_re,
|
||||
explicit_title_re,
|
||||
nested_parse_with_titles,
|
||||
split_explicit_title,
|
||||
)
|
||||
from sphinx.util.osutil import (
|
||||
SEP,
|
||||
copyfile,
|
||||
ensuredir,
|
||||
make_filename,
|
||||
os_path,
|
||||
relative_uri,
|
||||
)
|
||||
|
||||
|
||||
def test_ensuredir(tmp_path):
|
||||
@ -12,3 +37,55 @@ def test_ensuredir(tmp_path):
|
||||
path = tmp_path / 'a' / 'b' / 'c'
|
||||
ensuredir(path)
|
||||
assert path.is_dir()
|
||||
|
||||
|
||||
def test_exported_attributes():
|
||||
# RemovedInSphinx90Warning
|
||||
with pytest.warns(
|
||||
RemovedInSphinx90Warning,
|
||||
match=r"deprecated, use 'sphinx.util.index_entries.split_index_msg' instead.",
|
||||
):
|
||||
assert sphinx.util.split_index_msg is split_index_msg
|
||||
with pytest.warns(RemovedInSphinx90Warning, match=r'deprecated.'):
|
||||
assert sphinx.util.split_into is _split_into
|
||||
with pytest.warns(
|
||||
RemovedInSphinx90Warning,
|
||||
match=r"deprecated, use 'sphinx.errors.ExtensionError' instead.",
|
||||
):
|
||||
assert sphinx.util.ExtensionError is ExtensionError
|
||||
with pytest.warns(
|
||||
RemovedInSphinx90Warning,
|
||||
match=r"deprecated, use 'hashlib.md5' instead.",
|
||||
):
|
||||
_ = sphinx.util.md5
|
||||
with pytest.warns(
|
||||
RemovedInSphinx90Warning,
|
||||
match=r"deprecated, use 'hashlib.sha1' instead.",
|
||||
):
|
||||
_ = sphinx.util.sha1
|
||||
|
||||
# RemovedInSphinx10Warning
|
||||
with pytest.warns(RemovedInSphinx10Warning, match=r'deprecated.'):
|
||||
assert sphinx.util.FilenameUniqDict is FilenameUniqDict
|
||||
with pytest.warns(RemovedInSphinx10Warning, match=r'deprecated.'):
|
||||
assert sphinx.util.DownloadFiles is DownloadFiles
|
||||
with pytest.warns(RemovedInSphinx10Warning, match=r'deprecated.'):
|
||||
assert sphinx.util.import_object is import_object
|
||||
|
||||
# Re-exported for backwards compatibility,
|
||||
# but not currently deprecated
|
||||
assert sphinx.util.encode_uri is encode_uri
|
||||
assert sphinx.util.isurl is is_url
|
||||
assert sphinx.util.parselinenos is parse_line_num_spec
|
||||
assert sphinx.util.patfilter is patfilter
|
||||
assert sphinx.util.strip_colors is strip_colors
|
||||
assert sphinx.util.caption_ref_re is caption_ref_re
|
||||
assert sphinx.util.explicit_title_re is explicit_title_re
|
||||
assert sphinx.util.nested_parse_with_titles is nested_parse_with_titles
|
||||
assert sphinx.util.split_explicit_title is split_explicit_title
|
||||
assert sphinx.util.SEP is SEP
|
||||
assert sphinx.util.copyfile is copyfile
|
||||
assert sphinx.util.ensuredir is ensuredir
|
||||
assert sphinx.util.make_filename is make_filename
|
||||
assert sphinx.util.os_path is os_path
|
||||
assert sphinx.util.relative_uri is relative_uri
|
||||
|
Loading…
Reference in New Issue
Block a user