Skip to content

Commit aa2c75e

Browse files
committed
-
1 parent 7990529 commit aa2c75e

File tree

6 files changed

+196
-115
lines changed

6 files changed

+196
-115
lines changed

source_py3/python_toolbox/emitting/emitter.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,13 @@ def __init__(self, inputs=(), outputs=(), name=None):
6565
6666
`name` is a string name for the emitter.
6767
'''
68+
69+
from python_toolbox import sequence_tools
6870

69-
assert cute_iter_tools.is_iterable(inputs) and \
70-
cute_iter_tools.is_iterable(outputs)
71+
inputs = sequence_tools.to_tuple(inputs,
72+
item_type=collections.Callable)
73+
outputs = sequence_tools.to_tuple(outputs,
74+
item_type=collections.Callable)
7175

7276
self._inputs = set()
7377
'''The emitter's inputs.'''

source_py3/python_toolbox/nifty_collections/various_ordered_sets.py

Lines changed: 72 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44
import collections
55

66
from python_toolbox import comparison_tools
7+
from python_toolbox import context_management
8+
from python_toolbox import caching
9+
from python_toolbox import freezing
10+
11+
712

813
KEY, PREV, NEXT = range(3)
914

@@ -16,10 +21,10 @@ class BaseOrderedSet(collections.Set, collections.Sequence):
1621
ordered by insertion order, but that order can be changed.)
1722
'''
1823

19-
def __init__(self, iterable=None):
20-
self.clear()
21-
if iterable is not None:
22-
self |= iterable
24+
def __init__(self, iterable=()):
25+
self.__clear()
26+
for item in iterable:
27+
self.__add(item)
2328

2429
def __getitem__(self, index):
2530
for i, item in enumerate(self):
@@ -34,27 +39,6 @@ def __len__(self):
3439
def __contains__(self, key):
3540
return key in self._map
3641

37-
def add(self, key):
38-
'''
39-
Add an element to a set.
40-
41-
This has no effect if the element is already present.
42-
'''
43-
if key not in self._map:
44-
end = self._end
45-
curr = end[PREV]
46-
curr[NEXT] = end[PREV] = self._map[key] = [key, curr, end]
47-
48-
def discard(self, key):
49-
"""
50-
Remove an element from a set if it is a member.
51-
52-
If the element is not a member, do nothing.
53-
"""
54-
if key in self._map:
55-
key, prev, next = self._map.pop(key)
56-
prev[NEXT] = next
57-
next[PREV] = prev
5842

5943
def __iter__(self):
6044
end = self._end
@@ -82,7 +66,33 @@ def __eq__(self, other):
8266
len(self) == len(other) and
8367
tuple(self) == tuple(other)
8468
)
69+
70+
def __clear(self):
71+
'''Clear the ordered set, removing all items.'''
72+
self._end = []
73+
self._end += [None, self._end, self._end]
74+
self._map = {}
75+
76+
77+
def __add(self, key, last=True):
78+
'''
79+
Add an element to a set.
80+
81+
This has no effect if the element is already present.
82+
83+
Specify `last=False` to add the item at the start of the ordered set.
84+
'''
85+
86+
if key not in self._map:
87+
end = self._end
88+
if last:
89+
last = end[PREV]
90+
last[NEXT] = end[PREV] = self._map[key] = [key, last, end]
91+
else:
92+
first = end[NEXT]
93+
first[PREV] = end[NEXT] = self._map[key] = [key, end, first]
8594

95+
8696

8797
class FrozenOrderedSet(BaseOrderedSet):
8898
'''
@@ -93,6 +103,7 @@ class FrozenOrderedSet(BaseOrderedSet):
93103
insertion order, but that order can be changed.)
94104
'''
95105

106+
96107
class OrderedSet(BaseOrderedSet, collections.MutableSet):
97108
'''
98109
A `set` with an order.
@@ -101,18 +112,16 @@ class OrderedSet(BaseOrderedSet, collections.MutableSet):
101112
ordered by insertion order, but that order can be changed.)
102113
'''
103114

104-
def move_to_end(self, key):
105-
'''
106-
Move an existing element to the end (or beginning if last==False).
107-
108-
Raises KeyError if the element does not exist.
109-
When last=True, acts like a fast version of self[key]=self.pop(key).
115+
add = BaseOrderedSet._BaseOrderedSet__add
116+
clear = BaseOrderedSet._BaseOrderedSet__clear
110117

118+
def move_to_end(self, key, last=True):
119+
'''
120+
Move an existing element to the end (or start if `last=False`.)
111121
'''
112122
# Inefficient implementation until someone cares.
113-
if key in self:
114-
self.remove(key)
115-
self.add(key)
123+
self.remove(key)
124+
self.add(key, last=last)
116125

117126

118127
def sort(self, key=None, reverse=False):
@@ -130,23 +139,7 @@ def sort(self, key=None, reverse=False):
130139
self.clear()
131140
self |= sorted_members
132141

133-
def clear(self):
134-
self._end = []
135-
self._end += [None, self._end, self._end]
136-
self._map = {}
137-
138-
139-
def add(self, key):
140-
'''
141-
Add an element to a set.
142142

143-
This has no effect if the element is already present.
144-
'''
145-
if key not in self._map:
146-
end = self._end
147-
curr = end[PREV]
148-
curr[NEXT] = end[PREV] = self._map[key] = [key, curr, end]
149-
150143
def discard(self, key):
151144
"""
152145
Remove an element from a set if it is a member.
@@ -170,42 +163,54 @@ def pop(self, last=True):
170163
class EmittingOrderedSet(OrderedSet):
171164
'''An ordered set that emits to `.emitter` every time it's modified.'''
172165

173-
def __init__(self, emitter, items=()):
166+
def __init__(self, iterable=(), *, emitter=None):
174167
if emitter:
175168
from python_toolbox.emitting import Emitter
176169
assert isinstance(emitter, Emitter)
177170
self.emitter = emitter
178-
OrderedSet.__init__(self, items)
171+
OrderedSet.__init__(self, iterable)
179172

180-
181-
def add(self, key):
173+
def add(self, key, last=True):
182174
'''
183175
Add an element to a set.
184176
185177
This has no effect if the element is already present.
186178
'''
187179
if key not in self._map:
188-
end = self._end
189-
curr = end[PREV]
190-
curr[NEXT] = end[PREV] = self._map[key] = [key, curr, end]
191-
if self.emitter:
192-
self.emitter.emit()
180+
super().add(key, last=last)
181+
self._emit()
193182

194-
195183
def discard(self, key):
196184
'''
197185
Remove an element from a set if it is a member.
198186
199187
If the element is not a member, do nothing.
200188
'''
201189
if key in self._map:
202-
key, prev, next = self._map.pop(key)
203-
prev[NEXT] = next
204-
next[PREV] = prev
205-
if self.emitter:
206-
self.emitter.emit()
207-
190+
super().discard(key)
191+
self._emit()
192+
193+
def clear(self):
194+
'''Clear the ordered set, removing all items.'''
195+
if self:
196+
super().clear()
197+
self._emit()
208198

209199
def set_emitter(self, emitter):
210200
'''Set `emitter` to be emitted with on every modification.'''
211-
self.emitter = emitter
201+
self.emitter = emitter
202+
203+
def _emit(self):
204+
if (self.emitter is not None) and not self._emitter_freezer.frozen:
205+
self.emitter.emit()
206+
207+
def move_to_end(self, key, last=True):
208+
'''
209+
Move an existing element to the end (or start if `last=False`.)
210+
'''
211+
# Inefficient implementation until someone cares.
212+
with self._emitter_freezer:
213+
self.remove(key)
214+
self.add(key, last=last)
215+
216+
_emitter_freezer = freezing.FreezerProperty()

source_py3/test_python_toolbox/test_emitting/test_emitter.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
def test():
1010
emitter_1 = emitting.Emitter()
11-
emitter_2 = emitting.Emitter(inputs=(emitter_1,))
11+
emitter_2 = emitting.Emitter(inputs=emitter_1) # Single item without tuple
1212
emitter_0 = emitting.Emitter(outputs=(emitter_1,))
1313

1414
@misc_tools.set_attributes(call_counter=0)

source_py3/test_python_toolbox/test_nifty_collections/test_ordered_set/__init__.py

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

source_py3/test_python_toolbox/test_nifty_collections/test_ordered_set/test.py

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

0 commit comments

Comments
 (0)