Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 39 additions & 12 deletions src/spellbind/observable_collections.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@

import functools
from abc import ABC, abstractmethod
from typing import TypeVar, Generic, Collection, Callable, Iterable, Iterator
from typing import TypeVar, Generic, Collection, Callable, Iterable, Iterator, Any

from typing_extensions import override

from spellbind.actions import CollectionAction, DeltaAction, DeltasAction, ClearAction
from spellbind.deriveds import Derived
from spellbind.event import BiEvent
from spellbind.int_values import IntValue
from spellbind.observables import ValuesObservable, ValueObservable, BiObservable
from spellbind.observables import ValuesObservable, ValueObservable, Observer, ValueObserver, BiObserver, \
Subscription
from spellbind.str_values import StrValue
from spellbind.values import Value, EMPTY_FROZEN_SET

Expand Down Expand Up @@ -121,16 +122,29 @@ def _set_value(self, value: _S) -> None:
def value(self) -> _S:
return self._value

@property
@override
def observable(self) -> BiObservable[_S, _S]:
return self._on_change

@property
@override
def derived_from(self) -> frozenset[Derived]:
return EMPTY_FROZEN_SET

@override
def observe(self, observer: Observer | ValueObserver[_S] | BiObserver[_S, _S],
times: int | None = None) -> Subscription:
return self._on_change.observe(observer, times=times)

@override
def weak_observe(self, observer: Observer | ValueObserver[_S] | BiObserver[_S, _S],
times: int | None = None) -> Subscription:
return self._on_change.weak_observe(observer, times=times)

@override
def unobserve(self, observer: Observer | ValueObserver[_S] | BiObserver[_S, _S]) -> None:
self._on_change.unobserve(observer)

@override
def is_observed(self, by: Callable[..., Any] | None = None) -> bool:
return self._on_change.is_observed(by=by)


class ValueCollection(ObservableCollection[Value[_S]], Generic[_S], ABC):
@override
Expand Down Expand Up @@ -161,11 +175,6 @@ def __init__(self, collection: ObservableCollection[_T], combiner: Callable[[Ite
self._collection.on_change.observe(self._recalculate_value)
self._on_change: BiEvent[_S, _S] = BiEvent[_S, _S]()

@property
@override
def observable(self) -> BiObservable[_S, _S]:
return self._on_change

def _recalculate_value(self) -> None:
old_value = self._value
self._value = self._combiner(self._collection)
Expand All @@ -181,3 +190,21 @@ def value(self) -> _S:
@override
def derived_from(self) -> frozenset[Derived]:
return EMPTY_FROZEN_SET

@override
def observe(self, observer: Observer | ValueObserver[_S] | BiObserver[_S, _S],
times: int | None = None) -> Subscription:
return self._on_change.observe(observer, times=times)

@override
def weak_observe(self, observer: Observer | ValueObserver[_S] | BiObserver[_S, _S],
times: int | None = None) -> Subscription:
return self._on_change.weak_observe(observer, times=times)

@override
def unobserve(self, observer: Observer | ValueObserver[_S] | BiObserver[_S, _S]) -> None:
self._on_change.unobserve(observer)

@override
def is_observed(self, by: Callable[..., Any] | None = None) -> bool:
return self._on_change.is_observed(by=by)
20 changes: 10 additions & 10 deletions src/spellbind/observable_sequences.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
from __future__ import annotations

from functools import cached_property

from typing_extensions import TypeIs, Self, override

from abc import ABC, abstractmethod
from functools import cached_property
from typing import Sequence, Generic, MutableSequence, Iterable, overload, SupportsIndex, Callable, Iterator, \
TypeVar, Any

from typing_extensions import TypeIs, Self, override

from spellbind import int_values
from spellbind.actions import AtIndicesDeltasAction, ClearAction, ReverseAction, OneElementChangedAction, \
AtIndexDeltaAction, \
Expand All @@ -19,7 +18,8 @@
from spellbind.event import ValueEvent
from spellbind.int_values import IntVariable, IntValue
from spellbind.observable_collections import ObservableCollection, ValueCollection
from spellbind.observables import ValueObservable, ValuesObservable, void_value_observable, void_values_observable
from spellbind.observables import ValueObservable, ValuesObservable, void_value_observable, void_values_observable, \
combine_values_observables, combine_value_observables
from spellbind.values import Value, NotConstantError, Constant

_S = TypeVar("_S")
Expand Down Expand Up @@ -251,7 +251,7 @@ def __init__(self, iterable: Iterable[_S] = ()):
self._values = list(iterable)
self._action_event = ValueEvent[AtIndicesDeltasAction[_S] | ClearAction[_S] | ReverseAction[_S]]()
self._deltas_event = ValueEvent[AtIndicesDeltasAction[_S]]()
self._delta_observable = self._deltas_event.map_to_many(
self._delta_observable = self._deltas_event.map_to_values_observable(
transformer=lambda deltas_action: deltas_action.delta_actions
)
self._len_value = IntVariable(len(self._values))
Expand Down Expand Up @@ -558,15 +558,15 @@ def __init__(self, iterable: Iterable[Value[_S]] = ()):
super().__init__(iterable)
self._cells = {}

self._on_value_action = self.on_change.map(lambda action: action.map(lambda item: item.value))
self._on_value_action = self.on_change.map_to_value_observable(lambda action: action.map(lambda item: item.value))
self._on_value_changed_event = ValueEvent[ValueChangedMultipleTimesAction[_S]]()
self._final_on_value_action = self._on_value_action.or_value(self._on_value_changed_event)
self._final_on_value_action = combine_value_observables(self._on_value_action, self._on_value_changed_event)

self._on_value_delta_action = self.delta_observable.map(lambda action: action.map(lambda item: item.value))
self._on_value_delta_action_event = self._on_value_changed_event.map_to_many(
self._on_value_delta_action_event = self._on_value_changed_event.map_to_values_observable(
transformer=lambda deltas_action: deltas_action.delta_actions
)
self._final_on_value_delta_action = self._on_value_delta_action.or_values(self._on_value_delta_action_event)
self._final_on_value_delta_action = combine_values_observables(self._on_value_delta_action, self._on_value_delta_action_event)
self.delta_observable.observe_single(self._on_value_sequence_delta)

for value in self:
Expand Down
59 changes: 35 additions & 24 deletions src/spellbind/observables.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ def unobserve(self, observer: Observer) -> None: ...
@abstractmethod
def is_observed(self, by: _O | None = None) -> bool: ...

def __or__(self, other: Observable) -> Observable:
def or_observable(self, other: Observable) -> Observable:
return CombinedObservable((self, other), weakly=True)


Expand All @@ -212,23 +212,23 @@ def weak_observe(self, observer: Observer | ValueObserver[_S_co], times: int | N
@override
def unobserve(self, observer: Observer | ValueObserver[_S_co]) -> None: ...

def map(self, transformer: Callable[[_S_co], _T], weakly: bool = False,
predicate: Callable[[_S_co], bool] | None = None) -> ValueObservable[_T]:
def map_to_value_observable(self, transformer: Callable[[_S_co], _T], weakly: bool = False,
predicate: Callable[[_S_co], bool] | None = None) -> ValueObservable[_T]:
return MappedValueObservable(self, transformer, weakly=weakly, predicate=predicate)

def map_to_two(self, transformer: Callable[[_S_co], tuple[_T, _U]], weakly: bool = False,
predicate: Callable[[_S_co], bool] | None = None) -> BiObservable[_T, _U]:
def map_to_bi_observable(self, transformer: Callable[[_S_co], tuple[_T, _U]], weakly: bool = False,
predicate: Callable[[_S_co], bool] | None = None) -> BiObservable[_T, _U]:
return SplitOneInTwoObservable(self, transformer, weakly=weakly, predicate=predicate)

def map_to_three(self, transformer: Callable[[_S_co], tuple[_T, _U, _V]], weakly: bool = False,
predicate: Callable[[_S_co], bool] | None = None) -> TriObservable[_T, _U, _V]:
def map_to_tri_observable(self, transformer: Callable[[_S_co], tuple[_T, _U, _V]], weakly: bool = False,
predicate: Callable[[_S_co], bool] | None = None) -> TriObservable[_T, _U, _V]:
return SplitOneInThreeObservable(self, transformer, weakly=weakly, predicate=predicate)

def map_to_many(self, transformer: Callable[[_S_co], tuple[_T, ...]], weakly: bool = False,
predicate: Callable[[_S_co], bool] | None = None) -> ValuesObservable[_T]:
def map_to_values_observable(self, transformer: Callable[[_S_co], tuple[_T, ...]], weakly: bool = False,
predicate: Callable[[_S_co], bool] | None = None) -> ValuesObservable[_T]:
return SplitOneInManyObservable(self, transformer, weakly=weakly, predicate=predicate)

def or_value(self, other: ValueObservable[_T]) -> ValueObservable[_S_co | _T]:
def or_value_observable(self, other: ValueObservable[_T]) -> ValueObservable[_S_co | _T]:
return CombinedValueObservable((self, other), weakly=True)


Expand All @@ -247,21 +247,18 @@ def weak_observe(self, observer: Observer | ValueObserver[_S_co] | BiObserver[_S
@override
def unobserve(self, observer: Observer | ValueObserver[_S_co] | BiObserver[_S_co, _T_co]) -> None: ...

def map_to_one(self, transformer: Callable[[_S_co, _T_co], _U], weakly: bool = False,
predicate: Callable[[_S_co, _T_co], bool] | None = None) -> ValueObservable[_U]:
def map_to_value_observable(self, transformer: Callable[[_S_co, _T_co], _U], weakly: bool = False,
predicate: Callable[[_S_co, _T_co], bool] | None = None) -> ValueObservable[_U]:
return MergeTwoToOneObservable(self, transformer, weakly=weakly, predicate=predicate)

def map(self, transformer: Callable[[_S_co, _T_co], tuple[_U, _V]], weakly: bool = False,
predicate: Callable[[_S_co, _T_co], bool] | None = None) -> BiObservable[_U, _V]:
def map_to_bi_observable(self, transformer: Callable[[_S_co, _T_co], tuple[_U, _V]], weakly: bool = False,
predicate: Callable[[_S_co, _T_co], bool] | None = None) -> BiObservable[_U, _V]:
return MappedBiObservable(self, transformer, weakly=weakly, predicate=predicate)

def map_to_three(self, transformer: Callable[[_S_co, _T_co], tuple[_U, _V, _W]], weakly: bool = False,
predicate: Callable[[_S_co, _T_co], bool] | None = None) -> TriObservable[_U, _V, _W]:
def map_to_tri_observable(self, transformer: Callable[[_S_co, _T_co], tuple[_U, _V, _W]], weakly: bool = False,
predicate: Callable[[_S_co, _T_co], bool] | None = None) -> TriObservable[_U, _V, _W]:
return SplitTwoToThreeObservable(self, transformer, weakly=weakly, predicate=predicate)

def or_bi(self, other: BiObservable[_S_co, _T_co]) -> BiObservable[_S_co, _T_co]:
return CombinedBiObservable((self, other), weakly=True)


class TriObservable(BiObservable[_S_co, _T_co], Generic[_S_co, _T_co, _U_co], ABC):
@abstractmethod
Expand All @@ -278,9 +275,6 @@ def weak_observe(self, observer: Observer | ValueObserver[_S_co] | BiObserver[_S
@override
def unobserve(self, observer: Observer | ValueObserver[_S_co] | BiObserver[_S_co, _T_co] | TriObserver[_S_co, _T_co, _U_co]) -> None: ...

def or_tri(self, other: TriObservable[_S_co, _T_co, _U_co]) -> TriObservable[_S_co, _T_co, _U_co]:
return CombinedTriObservable((self, other), weakly=True)


class ValuesObservable(Observable, Generic[_S_co], ABC):
@abstractmethod
Expand Down Expand Up @@ -317,8 +311,25 @@ def map(self, transformer: Callable[[_S_co], _T_co], weakly: bool = False,
predicate: Callable[[_S_co], bool] | None = None) -> ValuesObservable[_T_co]:
return MappedValuesObservable(self, transformer, weakly=weakly, predicate=predicate)

def or_values(self, other: ValuesObservable[_T]) -> ValuesObservable[_S_co | _T]:
return CombinedValuesObservable((self, other), weakly=True)

def combine_observables(*observables: Observable, observe_weakly: bool = False) -> Observable:
return CombinedObservable(observables, weakly=observe_weakly)


def combine_value_observables(*observables: ValueObservable[_S], observe_weakly: bool = False) -> ValueObservable[_S]:
return CombinedValueObservable(observables, weakly=observe_weakly)


def combine_bi_observables(*observables: BiObservable[_S, _T], observe_weakly: bool = False) -> BiObservable[_S, _T]:
return CombinedBiObservable(observables, weakly=observe_weakly)


def combine_tri_observables(*observables: TriObservable[_S, _T, _U], observe_weakly: bool = False) -> TriObservable[_S, _T, _U]:
return CombinedTriObservable(observables, weakly=observe_weakly)


def combine_values_observables(*observables: ValuesObservable[_S], observe_weakly: bool = False) -> ValuesObservable[_S]:
return CombinedValuesObservable(observables, weakly=observe_weakly)


class _BaseObservable(Generic[_O], ABC):
Expand Down
Loading