mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Remove `_StrPath` (#12650)
This commit is contained in:
@@ -68,6 +68,10 @@ Incompatible changes
|
|||||||
* #12096: Do not overwrite user-supplied files when copying assets
|
* #12096: Do not overwrite user-supplied files when copying assets
|
||||||
unless forced with ``force=True``.
|
unless forced with ``force=True``.
|
||||||
Patch by Adam Turner.
|
Patch by Adam Turner.
|
||||||
|
* #12650: Remove support for string methods on :py:class:`~pathlib.Path` objects.
|
||||||
|
Use :py:func:`os.fspath` to convert :py:class:`~pathlib.Path` objects to strings,
|
||||||
|
or :py:class:`~pathlib.Path`'s methods to work with path objects.
|
||||||
|
Patch by Adam Turner.
|
||||||
|
|
||||||
Deprecated
|
Deprecated
|
||||||
----------
|
----------
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ from collections import deque
|
|||||||
from collections.abc import Callable, Collection, Sequence # NoQA: TCH003
|
from collections.abc import Callable, Collection, Sequence # NoQA: TCH003
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
from os import path
|
from os import path
|
||||||
|
from pathlib import Path
|
||||||
from typing import IO, TYPE_CHECKING, Any, Literal
|
from typing import IO, TYPE_CHECKING, Any, Literal
|
||||||
|
|
||||||
from docutils.nodes import TextElement # NoQA: TCH002
|
from docutils.nodes import TextElement # NoQA: TCH002
|
||||||
@@ -31,7 +32,6 @@ from sphinx.locale import __
|
|||||||
from sphinx.project import Project
|
from sphinx.project import Project
|
||||||
from sphinx.registry import SphinxComponentRegistry
|
from sphinx.registry import SphinxComponentRegistry
|
||||||
from sphinx.util import docutils, logging
|
from sphinx.util import docutils, logging
|
||||||
from sphinx.util._pathlib import _StrPath
|
|
||||||
from sphinx.util.build_phase import BuildPhase
|
from sphinx.util.build_phase import BuildPhase
|
||||||
from sphinx.util.console import bold
|
from sphinx.util.console import bold
|
||||||
from sphinx.util.display import progress_message
|
from sphinx.util.display import progress_message
|
||||||
@@ -173,9 +173,9 @@ class Sphinx:
|
|||||||
self.registry = SphinxComponentRegistry()
|
self.registry = SphinxComponentRegistry()
|
||||||
|
|
||||||
# validate provided directories
|
# validate provided directories
|
||||||
self.srcdir = _StrPath(srcdir).resolve()
|
self.srcdir = Path(srcdir).resolve()
|
||||||
self.outdir = _StrPath(outdir).resolve()
|
self.outdir = Path(outdir).resolve()
|
||||||
self.doctreedir = _StrPath(doctreedir).resolve()
|
self.doctreedir = Path(doctreedir).resolve()
|
||||||
|
|
||||||
if not path.isdir(self.srcdir):
|
if not path.isdir(self.srcdir):
|
||||||
raise ApplicationError(__('Cannot find source directory (%s)') %
|
raise ApplicationError(__('Cannot find source directory (%s)') %
|
||||||
@@ -231,7 +231,7 @@ class Sphinx:
|
|||||||
self.confdir = self.srcdir
|
self.confdir = self.srcdir
|
||||||
self.config = Config({}, confoverrides or {})
|
self.config = Config({}, confoverrides or {})
|
||||||
else:
|
else:
|
||||||
self.confdir = _StrPath(confdir).resolve()
|
self.confdir = Path(confdir).resolve()
|
||||||
self.config = Config.read(self.confdir, confoverrides or {}, self.tags)
|
self.config = Config.read(self.confdir, confoverrides or {}, self.tags)
|
||||||
|
|
||||||
# set up translation infrastructure
|
# set up translation infrastructure
|
||||||
|
|||||||
@@ -1,120 +0,0 @@
|
|||||||
"""What follows is awful and will be gone in Sphinx 8"""
|
|
||||||
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import warnings
|
|
||||||
from pathlib import Path, PosixPath, PurePath, WindowsPath
|
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
from sphinx.deprecation import RemovedInSphinx80Warning
|
|
||||||
|
|
||||||
_STR_METHODS = frozenset(str.__dict__)
|
|
||||||
_PATH_NAME = Path().__class__.__name__
|
|
||||||
|
|
||||||
_MSG = (
|
|
||||||
'Sphinx 8 will drop support for representing paths as strings. '
|
|
||||||
'Use "pathlib.Path" or "os.fspath" instead.'
|
|
||||||
)
|
|
||||||
|
|
||||||
# https://docs.python.org/3/library/stdtypes.html#typesseq-common
|
|
||||||
# https://docs.python.org/3/library/stdtypes.html#string-methods
|
|
||||||
|
|
||||||
if sys.platform == 'win32':
|
|
||||||
class _StrPath(WindowsPath):
|
|
||||||
def replace( # type: ignore[override]
|
|
||||||
self, old: str, new: str, count: int = -1, /,
|
|
||||||
) -> str:
|
|
||||||
# replace exists in both Path and str;
|
|
||||||
# in Path it makes filesystem changes, so we use the safer str version
|
|
||||||
warnings.warn(_MSG, RemovedInSphinx80Warning, stacklevel=2)
|
|
||||||
return self.__str__().replace(old, new, count) # NoQA: PLC2801
|
|
||||||
|
|
||||||
def __getattr__(self, item: str) -> Any:
|
|
||||||
if item in _STR_METHODS:
|
|
||||||
warnings.warn(_MSG, RemovedInSphinx80Warning, stacklevel=2)
|
|
||||||
return getattr(self.__str__(), item)
|
|
||||||
msg = f'{_PATH_NAME!r} has no attribute {item!r}'
|
|
||||||
raise AttributeError(msg)
|
|
||||||
|
|
||||||
def __add__(self, other: str) -> str:
|
|
||||||
warnings.warn(_MSG, RemovedInSphinx80Warning, stacklevel=2)
|
|
||||||
return self.__str__() + other
|
|
||||||
|
|
||||||
def __bool__(self) -> bool:
|
|
||||||
if not self.__str__():
|
|
||||||
warnings.warn(_MSG, RemovedInSphinx80Warning, stacklevel=2)
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
def __contains__(self, item: str) -> bool:
|
|
||||||
warnings.warn(_MSG, RemovedInSphinx80Warning, stacklevel=2)
|
|
||||||
return item in self.__str__()
|
|
||||||
|
|
||||||
def __eq__(self, other: object) -> bool:
|
|
||||||
if isinstance(other, PurePath):
|
|
||||||
return super().__eq__(other)
|
|
||||||
if isinstance(other, str):
|
|
||||||
warnings.warn(_MSG, RemovedInSphinx80Warning, stacklevel=2)
|
|
||||||
return self.__str__() == other
|
|
||||||
return NotImplemented
|
|
||||||
|
|
||||||
def __hash__(self) -> int:
|
|
||||||
return super().__hash__()
|
|
||||||
|
|
||||||
def __getitem__(self, item: int | slice) -> str:
|
|
||||||
warnings.warn(_MSG, RemovedInSphinx80Warning, stacklevel=2)
|
|
||||||
return self.__str__()[item]
|
|
||||||
|
|
||||||
def __len__(self) -> int:
|
|
||||||
warnings.warn(_MSG, RemovedInSphinx80Warning, stacklevel=2)
|
|
||||||
return len(self.__str__())
|
|
||||||
else:
|
|
||||||
class _StrPath(PosixPath):
|
|
||||||
def replace( # type: ignore[override]
|
|
||||||
self, old: str, new: str, count: int = -1, /,
|
|
||||||
) -> str:
|
|
||||||
# replace exists in both Path and str;
|
|
||||||
# in Path it makes filesystem changes, so we use the safer str version
|
|
||||||
warnings.warn(_MSG, RemovedInSphinx80Warning, stacklevel=2)
|
|
||||||
return self.__str__().replace(old, new, count) # NoQA: PLC2801
|
|
||||||
|
|
||||||
def __getattr__(self, item: str) -> Any:
|
|
||||||
if item in _STR_METHODS:
|
|
||||||
warnings.warn(_MSG, RemovedInSphinx80Warning, stacklevel=2)
|
|
||||||
return getattr(self.__str__(), item)
|
|
||||||
msg = f'{_PATH_NAME!r} has no attribute {item!r}'
|
|
||||||
raise AttributeError(msg)
|
|
||||||
|
|
||||||
def __add__(self, other: str) -> str:
|
|
||||||
warnings.warn(_MSG, RemovedInSphinx80Warning, stacklevel=2)
|
|
||||||
return self.__str__() + other
|
|
||||||
|
|
||||||
def __bool__(self) -> bool:
|
|
||||||
if not self.__str__():
|
|
||||||
warnings.warn(_MSG, RemovedInSphinx80Warning, stacklevel=2)
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
def __contains__(self, item: str) -> bool:
|
|
||||||
warnings.warn(_MSG, RemovedInSphinx80Warning, stacklevel=2)
|
|
||||||
return item in self.__str__()
|
|
||||||
|
|
||||||
def __eq__(self, other: object) -> bool:
|
|
||||||
if isinstance(other, PurePath):
|
|
||||||
return super().__eq__(other)
|
|
||||||
if isinstance(other, str):
|
|
||||||
warnings.warn(_MSG, RemovedInSphinx80Warning, stacklevel=2)
|
|
||||||
return self.__str__() == other
|
|
||||||
return NotImplemented
|
|
||||||
|
|
||||||
def __hash__(self) -> int:
|
|
||||||
return super().__hash__()
|
|
||||||
|
|
||||||
def __getitem__(self, item: int | slice) -> str:
|
|
||||||
warnings.warn(_MSG, RemovedInSphinx80Warning, stacklevel=2)
|
|
||||||
return self.__str__()[item]
|
|
||||||
|
|
||||||
def __len__(self) -> int:
|
|
||||||
warnings.warn(_MSG, RemovedInSphinx80Warning, stacklevel=2)
|
|
||||||
return len(self.__str__())
|
|
||||||
@@ -7,7 +7,6 @@ import re
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from sphinx.builders.html import validate_html_extra_path, validate_html_static_path
|
from sphinx.builders.html import validate_html_extra_path, validate_html_static_path
|
||||||
from sphinx.deprecation import RemovedInSphinx80Warning
|
|
||||||
from sphinx.errors import ConfigError
|
from sphinx.errors import ConfigError
|
||||||
from sphinx.util.console import strip_colors
|
from sphinx.util.console import strip_colors
|
||||||
from sphinx.util.inventory import InventoryFile
|
from sphinx.util.inventory import InventoryFile
|
||||||
@@ -324,8 +323,7 @@ def test_validate_html_extra_path(app):
|
|||||||
app.outdir, # outdir
|
app.outdir, # outdir
|
||||||
app.outdir / '_static', # inside outdir
|
app.outdir / '_static', # inside outdir
|
||||||
]
|
]
|
||||||
with pytest.warns(RemovedInSphinx80Warning, match='Use "pathlib.Path" or "os.fspath" instead'):
|
validate_html_extra_path(app, app.config)
|
||||||
validate_html_extra_path(app, app.config)
|
|
||||||
assert app.config.html_extra_path == ['_static']
|
assert app.config.html_extra_path == ['_static']
|
||||||
|
|
||||||
|
|
||||||
@@ -338,8 +336,7 @@ def test_validate_html_static_path(app):
|
|||||||
app.outdir, # outdir
|
app.outdir, # outdir
|
||||||
app.outdir / '_static', # inside outdir
|
app.outdir / '_static', # inside outdir
|
||||||
]
|
]
|
||||||
with pytest.warns(RemovedInSphinx80Warning, match='Use "pathlib.Path" or "os.fspath" instead'):
|
validate_html_static_path(app, app.config)
|
||||||
validate_html_static_path(app, app.config)
|
|
||||||
assert app.config.html_static_path == ['_static']
|
assert app.config.html_static_path == ['_static']
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user