"""
The Attr API.
"""
from __future__ import annotations
from abc import ABC, abstractmethod
from typing import overload, TypeVar, Generic, Self, cast
_InstanceT = TypeVar("_InstanceT")
_ValueT = TypeVar("_ValueT")
_SetT = TypeVar("_SetT")
[docs]
class Attr(Generic[_InstanceT, _ValueT], ABC):
"""
A base class for an immutable property-like attribute.
To test your own subclasses, use :py:class:`betty.test_utils.attr.AttrTestBase`.
"""
[docs]
@abstractmethod
def new_attr(self, instance: _InstanceT) -> _ValueT:
"""
Create a new attribute value.
"""
pass
[docs]
def get_attr(self, instance: _InstanceT) -> _ValueT:
"""
Get the attribute value.
"""
try:
return cast(
_ValueT,
getattr(instance, self._attr_name),
)
except AttributeError:
value = self.new_attr(instance)
setattr(instance, self._attr_name, value)
return value
[docs]
class MutableAttr(Generic[_InstanceT, _ValueT, _SetT], Attr[_InstanceT, _ValueT]):
"""
A base class for a mutable property-like attribute.
To test your own subclasses, use :py:class:`betty.test_utils.attr.MutableAttrTestBase`.
"""
def __set__(self, instance: _InstanceT, value: _SetT) -> None:
self.set_attr(instance, value)
def __delete__(self, instance: _InstanceT) -> None:
self.del_attr(instance)
[docs]
@abstractmethod
def set_attr(self, instance: _InstanceT, value: _SetT) -> None:
"""
Set the attribute value.
"""
pass