itkdb-gtk 0.0.16.dev7__py3-none-any.whl → 0.0.16.dev20__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 itkdb-gtk might be problematic. Click here for more details.

itkdb_gtk/WireBondGui.py CHANGED
@@ -10,7 +10,7 @@ from gi.repository import Gtk, Gio, GLib
10
10
 
11
11
  try:
12
12
  import itkdb_gtk
13
-
13
+
14
14
  except ImportError:
15
15
  from pathlib import Path
16
16
  cwd = Path(sys.argv[0]).parent.parent
@@ -34,6 +34,380 @@ test_parameters = {
34
34
  "Failed Module->Frame": "FAILED_MODULE_TO_FRAME"
35
35
  }
36
36
 
37
+ # module_param[iring][i_sensor][i_hybrid][i_row]
38
+ module_param = {
39
+ 0: [
40
+ [
41
+ [[255, 830], [1343, 1918], [2431, 3006], [3519, 4094]],
42
+ [[831, 1342], [1919, 2430], [3007, 3518], [4095, 4606]],
43
+ ]
44
+ ],
45
+ 1: [
46
+ [
47
+ [[271, 974], [1615, 2318], [2959, 3662], [4303, 5006]],
48
+ [[975, 1614], [2319, 2958], [3663, 4302], [5007, 5646]],
49
+ ]
50
+ ],
51
+ 2: [
52
+ [
53
+ [[201, 968], [969, 1736], [1737, 2504], [2505, 3272]]
54
+ ]
55
+ ],
56
+ 3: [
57
+ [
58
+ [[566, 1013], [2358, 2805], [4150, 4597], [5942, 6389]],
59
+ [[1462, 1909], [3254, 3701], [5046, 5493], [6838, 7285]]
60
+ ],
61
+ [
62
+ [[1014, 1461], [2806, 3253], [4598, 5045], [6390, 6837]],
63
+ [[1910, 2357], [3702, 4149], [5494, 5941], [7286, 7733]]
64
+ ]
65
+ ],
66
+ 4: [
67
+ [
68
+ [[318, 829], [1342, 1853], [2366, 2877], [3390, 3901]]
69
+ ],
70
+ [
71
+ [[830, 1341], [1854, 2365], [2878, 3389], [3902, 4413]]
72
+ ]
73
+ ],
74
+ 5: [
75
+ [
76
+ [[332, 907], [1484, 2059], [2636, 3211], [3788, 4363]]
77
+ ],
78
+ [
79
+ [[908, 1483], [2060, 2635], [3212, 3787], [4364, 4939]]
80
+ ]
81
+ ],
82
+ }
83
+
84
+ def wire2strip(mod_par, irow, iwire):
85
+ """Convert from wirebond index to strip_number."""
86
+ for sensor in mod_par:
87
+ for hyb in sensor:
88
+ rng = hyb[irow]
89
+ if iwire>= rng[0] and iwire<=rng[1]:
90
+ if irow % 2:
91
+ ichan = 2*(iwire-rng[0]) + 1
92
+ else:
93
+ ichan = 2*(iwire-rng[0])
94
+
95
+ return ichan
96
+
97
+ return None
98
+
99
+
100
+ def find_holes(chan_list, min_chan=0, max_chan=999999):
101
+ """Find groups of consecutive channels."""
102
+ out = sorted(chan_list)
103
+ nchan = 0
104
+ last_chan = -1
105
+ ichan = -1
106
+ holes = []
107
+ for chan in out:
108
+ if chan < min_chan or chan > max_chan:
109
+ continue
110
+
111
+ if last_chan < 0:
112
+ last_chan = chan
113
+ continue
114
+
115
+ if chan - last_chan > 1:
116
+ if nchan:
117
+ holes.append([ichan, nchan])
118
+ nchan = 0
119
+ ichan = -1
120
+ else:
121
+ if last_chan < max_chan and chan >= max_chan:
122
+ # WE are in another sensor
123
+ holes.append([ichan, nchan])
124
+ nchan = 0
125
+ ichan = -1
126
+ last_chan = chan
127
+ continue
128
+
129
+ nchan += 1
130
+ if ichan < 0:
131
+ ichan = last_chan
132
+ nchan += 1
133
+
134
+ last_chan = chan
135
+
136
+ if nchan:
137
+ holes.append([ichan, nchan])
138
+
139
+ return holes
140
+
141
+
142
+ class HybridHoles:
143
+ """Holes in hybrid bomds.
144
+
145
+ Holes are defined by a list [first_chan, n_chan].
146
+ """
147
+
148
+ def __init__(self, param, hid=0):
149
+ """Initialization.
150
+
151
+ Args:
152
+ param: Hybrid wirebon parameters.
153
+
154
+ """
155
+ self.id = hid
156
+ self.param = param
157
+ self.nchan = 0
158
+ for min_chan, max_chan in param:
159
+ self.nchan += (max_chan-min_chan+1)
160
+
161
+ self.holes = [[] for irow in range(4)]
162
+ self.channels = [[] for irow in range(4)]
163
+
164
+ def add_channel(self, irow, ichan)->bool:
165
+ """Add a new channel in row.
166
+
167
+ Args:
168
+ irow: rown number
169
+ ichan: channel number
170
+
171
+ Return:
172
+ True if added, False otherwise.
173
+ """
174
+ first_chan = self.param[irow][0]
175
+ last_chan = self.param[irow][1]
176
+ if isinstance(ichan, list) or isinstance(ichan, tuple):
177
+ nadded = 0
178
+ for ich in ichan:
179
+ if ich >= first_chan and ich <= last_chan:
180
+ self.channels[irow].append(ich)
181
+ nadded += 1
182
+
183
+ self.channels[irow] = sorted(self.channels[irow])
184
+ return nadded>0
185
+ else:
186
+ if ichan >= first_chan and ichan <= last_chan:
187
+ self.channels[irow].append(ichan)
188
+ return True
189
+ else:
190
+ return False
191
+
192
+ def get_n_unconnected(self):
193
+ """Count number of unconnected channels.
194
+
195
+ Return a list, one item per row.
196
+ """
197
+ nchan = []
198
+ for row in self.holes:
199
+ nch = 0
200
+ for h in row:
201
+ nch += h[1]
202
+
203
+ nchan.append(nch)
204
+
205
+ return nchan
206
+
207
+ def get_max_consecutive(self):
208
+ """Returns the largest 'hole'."""
209
+ mx_width = []
210
+
211
+ for row in self.holes:
212
+ mxW = -1
213
+ for h in row:
214
+ if h[1] > mxW:
215
+ mxW = h[1]
216
+
217
+ mx_width.append(mxW)
218
+
219
+ return mx_width
220
+
221
+ def get_sensor_holes(self):
222
+ """Compute holes in 'sensor' strips.
223
+
224
+ Each hybrid has 2 sensor segments corresponding to
225
+ rows (1,2) and (3, 4).
226
+
227
+ Return a list of [sensor, hybrid, segment, ichan, width]
228
+ """
229
+ holes = []
230
+ channels = [[], []]
231
+ for irow, row in enumerate(self.channels):
232
+ isegment = int(irow/2)
233
+ for ich in row:
234
+ rng = self.param[irow]
235
+ if irow % 2:
236
+ chan = 2*(ich-rng[0]) + 1
237
+ else:
238
+ chan = 2*(ich-rng[0])
239
+
240
+ channels[isegment].append(chan)
241
+
242
+ channels[isegment] = sorted(channels[isegment])
243
+
244
+ for isegment, S in enumerate(channels):
245
+ H = find_holes(S)
246
+ if len(H)>0:
247
+ out = [ [0, self.id, isegment, chan, width] for chan, width in H ]
248
+ holes.extend(out)
249
+
250
+ return holes
251
+
252
+
253
+ class SensorHoles:
254
+ """Holes in sensor."""
255
+
256
+ def __init__(self, param, sid=0):
257
+ """Initialization.
258
+
259
+ Args:
260
+ param: sensor wirebon params
261
+ """
262
+ self.id = sid
263
+ self.param = param
264
+ self.nchan = 0
265
+ self.nhybrid = len(param)
266
+ self.hybrids = []
267
+ for i, P in enumerate(param):
268
+ H = HybridHoles(P, hid=i)
269
+ self.hybrids.append(H)
270
+ self.nchan += H.nchan
271
+
272
+ def get_n_hyb(self):
273
+ """Return number of hybrids."""
274
+ return len(self.hybrids)
275
+
276
+ def get_hybrid(self, i):
277
+ """Return i-th hybrid."""
278
+ return self.hybrids[i]
279
+
280
+ def get_max_consecutive(self):
281
+ """Max number of consecutive unconnected channels.
282
+
283
+ This is ordered by row.
284
+ """
285
+ mx_width = [0, 0, 0, 0]
286
+ for hyb in self.hybrids:
287
+ mxW = hyb.get_max_consecutive()
288
+ for j in range(4):
289
+ if mxW[j] > mx_width[j]:
290
+ mx_width[j] = mxW[j]
291
+
292
+ return mx_width
293
+
294
+ def get_n_unconnected(self):
295
+ """Count number of unconnected channels.
296
+
297
+ Return a list, one item per row.
298
+ """
299
+ nchan = [0, 0, 0, 0]
300
+ for hyb in self.hybrids:
301
+ nc = hyb.get_n_unconnected()
302
+ for i, n in enumerate(nc):
303
+ nchan[i] += n
304
+
305
+ return nchan
306
+
307
+ def get_sensor_holes(self):
308
+ """Return holes sensor.
309
+
310
+ Return a list of [sensor, hybrid, segment, ichan, width]
311
+ """
312
+ holes = []
313
+ for hyb in self.hybrids:
314
+ H = hyb.get_sensor_holes()
315
+ for _, ih, isegment, ichan, width in H:
316
+ holes.append([self.id, ih, isegment, ichan, width])
317
+
318
+ return holes
319
+
320
+
321
+ class ModuleHoles:
322
+ """Holes in Modules."""
323
+
324
+ def __init__(self, param):
325
+ """Initialization.
326
+
327
+ Args:
328
+ param: module wirebond params
329
+ """
330
+ self.nsensor = len(param)
331
+ self.nchan = 0
332
+ self.sensors = []
333
+ for i, P in enumerate(param):
334
+ S = SensorHoles(P, sid=i)
335
+ self.sensors.append(S)
336
+ self.nchan += S.nchan
337
+
338
+ def get_max_consecutive(self):
339
+ """Max number of consecutive unconnected channels.
340
+
341
+ This is ordered by row.
342
+ """
343
+ mx_width = [-1, -1, -1, -1]
344
+ for S in self.sensors:
345
+ mxW = S.get_max_consecutive()
346
+ for j in range(4):
347
+ if mxW[j] > mx_width[j]:
348
+ mx_width[j] = mxW[j]
349
+
350
+ return mx_width
351
+
352
+ def get_sensor_holes(self) -> list:
353
+ """Return. holesin sensor strips.
354
+
355
+ Return a list of [sensor, hybrid, segment, ichan, width]
356
+ """
357
+ holes = []
358
+ for S in self.sensors:
359
+ for _, ihyb, isegment, ichan, width in S.get_sensor_holes():
360
+ holes.append([S.id, ihyb, isegment, ichan, width])
361
+
362
+ return holes
363
+
364
+ def get_n_unconnected(self) -> list:
365
+ """Count number of unconnected channels.
366
+
367
+ Return a list, one item per row.
368
+ """
369
+ nchan = [0, 0, 0, 0]
370
+ for S in self.sensors:
371
+ nc = S.get_n_unconnected()
372
+ for i, n in enumerate(nc):
373
+ nchan[i] += n
374
+
375
+ return nchan
376
+
377
+ def get_total_unconnected(self) -> int:
378
+ """Return total number of unconnected wires."""
379
+ unc = self.get_n_unconnected()
380
+ out = 0
381
+ for v in unc:
382
+ out += v
383
+
384
+ return int(out)
385
+
386
+
387
+ def get_module_param(SN):
388
+ """Get parameters of module type.
389
+
390
+ Args:
391
+ SN: Serial Number
392
+
393
+ Returns:
394
+ list: list with bond numbers.
395
+ """
396
+ if len(SN) != 14 or SN[:3]!="20U":
397
+ raise ValueError("Wrong serial number {}".format(SN))
398
+
399
+ if SN[3:5] != "SE":
400
+ raise ValueError("Cannot handle barrel modules yet.")
401
+
402
+ mod_type = SN[5:7]
403
+ if mod_type[0] != "M":
404
+ raise ValueError("Does not seem to be a RingModule: {}".format(SN))
405
+
406
+ ring = int(mod_type[-1])
407
+ param = module_param[ring]
408
+
409
+ return param
410
+
37
411
 
38
412
  class WireBond(Gtk.Window):
39
413
  """Main window."""
@@ -44,6 +418,7 @@ class WireBond(Gtk.Window):
44
418
  self.pdb = None
45
419
  self.session = session
46
420
  self.models = {}
421
+ self.holes = {}
47
422
  self.prepare_window()
48
423
 
49
424
  def prepare_window(self):
@@ -70,6 +445,15 @@ class WireBond(Gtk.Window):
70
445
  button.connect("clicked", self.save_test)
71
446
  self.hb.pack_end(button)
72
447
 
448
+ # Button to upload
449
+ button = Gtk.Button()
450
+ icon = Gio.ThemedIcon(name="document-open-symbolic")
451
+ image = Gtk.Image.new_from_gicon(icon, Gtk.IconSize.BUTTON)
452
+ button.add(image)
453
+ button.set_tooltip_text("Click to read local data file.")
454
+ button.connect("clicked", self.read_file)
455
+ self.hb.pack_end(button)
456
+
73
457
  # Create the main box and add it to the window
74
458
  self.mainBox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
75
459
  self.mainBox.set_property("margin-left", 6)
@@ -78,7 +462,7 @@ class WireBond(Gtk.Window):
78
462
 
79
463
  # Data panel
80
464
  grid = Gtk.Grid(column_spacing=5, row_spacing=1)
81
- for i, tit in enumerate(["Operator", "Bond Machine", "Wire Batch", "SN"]):
465
+ for i, tit in enumerate(["Operator", "Bond Machine", "Wire Batch", "SN", "Date"]):
82
466
  lbl = Gtk.Label(label=tit)
83
467
  lbl.set_xalign(0)
84
468
  grid.attach(lbl, 0, i, 1, 1)
@@ -87,11 +471,14 @@ class WireBond(Gtk.Window):
87
471
  self.machine = dbGtkUtils.new_small_text_entry()
88
472
  self.batch = dbGtkUtils.new_small_text_entry()
89
473
  self.SN = dbGtkUtils.new_small_text_entry()
474
+ self.date = dbGtkUtils.TextEntry(small=True)
475
+ self.date.connect("text_changed", self.new_date)
90
476
 
91
- grid.attach(self.operator, 1, 0, 1, 1)
92
- grid.attach(self.machine, 1, 1, 1, 1)
93
- grid.attach(self.batch, 1, 2, 1, 1)
94
- grid.attach(self.SN, 1, 3, 1, 1)
477
+ grid.attach(self.operator, 1, 0, 1, 1)
478
+ grid.attach(self.machine, 1, 1, 1, 1)
479
+ grid.attach(self.batch, 1, 2, 1, 1)
480
+ grid.attach(self.SN, 1, 3, 1, 1)
481
+ grid.attach(self.date.widget, 1, 4, 1, 1)
95
482
 
96
483
  self.mainBox.pack_start(grid, True, True, 0)
97
484
 
@@ -118,7 +505,7 @@ class WireBond(Gtk.Window):
118
505
  #
119
506
  self.message_panel = dbGtkUtils.MessagePanel(size=100)
120
507
  self.mainBox.pack_start(self.message_panel.frame, True, True, 0)
121
- self.write_message("wirebond GUI")
508
+ self.write_message("wirebond GUI\n")
122
509
 
123
510
  # The button box
124
511
  btnBox = Gtk.ButtonBox(orientation=Gtk.Orientation.HORIZONTAL)
@@ -212,22 +599,30 @@ class WireBond(Gtk.Window):
212
599
  """Handles edition in comment."""
213
600
  self.text_edited(1, path, text)
214
601
 
602
+
603
+ def new_date(self, entry, value):
604
+ """new date given at input."""
605
+ d = dbGtkUtils.parse_date_as_string(value)
606
+ if d is not None:
607
+ self.date.set_text(d)
608
+
215
609
  def button_pressed(self, *args):
610
+ """Button pressed."""
216
611
  pass
217
612
 
218
613
  def add_item(self, *args):
219
614
  """Adds a new item in the current model."""
220
615
  out = dbGtkUtils.get_a_list_of_values("Add Item", ["Channel", "Comment"])
221
- model = self.tree.get_model()
222
- n_child = model.iter_n_children()
223
- model[-1] = out
224
- model.append(["", ""])
616
+ if len(out) == 2:
617
+ model = self.tree.get_model()
618
+ model[-1] = out
619
+ model.append(["", ""])
225
620
 
226
621
  def quit(self, *args):
227
622
  """Quits the application."""
228
623
  if self.pdb:
229
624
  self.pdb.die()
230
-
625
+
231
626
  self.hide()
232
627
  self.destroy()
233
628
 
@@ -235,6 +630,116 @@ class WireBond(Gtk.Window):
235
630
  """Writes text to Text Viewer."""
236
631
  self.message_panel.write_message(text)
237
632
 
633
+ def compute_unconnected(self):
634
+ """Compute number of unconnected."""
635
+ param = get_module_param(self.SN.get_text())
636
+ M = ModuleHoles(param=param)
637
+
638
+ for test in test_parameters.values():
639
+ if test.find("FAILED") < 0:
640
+ continue
641
+ if test.find("ROW") < 0:
642
+ continue
643
+
644
+ irow = int(test[-1]) - 1
645
+
646
+ # Get list of all channels with wirebond notation.
647
+ model = self.models[test]
648
+ it = model.get_iter_first()
649
+ out = []
650
+ while it:
651
+ chan, _ = model[it]
652
+ if len(chan) > 0:
653
+ out.append(int(chan))
654
+
655
+ it = model.iter_next(it)
656
+
657
+ # Translate to sensor, hybrids, etc.
658
+ for S in M.sensors:
659
+ for H in S.hybrids:
660
+ H.add_channel(irow, out)
661
+ H.holes[irow] = find_holes(H.channels[irow])
662
+
663
+
664
+ # Now get sensor strips.
665
+ unconnected = M.get_n_unconnected()
666
+ mx_consecutive = M.get_max_consecutive()
667
+ module_holes = M.get_sensor_holes()
668
+
669
+ out = {}
670
+ for irow in range(4):
671
+ key = "MAX_CONT_UNCON_ROW{}".format(irow+1)
672
+ out[key] = mx_consecutive[irow]
673
+
674
+ mxW = 0
675
+ self.write_message("Found {} clusters of unconnected strips in sensor.\n".format(len(module_holes)))
676
+ for H in module_holes:
677
+ self.write_message("{}\n".format(str(H)))
678
+ if H[-1] > mxW:
679
+ mxW = H[-1]
680
+
681
+ if mxW > 0:
682
+ self.write_message("Max width: {}". format(mxW))
683
+
684
+ out["MAX_UNCON_SENSOR_CHAN"] = mxW
685
+ nstrips = 0
686
+ for v in unconnected:
687
+ nstrips += v
688
+
689
+ out["TOTAL_PERC_UNCON_SENSOR_CHAN"] = nstrips/M.nchan
690
+
691
+ return out
692
+
693
+ def get_unconnected(self, skeleton):
694
+ """Fill the test DTO with unconnected information."""
695
+ out = self.compute_unconnected()
696
+ for key, val in out.items():
697
+ skeleton["results"][key] = val
698
+
699
+ def read_file(self, *args):
700
+ """Read local data file."""
701
+ dialog = Gtk.FileChooserDialog(
702
+ title="Please choose a file",
703
+ parent=self,
704
+ action=Gtk.FileChooserAction.OPEN
705
+ )
706
+ dialog.add_buttons(
707
+ Gtk.STOCK_CANCEL,
708
+ Gtk.ResponseType.CANCEL,
709
+ Gtk.STOCK_OPEN,
710
+ Gtk.ResponseType.OK,
711
+ )
712
+ filter_text = Gtk.FileFilter()
713
+ filter_text.set_name("JSON files")
714
+ filter_text.add_mime_type("application/json")
715
+ dialog.add_filter(filter_text)
716
+
717
+ response = dialog.run()
718
+ if response == Gtk.ResponseType.OK:
719
+ ofile = dialog.get_filename()
720
+ self.write_message("Loading data from {}\n".format(ofile))
721
+ with open(ofile, 'r', encoding="utf-8") as data_file:
722
+ data = json.load(data_file)
723
+ self.parse(data)
724
+
725
+ dialog.hide()
726
+ dialog.destroy()
727
+
728
+ def parse(self, data):
729
+ """Parses a JSon dictionary."""
730
+ self.operator.set_text(data["properties"]["OPERATOR"])
731
+ self.machine.set_text(data["properties"]["BOND_MACHINE"])
732
+ self.batch.set_text(data["properties"]["BONDWIRE_BATCH"])
733
+ self.SN.set_text(data["component"])
734
+ self.date.set_text(data["date"])
735
+ for key, val in data["results"].items():
736
+ model = self.models[key]
737
+ model.clear()
738
+ for chan, msg in val.items():
739
+ model.append([chan, msg])
740
+
741
+ model.append(["", ""])
742
+
238
743
  def get_list_of_channels(self, data):
239
744
  """Creates the lists of channels."""
240
745
  for key, model in self.models.items():
@@ -244,11 +749,11 @@ class WireBond(Gtk.Window):
244
749
  chan, comm = model[iter]
245
750
  if len(chan) > 0:
246
751
  out[chan] = comm
247
-
752
+
248
753
  iter = model.iter_next(iter)
249
754
 
250
755
  data["results"][key] = out
251
-
756
+
252
757
  def save_test(self, *args):
253
758
  """Save Test file."""
254
759
  dialog = Gtk.FileChooserDialog(
@@ -264,17 +769,17 @@ class WireBond(Gtk.Window):
264
769
  filter_text.set_name("JSON files")
265
770
  filter_text.add_mime_type("application/json")
266
771
  dialog.add_filter(filter_text)
267
-
772
+
268
773
  response = dialog.run()
269
774
  if response == Gtk.ResponseType.OK:
270
775
  ofile = dialog.get_filename()
271
776
  data = self.get_test_data()
272
777
  with open(ofile, 'w') as of:
273
778
  json.dump(data, of, indent=3)
274
-
779
+
275
780
  dialog.hide()
276
781
  dialog.destroy()
277
-
782
+
278
783
  def get_test_data(self):
279
784
  """Get the test data."""
280
785
  data = {
@@ -287,7 +792,7 @@ class WireBond(Gtk.Window):
287
792
  self.get_test_header(data)
288
793
  self.get_list_of_channels(data)
289
794
  return data
290
-
795
+
291
796
  def get_test_header(self, data):
292
797
  """Get Basic test data."""
293
798
  SN = self.SN.get_text()
@@ -296,7 +801,7 @@ class WireBond(Gtk.Window):
296
801
  batch = self.batch.get_text()
297
802
 
298
803
  if not SN or len(SN)==0:
299
- SN = dbGtkUtils.get_a_value("Module Serial Number",
804
+ SN = dbGtkUtils.get_a_value("Module Serial Number",
300
805
  "Module serial Number is missing")
301
806
 
302
807
  if len(operator) == 0 or len(machine) == 0 or len(batch) == 0:
@@ -315,7 +820,7 @@ class WireBond(Gtk.Window):
315
820
  data["properties"]["BOND_MACHINE"] = machine
316
821
  data["properties"]["BONDWIRE_BATCH"] = batch
317
822
 
318
-
823
+
319
824
  def upload_test(self, *args):
320
825
  """Upload test."""
321
826
  if self.session is None:
@@ -327,7 +832,7 @@ class WireBond(Gtk.Window):
327
832
 
328
833
  else:
329
834
  self.session = client
330
-
835
+
331
836
  defaults = {
332
837
  "institution": "IFIC",
333
838
  "runNumber": "1",
@@ -335,19 +840,24 @@ class WireBond(Gtk.Window):
335
840
  }
336
841
  skeleton = ITkDButils.get_test_skeleton(self.session, "MODULE", "MODULE_WIRE_BONDING", defaults)
337
842
 
338
- self.get_test_header(skeleton)
843
+ self.get_test_header(skeleton)
339
844
  self.get_list_of_channels(skeleton)
845
+ self.get_unconnected(skeleton)
340
846
 
341
847
  uploadW = UploadTest.UploadTest(self.session, payload=skeleton)
342
848
  # uploadW.run()
343
849
 
344
850
 
345
- if __name__ == "__main__":
346
-
347
- win = WireBond("WireBond")
851
+ def main():
852
+ """Main entry."""
853
+ win = WireBond(title="WireBond")
348
854
  win.connect("destroy", Gtk.main_quit)
349
855
  try:
350
856
  Gtk.main()
351
857
 
352
858
  except KeyboardInterrupt:
353
859
  print("Arrrgggg!!!")
860
+
861
+
862
+ if __name__ == "__main__":
863
+ main()
itkdb_gtk/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
- __version__ = "0.0.16.dev7"
1
+ __version__ = "0.0.16.dev20"
2
2
 
3
3
 
4
4
  def dash_board():
@@ -45,3 +45,8 @@ def uploadModuleIV():
45
45
  """Upload IV files of single and double modules"""
46
46
  from .UploadModuleIV import main
47
47
  main()
48
+
49
+ def wirebondTest():
50
+ """Inputs data and eventually upload wirebod test."""
51
+ from .WireBondGui import main
52
+ main()
itkdb_gtk/dashBoard.py CHANGED
@@ -180,7 +180,7 @@ class DashWindow(dbGtkUtils.ITkDBWindow):
180
180
  return
181
181
 
182
182
  self.mask |= bt
183
- W = WireBondGui.WireBond(session=self.session)
183
+ W = WireBondGui.WireBond(session=self.session, title="Wirebond")
184
184
  W.connect("destroy", self.app_closed, bitn)
185
185
 
186
186
  def app_closed(self, *args):
itkdb_gtk/dbGtkUtils.py CHANGED
@@ -11,8 +11,26 @@ import numpy as np
11
11
 
12
12
 
13
13
  gi.require_version("Gtk", "3.0")
14
- from gi.repository import Gtk, Gio, GLib
14
+ from gi.repository import Gtk, GObject, Gio, GLib
15
15
 
16
+ def parse_date(txt):
17
+ """Parse a date."""
18
+ try:
19
+ return dateutil.parser.parse(txt, fuzzy=False)
20
+
21
+ except Exception:
22
+ return None
23
+ def parse_date_as_string(txt):
24
+ """Parse data and return DB compatible string."""
25
+ D = parse_date(txt)
26
+ if D is None:
27
+ return D
28
+
29
+ out = D.isoformat(timespec='milliseconds')
30
+ if out[-1] not in ['zZ']:
31
+ out += 'Z'
32
+
33
+ return out
16
34
 
17
35
  def is_a_date(txt):
18
36
  """check tha the input string is a date."""
@@ -34,6 +52,16 @@ def new_small_text_entry():
34
52
  style_context.add_provider(provider, Gtk.STYLE_PROVIDER_PRIORITY_SETTINGS)
35
53
  return entry
36
54
 
55
+ def set_entry_style(container):
56
+ """Set max entry."""
57
+ provider = Gtk.CssProvider()
58
+ style_context = container.get_style_context()
59
+ font_size = 2.25*style_context.get_property("font-size", 0)
60
+ css = "{} {{ min-height: {}px; }}".format(container.get_name(), font_size)
61
+ provider.load_from_data(css.encode())
62
+ style_context.add_provider(provider, Gtk.STYLE_PROVIDER_PRIORITY_SETTINGS)
63
+ return container
64
+
37
65
  def set_combo_iter(combo, txt, col=0):
38
66
  """Set scombo active iter to that containing txt in column col."""
39
67
  model = combo.get_model()
@@ -47,17 +75,6 @@ def set_combo_iter(combo, txt, col=0):
47
75
  iter = model.iter_next(iter)
48
76
 
49
77
 
50
- def set_entry_style(container):
51
- """Set max entry."""
52
- provider = Gtk.CssProvider()
53
- print(container.get_name())
54
- style_context = container.get_style_context()
55
- font_size = 2.25*style_context.get_property("font-size", 0)
56
- css = "{} {{ min-height: {}px; }}".format(container.get_name(), font_size)
57
- provider.load_from_data(css.encode())
58
- style_context.add_provider(provider, Gtk.STYLE_PROVIDER_PRIORITY_SETTINGS)
59
-
60
-
61
78
  def is_iterable(obj):
62
79
  """Tell if an object is iterable. Strings are not considered iterables."""
63
80
  if isinstance(obj, Iterable):
@@ -166,11 +183,16 @@ def ask_for_confirmation(main_title, second_text, parent=None):
166
183
  return (out == Gtk.ResponseType.OK)
167
184
 
168
185
 
169
- class TextEntry(object):
186
+ class TextEntry(GObject.GObject):
170
187
  """Create a Gtk text entry/view object."""
188
+ __gsignals__ = {
189
+ "text_changed": (GObject.SIGNAL_RUN_FIRST, None, (str,))
190
+ }
171
191
 
172
- def __init__(self, n_lines=1):
192
+ def __init__(self, n_lines=1, small=False):
173
193
  """Init."""
194
+ GObject.GObject.__init__(self)
195
+ self.tmp_txt = ""
174
196
  self.nlines = n_lines
175
197
  if self.nlines > 1:
176
198
  self.widget = Gtk.Frame()
@@ -184,9 +206,31 @@ class TextEntry(object):
184
206
  scrolled.add(self.entry)
185
207
 
186
208
  else:
187
- self.widget = Gtk.Entry()
209
+ if small:
210
+ self.widget = new_small_text_entry()
211
+ else:
212
+ self.widget = Gtk.Entry()
213
+
214
+ self.widget.connect("focus-in-event", self.on_enter)
215
+ self.widget.connect("focus-out-event", self.on_leave)
216
+
188
217
  self.entry = self.widget
189
218
 
219
+ def do_my_signal(self, *args):
220
+ """Signal handler."""
221
+ pass
222
+
223
+ def on_enter(self, *args):
224
+ """On enter."""
225
+ self.tmp_txt = self.widget.get_text().strip()
226
+ return False
227
+
228
+ def on_leave(self, *args):
229
+ """On leave."""
230
+ val = self.widget.get_text().strip()
231
+ if val != self.tmp_txt:
232
+ self.emit("text_changed", val)
233
+
190
234
  def get_text(self):
191
235
  """Return the text."""
192
236
  if self.nlines > 1:
@@ -197,7 +241,7 @@ class TextEntry(object):
197
241
 
198
242
  else:
199
243
  return self.entry.get_text()
200
-
244
+
201
245
  def set_text(self, text):
202
246
  """Sets text."""
203
247
  if self.nlines > 1:
@@ -306,7 +350,7 @@ def get_a_list_of_values(main_title, labels, defaults=None, second_text=None, pa
306
350
  entry.set_text(defaults[i])
307
351
  except Exception:
308
352
  pass
309
-
353
+
310
354
  vbox.pack_start(entry.widget, False, False, 0)
311
355
  entries.append(entry)
312
356
 
@@ -378,7 +422,7 @@ class MessagePanel(object):
378
422
 
379
423
  # A scroll window with the text view
380
424
  scrolled = Gtk.ScrolledWindow()
381
- scrolled.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
425
+ scrolled.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
382
426
  scrolled.add(self.text_view)
383
427
  box.pack_start(scrolled, True, True, 0)
384
428
  self.frame = frame
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: itkdb_gtk
3
- Version: 0.0.16.dev7
3
+ Version: 0.0.16.dev20
4
4
  Summary: A collection of Gtk based GUI to access ITkDB.
5
5
  Author-email: Carlos Lacasta <carlos.lacasta@cern.ch>
6
6
  Project-URL: Homepage, https://gitlab.cern.ch/atlas-itk/sw/db/itk-pdb-gtk-gui-utils
@@ -10,10 +10,13 @@ Classifier: Operating System :: OS Independent
10
10
  Requires-Python: >=3.7
11
11
  Description-Content-Type: text/markdown
12
12
  Requires-Dist: itkdb >=0.4.0
13
+ Requires-Dist: numpy
14
+ Requires-Dist: matplotlib
13
15
  Requires-Dist: openpyxl
14
16
  Requires-Dist: pyserial
15
17
  Requires-Dist: python-dateutil
16
18
  Requires-Dist: requests
19
+ Requires-Dist: PyGObject
17
20
 
18
21
  # Interaction with the ITk PDB.
19
22
 
@@ -13,15 +13,15 @@ itkdb_gtk/UploadModuleIV.py,sha256=JSvfQSjMxCEy_9KtcydIjpSSCBJ6xJbCwo24-xszabk,2
13
13
  itkdb_gtk/UploadMultipleTests.py,sha256=hI-LK_WWFCoUI8AQTEfrjoHYdYCbOru9DuBUA-R2id4,19730
14
14
  itkdb_gtk/UploadPetalInformation.py,sha256=IsZGa_i6jW8lEUnJOhPFmq-GCemLg_nhlHuQlJQMbjc,22210
15
15
  itkdb_gtk/UploadTest.py,sha256=AwMHwuS2PzyuOGsinyoFcuHZ2m_ZsNktHudp2667_Q4,13590
16
- itkdb_gtk/WireBondGui.py,sha256=NrCsuEMzEA51Xnh92a3T-uT_5Enli2IwK110Jx_zHwA,11760
17
- itkdb_gtk/__init__.py,sha256=KjtY0r-zuyEgEMa976qv9sMtgJLGjJuXX57cKrQpdPA,838
18
- itkdb_gtk/dashBoard.py,sha256=Ps_F--V0QgrDWbMD1TwmB9EjPV1EWi8WTVl-mIEDvAM,5742
19
- itkdb_gtk/dbGtkUtils.py,sha256=6p1qi6nu-nmv6YVy2nCF6vhml9jUf4Oy3kqdgIpZk1s,23911
16
+ itkdb_gtk/WireBondGui.py,sha256=v9oWHIBCU2tbnje2T_3fystPNlks366Dk269pmX9dds,25747
17
+ itkdb_gtk/__init__.py,sha256=uTLh_Z2X49YBX2Bca0JVJxniEw0OiVZY45EEgDDsecM,963
18
+ itkdb_gtk/dashBoard.py,sha256=mguE5QXvCwD4wZgHx5PViRHrY3mgoJh4ijiyz1P2DfA,5760
19
+ itkdb_gtk/dbGtkUtils.py,sha256=xVqRgtg7F7tua41iqHVLFCjgqo4lRVaDD063409i8q0,25120
20
20
  itkdb_gtk/readAVSdata.py,sha256=SvHWFoqvlrEDGKeVaQEPGxsjcNY21KItMSVuWE5q05E,19457
21
21
  itkdb_gtk/readGoogleSheet.py,sha256=UCSfFCQncc0pWxqfCKTaa0K4HkQmwOI07eErepOMlGU,2682
22
22
  itkdb_gtk/untrash_component.py,sha256=fZWanuPww1RLJ-Fduso4EqfLlcBsd5ryJymr1xJZEUM,756
23
- itkdb_gtk-0.0.16.dev7.dist-info/METADATA,sha256=CQKPlrqgl6PYn4ksasjQH4vPG_UK-CiksY2wIXYbuDY,3081
24
- itkdb_gtk-0.0.16.dev7.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
25
- itkdb_gtk-0.0.16.dev7.dist-info/entry_points.txt,sha256=n71x6ofqLQm3n5kIwdwI_dBNFLBVbf_G6G2nxyyxwcE,333
26
- itkdb_gtk-0.0.16.dev7.dist-info/top_level.txt,sha256=KVRrH4OS8ovzNR9bvADE0ABn5bNpSk987tuH0jCfkbU,10
27
- itkdb_gtk-0.0.16.dev7.dist-info/RECORD,,
23
+ itkdb_gtk-0.0.16.dev20.dist-info/METADATA,sha256=1TRkMOqgjFif1VgkAs-zkAVmaK7UYr-CArc4c3c57aw,3154
24
+ itkdb_gtk-0.0.16.dev20.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
25
+ itkdb_gtk-0.0.16.dev20.dist-info/entry_points.txt,sha256=FuSmtQZK5jEzNomHiJqdFZAJZoRueejwoWMg53aZSu0,371
26
+ itkdb_gtk-0.0.16.dev20.dist-info/top_level.txt,sha256=KVRrH4OS8ovzNR9bvADE0ABn5bNpSk987tuH0jCfkbU,10
27
+ itkdb_gtk-0.0.16.dev20.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.42.0)
2
+ Generator: bdist_wheel (0.43.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -7,3 +7,4 @@ sendShipments = itkdb_gtk:sendShipments
7
7
  uploadModuleIV = itkdb_gtk:uploadModuleIV
8
8
  uploadMultipleTests = itkdb_gtk:uploadMultipleTests
9
9
  uploadTest = itkdb_gtk:uploadTest
10
+ wirebondTest = itkdb_gtk:wirebondTest