from __future__ import annotations
from pathlib import PurePosixPath
from typing import Any, Tuple, Union
from ..errors import PathSyntaxError
[docs]class PagePath:
"""An encapsulation of an absolute pseudo-filesystem path."""
def __init__(
self,
path: PagePathLike
) -> None:
candidate_path: str = str(path)
self.__class__.assert_absolute_path(candidate_path)
self._segments: Tuple[str, ...] = PurePosixPath(candidate_path).parts
self._path: str = '/' + '/'.join(self._segments[1:])
self._parent_dirs = tuple(
'/' + '/'.join(self._segments[1:i]) for i in
range(1, len(self._segments))
)
[docs] @staticmethod
def assert_absolute_path(
path: PagePathLike
) -> None:
"""Assert that the specified path is absolut.
Raises:
:class:`PathSyntaxError`: If the path is not absolute.
"""
if not str(path).startswith('/'):
raise PathSyntaxError('Not an absolute path', 0)
@property
def path(
self
) -> str:
"""The string path wrapped in this instance."""
return self._path
@property
def segments(
self
) -> Tuple[str, ...]:
"""The path segments of this class.
.. code-block:: python
>>> from almanac import PagePath
>>> PagePath('/a/b/c').segments
('/', 'a', 'b', 'c')
>>> PagePath('/').segments
('/',)
"""
return self._segments
@property
def parent_dirs(
self
) -> Tuple[str, ...]:
"""All parent directory paths of this path.
.. code-block:: python
>>> from almanac import PagePath
>>> print('\\n'.join(PagePath('/a/b/c/d/e').parent_dirs))
/
/a
/a/b
/a/b/c
/a/b/c/d
"""
return self._parent_dirs
def __contains__(
self,
path: PagePathLike
) -> bool:
"""Whether the :class:`PathLike` is contained in this instance."""
return str(path) in self._path
def __eq__(
self,
other: Any
) -> bool:
if isinstance(other, (str, PagePath,)):
return self._path == str(other)
return NotImplemented
def __hash__(
self
) -> int:
return hash(self._path)
def __str__(
self
) -> str:
return self._path
def __repr__(
self
) -> str:
return f'<{self.__class__.__qualname__} [{str(self)}]>'
PagePathLike = Union[str, PagePath]