mwxlib 1.2.4__py3-none-any.whl → 1.2.7__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/controls.py CHANGED
@@ -770,6 +770,7 @@ class Clipboard:
770
770
  return text
771
771
  else:
772
772
  print("- Unable to open clipboard.")
773
+ return None
773
774
 
774
775
  @staticmethod
775
776
  def write(text, verbose=False):
@@ -792,7 +793,7 @@ class Clipboard:
792
793
  bmp = do.GetBitmap()
793
794
  else:
794
795
  print("- Unable to open clipboard.")
795
- return
796
+ return None
796
797
  try:
797
798
  ## Convert bmp --> buf
798
799
  img = bmp.ConvertToImage()
@@ -802,7 +803,8 @@ class Clipboard:
802
803
  w, h = img.GetSize()
803
804
  return buf.reshape(h, w, 3)
804
805
  except Exception:
805
- print("- The contents of the clipboard are not images.")
806
+ print("- Contents of the clipboard are not images.")
807
+ return None
806
808
 
807
809
  @staticmethod
808
810
  def imwrite(buf, verbose=False):
@@ -815,7 +817,7 @@ class Clipboard:
815
817
  img = wx.Image(w, h, buf.tobytes())
816
818
  bmp = img.ConvertToBitmap()
817
819
  except Exception:
818
- print("- The contents of the clipboard are not images.")
820
+ print("- Argument 'buf' is not a 2d array.")
819
821
  return
820
822
  do = wx.BitmapDataObject(bmp)
821
823
  if wx.TheClipboard.Open():
mwx/framework.py CHANGED
@@ -1,7 +1,7 @@
1
1
  #! python3
2
2
  """mwxlib framework.
3
3
  """
4
- __version__ = "1.2.4"
4
+ __version__ = "1.2.7"
5
5
  __author__ = "Kazuya O'moto <komoto@jeol.co.jp>"
6
6
 
7
7
  from contextlib import contextmanager
mwx/graphman.py CHANGED
@@ -1410,7 +1410,7 @@ class Frame(mwx.Frame):
1410
1410
  frames = self.load_buffer(paths, view)
1411
1411
  if frames:
1412
1412
  for frame in frames:
1413
- frame.update_attributes(res.get(frame.name))
1413
+ frame.set_attributes(res.get(frame.name))
1414
1414
 
1415
1415
  n = len(frames)
1416
1416
  self.message(
@@ -1507,7 +1507,7 @@ class Frame(mwx.Frame):
1507
1507
  """Write attributes file."""
1508
1508
  try:
1509
1509
  res, mis = self.read_attributes(filename)
1510
- new = dict((x.name, x.attributes) for x in frames)
1510
+ new = dict((x.name, x.get_attributes()) for x in frames)
1511
1511
 
1512
1512
  ## `res` order may differ from that of given frames,
1513
1513
  ## so we take a few steps to merge `new` to be exported.
@@ -1540,7 +1540,7 @@ class Frame(mwx.Frame):
1540
1540
  res, mis = self.read_attributes(fn)
1541
1541
  savedirs[savedir] = res
1542
1542
  results = savedirs[savedir]
1543
- frame.update_attributes(results.get(frame.name))
1543
+ frame.set_attributes(results.get(frame.name))
1544
1544
  return frames
1545
1545
 
1546
1546
  def save_frame(self, path=None, frame=None):
mwx/matplot2g.py CHANGED
@@ -1,7 +1,6 @@
1
1
  #! python3
2
2
  """mwxlib graph plot for images.
3
3
  """
4
- import traceback
5
4
  import wx
6
5
 
7
6
  from matplotlib import cm
@@ -49,6 +48,11 @@ def _to_buffer(img):
49
48
  w, h = img.GetSize()
50
49
  img = np.frombuffer(img.GetDataBuffer(), dtype='uint8').reshape(h, w, 3)
51
50
 
51
+ if not isinstance(img, np.ndarray):
52
+ raise ValueError("targets must be arrays or images.")
53
+
54
+ assert img.ndim > 1, "targets must be 2d arrays."
55
+
52
56
  if img.ndim > 2:
53
57
  return cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
54
58
  return img
@@ -114,25 +118,22 @@ class AxesImagePhantom:
114
118
  """Phantom of frame facade
115
119
 
116
120
  Args:
117
- buf : buffer
118
- name : buffer name
119
- show : show immediately when loaded
120
- aspect : initial aspect ratio
121
- localunit : initial localunit
122
- attributes : additional info:dict
121
+ buf : buffer
122
+ name : buffer name
123
+ show : show immediately when loaded
124
+ **kwargs: frame attributes
123
125
 
124
126
  Note:
125
127
  Due to the problem of performance,
126
128
  the image pixel size could be reduced by binning.
127
129
  """
128
- def __init__(self, parent, buf, name, show=True,
129
- localunit=None, aspect=1.0, **attributes):
130
+ def __init__(self, parent, buf, name, show=True, **kwargs):
130
131
  self.parent = parent
131
132
  self.__name = name
132
- self.__localunit = localunit or None # [+] value, no assertion
133
- self.__aspect_ratio = aspect
134
- self.__attributes = attributes
135
- self.__attributes['localunit'] = self.__localunit
133
+ self.__attributes = kwargs
134
+ self.__localunit = kwargs.get('localunit')
135
+ self.__center = kwargs.get('center', (0, 0))
136
+ self.__aspect_ratio = 1
136
137
  self.__buf = _to_buffer(buf)
137
138
  bins, vlim, img = _to_image(self.__buf,
138
139
  cutoff = self.parent.score_percentile,
@@ -147,7 +148,7 @@ class AxesImagePhantom:
147
148
  visible = show,
148
149
  picker = True,
149
150
  )
150
- self.update_extent() # this determines the aspect ratio
151
+ self.update_extent()
151
152
 
152
153
  def __getattr__(self, attr):
153
154
  return getattr(self.__art, attr)
@@ -156,22 +157,27 @@ class AxesImagePhantom:
156
157
  ## Called in `on_pick` and `__contains__` to check objects in.
157
158
  return x is self.__art
158
159
 
159
- def update_attributes(self, attr=None, **kwargs):
160
- """Update frame-specifc attributes.
161
- The frame holds any attributes with dictionary
162
- There are some keys which acts as the value setter when given,
163
- `annotation` also shows the message with infobar
164
- `localunit` also updates the frame.unit
160
+ def get_attributes(self):
161
+ """Auxiliary info about the frame."""
162
+ return self.__attributes
163
+
164
+ def set_attributes(self, attr):
165
+ """Update frame-specifc attributes:
166
+
167
+ annotation : aux info (also displayed as a message in the infobar)
168
+ center : frame.center defaults to (0, 0)
169
+ localunit : frame.unit
170
+ pathname : full path of the buffer file
165
171
  """
166
- attr = attr or {}
167
- attr.update(kwargs)
172
+ if not attr:
173
+ return
168
174
  self.__attributes.update(attr)
169
175
 
170
176
  if 'localunit' in attr:
171
- self.unit = attr['localunit']
177
+ self.unit = attr['localunit'] # => [frame_updated]
172
178
 
173
- if 'aspect' in attr:
174
- self.aspect_ratio = attr['aspect']
179
+ if 'center' in attr:
180
+ self.center = attr['center'] # => [frame_updated]
175
181
 
176
182
  if 'annotation' in attr:
177
183
  v = attr['annotation']
@@ -201,7 +207,8 @@ class AxesImagePhantom:
201
207
  ux, uy = self.xy_unit
202
208
  w *= ux/2
203
209
  h *= uy/2
204
- self.__art.set_extent((-w,w,-h,h))
210
+ cx, cy = self.center
211
+ self.__art.set_extent((cx-w, cx+w, cy-h, cy+h))
205
212
 
206
213
  selector = _Property('Selector')
207
214
  markers = _Property('Markers')
@@ -227,18 +234,14 @@ class AxesImagePhantom:
227
234
  lambda self,v: self.__art.set_clim(v),
228
235
  doc="Lower/Upper color limit values of the buffer.")
229
236
 
230
- attributes = property(
231
- lambda self: self.__attributes,
232
- doc="Miscellaneous info about the frame/buffer.")
233
-
234
237
  pathname = property(
235
238
  lambda self: self.__attributes.get('pathname'),
236
- lambda self,v: self.update_attributes({'pathname': v}),
239
+ lambda self,v: self.set_attributes({'pathname': v}),
237
240
  doc="Fullpath of the buffer, if bound to a file.")
238
241
 
239
242
  annotation = property(
240
243
  lambda self: self.__attributes.get('annotation', ''),
241
- lambda self,v: self.update_attributes({'annotation': v}),
244
+ lambda self,v: self.set_attributes({'annotation': v}),
242
245
  doc="Annotation of the buffer.")
243
246
 
244
247
  @property
@@ -261,17 +264,16 @@ class AxesImagePhantom:
261
264
 
262
265
  @unit.setter
263
266
  def unit(self, v):
267
+ if v == self.__localunit: # no effect
268
+ return
264
269
  if v is None or np.isnan(v): # nan => undefined
265
- v = self.parent.unit
266
- self.__localunit = None
270
+ v = None
267
271
  elif np.isinf(v):
268
272
  raise ValueError("The unit value must not be inf")
269
273
  elif v <= 0:
270
274
  raise ValueError("The unit value must be greater than zero")
271
- else:
272
- if v == self.__localunit: # no effect when v is localunit
273
- return
274
- self.__localunit = v
275
+
276
+ self.__localunit = v
275
277
  self.__attributes['localunit'] = self.__localunit
276
278
  self.update_extent()
277
279
  self.parent.handler('frame_updated', self)
@@ -286,6 +288,18 @@ class AxesImagePhantom:
286
288
  u = self.__localunit or self.parent.unit
287
289
  return (u, u * self.__aspect_ratio)
288
290
 
291
+ @property
292
+ def center(self):
293
+ """Center of logical unit."""
294
+ return self.__center
295
+
296
+ @center.setter
297
+ def center(self, v):
298
+ self.__center = tuple(v)
299
+ self.__attributes['center'] = self.__center
300
+ self.update_extent()
301
+ self.parent.handler('frame_updated', self)
302
+
289
303
  @property
290
304
  def aspect_ratio(self):
291
305
  """Aspect ratio of logical unit."""
@@ -293,9 +307,7 @@ class AxesImagePhantom:
293
307
 
294
308
  @aspect_ratio.setter
295
309
  def aspect_ratio(self, v):
296
- if v == self.__aspect_ratio:
297
- return
298
- self.__aspect_ratio = v or 1.0
310
+ self.__aspect_ratio = v or 1
299
311
  self.update_extent()
300
312
  self.parent.handler('frame_updated', self)
301
313
 
@@ -620,20 +632,11 @@ class GraphPlot(MatplotPanel):
620
632
  name : buffer name (default to *temp*).
621
633
  pos : Insertion position in the frame list.
622
634
  show : Show immediately when loaded.
623
-
624
635
  **kwargs: frame attributes.
625
-
626
- - localunit : localunit
627
- - aspect : aspect ratio
628
- - pathname : full path of the buffer file
629
636
  """
630
637
  if isinstance(buf, str):
631
638
  buf = Image.open(buf)
632
639
 
633
- if not isinstance(buf, (np.ndarray, Image.Image, wx.Bitmap, wx.Image)):
634
- warn("Load targets must be either arrays or images.")
635
- return None
636
-
637
640
  pathname = kwargs.get('pathname')
638
641
  paths = [art.pathname for art in self.__Arts]
639
642
  names = [art.name for art in self.__Arts]
@@ -645,8 +648,8 @@ class GraphPlot(MatplotPanel):
645
648
  j = names.index(name) # existing frame
646
649
  if j != -1:
647
650
  art = self.__Arts[j]
648
- art.update_buffer(buf) # => [frame_modified]
649
- art.update_attributes(kwargs) # => [frame_updated] localunit => [canvas_draw]
651
+ art.update_buffer(buf) # => [frame_modified]
652
+ art.set_attributes(kwargs) # => [frame_updated] localunit => [canvas_draw]
650
653
  art.update_extent()
651
654
  if show:
652
655
  self.select(j)
@@ -697,31 +700,32 @@ class GraphPlot(MatplotPanel):
697
700
  j = self.index(j)
698
701
 
699
702
  buffers = [art.buffer for art in self.__Arts]
703
+ if hasattr(j, '__iter__'):
704
+ return [buffers[i] for i in j]
700
705
  return buffers[j] # j can also be slicing
701
706
 
702
707
  def __setitem__(self, j, v):
708
+ if v is None:
709
+ raise ValueError("values must be buffers, not NoneType")
710
+
703
711
  if isinstance(j, str):
704
- try:
705
- j = self.index(j) # overwrite buffer
706
- except ValueError:
707
- return self.load(v, name=j) # new buffer
712
+ return self.load(v, name=j) # update buffer or new buffer
708
713
 
709
- if isinstance(j, slice):
710
- raise ValueError("attempt to assign buffers via slicing")
714
+ if isinstance(j, slice) or hasattr(j, '__iter__'):
715
+ raise ValueError("attempt to assign buffers via slicing or iterator")
711
716
 
712
- if v is None:
713
- raise ValueError("values must be buffers, not NoneType.")
714
- else:
715
- art = self.__Arts[j]
716
- art.update_buffer(v) # update buffer
717
- art.update_extent()
718
- self.select(j)
717
+ art = self.__Arts[j]
718
+ art.update_buffer(v) # update buffer
719
+ art.update_extent()
720
+ self.select(j)
719
721
 
720
722
  def __delitem__(self, j):
721
723
  if isinstance(j, str):
722
724
  j = self.index(j)
723
725
 
724
- if isinstance(j, slice):
726
+ if hasattr(j, '__iter__'):
727
+ arts = [self.__Arts[i] for i in j]
728
+ elif isinstance(j, slice):
725
729
  arts = self.__Arts[j]
726
730
  else:
727
731
  arts = [self.__Arts[j]]
@@ -818,13 +822,13 @@ class GraphPlot(MatplotPanel):
818
822
 
819
823
  @unit.setter
820
824
  def unit(self, v):
825
+ if v == self.__unit: # no effect unless unit changes
826
+ return
821
827
  if v is None or np.isnan(v) or np.isinf(v):
822
828
  raise ValueError("The unit value must not be nan or inf")
823
829
  elif v <= 0:
824
830
  raise ValueError("The unit value must be greater than zero")
825
831
  else:
826
- if v == self.__unit: # no effect unless unit changes
827
- return
828
832
  self.__unit = v
829
833
  for art in self.__Arts:
830
834
  art.update_extent()
@@ -962,34 +966,28 @@ class GraphPlot(MatplotPanel):
962
966
  if not frame:
963
967
  self.message("No frame")
964
968
  return
965
- try:
966
- name = frame.name
967
- data = frame.roi
968
- GraphPlot.clipboard_name = name
969
- GraphPlot.clipboard_data = data
970
- bins, vlim, img = _to_image(data, frame.cuts)
971
- Clipboard.imwrite(img)
972
- self.message("Write buffer to clipboard.")
973
- except Exception as e:
974
- traceback.print_exc()
975
- self.message("- Failed to write to clipboard.", e)
969
+
970
+ name = frame.name
971
+ data = frame.roi
972
+ GraphPlot.clipboard_name = name
973
+ GraphPlot.clipboard_data = data
974
+ bins, vlim, img = _to_image(data, frame.cuts)
975
+ Clipboard.imwrite(img)
976
+ self.message("Write buffer to clipboard.")
976
977
 
977
978
  def read_buffer_from_clipboard(self):
978
979
  """Read buffer data from clipboard."""
979
- try:
980
- name = GraphPlot.clipboard_name
981
- data = GraphPlot.clipboard_data
982
- if name:
983
- self.message("Read buffer from clipboard.")
984
- GraphPlot.clipboard_name = None
985
- GraphPlot.clipboard_data = None
986
- else:
987
- self.message("Read image from clipboard.")
988
- data = Clipboard.imread()
980
+ name = GraphPlot.clipboard_name
981
+ data = GraphPlot.clipboard_data
982
+ if name:
983
+ self.message("Read buffer from clipboard.")
984
+ GraphPlot.clipboard_name = None
985
+ GraphPlot.clipboard_data = None
986
+ else:
987
+ self.message("Read image from clipboard.")
988
+ data = Clipboard.imread()
989
+ if data is not None:
989
990
  self.load(data)
990
- except Exception as e:
991
- traceback.print_exc()
992
- self.message("- No data in clipboard.", e)
993
991
 
994
992
  def destroy_colorbar(self):
995
993
  if self.cbar:
@@ -185,7 +185,7 @@ class CheckList(wx.ListCtrl, ListCtrlAutoWidthMixin, CtrlInterface):
185
185
  if selected_frames:
186
186
  text = ''
187
187
  for frame in selected_frames:
188
- text += pformat(frame.attributes, sort_dicts=0) # ALL attributes
188
+ text += pformat(frame.get_attributes(), sort_dicts=0) # ALL attributes
189
189
  ## text += '{}\n{}\n'.format(frame.name, frame.annotation)
190
190
  Clipboard.write(text)
191
191
  else:
mwx/utilus.py CHANGED
@@ -37,15 +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
- if not frame:
47
- break
48
- stacklevel += 1
40
+ def warn(message, category=None, stacklevel=None):
41
+ if stacklevel is None:
42
+ frame = inspect.currentframe().f_back # previous call stack frame
43
+ skip = [frame.f_code.co_filename]
44
+ stacklevel = 1
45
+ while frame.f_code.co_filename in skip:
46
+ frame = frame.f_back
47
+ if not frame:
48
+ break
49
+ stacklevel += 1
49
50
  return warnings.warn(message, category, stacklevel+1)
50
51
 
51
52
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mwxlib
3
- Version: 1.2.4
3
+ Version: 1.2.7
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
@@ -1,16 +1,16 @@
1
1
  mwx/__init__.py,sha256=pS7ZG8QKRypiFFiaWAq_opBB6I_1viZ0zUMk2TbjzE0,667
2
2
  mwx/bookshelf.py,sha256=b_TMDaNIzLHoL0xbbqb3tt0BnRvhLAqaCn_pBdrigZw,7523
3
- mwx/controls.py,sha256=X4zx2h6oggUsQxi2PRk4RUsJieYTmcAPIvWwaz-ysTI,48107
4
- mwx/framework.py,sha256=8Vh1Tkqod9sWp81ObY5Ofcqto_UJerT_VtEgA97huoA,76125
5
- mwx/graphman.py,sha256=RqD0W9I2BvJ3Q2kyMiyyg4n-T4-_x7PDuCI5bGAg5k4,70110
3
+ mwx/controls.py,sha256=5PCy3zguDRuwYl89P9tOCUU7xAGUETs944qZBy5MS9g,48146
4
+ mwx/framework.py,sha256=wurY8uvLFJW6Xig5kTTI84MkFWAK3v4-a6H2eSEwv7M,76125
5
+ mwx/graphman.py,sha256=6ON1lckAyCbIMhIPHRbi9yvWYI2yT_CIWhNFbW31-mc,70110
6
6
  mwx/images.py,sha256=oxCn0P-emiWujSS2gUgU5TUnr5cPjix2jBcjOBDr24I,48701
7
7
  mwx/matplot2.py,sha256=Zwte-wwzCg_OHzsBniVgKdaNLzsvJaa1gc0n7VdAqxw,33150
8
- mwx/matplot2g.py,sha256=tp0KD_dqDgupTVROY4YFZyfvHS_d21w4uS3x0Sd_zSA,64643
8
+ mwx/matplot2g.py,sha256=gs9U6VDdSX9wmzgrzDCWEZEL3DTOc5XkZOWZE5mffxc,64207
9
9
  mwx/matplot2lg.py,sha256=JRWjWnLJUytbSq6wxs4P0gbVUr3xoLSF6Wwqd5V_pJI,27404
10
10
  mwx/mgplt.py,sha256=8mXbHpCmm7lz3XbAxOg7IVC7DaSGBEby1UfTlMl9kjk,5604
11
11
  mwx/nutshell.py,sha256=7nQ7UUFM9kvjDjHNUEdOkkeqZPiU6zOERwamqBdJpQs,140856
12
12
  mwx/testsuite.py,sha256=kiM3-BVhr42LRRN7xG7pYl3at8o2vnypWSxD8KRvA7c,1228
13
- mwx/utilus.py,sha256=HFvP682SyeSp8yNfUrdUXPhWdLuWVlsUSg6LqNBJOT8,37451
13
+ mwx/utilus.py,sha256=bDeooo2bOcZwvkIdi0ElkT-qoblqzHNFsIveb72NFOo,37528
14
14
  mwx/wxmon.py,sha256=yzWqrbY6LzpfRwQeytYUeqFhFuLVm_XEvrVAL_k0HBQ,12756
15
15
  mwx/wxpdb.py,sha256=ge4hNfeigHGcpnioU1B_BJX_QZjNdtnokUrcZOxcEcI,18814
16
16
  mwx/wxwil.py,sha256=hhyB1lPrF9ixeObxCOKQv0Theu-B-kpJg_yVU3EGSNg,5406
@@ -18,12 +18,12 @@ mwx/wxwit.py,sha256=1hHtMi2YEy2T_LnUpwdmrIdtCuvxMOFyykqnbq6jLP0,7294
18
18
  mwx/plugins/__init__.py,sha256=jnJ-Sl9XJ_7BFDslD_r7dsbxsOT57q_IaEriV53XIGY,41
19
19
  mwx/plugins/ffmpeg_view.py,sha256=NIHFJLPeliOXH3ke0NvQzYBhY0oeEP6dgZQofB5Ry1c,11031
20
20
  mwx/plugins/fft_view.py,sha256=08A_Y73XirV7kXpwf-v0mUA0Hr0MOfdMXv3tvL1hvWA,2789
21
- mwx/plugins/frame_listview.py,sha256=gowjQ-ARNonMkDSXkQgPKq4U9YBJ-vQ0jK2krBVOdCs,10420
21
+ mwx/plugins/frame_listview.py,sha256=z2mGbOTStjaICU7vkn-fs_C8uvCD1xMldSOdr-_IKH0,10426
22
22
  mwx/plugins/line_profile.py,sha256=zzm6_7lnAnNepLbh07ordp3nRWDFQJtu719ZVjrVf8s,819
23
23
  mwx/py/__init__.py,sha256=xykgfOytOwNuvXsfkLoumFZSTN-iBsHOjczYXngjmUE,12
24
24
  mwx/py/filling.py,sha256=fumUG1F5M9TL-Dfqni4G85uk7TmvnUunTbdcPDV0vfo,16857
25
- mwxlib-1.2.4.dist-info/LICENSE,sha256=PGtRKCaTkmUDlBQwpptJAxJtdqxIUtAmdBsaT9nUVkA,1091
26
- mwxlib-1.2.4.dist-info/METADATA,sha256=jgZUZOULgdBFRgLPPjGzxfiPOsz4xdibdZgiXipWvK0,7258
27
- mwxlib-1.2.4.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
28
- mwxlib-1.2.4.dist-info/top_level.txt,sha256=SI1Mh118AstnUFGPNq5aMNKiAnVNmZk1S9Ij-OwAEpY,4
29
- mwxlib-1.2.4.dist-info/RECORD,,
25
+ mwxlib-1.2.7.dist-info/LICENSE,sha256=PGtRKCaTkmUDlBQwpptJAxJtdqxIUtAmdBsaT9nUVkA,1091
26
+ mwxlib-1.2.7.dist-info/METADATA,sha256=sEkzDsdCV7wSQmHtCWDZLv9-2pbqdEQ7XvuD_VSyo5o,7258
27
+ mwxlib-1.2.7.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
28
+ mwxlib-1.2.7.dist-info/top_level.txt,sha256=SI1Mh118AstnUFGPNq5aMNKiAnVNmZk1S9Ij-OwAEpY,4
29
+ mwxlib-1.2.7.dist-info/RECORD,,
File without changes