mwxlib 1.6.10__py3-none-any.whl → 1.7.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of mwxlib might be problematic. Click here for more details.
- mwx/bookshelf.py +26 -22
- mwx/controls.py +142 -143
- mwx/framework.py +105 -105
- mwx/graphman.py +85 -85
- mwx/matplot2.py +82 -81
- mwx/matplot2g.py +165 -165
- mwx/matplot2lg.py +57 -57
- mwx/mgplt.py +12 -12
- mwx/nutshell.py +305 -287
- mwx/plugins/ffmpeg_view.py +15 -15
- mwx/plugins/fft_view.py +4 -4
- mwx/plugins/frame_listview.py +26 -26
- mwx/plugins/line_profile.py +1 -1
- mwx/utilus.py +40 -40
- mwx/wxmon.py +20 -20
- mwx/wxpdb.py +45 -45
- mwx/wxwil.py +11 -11
- mwx/wxwit.py +15 -15
- {mwxlib-1.6.10.dist-info → mwxlib-1.7.0.dist-info}/METADATA +1 -1
- mwxlib-1.7.0.dist-info/RECORD +28 -0
- mwxlib-1.6.10.dist-info/RECORD +0 -28
- {mwxlib-1.6.10.dist-info → mwxlib-1.7.0.dist-info}/WHEEL +0 -0
- {mwxlib-1.6.10.dist-info → mwxlib-1.7.0.dist-info}/top_level.txt +0 -0
mwx/plugins/ffmpeg_view.py
CHANGED
|
@@ -62,7 +62,7 @@ class MyFileDropLoader(wx.FileDropTarget):
|
|
|
62
62
|
def __init__(self, target):
|
|
63
63
|
wx.FileDropTarget.__init__(self)
|
|
64
64
|
self.target = target
|
|
65
|
-
|
|
65
|
+
|
|
66
66
|
def OnDropFiles(self, x, y, filenames):
|
|
67
67
|
path = filenames[-1] # Only the last one will be loaded.
|
|
68
68
|
if len(filenames) > 1:
|
|
@@ -77,7 +77,7 @@ class Plugin(Layer):
|
|
|
77
77
|
"""
|
|
78
78
|
menukey = "Plugins/Extensions/FFMpeg viewer"
|
|
79
79
|
dockable = False
|
|
80
|
-
|
|
80
|
+
|
|
81
81
|
def Init(self):
|
|
82
82
|
self.mc = wx.media.MediaCtrl()
|
|
83
83
|
self.mc.Create(self, size=(300,300),
|
|
@@ -156,25 +156,25 @@ class Plugin(Layer):
|
|
|
156
156
|
|
|
157
157
|
self.mc.Bind(wx.EVT_KEY_DOWN, self.on_hotkey_down)
|
|
158
158
|
self.mc.Bind(wx.EVT_KEY_UP, self.on_hotkey_up)
|
|
159
|
-
|
|
159
|
+
|
|
160
160
|
def Destroy(self):
|
|
161
161
|
self.parent.handler.unbind("unknown_format", self.load_media)
|
|
162
162
|
if self.mc:
|
|
163
163
|
self.mc.Destroy()
|
|
164
164
|
return Layer.Destroy(self)
|
|
165
|
-
|
|
165
|
+
|
|
166
166
|
def OnShow(self, evt):
|
|
167
167
|
if not evt.IsShown():
|
|
168
168
|
if self.mc:
|
|
169
169
|
self.mc.Stop()
|
|
170
170
|
Layer.OnShow(self, evt)
|
|
171
|
-
|
|
171
|
+
|
|
172
172
|
def OnMediaLoaded(self, evt):
|
|
173
173
|
self.ss.range = (0, self.video_dur, 0.01)
|
|
174
174
|
self.to.range = (0, self.video_dur, 0.01)
|
|
175
175
|
self.Show()
|
|
176
176
|
evt.Skip()
|
|
177
|
-
|
|
177
|
+
|
|
178
178
|
def load_media(self, path=None):
|
|
179
179
|
if path is None:
|
|
180
180
|
with wx.FileDialog(self, "Choose a media file",
|
|
@@ -202,19 +202,19 @@ class Plugin(Layer):
|
|
|
202
202
|
else:
|
|
203
203
|
self.message(f"Failed to load file {path!r}.")
|
|
204
204
|
return False
|
|
205
|
-
|
|
205
|
+
|
|
206
206
|
DELTA = 1000 # correction ▲理由は不明 (WMP10 backend only?)
|
|
207
|
-
|
|
207
|
+
|
|
208
208
|
def set_offset(self, tc):
|
|
209
209
|
"""Set offset value by referring to ss/to value."""
|
|
210
210
|
if self._path:
|
|
211
211
|
self.mc.Seek(self.DELTA + int(tc.value * 1000))
|
|
212
|
-
|
|
212
|
+
|
|
213
213
|
def get_offset(self, tc):
|
|
214
214
|
"""Get offset value and assigns it to ss/to value."""
|
|
215
215
|
if self._path:
|
|
216
216
|
tc.value = round(self.mc.Tell()) / 1000
|
|
217
|
-
|
|
217
|
+
|
|
218
218
|
def set_crop(self):
|
|
219
219
|
"""Set crop area (W:H:Left:Top) to ROI."""
|
|
220
220
|
if not self._path:
|
|
@@ -230,7 +230,7 @@ class Plugin(Layer):
|
|
|
230
230
|
frame.region = frame.xyfrompixel(nx, ny)
|
|
231
231
|
except Exception:
|
|
232
232
|
self.message("Failed to evaluate crop text.")
|
|
233
|
-
|
|
233
|
+
|
|
234
234
|
def get_crop(self):
|
|
235
235
|
"""Get crop area (W:H:Left:Top) from ROI."""
|
|
236
236
|
if not self._path:
|
|
@@ -246,7 +246,7 @@ class Plugin(Layer):
|
|
|
246
246
|
if not crop:
|
|
247
247
|
crop = "{}:{}:0:0".format(*self.video_size)
|
|
248
248
|
self.crop.Value = crop
|
|
249
|
-
|
|
249
|
+
|
|
250
250
|
def seekto(self, offset):
|
|
251
251
|
"""Seek position with offset [ms] from the `to` position."""
|
|
252
252
|
if self._path:
|
|
@@ -254,14 +254,14 @@ class Plugin(Layer):
|
|
|
254
254
|
if 0 <= t < self.video_dur:
|
|
255
255
|
self.to.value = round(t, 3)
|
|
256
256
|
self.set_offset(self.to)
|
|
257
|
-
|
|
257
|
+
|
|
258
258
|
def seekd(self, offset):
|
|
259
259
|
"""Seek position with offset [ms] from the current position."""
|
|
260
260
|
if self._path:
|
|
261
261
|
t = self.mc.Tell() + offset
|
|
262
262
|
if 0 <= t < self.video_dur * 1000:
|
|
263
263
|
self.mc.Seek(self.DELTA + t)
|
|
264
|
-
|
|
264
|
+
|
|
265
265
|
def snapshot(self):
|
|
266
266
|
"""Create a snapshot of the current frame.
|
|
267
267
|
Load the snapshot image into the graph window.
|
|
@@ -273,7 +273,7 @@ class Plugin(Layer):
|
|
|
273
273
|
buf = capture_video(self._path, t/1000).reshape((h,w,3))
|
|
274
274
|
name = "{}-ss{}".format(os.path.basename(self._path), int(t))
|
|
275
275
|
self.graph.load(buf, name)
|
|
276
|
-
|
|
276
|
+
|
|
277
277
|
def export(self):
|
|
278
278
|
"""Export the cropped / clipped data to a media file."""
|
|
279
279
|
if not self._path:
|
mwx/plugins/fft_view.py
CHANGED
|
@@ -28,7 +28,7 @@ class Plugin(Layer):
|
|
|
28
28
|
"""
|
|
29
29
|
menukey = "Plugins/Extensions/&FFT view\tAlt+f"
|
|
30
30
|
caption = "FFT view"
|
|
31
|
-
|
|
31
|
+
|
|
32
32
|
def Init(self):
|
|
33
33
|
self.pchk = wx.CheckBox(self, label="logical unit")
|
|
34
34
|
self.pchk.Value = True
|
|
@@ -40,12 +40,12 @@ class Plugin(Layer):
|
|
|
40
40
|
|
|
41
41
|
self.parent.define_key('C-f', self.newfft)
|
|
42
42
|
self.parent.define_key('C-S-f', self.newifft)
|
|
43
|
-
|
|
43
|
+
|
|
44
44
|
def Destroy(self):
|
|
45
45
|
self.parent.undefine_key('C-f')
|
|
46
46
|
self.parent.undefine_key('C-S-f')
|
|
47
47
|
return Layer.Destroy(self)
|
|
48
|
-
|
|
48
|
+
|
|
49
49
|
def newfft(self):
|
|
50
50
|
"""New FFT of graph to output."""
|
|
51
51
|
frame = self.graph.frame
|
|
@@ -62,7 +62,7 @@ class Plugin(Layer):
|
|
|
62
62
|
u /= frame.unit
|
|
63
63
|
self.output.load(dst, f"*fft of {frame.name}*", localunit=u)
|
|
64
64
|
self.message("\b done")
|
|
65
|
-
|
|
65
|
+
|
|
66
66
|
def newifft(self):
|
|
67
67
|
"""New inverse FFT of output to graph."""
|
|
68
68
|
frame = self.output.frame
|
mwx/plugins/frame_listview.py
CHANGED
|
@@ -21,15 +21,15 @@ class CheckList(wx.ListCtrl, ListCtrlAutoWidthMixin, CtrlInterface):
|
|
|
21
21
|
@property
|
|
22
22
|
def selected_items(self):
|
|
23
23
|
return filter(self.IsSelected, range(self.ItemCount))
|
|
24
|
-
|
|
24
|
+
|
|
25
25
|
@property
|
|
26
26
|
def checked_items(self):
|
|
27
27
|
return filter(self.IsItemChecked, range(self.ItemCount))
|
|
28
|
-
|
|
28
|
+
|
|
29
29
|
@property
|
|
30
30
|
def focused_item(self):
|
|
31
31
|
return self.FocusedItem
|
|
32
|
-
|
|
32
|
+
|
|
33
33
|
@property
|
|
34
34
|
def all_items(self):
|
|
35
35
|
rows = range(self.ItemCount)
|
|
@@ -37,7 +37,7 @@ class CheckList(wx.ListCtrl, ListCtrlAutoWidthMixin, CtrlInterface):
|
|
|
37
37
|
## return [[self.GetItemText(j, k) for k in cols] for j in rows]
|
|
38
38
|
for j in rows:
|
|
39
39
|
yield [self.GetItemText(j, k) for k in cols]
|
|
40
|
-
|
|
40
|
+
|
|
41
41
|
def __init__(self, parent, target, **kwargs):
|
|
42
42
|
wx.ListCtrl.__init__(self, parent, size=(400,130),
|
|
43
43
|
style=wx.LC_REPORT|wx.LC_HRULES, **kwargs)
|
|
@@ -115,11 +115,11 @@ class CheckList(wx.ListCtrl, ListCtrlAutoWidthMixin, CtrlInterface):
|
|
|
115
115
|
]
|
|
116
116
|
self.Bind(wx.EVT_CONTEXT_MENU,
|
|
117
117
|
lambda v: Menu.Popup(self, self.menu))
|
|
118
|
-
|
|
118
|
+
|
|
119
119
|
def Destroy(self):
|
|
120
120
|
self.Target.handler.remove(self.context)
|
|
121
121
|
return wx.ListCtrl.Destroy(self)
|
|
122
|
-
|
|
122
|
+
|
|
123
123
|
def UpdateInfo(self, frame):
|
|
124
124
|
ls = ("{}".format(frame.index),
|
|
125
125
|
"{}".format(frame.name),
|
|
@@ -134,13 +134,13 @@ class CheckList(wx.ListCtrl, ListCtrlAutoWidthMixin, CtrlInterface):
|
|
|
134
134
|
self.SetItem(j, k, v)
|
|
135
135
|
if frame.pathname:
|
|
136
136
|
self.CheckItem(j)
|
|
137
|
-
|
|
137
|
+
|
|
138
138
|
def OnShowItems(self, evt):
|
|
139
139
|
self.Target.select(self.focused_item)
|
|
140
|
-
|
|
140
|
+
|
|
141
141
|
def OnRemoveItems(self, evt):
|
|
142
142
|
del self.Target[self.selected_items]
|
|
143
|
-
|
|
143
|
+
|
|
144
144
|
def OnSortItems(self, evt): #<wx._controls.ListEvent>
|
|
145
145
|
col = evt.Column
|
|
146
146
|
if col == 0: # reverse the first column
|
|
@@ -166,14 +166,14 @@ class CheckList(wx.ListCtrl, ListCtrlAutoWidthMixin, CtrlInterface):
|
|
|
166
166
|
for k, v in enumerate(c[1:]): # update data except for id(0)
|
|
167
167
|
self.SetItem(j, k+1, v)
|
|
168
168
|
self.Target.select(frame) # invokes [frame_shown] to select the item
|
|
169
|
-
|
|
169
|
+
|
|
170
170
|
def OnSelectAllItems(self, evt):
|
|
171
171
|
for j in range(self.ItemCount):
|
|
172
172
|
self.Select(j)
|
|
173
|
-
|
|
173
|
+
|
|
174
174
|
def OnLoadItems(self, evt):
|
|
175
175
|
self.parent.parent.load_index(view=self.Target)
|
|
176
|
-
|
|
176
|
+
|
|
177
177
|
def OnSaveItems(self, evt):
|
|
178
178
|
selected_frames = [self.Target.all_frames[j] for j in self.selected_items]
|
|
179
179
|
if selected_frames:
|
|
@@ -181,7 +181,7 @@ class CheckList(wx.ListCtrl, ListCtrlAutoWidthMixin, CtrlInterface):
|
|
|
181
181
|
self.parent.parent.save_index(frames=selected_frames)
|
|
182
182
|
else:
|
|
183
183
|
self.parent.message("No frame selected.")
|
|
184
|
-
|
|
184
|
+
|
|
185
185
|
def OnCopyInfo(self, evt):
|
|
186
186
|
selected_frames = [self.Target.all_frames[j] for j in self.selected_items]
|
|
187
187
|
if selected_frames:
|
|
@@ -191,7 +191,7 @@ class CheckList(wx.ListCtrl, ListCtrlAutoWidthMixin, CtrlInterface):
|
|
|
191
191
|
Clipboard.write('\n'.join(text))
|
|
192
192
|
else:
|
|
193
193
|
self.parent.message("No frame selected.")
|
|
194
|
-
|
|
194
|
+
|
|
195
195
|
def OnEditLocalUnit(self, evt):
|
|
196
196
|
frame = self.Target.all_frames[self.focused_item]
|
|
197
197
|
with wx.TextEntryDialog(self, frame.name,
|
|
@@ -199,7 +199,7 @@ class CheckList(wx.ListCtrl, ListCtrlAutoWidthMixin, CtrlInterface):
|
|
|
199
199
|
if dlg.ShowModal() == wx.ID_OK:
|
|
200
200
|
frame.unit = eval(dlg.Value or 'None')
|
|
201
201
|
self.SetFocus()
|
|
202
|
-
|
|
202
|
+
|
|
203
203
|
def OnEditAnnotation(self, evt):
|
|
204
204
|
frame = self.Target.all_frames[self.focused_item]
|
|
205
205
|
with wx.TextEntryDialog(self, frame.name,
|
|
@@ -207,34 +207,34 @@ class CheckList(wx.ListCtrl, ListCtrlAutoWidthMixin, CtrlInterface):
|
|
|
207
207
|
if dlg.ShowModal() == wx.ID_OK:
|
|
208
208
|
frame.annotation = dlg.Value
|
|
209
209
|
self.SetFocus()
|
|
210
|
-
|
|
210
|
+
|
|
211
211
|
def OnItemSelected(self, evt):
|
|
212
212
|
frame = self.Target.all_frames[evt.Index]
|
|
213
213
|
self.parent.message(frame.pathname)
|
|
214
214
|
evt.Skip()
|
|
215
|
-
|
|
215
|
+
|
|
216
216
|
## --------------------------------
|
|
217
217
|
## Actions of frame-handler
|
|
218
218
|
## --------------------------------
|
|
219
|
-
|
|
219
|
+
|
|
220
220
|
def on_frame_loaded(self, frame):
|
|
221
221
|
j = frame.index
|
|
222
222
|
self.InsertItem(j, str(j))
|
|
223
223
|
for k in range(j+1, self.ItemCount): # id(0) を更新する
|
|
224
224
|
self.SetItem(k, 0, str(k))
|
|
225
225
|
self.UpdateInfo(frame)
|
|
226
|
-
|
|
226
|
+
|
|
227
227
|
def on_frame_shown(self, frame):
|
|
228
228
|
j = frame.index
|
|
229
229
|
self.SetItemFont(j, self.Font.Bold())
|
|
230
230
|
self.Select(j)
|
|
231
231
|
self.Focus(j)
|
|
232
|
-
|
|
232
|
+
|
|
233
233
|
def on_frame_hidden(self, frame):
|
|
234
234
|
j = frame.index
|
|
235
235
|
self.SetItemFont(j, self.Font)
|
|
236
236
|
self.Select(j, False)
|
|
237
|
-
|
|
237
|
+
|
|
238
238
|
def on_frames_removed(self, indices):
|
|
239
239
|
with wx.FrozenWindow(self):
|
|
240
240
|
for j in reversed(indices):
|
|
@@ -249,15 +249,15 @@ class Plugin(Layer):
|
|
|
249
249
|
menukey = "Plugins/Extensions/&Buffer listbox\tAlt+b"
|
|
250
250
|
caption = "Property list"
|
|
251
251
|
dockable = False
|
|
252
|
-
|
|
252
|
+
|
|
253
253
|
@property
|
|
254
254
|
def all_pages(self):
|
|
255
255
|
return [self.nb.GetPage(i) for i in range(self.nb.PageCount)]
|
|
256
|
-
|
|
256
|
+
|
|
257
257
|
@property
|
|
258
258
|
def message(self):
|
|
259
259
|
return self.statusline
|
|
260
|
-
|
|
260
|
+
|
|
261
261
|
def Init(self):
|
|
262
262
|
self.nb = aui.AuiNotebook(self, size=(400,150),
|
|
263
263
|
style = (aui.AUI_NB_DEFAULT_STYLE|aui.AUI_NB_RIGHT)
|
|
@@ -278,12 +278,12 @@ class Plugin(Layer):
|
|
|
278
278
|
self.parent.select_view(self.nb.CurrentPage.Target)
|
|
279
279
|
evt.Skip()
|
|
280
280
|
self.nb.Bind(wx.EVT_CHILD_FOCUS, on_focus_set)
|
|
281
|
-
|
|
281
|
+
|
|
282
282
|
def attach(self, target, caption):
|
|
283
283
|
if target not in [lc.Target for lc in self.all_pages]:
|
|
284
284
|
lc = CheckList(self, target)
|
|
285
285
|
self.nb.AddPage(lc, caption)
|
|
286
|
-
|
|
286
|
+
|
|
287
287
|
def detach(self, target):
|
|
288
288
|
for k, lc in enumerate(self.all_pages):
|
|
289
289
|
if target is lc.Target:
|
mwx/plugins/line_profile.py
CHANGED
mwx/utilus.py
CHANGED
|
@@ -467,15 +467,15 @@ def get_rootpath(fn):
|
|
|
467
467
|
## --------------------------------
|
|
468
468
|
|
|
469
469
|
class SSM(dict):
|
|
470
|
-
"""Single State Machine/Context of FSM
|
|
470
|
+
"""Single State Machine/Context of FSM.
|
|
471
471
|
"""
|
|
472
472
|
def __call__(self, event, *args, **kwargs):
|
|
473
473
|
for act in self[event]:
|
|
474
474
|
act(*args, **kwargs)
|
|
475
|
-
|
|
475
|
+
|
|
476
476
|
def __repr__(self):
|
|
477
477
|
return "<{} object at 0x{:X}>".format(self.__class__.__name__, id(self))
|
|
478
|
-
|
|
478
|
+
|
|
479
479
|
def __str__(self):
|
|
480
480
|
def _lstr(v):
|
|
481
481
|
def _name(a):
|
|
@@ -484,7 +484,7 @@ class SSM(dict):
|
|
|
484
484
|
return repr(a)
|
|
485
485
|
return ', '.join(_name(a) for a in v)
|
|
486
486
|
return '\n'.join("{:>32} : {}".format(str(k), _lstr(v)) for k, v in self.items())
|
|
487
|
-
|
|
487
|
+
|
|
488
488
|
def bind(self, event, action=None):
|
|
489
489
|
"""Append a transaction to the context."""
|
|
490
490
|
assert callable(action) or action is None
|
|
@@ -496,7 +496,7 @@ class SSM(dict):
|
|
|
496
496
|
if action not in transaction:
|
|
497
497
|
transaction.append(action)
|
|
498
498
|
return action
|
|
499
|
-
|
|
499
|
+
|
|
500
500
|
def unbind(self, event, action=None):
|
|
501
501
|
"""Remove a transaction from the context."""
|
|
502
502
|
assert callable(action) or action is None
|
|
@@ -513,7 +513,7 @@ class SSM(dict):
|
|
|
513
513
|
|
|
514
514
|
|
|
515
515
|
class FSM(dict):
|
|
516
|
-
"""Finite State Machine
|
|
516
|
+
"""Finite State Machine.
|
|
517
517
|
|
|
518
518
|
Args:
|
|
519
519
|
contexts: map of context <DNA>
|
|
@@ -544,20 +544,20 @@ class FSM(dict):
|
|
|
544
544
|
There is no enter/exit event handler.
|
|
545
545
|
"""
|
|
546
546
|
debug = 0
|
|
547
|
-
|
|
547
|
+
|
|
548
548
|
default_state = None
|
|
549
549
|
current_state = property(lambda self: self.__state)
|
|
550
550
|
previous_state = property(lambda self: self.__prev_state)
|
|
551
|
-
|
|
551
|
+
|
|
552
552
|
current_event = property(lambda self: self.__event)
|
|
553
553
|
previous_event = property(lambda self: self.__prev_event)
|
|
554
|
-
|
|
554
|
+
|
|
555
555
|
@current_state.setter
|
|
556
556
|
def current_state(self, state):
|
|
557
557
|
self.__state = state
|
|
558
558
|
self.__event = '*forced*'
|
|
559
559
|
self.__debcall__(self.__event)
|
|
560
|
-
|
|
560
|
+
|
|
561
561
|
def clear(self, state):
|
|
562
562
|
"""Reset current and previous states."""
|
|
563
563
|
self.__state = state
|
|
@@ -565,7 +565,7 @@ class FSM(dict):
|
|
|
565
565
|
self.__event = None
|
|
566
566
|
self.__prev_event = None
|
|
567
567
|
self.__matched_pattern = None
|
|
568
|
-
|
|
568
|
+
|
|
569
569
|
def __init__(self, contexts=None, default=None):
|
|
570
570
|
dict.__init__(self) # update dict, however, it does not clear
|
|
571
571
|
dict.clear(self) # if and when __init__ is called, all contents are cleared
|
|
@@ -577,16 +577,16 @@ class FSM(dict):
|
|
|
577
577
|
self.default_state = default
|
|
578
578
|
self.clear(default) # the first clear creates object localvars
|
|
579
579
|
self.update(contexts)
|
|
580
|
-
|
|
580
|
+
|
|
581
581
|
def __missing__(self, key):
|
|
582
582
|
raise Exception("FSM logic-error: undefined state {!r}".format(key))
|
|
583
|
-
|
|
583
|
+
|
|
584
584
|
def __repr__(self):
|
|
585
585
|
return "<{} object at 0x{:X}>".format(self.__class__.__name__, id(self))
|
|
586
|
-
|
|
586
|
+
|
|
587
587
|
def __str__(self):
|
|
588
588
|
return '\n'.join("[ {!r} ]\n{!s}".format(k, v) for k, v in self.items())
|
|
589
|
-
|
|
589
|
+
|
|
590
590
|
def __call__(self, event, *args, **kwargs):
|
|
591
591
|
"""Handle the event.
|
|
592
592
|
|
|
@@ -629,7 +629,7 @@ class FSM(dict):
|
|
|
629
629
|
self.__prev_state = self.__state
|
|
630
630
|
if recept:
|
|
631
631
|
return retvals
|
|
632
|
-
|
|
632
|
+
|
|
633
633
|
def fork(self, event, *args, **kwargs):
|
|
634
634
|
"""Invoke the event handlers (internal use only).
|
|
635
635
|
|
|
@@ -640,7 +640,7 @@ class FSM(dict):
|
|
|
640
640
|
ret = self.call(event, *args, **kwargs)
|
|
641
641
|
self.__prev_event = self.__event
|
|
642
642
|
return ret
|
|
643
|
-
|
|
643
|
+
|
|
644
644
|
def call(self, event, *args, **kwargs):
|
|
645
645
|
"""Invoke the event handlers (internal use only).
|
|
646
646
|
|
|
@@ -690,7 +690,7 @@ class FSM(dict):
|
|
|
690
690
|
|
|
691
691
|
self.__debcall__(event, *args, **kwargs) # check when no transition
|
|
692
692
|
return None # no event, no action
|
|
693
|
-
|
|
693
|
+
|
|
694
694
|
def __debcall__(self, pattern, *args, **kwargs):
|
|
695
695
|
v = self.debug
|
|
696
696
|
if v and self.__state is not None:
|
|
@@ -715,11 +715,11 @@ class FSM(dict):
|
|
|
715
715
|
|
|
716
716
|
if v > 7: # max verbose level puts all args
|
|
717
717
|
self.log("\t:", args, kwargs)
|
|
718
|
-
|
|
718
|
+
|
|
719
719
|
@staticmethod
|
|
720
720
|
def log(*args):
|
|
721
721
|
print(*args, file=sys.__stdout__)
|
|
722
|
-
|
|
722
|
+
|
|
723
723
|
@staticmethod
|
|
724
724
|
def dump(*args):
|
|
725
725
|
fn = get_rootpath("deb-dump.log")
|
|
@@ -727,7 +727,7 @@ class FSM(dict):
|
|
|
727
727
|
print(time.strftime('!!! %Y/%m/%d %H:%M:%S'), file=o)
|
|
728
728
|
print(*args, traceback.format_exc(), sep='\n', file=o)
|
|
729
729
|
print(*args, traceback.format_exc(), sep='\n', file=sys.__stderr__)
|
|
730
|
-
|
|
730
|
+
|
|
731
731
|
@staticmethod
|
|
732
732
|
def duplicate(context):
|
|
733
733
|
"""Duplicate the transaction:list in the context.
|
|
@@ -736,7 +736,7 @@ class FSM(dict):
|
|
|
736
736
|
so that the original transaction (if they are lists) is not removed.
|
|
737
737
|
"""
|
|
738
738
|
return {event: transaction[:] for event, transaction in context.items()}
|
|
739
|
-
|
|
739
|
+
|
|
740
740
|
def validate(self, state):
|
|
741
741
|
"""Sort and move to end items with key which includes ``*?[]``."""
|
|
742
742
|
context = self[state]
|
|
@@ -753,7 +753,7 @@ class FSM(dict):
|
|
|
753
753
|
context.update(temp)
|
|
754
754
|
context.update(sorted(bra, reverse=1))
|
|
755
755
|
context.update(sorted(ast, reverse=1, key=lambda v: len(v[0])))
|
|
756
|
-
|
|
756
|
+
|
|
757
757
|
def update(self, contexts):
|
|
758
758
|
"""Update each context or Add new contexts."""
|
|
759
759
|
for k, v in contexts.items():
|
|
@@ -762,7 +762,7 @@ class FSM(dict):
|
|
|
762
762
|
else:
|
|
763
763
|
self[k] = SSM(self.duplicate(v)) # new context
|
|
764
764
|
self.validate(k)
|
|
765
|
-
|
|
765
|
+
|
|
766
766
|
def append(self, contexts):
|
|
767
767
|
"""Append new contexts."""
|
|
768
768
|
for k, v in contexts.items():
|
|
@@ -776,7 +776,7 @@ class FSM(dict):
|
|
|
776
776
|
else:
|
|
777
777
|
self[k] = SSM(self.duplicate(v)) # new context
|
|
778
778
|
self.validate(k)
|
|
779
|
-
|
|
779
|
+
|
|
780
780
|
def remove(self, contexts):
|
|
781
781
|
"""Remove old contexts."""
|
|
782
782
|
for k, v in contexts.items():
|
|
@@ -791,7 +791,7 @@ class FSM(dict):
|
|
|
791
791
|
for k, v in list(self.items()): # self mutates during iteration
|
|
792
792
|
if not v:
|
|
793
793
|
del self[k]
|
|
794
|
-
|
|
794
|
+
|
|
795
795
|
def bind(self, event, action=None, state=None, state2=None):
|
|
796
796
|
"""Append a transaction to the context.
|
|
797
797
|
|
|
@@ -835,7 +835,7 @@ class FSM(dict):
|
|
|
835
835
|
warn(f"- FSM cannot append new transaction ({state!r} : {event!r}).\n"
|
|
836
836
|
f" The transaction must be a list, not a tuple.")
|
|
837
837
|
return action
|
|
838
|
-
|
|
838
|
+
|
|
839
839
|
def binds(self, event, action=None, state=None, state2=None):
|
|
840
840
|
"""Append a one-time transaction to the context.
|
|
841
841
|
|
|
@@ -851,7 +851,7 @@ class FSM(dict):
|
|
|
851
851
|
finally:
|
|
852
852
|
self.unbind(event, _act, state)
|
|
853
853
|
return self.bind(event, _act, state, state2)
|
|
854
|
-
|
|
854
|
+
|
|
855
855
|
def unbind(self, event, action=None, state=None):
|
|
856
856
|
"""Remove a transaction from the context.
|
|
857
857
|
|
|
@@ -901,41 +901,41 @@ class TreeList:
|
|
|
901
901
|
"""
|
|
902
902
|
def __init__(self, ls=None):
|
|
903
903
|
self.__items = ls or []
|
|
904
|
-
|
|
904
|
+
|
|
905
905
|
def __call__(self, k):
|
|
906
906
|
return TreeList(self[k])
|
|
907
|
-
|
|
907
|
+
|
|
908
908
|
def __len__(self):
|
|
909
909
|
return len(self.__items)
|
|
910
|
-
|
|
910
|
+
|
|
911
911
|
def __contains__(self, k):
|
|
912
912
|
return self._getf(self.__items, k)
|
|
913
|
-
|
|
913
|
+
|
|
914
914
|
def __iter__(self):
|
|
915
915
|
return self.__items.__iter__()
|
|
916
|
-
|
|
916
|
+
|
|
917
917
|
def __getitem__(self, k):
|
|
918
918
|
if isinstance(k, str):
|
|
919
919
|
return self._getf(self.__items, k)
|
|
920
920
|
return self.__items.__getitem__(k)
|
|
921
|
-
|
|
921
|
+
|
|
922
922
|
def __setitem__(self, k, v):
|
|
923
923
|
if isinstance(k, str):
|
|
924
924
|
return self._setf(self.__items, k, v)
|
|
925
925
|
return self.__items.__setitem__(k, v)
|
|
926
|
-
|
|
926
|
+
|
|
927
927
|
def __delitem__(self, k):
|
|
928
928
|
if isinstance(k, str):
|
|
929
929
|
return self._delf(self.__items, k)
|
|
930
930
|
return self.__items.__delitem__(k)
|
|
931
|
-
|
|
931
|
+
|
|
932
932
|
def _find_item(self, ls, key):
|
|
933
933
|
for x in ls:
|
|
934
934
|
if isinstance(x, (tuple, list)) and x and x[0] == key:
|
|
935
935
|
if len(x) < 2:
|
|
936
936
|
raise ValueError(f"No value for {key=!r}")
|
|
937
937
|
return x
|
|
938
|
-
|
|
938
|
+
|
|
939
939
|
def _getf(self, ls, key):
|
|
940
940
|
if '/' in key:
|
|
941
941
|
a, b = key.split('/', 1)
|
|
@@ -946,7 +946,7 @@ class TreeList:
|
|
|
946
946
|
li = self._find_item(ls, key)
|
|
947
947
|
if li is not None:
|
|
948
948
|
return li[-1]
|
|
949
|
-
|
|
949
|
+
|
|
950
950
|
def _setf(self, ls, key, value):
|
|
951
951
|
if '/' in key:
|
|
952
952
|
a, b = key.split('/', 1)
|
|
@@ -966,7 +966,7 @@ class TreeList:
|
|
|
966
966
|
ls.append([key, value]) # append to items:list
|
|
967
967
|
except (ValueError, TypeError, AttributeError) as e:
|
|
968
968
|
warn(f"- TreeList {e!r}: {key=!r}")
|
|
969
|
-
|
|
969
|
+
|
|
970
970
|
def _delf(self, ls, key):
|
|
971
971
|
if '/' in key:
|
|
972
972
|
p, key = key.rsplit('/', 1)
|
|
@@ -1055,7 +1055,7 @@ def get_fullargspec(f):
|
|
|
1055
1055
|
|
|
1056
1056
|
|
|
1057
1057
|
def funcall(f, *args, doc=None, alias=None, **kwargs):
|
|
1058
|
-
"""Decorator of event handler
|
|
1058
|
+
"""Decorator of event handler.
|
|
1059
1059
|
|
|
1060
1060
|
Check if the event argument can be omitted and if any other
|
|
1061
1061
|
required arguments are specified in args and kwargs.
|