# -*- coding: utf-8 -*-
#
# This module is part of the Frequent project, Copyright (C) 2019,
# Douglas Daly. The Frequent package is free software, licensed under
# the MIT License.
#
# Source Code:
# https://github.com/douglasdaly/frequent-py
# Documentation:
# https://frequent-py.readthedocs.io/en/latest
# License:
# https://frequent-py.readthedocs.io/en/latest/license.html
#
"""
Repository base class for creating system-agnostic object storage.
"""
from abc import ABC
from abc import abstractmethod
from typing import Any
from typing import Iterable
from typing import Optional
from typing import Type
[docs]class RepositoryException(Exception):
"""
Exception class for repository-related errors.
"""
pass
[docs]class ObjectNotFoundError(RepositoryException):
"""
Exception thrown when an object could not be found.
Parameters
----------
id : object
The identifier for which no object could be found.
field : str
The lookup field, which for the value `id`, no object could be
found.
"""
__obj_cls__: type = object
def __init__(self, id: Any, field: str = 'id'):
return super().__init__(
f"No {self.__obj_cls__.__name__} found for: {field}={id}."
)
[docs]class Repository(ABC):
"""
Base class for creating object repositories.
"""
__not_found_ex__: Type[ObjectNotFoundError] = ObjectNotFoundError
[docs] @abstractmethod
def add(self, obj: Any) -> None:
"""Adds an object to this storage repository.
Parameters
----------
obj : object
The object to add to this storage repository.
"""
pass
[docs] @abstractmethod
def all(self) -> Iterable[Any]:
"""All the objects stored in this repository.
Returns
-------
:obj:`Iterable` of :obj:`object`
An iterable object of all the objects contained in this
repository.
Note
----
If you don't want your implementation to have the ability to
return all of the objects simply have your implementation either
return an empty container (e.g. `return []`) or (more
pythonically) raise a :obj:`NotImplementedError`.
"""
pass
@abstractmethod
def _get(self, id: Any) -> Optional[Any]:
"""Helper method to get the object with the given `id`.
Parameters
----------
id : object
The identifier to use to get the associated object for.
Returns
-------
:obj:`object` or :obj:`None`
The object found for the given `id` (if found, otherwise
:obj:`None`).
"""
pass
[docs] def get(self, id: Any) -> Any:
"""Gets an object from this storage repository.
Parameters
----------
id : object
The identifier to use to get the associated object for.
Returns
-------
object
The object associated with the given `id`.
Raises
------
ObjectNotFoundError
If no object was found for the given `id`.
"""
obj = self._get(id)
if obj is None:
raise self.__not_found_ex__(id)
return obj
[docs] @abstractmethod
def remove(self, id: Any) -> Any:
"""Removes and returns an object from this repository.
Parameters
----------
id : object
The identifier to remove the associated object for.
Returns
-------
object
The object removed from this repository.
Raises
------
ObjectNotFoundError
If no object was found for the given `id`.
Note
----
If you don't want your implementation to have the ability to
remove objects simply have your implementation either return
:obj:`None` or (more pythonically) raise a
:obj:`NotImplementedError`.
"""
pass