mwxlib 0.96.1__py3-none-any.whl → 0.96.5__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 CHANGED
@@ -1,4 +1,5 @@
1
1
  #! python3
2
+ from functools import partial
2
3
  import re
3
4
  import wx
4
5
 
mwx/controls.py CHANGED
@@ -8,6 +8,7 @@ import wx.lib.scrolledpanel as scrolled
8
8
 
9
9
  from . import images
10
10
  from .utilus import SSM
11
+ from .utilus import warn
11
12
  from .utilus import funcall as _F
12
13
  from .framework import pack, Menu
13
14
 
@@ -15,11 +16,6 @@ import numpy as np
15
16
  from numpy import nan, inf # noqa: necessary to eval
16
17
 
17
18
 
18
- def _Tip(*tips):
19
- """Concatenate tips with newline char."""
20
- return '\n'.join(filter(None, tips)).strip()
21
-
22
-
23
19
  class Param(object):
24
20
  """Standard Parameter
25
21
 
@@ -43,7 +39,7 @@ class Param(object):
43
39
  - underflow -> when value underflows
44
40
  """
45
41
  def __init__(self, name, range=None, value=None, fmt=None,
46
- handler=None, updater=None, tip=None):
42
+ handler=None, updater=None):
47
43
  self.knobs = []
48
44
  self.name = name
49
45
  self.range = range
@@ -65,7 +61,9 @@ class Param(object):
65
61
  'overflow' : [],
66
62
  'underflow' : [],
67
63
  })
68
- self._tooltip = _Tip(tip, handler.__doc__, updater.__doc__)
64
+ ## Concatenate tips with newline char.
65
+ tips = (handler.__doc__, updater.__doc__)
66
+ self._tooltip = '\n'.join(filter(None, tips)).strip()
69
67
 
70
68
  def __str__(self, v=None):
71
69
  v = self.value if v is None else v
@@ -83,12 +81,12 @@ class Param(object):
83
81
  def __len__(self):
84
82
  return len(self.range)
85
83
 
86
- @wx.deprecatedMsg("Use `Param.callback.bind` instead.") #<DeprecationWarning>
87
84
  def bind(self, action=None, target='control'):
85
+ warn("Use `Param.callback.bind` instead.", DeprecationWarning)
88
86
  return self.callback.bind(target, action)
89
87
 
90
- @wx.deprecatedMsg("Use `Param.callback.unbind` instead.") #<DeprecationWarning>
91
88
  def unbind(self, action=None, target='control'):
89
+ warn("Use `Param.callback.unbind` instead.", DeprecationWarning)
92
90
  return self.callback.unbind(target, action)
93
91
 
94
92
  def reset(self, v=None, backcall=True):
@@ -295,7 +293,6 @@ class Knob(wx.Panel):
295
293
  None -> static text (default)
296
294
  chkbox -> label with check box
297
295
  button -> label with flat button
298
- editable: textctrl is editable or readonly
299
296
  cw : width of ctrl
300
297
  lw : width of label
301
298
  tw : width of textbox
@@ -355,23 +352,22 @@ class Knob(wx.Panel):
355
352
  else:
356
353
  raise Exception("unknown style: {!r}".format(style))
357
354
 
358
- self.label.Enable(lw)
359
355
  self.label.Bind(wx.EVT_MIDDLE_DOWN, lambda v: self.__par.reset())
360
-
361
356
  self.label.SetToolTip(self.__par._tooltip)
357
+ self.label.Enable(lw) # skip focus
362
358
 
363
- if editable:
364
- self.text = wx.TextCtrl(self, size=(tw,h), style=wx.TE_PROCESS_ENTER)
365
- self.text.Bind(wx.EVT_TEXT_ENTER, self.OnTextEnter)
366
- self.text.Bind(wx.EVT_KILL_FOCUS, self.OnTextExit)
367
- self.text.Bind(wx.EVT_KEY_DOWN, self.OnTextKeyDown)
368
- self.text.Bind(wx.EVT_KEY_UP, self.OnTextKeyUp)
369
- self.text.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheel)
370
- self.text.Bind(wx.EVT_MIDDLE_DOWN, lambda v: self.__par.reset())
371
- else:
372
- self.text = wx.TextCtrl(self, size=(tw,h), style=wx.TE_READONLY)
359
+ if not editable:
360
+ warn("Knob option `editable` is deprecated.", DeprecationWarning)
361
+
362
+ self.text = wx.TextCtrl(self, size=(tw,h), style=wx.TE_PROCESS_ENTER)
363
+ self.text.Bind(wx.EVT_TEXT_ENTER, self.OnTextEnter)
364
+ self.text.Bind(wx.EVT_KILL_FOCUS, self.OnTextExit)
365
+ self.text.Bind(wx.EVT_KEY_DOWN, self.OnTextKeyDown)
366
+ self.text.Bind(wx.EVT_KEY_UP, self.OnTextKeyUp)
367
+ self.text.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheel)
368
+ self.text.Bind(wx.EVT_MIDDLE_DOWN, lambda v: self.__par.reset())
373
369
 
374
- self.text.Enable(tw)
370
+ self.text.Enable(tw) # skip focus
375
371
 
376
372
  if type == 'slider':
377
373
  self.ctrl = wx.Slider(self, size=(cw,h), style=wx.SL_HORIZONTAL)
@@ -405,8 +401,8 @@ class Knob(wx.Panel):
405
401
  else:
406
402
  raise Exception("unknown type: {!r}".format(type))
407
403
 
408
- self.ctrl.Enable(cw != 0)
409
404
  self.ctrl.Bind(wx.EVT_MIDDLE_DOWN, lambda v: self.__par.reset())
405
+ self.ctrl.Enable(cw) # skip focus
410
406
 
411
407
  c = (cw and type != 'vspin')
412
408
  self.SetSizer(
@@ -426,6 +422,7 @@ class Knob(wx.Panel):
426
422
  evt.Skip()
427
423
 
428
424
  def update_range(self):
425
+ """Called when range is being changed (internal use only)."""
429
426
  v = self.__par
430
427
  if isinstance(self.ctrl, wx.Choice): #<wx.Choice>
431
428
  items = [v.__str__(x) for x in v.range]
@@ -436,6 +433,7 @@ class Knob(wx.Panel):
436
433
  self.ctrl.SetRange(0, len(v)-1) #<wx.Slider> <wx.SpinButton>
437
434
 
438
435
  def update_label(self):
436
+ """Called when label is being changed (internal use only)."""
439
437
  v = self.__par
440
438
  if isinstance(self.label, wx.CheckBox):
441
439
  self.label.SetValue(v.check)
@@ -446,6 +444,7 @@ class Knob(wx.Panel):
446
444
  self.label.Refresh()
447
445
 
448
446
  def update_ctrl(self, valid=True, notify=False):
447
+ """Called when value is being changed (internal use only)."""
449
448
  v = self.__par
450
449
  try:
451
450
  j = v.index
@@ -766,32 +765,32 @@ class Clipboard:
766
765
  The clipboard data cannot be transferred unless wx.Frame exists.
767
766
  """
768
767
  @staticmethod
769
- def read(verbose=True):
768
+ def read(verbose=False):
770
769
  do = wx.TextDataObject()
771
770
  if wx.TheClipboard.Open():
772
771
  wx.TheClipboard.GetData(do)
773
772
  wx.TheClipboard.Close()
774
773
  text = do.GetText()
775
774
  if verbose:
776
- print("From clipboard: {}".format(text))
775
+ print(f"From clipboard:\n{text}")
777
776
  return text
778
777
  else:
779
778
  print("- Unable to open clipboard.")
780
779
 
781
780
  @staticmethod
782
- def write(text, verbose=True):
781
+ def write(text, verbose=False):
783
782
  do = wx.TextDataObject(str(text))
784
783
  if wx.TheClipboard.Open():
785
784
  wx.TheClipboard.SetData(do)
786
785
  wx.TheClipboard.Flush()
787
786
  wx.TheClipboard.Close()
788
787
  if verbose:
789
- print("To clipboard: {}".format(text))
788
+ print(f"To clipboard:\n{text}")
790
789
  else:
791
790
  print("- Unable to open clipboard.")
792
791
 
793
792
  @staticmethod
794
- def imread(verbose=True):
793
+ def imread(verbose=False):
795
794
  do = wx.BitmapDataObject()
796
795
  if wx.TheClipboard.Open():
797
796
  wx.TheClipboard.GetData(do)
@@ -805,14 +804,14 @@ class Clipboard:
805
804
  img = bmp.ConvertToImage()
806
805
  buf = np.array(img.GetDataBuffer()) # do copy, don't ref
807
806
  if verbose:
808
- print("From clipboard {:.1f} Mb data".format(buf.nbytes/1e6))
807
+ print("From clipboard: {:.1f} Mb data read.".format(buf.nbytes/1e6))
809
808
  w, h = img.GetSize()
810
809
  return buf.reshape(h, w, 3)
811
810
  except Exception:
812
811
  print("- The contents of the clipboard are not images.")
813
812
 
814
813
  @staticmethod
815
- def imwrite(buf, verbose=True):
814
+ def imwrite(buf, verbose=False):
816
815
  try:
817
816
  ## Convert buf --> bmp
818
817
  h, w = buf.shape[:2]
@@ -830,7 +829,7 @@ class Clipboard:
830
829
  wx.TheClipboard.Flush()
831
830
  wx.TheClipboard.Close()
832
831
  if verbose:
833
- print("To clipboard: {:.1f} Mb data".format(buf.nbytes/1e6))
832
+ print("To clipboard: {:.1f} Mb data written.".format(buf.nbytes/1e6))
834
833
  else:
835
834
  print("- Unable to open clipboard.")
836
835
 
@@ -998,15 +997,14 @@ class Button(pb.PlateButton):
998
997
  self.SetBitmap(_Icon(v))
999
998
  self.Refresh()
1000
999
 
1001
- def __init__(self, parent, label='',
1002
- handler=None, icon=None, tip='', **kwargs):
1000
+ def __init__(self, parent, label='', handler=None, icon=None, **kwargs):
1003
1001
  kwargs.setdefault('style', pb.PB_STYLE_DEFAULT | pb.PB_STYLE_SQUARE)
1004
1002
  pb.PlateButton.__init__(self, parent, -1, label, **kwargs)
1005
1003
 
1006
1004
  if handler:
1007
1005
  self.Bind(wx.EVT_BUTTON, _F(handler))
1008
1006
 
1009
- self.ToolTip = _Tip(tip, handler.__doc__)
1007
+ self.ToolTip = handler.__doc__
1010
1008
  self.icon = icon
1011
1009
 
1012
1010
  def SetBitmap(self, bmp):
@@ -1046,14 +1044,13 @@ class ToggleButton(wx.ToggleButton):
1046
1044
  self.SetBitmap(_Icon(v))
1047
1045
  self.Refresh()
1048
1046
 
1049
- def __init__(self, parent, label='',
1050
- handler=None, icon=None, tip='', **kwargs):
1047
+ def __init__(self, parent, label='', handler=None, icon=None, **kwargs):
1051
1048
  wx.ToggleButton.__init__(self, parent, -1, label, **kwargs)
1052
1049
 
1053
1050
  if handler:
1054
1051
  self.Bind(wx.EVT_TOGGLEBUTTON, _F(handler))
1055
1052
 
1056
- self.ToolTip = _Tip(tip, handler.__doc__)
1053
+ self.ToolTip = handler.__doc__
1057
1054
  self.icon = icon
1058
1055
 
1059
1056
 
@@ -1085,20 +1082,20 @@ class TextCtrl(wx.Control):
1085
1082
  def icon(self, v):
1086
1083
  self._btn.icon = v
1087
1084
 
1088
- def __init__(self, parent, label='',
1089
- handler=None, updater=None, size=(-1,-1),
1090
- icon=None, tip='', readonly=False, **kwargs):
1085
+ def __init__(self, parent, label='', handler=None, updater=None,
1086
+ icon=None, readonly=False, size=(-1,-1), **kwargs):
1091
1087
  wx.Control.__init__(self, parent, size=size, style=wx.BORDER_NONE)
1092
1088
 
1093
1089
  kwargs['style'] = (kwargs.get('style', 0)
1094
1090
  | wx.TE_PROCESS_ENTER
1095
1091
  | (wx.TE_READONLY if readonly else 0))
1096
1092
 
1097
- tooltip = _Tip(tip, handler.__doc__, updater.__doc__)
1098
-
1099
1093
  self._ctrl = wx.TextCtrl(self, **kwargs)
1100
- self._btn = Button(self, label, None, icon, tooltip,
1094
+ self._btn = Button(self, label, None, icon,
1101
1095
  size=(-1,-1) if label or icon else (0,0))
1096
+ self._ctrl.ToolTip = handler.__doc__
1097
+ self._btn.ToolTip = updater.__doc__
1098
+
1102
1099
  self.SetSizer(
1103
1100
  pack(self, (
1104
1101
  (self._btn, 0, wx.ALIGN_CENTER | wx.LEFT | wx.RIGHT, 0),
@@ -1162,20 +1159,20 @@ class Choice(wx.Control):
1162
1159
  def icon(self, v):
1163
1160
  self._btn.icon = v
1164
1161
 
1165
- def __init__(self, parent, label='',
1166
- handler=None, updater=None, size=(-1,-1),
1167
- icon=None, tip='', readonly=False, **kwargs):
1162
+ def __init__(self, parent, label='', handler=None, updater=None,
1163
+ icon=None, readonly=False, size=(-1,-1), **kwargs):
1168
1164
  wx.Control.__init__(self, parent, size=size, style=wx.BORDER_NONE)
1169
1165
 
1170
1166
  kwargs['style'] = (kwargs.get('style', 0)
1171
1167
  | wx.TE_PROCESS_ENTER
1172
1168
  | (wx.CB_READONLY if readonly else 0))
1173
1169
 
1174
- tooltip = _Tip(tip, handler.__doc__, updater.__doc__)
1175
-
1176
1170
  self._ctrl = wx.ComboBox(self, **kwargs)
1177
- self._btn = Button(self, label, None, icon, tooltip,
1171
+ self._btn = Button(self, label, None, icon,
1178
1172
  size=(-1,-1) if label or icon else (0,0))
1173
+ self._ctrl.ToolTip = handler.__doc__
1174
+ self._btn.ToolTip = updater.__doc__
1175
+
1179
1176
  self.SetSizer(
1180
1177
  pack(self, (
1181
1178
  (self._btn, 0, wx.ALIGN_CENTER | wx.LEFT | wx.RIGHT, 0),
mwx/framework.py CHANGED
@@ -1,14 +1,12 @@
1
1
  #! python3
2
2
  """mwxlib framework.
3
3
  """
4
- __version__ = "0.96.1"
4
+ __version__ = "0.96.5"
5
5
  __author__ = "Kazuya O'moto <komoto@jeol.co.jp>"
6
6
 
7
7
  from functools import wraps, partial
8
8
  from importlib import reload
9
- from contextlib import contextmanager
10
9
  import traceback
11
- import warnings
12
10
  import builtins
13
11
  import datetime
14
12
  import textwrap
@@ -21,8 +19,8 @@ from wx import stc
21
19
  from wx.py import dispatcher
22
20
 
23
21
  from .utilus import funcall as _F
22
+ from .utilus import get_rootpath, ignore, warn # noqa
24
23
  from .utilus import FSM, TreeList, apropos, typename, where, mro, pp
25
- from .utilus import get_rootpath
26
24
 
27
25
 
28
26
  def deb(target=None, loop=True, locals=None, **kwargs):
@@ -290,14 +288,12 @@ class KeyCtrlInterfaceMixin:
290
288
  key += ' pressed'
291
289
 
292
290
  if map not in self.handler:
293
- warnings.warn(f"New map to define_key {keymap!r} in {self}.",
294
- stacklevel=2)
291
+ warn(f"New map to define_key {keymap!r} in {self}.")
295
292
  self.make_keymap(map) # make new keymap
296
293
 
297
294
  transaction = self.handler[map].get(key, [state])
298
295
  if len(transaction) > 1:
299
- warnings.warn(f"Duplicate define_key {keymap!r} in {self}.",
300
- stacklevel=2)
296
+ warn(f"Duplicate define_key {keymap!r} in {self}.")
301
297
 
302
298
  if action is None:
303
299
  self.handler[map].pop(key, None) # cf. undefine_key
@@ -322,10 +318,6 @@ class CtrlInterface(KeyCtrlInterfaceMixin):
322
318
  handler = property(lambda self: self.__handler)
323
319
 
324
320
  def __init__(self):
325
- if hasattr(self, 'handler'):
326
- warnings.warn(f"Duplicate iniheritance of CtrlInterface by {self}.",
327
- stacklevel=2)
328
- return
329
321
  self.__key = ''
330
322
  self.__button = ''
331
323
  self.__isDragging = False
@@ -629,8 +621,7 @@ class MenuBar(wx.MenuBar, TreeList):
629
621
  Call when the menulist is changed.
630
622
  """
631
623
  if not self.Parent:
632
- warnings.warn(f"No parents bound to {self}.",
633
- stacklevel=2)
624
+ warn(f"No parents bound to {self}.")
634
625
  return
635
626
 
636
627
  menu = self.getmenu(key)
@@ -657,8 +648,7 @@ class MenuBar(wx.MenuBar, TreeList):
657
648
  Call when the menulist is changed.
658
649
  """
659
650
  if not self.Parent:
660
- warnings.warn(f"No parents bound to {self}.",
661
- stacklevel=2)
651
+ warn(f"No parents bound to {self}.")
662
652
  return
663
653
 
664
654
  for j in range(self.GetMenuCount()): # remove and del all top-level menu
@@ -1604,7 +1594,7 @@ class ShellFrame(MiniFrame):
1604
1594
  if isinstance(editor, str):
1605
1595
  editor = getattr(self, editor, None)
1606
1596
  if editor:
1607
- return editor.load_file(filename, lineno, verbose=0)
1597
+ return editor.load_file(filename, lineno)
1608
1598
 
1609
1599
  def load(self, filename, lineno=0, show=True):
1610
1600
  """Load file @where the object is defined.
@@ -1625,7 +1615,7 @@ class ShellFrame(MiniFrame):
1625
1615
  filename, ln = m.groups()
1626
1616
  lineno = int(ln)
1627
1617
  editor = self.find_editor(filename) or self.Log
1628
- ret = editor.load_file(filename, lineno, verbose=1)
1618
+ ret = editor.load_file(filename, lineno)
1629
1619
  if ret:
1630
1620
  self.popup_window(editor, show)
1631
1621
  return ret
mwx/graphman.py CHANGED
@@ -9,7 +9,6 @@ from bdb import BdbQuit
9
9
  import subprocess
10
10
  import threading
11
11
  import traceback
12
- import warnings
13
12
  import inspect
14
13
  import sys
15
14
  import os
@@ -26,6 +25,7 @@ from PIL import Image
26
25
  from PIL.TiffImagePlugin import TiffImageFile
27
26
 
28
27
  from . import framework as mwx
28
+ from .utilus import ignore, warn
29
29
  from .utilus import funcall as _F
30
30
  from .controls import ControlPanel, Icon
31
31
  from .framework import CtrlInterface, AuiNotebook, Menu, FSM
@@ -310,7 +310,10 @@ class LayerInterface(CtrlInterface):
310
310
  self.__artists.remove(art)
311
311
 
312
312
  def __init__(self, parent, session=None):
313
- CtrlInterface.__init__(self)
313
+ if hasattr(self, 'handler'):
314
+ warn(f"Duplicate iniheritance of CtrlInterface by {self}.")
315
+ else:
316
+ CtrlInterface.__init__(self)
314
317
 
315
318
  self.parent = parent
316
319
  self.__artists = []
@@ -855,15 +858,14 @@ class Frame(mwx.Frame):
855
858
 
856
859
  Editor = "notepad"
857
860
 
861
+ @ignore(ResourceWarning)
858
862
  def edit(self, fn):
859
863
  if hasattr(fn, '__file__'):
860
864
  name, _ = os.path.splitext(fn.__file__)
861
865
  fn = name + '.py'
862
866
  cmd = '{} "{}"'.format(self.Editor, fn)
863
- with warnings.catch_warnings():
864
- warnings.simplefilter("ignore", ResourceWarning)
865
- subprocess.Popen(cmd)
866
- self.message(cmd)
867
+ subprocess.Popen(cmd)
868
+ self.message(cmd)
867
869
 
868
870
  def set_title(self, frame):
869
871
  ssn = os.path.basename(self.session_file or '--')
@@ -887,6 +889,20 @@ class Frame(mwx.Frame):
887
889
  elif ret == wx.ID_CANCEL:
888
890
  evt.Veto()
889
891
  return
892
+ for name in self.plugins:
893
+ plug = self.get_plug(name)
894
+ if plug.thread and plug.thread.active:
895
+ if wx.MessageBox( # Confirm thread close.
896
+ "The thread is running.\n\n"
897
+ "Enter [q]uit to exit before closing.\n"
898
+ "Continue closing?",
899
+ "Close {!r}".format(plug.Name),
900
+ style=wx.YES_NO|wx.ICON_INFORMATION) != wx.YES:
901
+ self.message("The close has been canceled.")
902
+ evt.Veto()
903
+ return
904
+ self.Quit()
905
+ break
890
906
  for frame in self.graph.all_frames:
891
907
  if frame.pathname is None:
892
908
  if wx.MessageBox( # Confirm close.
@@ -914,11 +930,9 @@ class Frame(mwx.Frame):
914
930
  Args:
915
931
  name : str or plug object.
916
932
  """
917
- if name in self.plugins:
918
- plug = self.plugins[name].__plug__
919
- name = plug.category or name
920
- elif isinstance(name, LayerInterface):
921
- name = name.category or name
933
+ plug = self.get_plug(name)
934
+ if plug:
935
+ name = plug.category or plug
922
936
  if name:
923
937
  return self._mgr.GetPane(name)
924
938
 
@@ -953,6 +967,7 @@ class Frame(mwx.Frame):
953
967
  ## Note: We need to distinguish cases whether:
954
968
  ## - pane.window is AuiNotebook or normal Panel,
955
969
  ## - pane.window is floating (win.Parent is AuiFloatingFrame) or docked.
970
+
956
971
  plug = self.get_plug(name) # -> None if pane.window is a Graph
957
972
  win = pane.window # -> Window (plug / notebook / Graph)
958
973
  try:
@@ -1029,7 +1044,7 @@ class Frame(mwx.Frame):
1029
1044
  win.handler('page_closed', win)
1030
1045
 
1031
1046
  ## --------------------------------
1032
- ## Plugin (Layer) interface
1047
+ ## Plugin <Layer> interface
1033
1048
  ## --------------------------------
1034
1049
  plugins = property(lambda self: self.__plugins)
1035
1050
 
@@ -1063,15 +1078,14 @@ class Frame(mwx.Frame):
1063
1078
 
1064
1079
  @staticmethod
1065
1080
  def register(cls, module=None):
1066
- """Register dummy plug; Add module.Plugin(Layer).
1081
+ """Register dummy plug; Add module.Plugin <Layer>.
1067
1082
  """
1068
1083
  if not module:
1069
1084
  module = inspect.getmodule(cls) # rebase module or __main__
1070
1085
 
1071
1086
  if issubclass(cls, LayerInterface):
1072
1087
  cls.__module__ = module.__name__ # __main__ to module
1073
- warnings.warn(f"Duplicate iniheritance of LayerInterface by {cls}.",
1074
- stacklevel=2)
1088
+ warn(f"Duplicate iniheritance of LayerInterface by {cls}.")
1075
1089
  module.Plugin = cls
1076
1090
  return cls
1077
1091
 
@@ -1121,8 +1135,7 @@ class Frame(mwx.Frame):
1121
1135
  ## the module must have a class `Plugin`.
1122
1136
  if not hasattr(module, 'Plugin'):
1123
1137
  if isinstance(root, type):
1124
- warnings.warn(f"Use dummy plug for debugging {name!r}.",
1125
- stacklevel=3)
1138
+ warn(f"Use dummy plug for debugging {name!r}.")
1126
1139
  module.__dummy_plug__ = root
1127
1140
  self.register(root, module)
1128
1141
  else:
@@ -1255,8 +1268,8 @@ class Frame(mwx.Frame):
1255
1268
  .Name(title).Caption(title)
1256
1269
  .FloatingSize(size).MinSize(size).Show(0))
1257
1270
  j = nb.GetPageIndex(plug)
1258
- tip = "[{}]\n{}".format(plug.__module__, plug.__doc__)
1259
- nb.SetPageToolTip(j, tip.strip())
1271
+ tips = "[{}]\n{}".format(plug.__module__, plug.__doc__)
1272
+ nb.SetPageToolTip(j, tips.strip())
1260
1273
  else:
1261
1274
  nb = None
1262
1275
  size = plug.GetSize()
@@ -1420,7 +1433,7 @@ class Frame(mwx.Frame):
1420
1433
  "ALL files (*.*)|*.*",
1421
1434
  style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST) as dlg:
1422
1435
  if dlg.ShowModal() != wx.ID_OK:
1423
- return
1436
+ return None
1424
1437
  filename = dlg.Path
1425
1438
 
1426
1439
  res, mis = self.read_attributes(filename)
@@ -1445,7 +1458,7 @@ class Frame(mwx.Frame):
1445
1458
  if not frames:
1446
1459
  frames = self.selected_view.all_frames
1447
1460
  if not frames:
1448
- return
1461
+ return None
1449
1462
 
1450
1463
  if not filename:
1451
1464
  fn = next((x.pathname for x in frames if x.pathname), '')
@@ -1455,7 +1468,7 @@ class Frame(mwx.Frame):
1455
1468
  wildcard="Index (*.index)|*.index",
1456
1469
  style=wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT) as dlg:
1457
1470
  if dlg.ShowModal() != wx.ID_OK:
1458
- return
1471
+ return None
1459
1472
  filename = dlg.Path
1460
1473
 
1461
1474
  savedir = os.path.dirname(filename)
@@ -1608,6 +1621,7 @@ class Frame(mwx.Frame):
1608
1621
  os.remove(path)
1609
1622
  raise
1610
1623
 
1624
+ @ignore(ResourceWarning)
1611
1625
  def load_buffer(self, paths=None, view=None):
1612
1626
  """Load buffers from paths to the view window.
1613
1627
 
@@ -1625,11 +1639,11 @@ class Frame(mwx.Frame):
1625
1639
  style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST
1626
1640
  |wx.FD_MULTIPLE) as dlg:
1627
1641
  if dlg.ShowModal() != wx.ID_OK:
1628
- return
1642
+ return None
1629
1643
  paths = dlg.Paths
1644
+ frames = []
1645
+ frame = None
1630
1646
  try:
1631
- frames = []
1632
- frame = None
1633
1647
  for i, path in enumerate(paths):
1634
1648
  fn = os.path.basename(path)
1635
1649
  self.message("Loading {!r} ({} of {})...".format(fn, i+1, len(paths)))
@@ -1672,7 +1686,7 @@ class Frame(mwx.Frame):
1672
1686
  if not frame:
1673
1687
  frame = self.selected_view.frame
1674
1688
  if not frame:
1675
- return
1689
+ return None
1676
1690
 
1677
1691
  if not path:
1678
1692
  with wx.FileDialog(self, "Save buffer as",
@@ -1680,7 +1694,7 @@ class Frame(mwx.Frame):
1680
1694
  wildcard='|'.join(self.wildcards),
1681
1695
  style=wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT) as dlg:
1682
1696
  if dlg.ShowModal() != wx.ID_OK:
1683
- return
1697
+ return None
1684
1698
  path = dlg.Path
1685
1699
  try:
1686
1700
  name = os.path.basename(path)
@@ -1700,13 +1714,14 @@ class Frame(mwx.Frame):
1700
1714
  except Exception as e:
1701
1715
  self.message("\b failed.")
1702
1716
  wx.MessageBox(str(e), style=wx.ICON_ERROR)
1717
+ return None
1703
1718
 
1704
1719
  def save_buffers_as_tiffs(self, path=None, frames=None):
1705
1720
  """Export buffers to a file as a multi-page tiff."""
1706
1721
  if not frames:
1707
1722
  frames = self.selected_view.all_frames
1708
1723
  if not frames:
1709
- return
1724
+ return None
1710
1725
 
1711
1726
  if not path:
1712
1727
  with wx.FileDialog(self, "Save frames as stack-tiff",
@@ -1714,7 +1729,7 @@ class Frame(mwx.Frame):
1714
1729
  wildcard="TIF file (*.tif)|*.tif",
1715
1730
  style=wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT) as dlg:
1716
1731
  if dlg.ShowModal() != wx.ID_OK:
1717
- return
1732
+ return None
1718
1733
  path = dlg.Path
1719
1734
  try:
1720
1735
  name = os.path.basename(path)
@@ -1733,6 +1748,7 @@ class Frame(mwx.Frame):
1733
1748
  except Exception as e:
1734
1749
  self.message("\b failed.")
1735
1750
  wx.MessageBox(str(e), style=wx.ICON_ERROR)
1751
+ return False
1736
1752
  finally:
1737
1753
  del busy
1738
1754
 
mwx/images.py CHANGED
@@ -178,6 +178,23 @@ colour_grey = PyEmbeddedImage(
178
178
  b'r7rzc2YUF8aOx3m0NYJWAPe76VmttzK1bzsbW0dAKwAAAID/tYu/URIDsoEAAAAASUVORK5C'
179
179
  b'YII=')
180
180
 
181
+ #----------------------------------------------------------------------
182
+ connect = PyEmbeddedImage(
183
+ b'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0'
184
+ b'RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAJ+SURBVBgZlcFLSBRhAAfw/858'
185
+ b's860aygiptIp9NChoDzkxYNUYIcO0TUIOghFUNElvEad6lBkdEqCIugi3QQfLR2yQumBaPh+'
186
+ b'7Li7o/uanfmes1972IOEQv5+Ma01DuPRh+U+StlEhSsZUnElprXGQd6kdomUsoOJaiflojXk'
187
+ b'4mIM+pZjaXCp8GslTwkOMDLlOVyoCamiXhkpVCOJRDyGpG2CCYlsgSPvh4TgACGVt21L97Y0'
188
+ b'meBCg0kNyiW28wHiJrC8VYAo0wsE+3g1vtRdquYeHyXHUfAldkohKJcIuUSjbWI5XYKXLQ5/'
189
+ b'fnk1RbDHyJTnSKHeCbF6SbVMGCteH5pxAk7cQLbAQZmAGbOQccuQZTqGGoK615M5woX6aRPd'
190
+ b'ZTkn4a+7kehMmdOzMmptaDOTNkEuzxE3gaAcQITMQ42BugpVHUzIrqRjwCJVOA3nzPLvMzKS'
191
+ b'cujPxnK04RbRdIQgYBxhIYSs0DRqDNSFnHUKIUG5xKZXQTweg5Potmyde9hz/quZ9RbgukWs'
192
+ b'LWQQlvxFFQkXNQbqKgFvDRhHyCRCKrC27cOxYmhrPksyP5rQMzAPd3FJZVdzoyrip+cn7yvU'
193
+ b'ENSVQnajvclCSAUqlIMyCa8oYVsmoPsxM/pJRVVxam7ywTz2IKi5+WLmXqNjXI4TA5lCgIRt'
194
+ b'wjI1GqwYhJBY39hFLt0+NPtxcB7/IIPPvt9N2MaTRNwAZQKWqbGeLmFnxwf1GZhPwXz+RXH2'
195
+ b'HPsgPuVP25qT0DrCZtbHpltEwQuGlRBjEedexFVaCenOjd9R2Acp+RQb2xFMaKS3iiju+v3T'
196
+ b'b69N4T8RGtBjK/lSRoWKKsYGvr2/nsIh/AUG0IfiieuuUQAAAABJRU5ErkJggg==')
197
+
181
198
  #----------------------------------------------------------------------
182
199
  copy = PyEmbeddedImage(
183
200
  b'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QAAAAAAAD5Q7t/AAAA'
@@ -209,6 +226,24 @@ core = PyEmbeddedImage(
209
226
  b'AQgglIQEcp6GhgaDtrY22JmgAAT5HRQOnz9/BqsB5Y2dO3eCNHOAYh8ggOAGgJyKbhgygAUa'
210
227
  b'VDMjTBwggMAGTJ48+flvIJCWlpYjlH2RNYMAQIABANLKHICUilYLAAAAAElFTkSuQmCC')
211
228
 
229
+ #----------------------------------------------------------------------
230
+ disconnect = PyEmbeddedImage(
231
+ b'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0'
232
+ b'RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAKuSURBVDjLlZLLS5RRGMbf7zrz'
233
+ b'ebdw8FaSqJAbF0GgRBvptinoPxDKRdDKQjBw2TKClgVJCwmUyMBKydDKS9TCME2tRhs1cZwZ'
234
+ b'57ud853bfB0HiiAVOvBuDuf5ve/7nEcJwxAOOgPTtk4Fr6ZU1OCAVyBCm2Td9jEdcxG5pBwE'
235
+ b'eDyZtaRwjAvWSpkAxjkITsGKqJBIuvB903upH9QdE3rd1MLW0gIVCMsBoYq8U8H2CUQNBdJZ'
236
+ b'p33fCe6PbJo+4XZVmRHFhEDKCXaB4Accii0NFlfT8GNt56a6X/er56qog/Cd1aQjRRQictas'
237
+ b'R8B2EXgIQyblAbX95X9WeDSRPiriz3oZY1pvZ2dH590Z7GB+q7LcjBZHVdhMBaCpEfBsCXDR'
238
+ b'9p8V+t9lLGlUP7PXLxyJbkUMw4DZ2dm+rq6ujjPdz09xTEZrY8VWYZEh/WAwNxWHwEV1eYDs'
239
+ b'qsuOCxFDaYRQwGZ8ljeUE31+fr4PY3xFVulM5mQzC4LRypoSy037kEykvuZytDnvAQ5oNSa8'
240
+ b'scAE0JQcGIeb9LcrJl02Tj+U4gcIoanG8MU35qKzK58SaCux9ZSLoGVxvJvnPfAQrQEQEhTC'
241
+ b'RhpBYVQB61CNyZY+v6qvrzdisRgMDg6O1+kjbUt+23EpTPz2LA9wMa7QFJBuhxIWQHKHQWmB'
242
+ b'DrXHGozJuTfQ4sWBEDI9NDSUkc8zf5ueB9gubiqyVJBacBDZXQm2MhSiugZW7QkYfj/NuGi5'
243
+ b'ttd3a9uxi6bM9FhFmak5fgCmHEXqQFcVEDkBiZVt+edhz8fh7om9AHrWxV5JgWoImXMfE1jb'
244
+ b'sMHd8QF7AQQyONjxp4UQ9/YLnJ710JgaGucXUi6sr2cY84MeQfmyCOg2p3RD5PjPL69v8H0B'
245
+ b'yEWXnSR7IoPSzjEt+jDQQeE/zi9kq6pv7shelwAAAABJRU5ErkJggg==')
246
+
212
247
  #----------------------------------------------------------------------
213
248
  exit = PyEmbeddedImage(
214
249
  b'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0'
mwx/matplot2g.py CHANGED
@@ -2,7 +2,6 @@
2
2
  """mwxlib graph plot for images.
3
3
  """
4
4
  import traceback
5
- import warnings
6
5
  import wx
7
6
 
8
7
  from matplotlib import cm
@@ -15,6 +14,7 @@ from scipy import ndimage as ndi
15
14
 
16
15
  from . import framework as mwx
17
16
  from .framework import Menu
17
+ from .utilus import warn
18
18
  from .utilus import funcall as _F
19
19
  from .controls import Clipboard
20
20
  from .matplot2 import MatplotPanel
@@ -242,8 +242,8 @@ class AxesImagePhantom(object):
242
242
  self.__localunit = v
243
243
  self.__attributes['localunit'] = self.__localunit
244
244
  self.update_extent()
245
- self.parent.update_markup_ratio(v/u)
246
245
  self.parent.handler('frame_updated', self)
246
+ self.parent.canvas.draw_idle()
247
247
 
248
248
  @unit.deleter
249
249
  def unit(self):
@@ -333,8 +333,7 @@ class AxesImagePhantom(object):
333
333
  def _cast(n):
334
334
  return np.int32(np.floor(np.round(n, 1)))
335
335
  if y is None:
336
- warnings.warn("Setting xy data with single tuple is deprecated.",
337
- DeprecationWarning, stacklevel=2)
336
+ warn("Setting xy data with single tuple.", DeprecationWarning)
338
337
  x, y = x
339
338
  if isinstance(x, (list, tuple)):
340
339
  x = np.array(x)
@@ -350,8 +349,7 @@ class AxesImagePhantom(object):
350
349
  def xyfrompixel(self, nx, ny=None):
351
350
  """Convert pixel [nx,ny] -> (x,y) xydata (float number)."""
352
351
  if ny is None:
353
- warnings.warn("Setting xy data with single tuple is deprecated.",
354
- DeprecationWarning, stacklevel=2)
352
+ warn("Setting xy data with single tuple.", DeprecationWarning)
355
353
  nx, ny = nx
356
354
  if isinstance(nx, (list, tuple)):
357
355
  nx = np.array(nx)
@@ -660,8 +658,8 @@ class GraphPlot(MatplotPanel):
660
658
  j = names.index(name) # existing frame
661
659
  if j != -1:
662
660
  art = self.__Arts[j]
663
- art.update_buffer(buf) # => frame_modified
664
- art.update_attributes(kwargs) # => frame_updated
661
+ art.update_buffer(buf) # => [frame_modified]
662
+ art.update_attributes(kwargs) # => [frame_updated] localunit => [canvas_draw]
665
663
  art.update_extent()
666
664
  if show:
667
665
  self.select(j)
@@ -676,7 +674,11 @@ class GraphPlot(MatplotPanel):
676
674
  self.__Arts.insert(j, art)
677
675
  self.handler('frame_loaded', art)
678
676
  if show:
677
+ u = self.frame and self.frame.unit # current frame unit
679
678
  self.select(j)
679
+ ## Update view if the unit length is different from before selection
680
+ if u != art.unit:
681
+ self.axes.axis(art.get_extent())
680
682
  return art
681
683
 
682
684
  def select(self, j):
@@ -690,17 +692,10 @@ class GraphPlot(MatplotPanel):
690
692
  self.handler('frame_hidden', self.frame)
691
693
 
692
694
  if j is not None:
693
- u = self.frame and self.frame.unit # current frame unit
694
-
695
695
  art = self.__Arts[j]
696
696
  art.set_visible(1)
697
697
  self.__index = j % len(self)
698
698
  self.handler('frame_shown', art)
699
-
700
- ## Update view if the unit length is different than before
701
- if u != art.unit:
702
- ## self.update_axis()
703
- self.axes.axis(art.get_extent())
704
699
  else:
705
700
  self.__index = None
706
701
 
@@ -843,20 +838,11 @@ class GraphPlot(MatplotPanel):
843
838
  self.__unit = v
844
839
  for art in self.__Arts:
845
840
  art.update_extent()
846
- else:
847
- self.update_markup_ratio(v/u)
848
- for art in self.__Arts:
849
841
  self.handler('frame_updated', art)
842
+ self.canvas.draw_idle()
850
843
 
851
844
  globalunit = unit # for backward compatibility
852
845
 
853
- def update_markup_ratio(self, r):
854
- """Modify markup objects position."""
855
- if self.Selector.size: self.Selector *= r
856
- if self.Markers.size: self.Markers *= r
857
- if self.Region.size: self.Region *= r
858
- self.draw()
859
-
860
846
  def kill_buffer(self):
861
847
  if self.buffer is not None:
862
848
  del self.buffer
mwx/matplot2lg.py CHANGED
@@ -623,7 +623,7 @@ class LineProfile(LinePlot):
623
623
  with io.StringIO() as o:
624
624
  for x, y in zip(X, Y):
625
625
  o.write("{:g}\t{:g}\n".format(x, y))
626
- Clipboard.write(o.getvalue(), verbose=0)
626
+ Clipboard.write(o.getvalue())
627
627
  self.message("Write data to clipboard.")
628
628
 
629
629
  def annotate(self):
mwx/nutshell.py CHANGED
@@ -7,7 +7,6 @@ from contextlib import contextmanager
7
7
  from pprint import pformat
8
8
  from bdb import BdbQuit
9
9
  import traceback
10
- import warnings
11
10
  import inspect
12
11
  import builtins
13
12
  import dis
@@ -26,6 +25,7 @@ from wx.py.shell import Shell
26
25
  from wx.py.editwindow import EditWindow
27
26
 
28
27
  from .utilus import funcall as _F
28
+ from .utilus import ignore
29
29
  from .utilus import split_words, split_paren, split_tokens, find_modules
30
30
  from .framework import CtrlInterface, AuiNotebook, Menu
31
31
 
@@ -2161,6 +2161,7 @@ class Interpreter(interpreter.Interpreter):
2161
2161
  except AttributeError:
2162
2162
  pass
2163
2163
 
2164
+ @ignore(DeprecationWarning)
2164
2165
  def getCallTip(self, command='', *args, **kwargs):
2165
2166
  """Return call tip text for a command.
2166
2167
 
@@ -2169,12 +2170,10 @@ class Interpreter(interpreter.Interpreter):
2169
2170
  (override) Ignore ValueError: no signature found for builtin
2170
2171
  if the unwrapped function is a builtin function.
2171
2172
  """
2172
- with warnings.catch_warnings():
2173
- warnings.simplefilter('ignore', DeprecationWarning)
2174
- try:
2175
- return interpreter.Interpreter.getCallTip(self, command, *args, **kwargs)
2176
- except ValueError:
2177
- return interpreter.Interpreter.getCallTip(self) # dummy
2173
+ try:
2174
+ return interpreter.Interpreter.getCallTip(self, command, *args, **kwargs)
2175
+ except ValueError:
2176
+ return interpreter.Interpreter.getCallTip(self) # dummy
2178
2177
 
2179
2178
 
2180
2179
  class Nautilus(Shell, EditorInterface):
@@ -106,7 +106,7 @@ class Plugin(Layer):
106
106
  updater=self.get_crop,
107
107
  )
108
108
 
109
- self.snp = Button(self, handler=self.snapshot, icon='clock')
109
+ self.snp = Button(self, handler=self.snapshot, icon='clip')
110
110
  self.exp = Button(self, handler=self.export, icon='save')
111
111
 
112
112
  self.rw = Button(self, handler=lambda v: self.seekdelta(-100), icon='|<-')
@@ -72,7 +72,6 @@ class CheckList(wx.ListCtrl, ListCtrlAutoWidthMixin, CtrlInterface):
72
72
  'Lbutton dblclick' : (0, self.OnShowItems), # -> frame_shown
73
73
  'enter pressed' : (0, self.OnShowItems), # -> frame_shown
74
74
  'delete pressed' : (0, self.OnRemoveItems), # -> frame_removed/shown
75
- 'f2 pressed' : (0, self.OnEditAnnotation),
76
75
  'C-a pressed' : (0, self.OnSelectAllItems),
77
76
  'C-o pressed' : (0, self.OnLoadItems),
78
77
  'C-s pressed' : (0, self.OnSaveItems),
@@ -97,26 +96,17 @@ class CheckList(wx.ListCtrl, ListCtrlAutoWidthMixin, CtrlInterface):
97
96
  }
98
97
  self.Target.handler.append(self.context)
99
98
 
100
- def copy_info(all=True):
101
- frames = self.Target.all_frames
102
- if frames:
103
- frame = frames[self.focused_item]
104
- if all:
105
- text = pformat(frame.attributes, sort_dicts=0)
106
- else:
107
- text = "{}\n{}".format(frame.name, frame.annotation)
108
- Clipboard.write(text)
109
-
110
99
  self.menu = [
111
- (101, "&Edit annotation", "Edit annotation", Icon('pencil'),
112
- self.OnEditAnnotation),
100
+ (100, "Edit localunit", Icon('image'),
101
+ self.OnEditUnit,
102
+ lambda v: v.Enable(self.focused_item != -1)),
103
+
104
+ (101, "Edit annotation", Icon('pencil'),
105
+ self.OnEditAnnotation,
106
+ lambda v: v.Enable(self.focused_item != -1)),
113
107
  (),
114
108
  (102, "Copy info", Icon('copy'),
115
- lambda v: copy_info(0),
116
- lambda v: v.Enable(len(list(self.selected_items)))),
117
-
118
- (103, "Copy ALL data", Icon('copy', '+'),
119
- lambda v: copy_info(1),
109
+ self.OnCopyInfo,
120
110
  lambda v: v.Enable(len(list(self.selected_items)))),
121
111
  ]
122
112
  self.Bind(wx.EVT_CONTEXT_MENU,
@@ -183,26 +173,40 @@ class CheckList(wx.ListCtrl, ListCtrlAutoWidthMixin, CtrlInterface):
183
173
  self.parent.parent.load_index(view=self.Target)
184
174
 
185
175
  def OnSaveItems(self, evt):
186
- frames = self.Target.all_frames
187
- selected_frames = [frames[j] for j in self.selected_items]
176
+ selected_frames = [self.Target.all_frames[j] for j in self.selected_items]
188
177
  if selected_frames:
189
178
  self.parent.message("Exporting {} frames.".format(len(selected_frames)))
190
179
  self.parent.parent.save_index(frames=selected_frames)
191
180
  else:
192
181
  self.parent.message("No frame selected.")
193
182
 
183
+ def OnCopyInfo(self, evt):
184
+ selected_frames = [self.Target.all_frames[j] for j in self.selected_items]
185
+ if selected_frames:
186
+ text = ''
187
+ for frame in selected_frames:
188
+ text += pformat(frame.attributes, sort_dicts=0) # ALL attributes
189
+ ## text += '{}\n{}\n'.format(frame.name, frame.annotation)
190
+ Clipboard.write(text)
191
+ else:
192
+ self.parent.message("No frame selected.")
193
+
194
+ def OnEditUnit(self, evt):
195
+ frame = self.Target.all_frames[self.focused_item]
196
+ with wx.TextEntryDialog(self, frame.name,
197
+ 'Enter localunit', repr(frame.localunit)) as dlg:
198
+ if dlg.ShowModal() == wx.ID_OK:
199
+ frame.unit = eval(dlg.Value or 'None')
200
+
194
201
  def OnEditAnnotation(self, evt):
195
- frames = self.Target.all_frames
196
- if frames:
197
- frame = frames[self.focused_item]
198
- with wx.TextEntryDialog(self, frame.name,
199
- 'Enter an annotation', frame.annotation) as dlg:
200
- if dlg.ShowModal() == wx.ID_OK:
201
- frame.annotation = dlg.Value
202
+ frame = self.Target.all_frames[self.focused_item]
203
+ with wx.TextEntryDialog(self, frame.name,
204
+ 'Enter an annotation', frame.annotation) as dlg:
205
+ if dlg.ShowModal() == wx.ID_OK:
206
+ frame.annotation = dlg.Value
202
207
 
203
208
  def OnItemSelected(self, evt):
204
- frames = self.Target.all_frames
205
- frame = frames[evt.Index]
209
+ frame = self.Target.all_frames[evt.Index]
206
210
  self.parent.message(frame.pathname)
207
211
  evt.Skip()
208
212
 
mwx/utilus.py CHANGED
@@ -37,6 +37,16 @@ def ignore(*category):
37
37
  yield
38
38
 
39
39
 
40
+ def warn(message, category=None):
41
+ frame = inspect.currentframe().f_back # previous call stack frame
42
+ skip = [frame.f_code.co_filename]
43
+ stacklevel = 1
44
+ while frame.f_code.co_filename in skip:
45
+ frame = frame.f_back
46
+ stacklevel += 1
47
+ return warnings.warn(message, category, stacklevel+1)
48
+
49
+
40
50
  def atom(v):
41
51
  return not hasattr(v, '__name__')
42
52
 
@@ -807,11 +817,8 @@ class FSM(dict):
807
817
  assert isinstance(event, str)
808
818
  assert callable(action) or action is None
809
819
 
810
- def warn(msg):
811
- warnings.warn(msg, stacklevel=3)
812
-
813
820
  if state not in self:
814
- warn("- FSM warning: [{!r}] context newly created.".format(state))
821
+ warn(f"- FSM [{state!r}] context newly created.")
815
822
  self[state] = SSM() # new context
816
823
 
817
824
  context = self[state]
@@ -820,17 +827,15 @@ class FSM(dict):
820
827
 
821
828
  if event in context:
822
829
  if state2 != context[event][0]:
823
- warn("- FSM warning: transaction may conflict.\n"
824
- " The state {2!r} and the original state is not the same."
825
- " {0!r} : {1!r} --> {2!r}".format(event, state, state2))
830
+ warn(f"- FSM transaction may conflict ({event!r} : {state!r} --> {state2!r}).\n"
831
+ f" The state {state2!r} is different from the original state.")
826
832
  pass
827
833
  context[event][0] = state2 # update transition
828
834
  else:
829
- ## if state2 not in self:
830
- ## warn("- FSM warning: transaction may contradict\n"
831
- ## " The state {2!r} is not found in the contexts."
832
- ## " {0!r} : {1!r} --> {2!r}".format(event, state, state2))
833
- ## pass
835
+ if state2 not in self:
836
+ warn(f"- FSM transaction may contradict ({event!r} : {state!r} --> {state2!r}).\n"
837
+ f" The state {state2!r} is not found in the contexts.")
838
+ pass
834
839
  context[event] = [state2] # new event:transaction
835
840
 
836
841
  transaction = context[event]
@@ -841,8 +846,8 @@ class FSM(dict):
841
846
  try:
842
847
  transaction.append(action)
843
848
  except AttributeError:
844
- warn("- FSM warning: cannot append new transaction ({!r} : {!r})\n"
845
- " The transaction must be a list, not a tuple".format(state, event))
849
+ warn(f"- FSM cannot append new transaction ({state!r} : {event!r}).\n"
850
+ f" The transaction must be a list, not a tuple.")
846
851
  return action
847
852
 
848
853
  def unbind(self, event, action=None, state=None):
@@ -855,16 +860,13 @@ class FSM(dict):
855
860
  """
856
861
  assert callable(action) or action is None
857
862
 
858
- def warn(msg):
859
- warnings.warn(msg, stacklevel=3)
860
-
861
863
  if state not in self:
862
- warn("- FSM warning: [{!r}] context does not exist.".format(state))
864
+ warn(f"- FSM [{state!r}] context does not exist.")
863
865
  return
864
866
 
865
867
  context = self[state]
866
868
  if event not in context:
867
- warn("- FSM warning: No such transaction ({!r} : {!r})".format(state, event))
869
+ warn(f"- FSM has no such transaction ({state!r} : {event!r}).")
868
870
  return
869
871
 
870
872
  transaction = context[event]
@@ -878,8 +880,8 @@ class FSM(dict):
878
880
  transaction.remove(action)
879
881
  return True
880
882
  except AttributeError:
881
- warn("- FSM warning: removing action from context ({!r} : {!r})\n"
882
- " The transaction must be a list, not a tuple".format(state, event))
883
+ warn(f"- FSM removing action from context ({state!r} : {event!r}).\n"
884
+ f" The transaction must be a list, not a tuple")
883
885
  return False
884
886
 
885
887
 
@@ -961,7 +963,7 @@ class TreeList(object):
961
963
  else:
962
964
  ls.append([key, value]) # append to items:list
963
965
  except (ValueError, TypeError, AttributeError) as e:
964
- print(f"- TreeList:warning {e!r}: {key=!r}")
966
+ warn(f"- TreeList {e!r}: {key=!r}")
965
967
 
966
968
  def _delf(self, ls, key):
967
969
  if '/' in key:
mwx/wxmon.py CHANGED
@@ -3,12 +3,11 @@
3
3
 
4
4
  *** Inspired by wx.lib.eventwatcher ***
5
5
  """
6
- import warnings
7
6
  import wx
8
7
  import wx.lib.eventwatcher as ew
9
8
  from wx.lib.mixins.listctrl import ListCtrlAutoWidthMixin
10
9
 
11
- from .utilus import where
10
+ from .utilus import where, ignore
12
11
  from .controls import Icon, Clipboard
13
12
  from .framework import CtrlInterface, Menu
14
13
 
@@ -176,8 +175,7 @@ class EventMonitor(wx.ListCtrl, ListCtrlAutoWidthMixin, CtrlInterface):
176
175
  source = ew._makeSourceString(obj) + " id=0x{:X}".format(id(evt))
177
176
  stamp = 1
178
177
 
179
- with warnings.catch_warnings():
180
- warnings.simplefilter('ignore', DeprecationWarning)
178
+ with ignore(DeprecationWarning):
181
179
  attribs = ew._makeAttribString(evt)
182
180
 
183
181
  data = self.__items
@@ -232,7 +230,7 @@ class EventMonitor(wx.ListCtrl, ListCtrlAutoWidthMixin, CtrlInterface):
232
230
  if self.IsSelected(i):
233
231
  event, name, *_, attribs = self.__items[i]
234
232
  text += "{}\t{}\n{}\n\n".format(event, name, attribs)
235
- Clipboard.write(text.strip('\n'))
233
+ Clipboard.write(text[:-1])
236
234
 
237
235
  def OnSortItems(self, evt): #<wx._controls.ListEvent>
238
236
  n = self.ItemCount
mwx/wxwil.py CHANGED
@@ -145,7 +145,7 @@ class LocalsWatcher(wx.ListCtrl, ListCtrlAutoWidthMixin, CtrlInterface):
145
145
  if self.IsSelected(i):
146
146
  key, vstr = self.__items[i]
147
147
  text += "{} = {}\n".format(key, vstr)
148
- Clipboard.write(text.strip('\n'))
148
+ Clipboard.write(text)
149
149
 
150
150
  def OnSortItems(self, evt): #<wx._controls.ListEvent>
151
151
  n = self.ItemCount
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mwxlib
3
- Version: 0.96.1
3
+ Version: 0.96.5
4
4
  Summary: A wrapper of matplotlib and wxPython (phoenix)
5
5
  Home-page: https://github.com/komoto48g/mwxlib
6
6
  Author: Kazuya O'moto
@@ -0,0 +1,28 @@
1
+ mwx/__init__.py,sha256=nN62CGTWjME7Zz2h-jIRB8MxwuErIkHPGrlBzydkF0o,643
2
+ mwx/bookshelf.py,sha256=CjcgtHC33KR5mHp1lW6Bqfndpzr7hC8ICkFihw4kM3g,5134
3
+ mwx/controls.py,sha256=CAfptYrYxHg1qix3MInXuSp3epI33gpQxf183jLPTvo,48321
4
+ mwx/framework.py,sha256=9-FMc30KMYYkYCuql8k8Wa8ynjj6GTbMamZV_x5GVgs,75227
5
+ mwx/graphman.py,sha256=XoD_wbt5wrmiRf8Q3lpn_eklakE2K-rLfpzfXG1L-Pc,71269
6
+ mwx/images.py,sha256=_-Eh3xF7Khu42ivkYp97NXIzSNGbjcidqtWjZQFGtqE,47827
7
+ mwx/matplot2.py,sha256=-G7z0Osozm9NjLfXvX5UcdFviwbNUktjbd904_g-PqQ,33516
8
+ mwx/matplot2g.py,sha256=22rpdkqJQEJADINPaG5htACutbt8oG1ewO8LMpxaqH4,65237
9
+ mwx/matplot2lg.py,sha256=MDbkO0vn5yi9rwTBCBJ4rsIHcWyoGXeNTbp0xfrvTdM,27381
10
+ mwx/mgplt.py,sha256=ITzxA97yDwr_35BUk5OqnyskSuKVDbpf2AQCKY1jHTI,5671
11
+ mwx/nutshell.py,sha256=HNo8ZuhLZPKd_Cg4s9NN-KfuSXHRP_jaw1s59GVXkN4,136971
12
+ mwx/utilus.py,sha256=d-cDI4n4S-v-Gya2ekbVURq686BQfFZ7S2i63wIKHQg,37298
13
+ mwx/wxmon.py,sha256=f3V24EF7kdMlYF7usLYK9QE5KU6fSu0jVqsvwAiA-Ag,12647
14
+ mwx/wxpdb.py,sha256=lLowkkAgMhPFHAfklD7wZHq0qbSMjRxnBFtSajmVgME,19133
15
+ mwx/wxwil.py,sha256=0bzSTfMEjllJheKxZPb4p8Luz6Il3V29bCLBty72U2o,5576
16
+ mwx/wxwit.py,sha256=yU6XeCCWRBP7CLmpphjT072PfXAL30DNaxoChDX2p0I,7322
17
+ mwx/plugins/__init__.py,sha256=jnJ-Sl9XJ_7BFDslD_r7dsbxsOT57q_IaEriV53XIGY,41
18
+ mwx/plugins/ffmpeg_view.py,sha256=QjNqnvPEd9vCwfATU2BOO75fIOFD5LQ-Wf-BBhvZNZs,9368
19
+ mwx/plugins/fft_view.py,sha256=HcnBr-y_yFdSfASPRzMLANta4SwSDShd65QWnCU3XhM,2665
20
+ mwx/plugins/frame_listview.py,sha256=Li993CV0pPY23Jb8cGQkc3wVeDlHWLEe8RuDbNZeB8s,10351
21
+ mwx/plugins/line_profile.py,sha256=--9NIc3x5EfRB3L59JvD7rzENQHyiYfu7wWJo6AuMkA,820
22
+ mwx/py/__init__.py,sha256=xykgfOytOwNuvXsfkLoumFZSTN-iBsHOjczYXngjmUE,12
23
+ mwx/py/filling.py,sha256=KaHooM32hrGGgqw75Cbt8lAvACwC6RXadob9LGgNnEc,16806
24
+ mwxlib-0.96.5.dist-info/LICENSE,sha256=PGtRKCaTkmUDlBQwpptJAxJtdqxIUtAmdBsaT9nUVkA,1091
25
+ mwxlib-0.96.5.dist-info/METADATA,sha256=7bmBbSe5QXryHXNY8gbPkgx7wMUMIl-wGVn_esBg5fU,1925
26
+ mwxlib-0.96.5.dist-info/WHEEL,sha256=y4mX-SOX4fYIkonsAGA5N0Oy-8_gI4FXw5HNI1xqvWg,91
27
+ mwxlib-0.96.5.dist-info/top_level.txt,sha256=SI1Mh118AstnUFGPNq5aMNKiAnVNmZk1S9Ij-OwAEpY,4
28
+ mwxlib-0.96.5.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (70.1.1)
2
+ Generator: setuptools (70.2.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,28 +0,0 @@
1
- mwx/__init__.py,sha256=nN62CGTWjME7Zz2h-jIRB8MxwuErIkHPGrlBzydkF0o,643
2
- mwx/bookshelf.py,sha256=DAhMQk3_J4rdE50adBMFu5wNz3WdMh_zzJ37O9ncceo,5103
3
- mwx/controls.py,sha256=2US02WAmYVydsPJ8ILzZ7opV83giX1P6kY5rr_ZTX2E,48278
4
- mwx/framework.py,sha256=rzhushWI0BYuGeorx4M6ElKEtpMxrQIrlKOxqqEIokI,75665
5
- mwx/graphman.py,sha256=4SRwCMs4-sS3n23FthythhuG9dBJ8TLz_TVyoYAbdoA,70639
6
- mwx/images.py,sha256=gyvqW4TLWdJMKmsaWiPiV_PuHJM1GbHgeELERLwGzg8,45291
7
- mwx/matplot2.py,sha256=-G7z0Osozm9NjLfXvX5UcdFviwbNUktjbd904_g-PqQ,33516
8
- mwx/matplot2g.py,sha256=2vDx1pY89b4A7uaLd_RHK2HQ5hnwtH4C4wiYZLzuQjw,65707
9
- mwx/matplot2lg.py,sha256=pcu1oDPE_BlpFqNGPPKf9vpTuDs_h_u3OTRAJx5-Sds,27392
10
- mwx/mgplt.py,sha256=ITzxA97yDwr_35BUk5OqnyskSuKVDbpf2AQCKY1jHTI,5671
11
- mwx/nutshell.py,sha256=yQbih2Q1SXexJPuFNSwJnky5teRHXEKks12laHo6joo,137049
12
- mwx/utilus.py,sha256=YShC4f67dIyjIOSZhSOEgBUfNR1nVOS6pxtm0GKMWrA,37320
13
- mwx/wxmon.py,sha256=6es-jVz9Ht7vZnG7VBJcaNYLHY0PnZtij60SXcZRTeY,12727
14
- mwx/wxpdb.py,sha256=lLowkkAgMhPFHAfklD7wZHq0qbSMjRxnBFtSajmVgME,19133
15
- mwx/wxwil.py,sha256=zP1-5Fpi1wpDQU977229zIH6QRuSkkyfuAlNKWjGoGg,5588
16
- mwx/wxwit.py,sha256=yU6XeCCWRBP7CLmpphjT072PfXAL30DNaxoChDX2p0I,7322
17
- mwx/plugins/__init__.py,sha256=jnJ-Sl9XJ_7BFDslD_r7dsbxsOT57q_IaEriV53XIGY,41
18
- mwx/plugins/ffmpeg_view.py,sha256=wZXRgsiPyIphcA8hvXQoE7NZp4cc_YBOO0ZpuKmUJKE,9369
19
- mwx/plugins/fft_view.py,sha256=HcnBr-y_yFdSfASPRzMLANta4SwSDShd65QWnCU3XhM,2665
20
- mwx/plugins/frame_listview.py,sha256=RaYOj-YKrpLqhT8TkBRDX1TQnSPv90V185j8OjrWJTs,10108
21
- mwx/plugins/line_profile.py,sha256=--9NIc3x5EfRB3L59JvD7rzENQHyiYfu7wWJo6AuMkA,820
22
- mwx/py/__init__.py,sha256=xykgfOytOwNuvXsfkLoumFZSTN-iBsHOjczYXngjmUE,12
23
- mwx/py/filling.py,sha256=KaHooM32hrGGgqw75Cbt8lAvACwC6RXadob9LGgNnEc,16806
24
- mwxlib-0.96.1.dist-info/LICENSE,sha256=PGtRKCaTkmUDlBQwpptJAxJtdqxIUtAmdBsaT9nUVkA,1091
25
- mwxlib-0.96.1.dist-info/METADATA,sha256=0D7iaLq2lSivCrt81_r6TINYUkXkU-tUAdsIVugNrrY,1925
26
- mwxlib-0.96.1.dist-info/WHEEL,sha256=mguMlWGMX-VHnMpKOjjQidIo1ssRlCFu4a4mBpz1s2M,91
27
- mwxlib-0.96.1.dist-info/top_level.txt,sha256=SI1Mh118AstnUFGPNq5aMNKiAnVNmZk1S9Ij-OwAEpY,4
28
- mwxlib-0.96.1.dist-info/RECORD,,