Override special methods for string paths

This commit is contained in:
Adam Turner 2023-08-23 22:45:58 +01:00
parent 07b87e9512
commit 2986aa113c

View File

@ -4,45 +4,94 @@ from __future__ import annotations
import sys import sys
import warnings import warnings
from pathlib import Path, PosixPath, WindowsPath from pathlib import Path, PosixPath, PurePath, WindowsPath
from sphinx.deprecation import RemovedInSphinx80Warning from sphinx.deprecation import RemovedInSphinx80Warning
_STR_METHODS = frozenset(str.__dict__) _STR_METHODS = frozenset(str.__dict__)
_PATH_NAME = Path().__class__.__name__ _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': if sys.platform == 'win32':
class _StrPath(WindowsPath): class _StrPath(WindowsPath):
def replace(self, old, new, count=-1, /): def replace(self, old, new, count=-1, /):
# replace exists in both Path and str; # replace exists in both Path and str;
# in Path it makes filesystem changes, so we use the safer str version # in Path it makes filesystem changes, so we use the safer str version
warnings.warn('Sphinx 8 will drop support for representing paths as strings. ' warnings.warn(_MSG, RemovedInSphinx80Warning, stacklevel=2)
'Use "pathlib.Path" or "os.fspath" instead.', return self.__str__().replace(old, new, count)
RemovedInSphinx80Warning, stacklevel=2)
return str(self).replace(old, new, count)
def __getattr__(self, item): def __getattr__(self, item):
if item in _STR_METHODS: if item in _STR_METHODS:
warnings.warn('Sphinx 8 will drop support for representing paths as strings. ' warnings.warn(_MSG, RemovedInSphinx80Warning, stacklevel=2)
'Use "pathlib.Path" or "os.fspath" instead.', return getattr(self.__str__(), item)
RemovedInSphinx80Warning, stacklevel=2)
return getattr(str(self), item)
msg = f'{_PATH_NAME!r} has no attribute {item!r}' msg = f'{_PATH_NAME!r} has no attribute {item!r}'
raise AttributeError(msg) raise AttributeError(msg)
def __add__(self, other):
warnings.warn(_MSG, RemovedInSphinx80Warning, stacklevel=2)
return self.__str__() + other
def __contains__(self, item):
warnings.warn(_MSG, RemovedInSphinx80Warning, stacklevel=2)
return item in self.__str__()
def __eq__(self, other):
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 __getitem__(self, item):
warnings.warn(_MSG, RemovedInSphinx80Warning, stacklevel=2)
return self.__str__()[item]
def __len__(self):
warnings.warn(_MSG, RemovedInSphinx80Warning, stacklevel=2)
return len(self.__str__())
else: else:
class _StrPath(PosixPath): class _StrPath(PosixPath):
def replace(self, old, new, count=-1, /): def replace(self, old, new, count=-1, /):
warnings.warn('Sphinx 8 will drop support for representing paths as strings. ' # replace exists in both Path and str;
'Use "pathlib.Path" or "os.fspath" instead.', # in Path it makes filesystem changes, so we use the safer str version
RemovedInSphinx80Warning, stacklevel=2) warnings.warn(_MSG, RemovedInSphinx80Warning, stacklevel=2)
return str(self).replace(old, new, count) return self.__str__().replace(old, new, count)
def __getattr__(self, item): def __getattr__(self, item):
if item in _STR_METHODS: if item in _STR_METHODS:
warnings.warn('Sphinx 8 will drop support for representing paths as strings. ' warnings.warn(_MSG, RemovedInSphinx80Warning, stacklevel=2)
'Use "pathlib.Path" or "os.fspath" instead.', return getattr(self.__str__(), item)
RemovedInSphinx80Warning, stacklevel=2)
return getattr(str(self), item)
msg = f'{_PATH_NAME!r} has no attribute {item!r}' msg = f'{_PATH_NAME!r} has no attribute {item!r}'
raise AttributeError(msg) raise AttributeError(msg)
def __add__(self, other):
warnings.warn(_MSG, RemovedInSphinx80Warning, stacklevel=2)
return self.__str__() + other
def __contains__(self, item):
warnings.warn(_MSG, RemovedInSphinx80Warning, stacklevel=2)
return item in self.__str__()
def __eq__(self, other):
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 __getitem__(self, item):
warnings.warn(_MSG, RemovedInSphinx80Warning, stacklevel=2)
return self.__str__()[item]
def __len__(self):
warnings.warn(_MSG, RemovedInSphinx80Warning, stacklevel=2)
return len(self.__str__())