""" Part of the BlackStar filesystem (bsfs) module. A copy of the license is provided with the project. Author: Matthias Baumgartner, 2022 """ # imports import typing # bsfs imports from bsfs.utils import URI, typename # exports __all__: typing.Sequence[str] = ( 'ClosedNamespace', 'Namespace', ) ## code ## class Namespace(): """A namespace consists of a common prefix that is used in a set of URIs. Note that the prefix must include the separator between path and fragment (typically a '#' or a '/'). """ # namespace prefix. prefix: URI def __init__(self, prefix: URI): self.prefix = URI(prefix) def __eq__(self, other: typing.Any) -> bool: return isinstance(other, type(self)) and self.prefix == other.prefix def __hash__(self) -> int: return hash((type(self), self.prefix)) def __str__(self) -> str: return f'{typename(self)}({self.prefix})' def __repr__(self) -> str: return f'{typename(self)}({self.prefix})' def __getattr__(self, fragment: str) -> URI: """Return prefix + fragment.""" return URI(self.prefix + fragment) def __getitem__(self, fragment: str) -> URI: """Alias for getattr(self, fragment).""" return self.__getattr__(fragment) class ClosedNamespace(Namespace): """Namespace that covers a restricted set of URIs.""" # set of permissible fragments. fragments: typing.Set[str] def __init__(self, prefix: URI, *args: str): super().__init__(prefix) self.fragments = set(args) def __eq__(self, other: typing.Any) -> bool: return super().__eq__(other) and self.fragments == other.fragments def __hash__(self) -> int: return hash((type(self), self.prefix, tuple(sorted(self.fragments)))) def __getattr__(self, fragment: str) -> URI: """Return prefix + fragment. Raises a KeyError if the fragment is not allowed in this namespace. """ if fragment not in self.fragments: raise KeyError('fragment') return super().__getattr__(fragment) ## EOF ##