Skip to content

Commit 2d67ad8

Browse files
committed
Add ObservableStrCollection and StrValueList
1 parent 15c416e commit 2d67ad8

34 files changed

+1537
-861
lines changed

src/spellbind/actions.py

Lines changed: 68 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,42 @@ def value(self) -> _S_co:
118118
return self._item
119119

120120

121-
class ChangedAction(DeltasAction[_S_co], Generic[_S_co], ABC):
121+
class ElementsChangedAction(DeltasAction[_S_co], Generic[_S_co], ABC):
122+
@property
123+
@abstractmethod
124+
def changes(self) -> Iterable[OneElementChangedAction[_S_co]]: ...
125+
126+
@property
127+
def delta_actions(self) -> tuple[DeltaAction[_S_co], ...]:
128+
return tuple(itertools.chain.from_iterable(
129+
(SimpleRemoveOneAction(change.old_item), SimpleAddOneAction(change.new_item))
130+
for change in self.changes
131+
))
132+
133+
def map(self, transformer: Callable[[_S_co], _T]) -> ElementsChangedAction[_T]:
134+
return SimpleElementsChangedAction(
135+
changes=tuple(change.map(transformer) for change in self.changes)
136+
)
137+
138+
139+
class SimpleElementsChangedAction(ElementsChangedAction[_S_co], Generic[_S_co]):
140+
def __init__(self, changes: tuple[OneElementChangedAction[_S_co], ...]):
141+
self._changes = changes
142+
143+
@property
144+
def changes(self) -> Iterable[OneElementChangedAction[_S_co]]:
145+
return self._changes
146+
147+
def __eq__(self, other):
148+
if not isinstance(other, ElementsChangedAction):
149+
return NotImplemented
150+
return self.changes == other.changes
151+
152+
def __repr__(self):
153+
return f"{self.__class__.__name__}(changes={self.changes})"
154+
155+
156+
class OneElementChangedAction(DeltasAction[_S_co], Generic[_S_co], ABC):
122157
@property
123158
@abstractmethod
124159
def new_item(self) -> _S_co: ...
@@ -131,11 +166,11 @@ def old_item(self) -> _S_co: ...
131166
def delta_actions(self) -> tuple[DeltaAction[_S_co], ...]:
132167
return SimpleRemoveOneAction(self.old_item), SimpleAddOneAction(self.new_item)
133168

134-
def map(self, transformer: Callable[[_S_co], _T]) -> DeltasAction[_T]:
135-
return SimpleChangedAction(new_item=transformer(self.new_item), old_item=transformer(self.old_item))
169+
def map(self, transformer: Callable[[_S_co], _T]) -> OneElementChangedAction[_T]:
170+
return SimpleOneElementChangedAction(new_item=transformer(self.new_item), old_item=transformer(self.old_item))
136171

137172

138-
class SimpleChangedAction(ChangedAction[_S_co], Generic[_S_co]):
173+
class SimpleOneElementChangedAction(OneElementChangedAction[_S_co], Generic[_S_co]):
139174
def __init__(self, *, new_item: _S_co, old_item: _S_co):
140175
self._new_item = new_item
141176
self._old_item = old_item
@@ -149,7 +184,7 @@ def old_item(self) -> _S_co:
149184
return self._old_item
150185

151186
def __eq__(self, other):
152-
if not isinstance(other, ChangedAction):
187+
if not isinstance(other, OneElementChangedAction):
153188
return NotImplemented
154189
return (self.new_item == other.new_item and
155190
self.old_item == other.old_item)
@@ -183,29 +218,29 @@ def is_permutation_only(self) -> bool:
183218
return False
184219

185220

186-
class SequenceDeltasAction(SequenceAction[_S_co], DeltasAction[_S_co], Generic[_S_co], ABC):
221+
class AtIndicesDeltasAction(SequenceAction[_S_co], DeltasAction[_S_co], Generic[_S_co], ABC):
187222
@property
188223
@abstractmethod
189-
def delta_actions(self) -> tuple[SequenceDeltaAction[_S_co], ...]: ...
224+
def delta_actions(self) -> tuple[AtIndexDeltaAction[_S_co], ...]: ...
190225

191-
def map(self, transformer: Callable[[_S_co], _T]) -> SequenceDeltasAction[_T]:
226+
def map(self, transformer: Callable[[_S_co], _T]) -> AtIndicesDeltasAction[_T]:
192227
mapped = tuple(action.map(transformer) for action in self.delta_actions)
193-
return SimpleSequenceDeltasAction(mapped)
228+
return SimpleAtIndicesDeltasAction(mapped)
194229

195230

196-
class SequenceDeltaAction(AtIndexAction[_S_co], DeltaAction[_S_co], SequenceDeltasAction[_S_co], Generic[_S_co], ABC):
231+
class AtIndexDeltaAction(AtIndexAction[_S_co], DeltaAction[_S_co], AtIndicesDeltasAction[_S_co], Generic[_S_co], ABC):
197232
@property
198-
def delta_actions(self) -> tuple[SequenceDeltaAction[_S_co], ...]:
233+
def delta_actions(self) -> tuple[AtIndexDeltaAction[_S_co], ...]:
199234
return (self,)
200235

201236
@abstractmethod
202-
def map(self, transformer: Callable[[_S_co], _T]) -> SequenceDeltaAction[_T]: ...
237+
def map(self, transformer: Callable[[_S_co], _T]) -> AtIndexDeltaAction[_T]: ...
203238

204239
def __repr__(self):
205240
return f"{self.__class__.__name__}(index={self.index}, value={self.value})"
206241

207242

208-
class InsertAction(SequenceDeltaAction[_S_co], AddOneAction[_S_co], Generic[_S_co], ABC):
243+
class InsertAction(AtIndexDeltaAction[_S_co], AddOneAction[_S_co], Generic[_S_co], ABC):
209244
def map(self, transformer: Callable[[_S_co], _T]) -> InsertAction[_T]:
210245
return SimpleInsertAction(self.index, transformer(self.value))
211246

@@ -229,13 +264,13 @@ def __eq__(self, other):
229264
return self.index == other.index and self.value == other.value
230265

231266

232-
class InsertAllAction(SequenceDeltasAction[_S_co], Generic[_S_co], ABC):
267+
class InsertAllAction(AtIndicesDeltasAction[_S_co], Generic[_S_co], ABC):
233268
@property
234269
@abstractmethod
235270
def index_with_items(self) -> tuple[tuple[int, _S_co], ...]: ...
236271

237272
@property
238-
def delta_actions(self) -> tuple[SequenceDeltaAction[_S_co], ...]:
273+
def delta_actions(self) -> tuple[AtIndexDeltaAction[_S_co], ...]:
239274
return tuple(SimpleInsertAction(index + i, item) for i, (index, item) in enumerate(self.index_with_items))
240275

241276
def map(self, transformer: Callable[[_S_co], _T]) -> InsertAllAction[_T]:
@@ -256,7 +291,7 @@ def index_with_items(self) -> tuple[tuple[int, _S_co], ...]:
256291
return self._index_with_items
257292

258293

259-
class RemoveAtIndexAction(SequenceDeltaAction[_S_co], RemoveOneAction[_S_co], Generic[_S_co], ABC):
294+
class RemoveAtIndexAction(AtIndexDeltaAction[_S_co], RemoveOneAction[_S_co], Generic[_S_co], ABC):
260295
def map(self, transformer: Callable[[_S_co], _T]) -> RemoveAtIndexAction[_T]:
261296
return SimpleRemoveAtIndexAction(self.index, transformer(self.value))
262297

@@ -280,7 +315,7 @@ def value(self) -> _S_co:
280315
return self._item
281316

282317

283-
class RemoveAtIndicesAction(SequenceDeltasAction[_S_co], Generic[_S_co], ABC):
318+
class RemoveAtIndicesAction(AtIndicesDeltasAction[_S_co], Generic[_S_co], ABC):
284319
@property
285320
@abstractmethod
286321
def removed_elements_with_index(self) -> tuple[tuple[int, _S_co], ...]: ...
@@ -310,20 +345,20 @@ def removed_elements_with_index(self) -> tuple[tuple[int, _S_co], ...]:
310345
return self._removed_elements_with_index
311346

312347
@property
313-
def delta_actions(self) -> tuple[SequenceDeltaAction[_S_co], ...]:
348+
def delta_actions(self) -> tuple[AtIndexDeltaAction[_S_co], ...]:
314349
return tuple(SimpleRemoveAtIndexAction(index - i, item) for i, (index, item) in enumerate(self._removed_elements_with_index))
315350

316351

317-
class SimpleSequenceDeltasAction(SequenceDeltasAction[_S_co], Generic[_S_co]):
318-
def __init__(self, delta_actions: tuple[SequenceDeltaAction[_S_co], ...]):
352+
class SimpleAtIndicesDeltasAction(AtIndicesDeltasAction[_S_co], Generic[_S_co]):
353+
def __init__(self, delta_actions: tuple[AtIndexDeltaAction[_S_co], ...]):
319354
self._delta_actions = delta_actions
320355

321356
@property
322-
def delta_actions(self) -> tuple[SequenceDeltaAction[_S_co], ...]:
357+
def delta_actions(self) -> tuple[AtIndexDeltaAction[_S_co], ...]:
323358
return self._delta_actions
324359

325360

326-
class SetAtIndexAction(AtIndexAction[_S_co], SequenceDeltasAction[_S_co], ChangedAction[_S_co], Generic[_S_co], ABC):
361+
class SetAtIndexAction(AtIndexAction[_S_co], AtIndicesDeltasAction[_S_co], OneElementChangedAction[_S_co], Generic[_S_co], ABC):
327362
@property
328363
@abstractmethod
329364
def index(self) -> int: ...
@@ -337,11 +372,11 @@ def new_item(self) -> _S_co: ...
337372
def old_item(self) -> _S_co: ...
338373

339374
@property
340-
def delta_actions(self) -> tuple[SequenceDeltaAction[_S_co], ...]:
375+
def delta_actions(self) -> tuple[AtIndexDeltaAction[_S_co], ...]:
341376
return (SimpleRemoveAtIndexAction(self.index, self.old_item),
342377
SimpleInsertAction(self.index, self.new_item))
343378

344-
def map(self, transformer: Callable[[_S_co], _T]) -> SequenceDeltasAction[_T]:
379+
def map(self, transformer: Callable[[_S_co], _T]) -> SetAtIndexAction[_T]:
345380
return SimpleSetAtIndexAction(self.index, old_item=transformer(self.old_item), new_item=transformer(self.new_item))
346381

347382
def __repr__(self):
@@ -374,7 +409,7 @@ def old_item(self) -> _S_co:
374409
return self._old_item
375410

376411

377-
class SliceSetAction(SequenceDeltasAction[_S_co], Generic[_S_co], ABC):
412+
class SliceSetAction(AtIndicesDeltasAction[_S_co], Generic[_S_co], ABC):
378413
@property
379414
@abstractmethod
380415
def indices(self) -> tuple[int, ...]: ...
@@ -427,20 +462,20 @@ def old_items(self) -> tuple[_S_co, ...]:
427462
return self._old_items
428463

429464
@property
430-
def delta_actions(self) -> tuple[SequenceDeltaAction[_S_co], ...]:
465+
def delta_actions(self) -> tuple[AtIndexDeltaAction[_S_co], ...]:
431466
return tuple(itertools.chain(self._remove_delta_actions, self._insert_delta_actions))
432467

433468
@property
434-
def _remove_delta_actions(self) -> Iterable[SequenceDeltaAction[_S_co]]:
469+
def _remove_delta_actions(self) -> Iterable[AtIndexDeltaAction[_S_co]]:
435470
return (SimpleRemoveAtIndexAction(index - i, item) for i, (index, item) in enumerate(zip(self._indices, self._old_items)))
436471

437472
@property
438-
def _insert_delta_actions(self) -> Iterable[SequenceDeltaAction[_S_co]]:
473+
def _insert_delta_actions(self) -> Iterable[AtIndexDeltaAction[_S_co]]:
439474
first_index = self._indices[0]
440475
return (SimpleInsertAction(first_index + i, item) for i, item in enumerate(self._new_items))
441476

442477

443-
class SetAtIndicesAction(SequenceDeltasAction[_S_co], Generic[_S_co], ABC):
478+
class SetAtIndicesAction(AtIndicesDeltasAction[_S_co], Generic[_S_co], ABC):
444479
@property
445480
@abstractmethod
446481
def indices_with_new_and_old_items(self) -> tuple[tuple[int, _S_co, _S_co], ...]: ...
@@ -450,7 +485,7 @@ def is_permutation_only(self) -> bool:
450485
return False
451486

452487
@property
453-
def delta_actions(self) -> tuple[SequenceDeltaAction[_S_co], ...]:
488+
def delta_actions(self) -> tuple[AtIndexDeltaAction[_S_co], ...]:
454489
return tuple(itertools.chain.from_iterable(
455490
(SimpleRemoveAtIndexAction(index, old), SimpleInsertAction(index, new))
456491
for index, new, old in self.indices_with_new_and_old_items))
@@ -465,7 +500,6 @@ def __eq__(self, other):
465500
return NotImplemented
466501
return self.indices_with_new_and_old_items == other.indices_with_new_and_old_items
467502

468-
469503
def __repr__(self):
470504
return f"{self.__class__.__name__}(indices_with_new_and_old_items={self.indices_with_new_and_old_items})"
471505

@@ -479,7 +513,7 @@ def indices_with_new_and_old_items(self) -> tuple[tuple[int, _S_co, _S_co], ...]
479513
return self._index_with_new_and_old_items
480514

481515
@property
482-
def delta_actions(self) -> tuple[SequenceDeltaAction[_S_co], ...]:
516+
def delta_actions(self) -> tuple[AtIndexDeltaAction[_S_co], ...]:
483517
return tuple(itertools.chain.from_iterable(
484518
(SimpleRemoveAtIndexAction(index, old), SimpleInsertAction(index, new))
485519
for index, new, old in self._index_with_new_and_old_items))
@@ -494,7 +528,7 @@ def map(self, transformer: Callable[[_S_co], _T]) -> ReverseAction[_T]:
494528
return reverse_action()
495529

496530

497-
class ExtendAction(SequenceDeltasAction[_S_co], SequenceAction[_S_co], Generic[_S_co], ABC):
531+
class ExtendAction(AtIndicesDeltasAction[_S_co], SequenceAction[_S_co], Generic[_S_co], ABC):
498532
@property
499533
def is_permutation_only(self) -> bool:
500534
return False
@@ -508,7 +542,7 @@ def items(self) -> Iterable[_S_co]: ...
508542
def old_sequence_length(self) -> int: ...
509543

510544
@property
511-
def delta_actions(self) -> tuple[SequenceDeltaAction[_S_co], ...]:
545+
def delta_actions(self) -> tuple[AtIndexDeltaAction[_S_co], ...]:
512546
return tuple(SimpleInsertAction(i, item) for i, item in enumerate(self.items, start=self.old_sequence_length))
513547

514548
def map(self, transformer: Callable[[_S_co], _T]) -> ExtendAction[_T]:

src/spellbind/collections.py

Lines changed: 0 additions & 29 deletions
This file was deleted.

src/spellbind/deriveds.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
from __future__ import annotations
2+
3+
from abc import ABC, abstractmethod
4+
from typing import Iterable
5+
6+
7+
class Derived(ABC):
8+
@property
9+
@abstractmethod
10+
def derived_from(self) -> frozenset[Derived]: ...
11+
12+
@property
13+
def deep_derived_from(self) -> Iterable[Derived]:
14+
found_derived = set()
15+
derive_queue = [self]
16+
17+
while derive_queue:
18+
current = derive_queue.pop(0)
19+
for dependency in current.derived_from:
20+
if dependency not in found_derived:
21+
found_derived.add(dependency)
22+
yield dependency
23+
derive_queue.append(dependency)
24+
25+
def is_derived_from(self, derived: Derived) -> bool:
26+
for dependency in self.deep_derived_from:
27+
if derived is dependency:
28+
return True
29+
return False

0 commit comments

Comments
 (0)