ethereum_types.frozen
Dataclass extension that supports immutability.
SlottedFreezable
A Protocol implemented by data classes annotated with
@slotted_freezable.
| 18 | @runtime_checkable |
|---|
class SlottedFreezable:
_frozen
| 28 | _frozen: bool |
|---|
_setattr_function
def _setattr_function(self: Any, attr: str, value: Any) -> None:
| 32 | if getattr(self, "_frozen", None): |
|---|---|
| 33 | raise AttributeError("Mutating frozen dataclasses is not allowed.") |
| 34 | else: |
| 35 | object.__setattr__(self, attr, value) |
_delattr_function
def _delattr_function(self: Any, attr: str) -> None:
| 39 | if self._frozen: |
|---|---|
| 40 | raise AttributeError("Mutating frozen dataclasses is not allowed.") |
| 41 | else: |
| 42 | object.__delattr__(self, attr) |
_S
| 45 | _S = TypeVar("_S", bound=SlottedFreezable) |
|---|
_P
| 46 | _P = ParamSpec("_P") |
|---|
_make_init_function
def _make_init_function(f: Callable[Concatenate[_S, _P], None]) -> Callable[Concatenate[_S, _P], None]:
| 53 | def init_function(self: _S, *args: _P.args, **kwargs: _P.kwargs) -> None: |
|---|---|
| 54 | will_be_frozen = kwargs.pop("_frozen", True) |
| 55 | assert isinstance(will_be_frozen, bool) |
| 56 | object.__setattr__(self, "_frozen", False) |
| 57 | f(self, *args, **kwargs) |
| 58 | self._frozen = will_be_frozen |
| 59 | |
| 60 | return init_function |
slotted_freezable
Monkey patches a dataclass so it can be frozen by setting _frozen to
True and uses __slots__ for efficiency.
Instances will be created frozen by default unless you pass _frozen=False
to __init__.
def slotted_freezable(cls: Any) -> Any:
| 64 | """ |
|---|---|
| 65 | Monkey patches a dataclass so it can be frozen by setting `_frozen` to |
| 66 | `True` and uses `__slots__` for efficiency. |
| 67 | |
| 68 | Instances will be created frozen by default unless you pass `_frozen=False` |
| 69 | to `__init__`. |
| 70 | """ |
| 71 | cls.__slots__ = ("_frozen",) + tuple(cls.__annotations__) |
| 72 | cls.__init__ = _make_init_function(cls.__init__) |
| 73 | cls.__setattr__ = _setattr_function |
| 74 | cls.__delattr__ = _delattr_function |
| 75 | return type(cls)(cls.__name__, cls.__bases__, dict(cls.__dict__)) |
S
| 78 | S = TypeVar("S") |
|---|
modify
Create a copy of obj (which must be @slotted_freezable), and modify
it by applying f. The returned copy will be frozen.
def modify(obj: S, f: Callable[[S], None]) -> S:
| 82 | """ |
|---|---|
| 83 | Create a copy of `obj` (which must be [`@slotted_freezable`]), and modify |
| 84 | it by applying `f`. The returned copy will be frozen. |
| 85 | |
| 86 | [`@slotted_freezable`]: ref:ethereum_types.frozen.slotted_freezable |
| 87 | """ |
| 88 | assert is_dataclass(obj) |
| 89 | assert isinstance(obj, SlottedFreezable) |
| 90 | new_obj = replace(obj, _frozen=False) # type: ignore[unreachable] |
| 91 | f(new_obj) |
| 92 | new_obj._frozen = True |
| 93 | return new_obj |