itkdb-gtk 0.0.3__py3-none-any.whl → 0.20.1__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.
Files changed (37) hide show
  1. itkdb_gtk/{sendShipments.py → CreateShipments.py} +74 -78
  2. itkdb_gtk/{getShipments.py → GetShipments.py} +99 -106
  3. itkdb_gtk/GlueWeight.py +45 -66
  4. itkdb_gtk/ITkDB.desktop +8 -0
  5. itkdb_gtk/ITkDB.svg +380 -0
  6. itkdb_gtk/ITkDBlogin.py +10 -6
  7. itkdb_gtk/ITkDButils.py +295 -57
  8. itkdb_gtk/PanelVisualInspection.py +590 -0
  9. itkdb_gtk/QRScanner.py +120 -0
  10. itkdb_gtk/SensorUtils.py +492 -0
  11. itkdb_gtk/ShowAttachments.py +267 -0
  12. itkdb_gtk/ShowComments.py +94 -0
  13. itkdb_gtk/ShowDefects.py +103 -0
  14. itkdb_gtk/UploadModuleIV.py +566 -0
  15. itkdb_gtk/UploadMultipleTests.py +746 -0
  16. itkdb_gtk/UploadTest.py +509 -0
  17. itkdb_gtk/VisualInspection.py +297 -0
  18. itkdb_gtk/WireBondGui.py +1304 -0
  19. itkdb_gtk/__init__.py +38 -12
  20. itkdb_gtk/dashBoard.py +292 -33
  21. itkdb_gtk/dbGtkUtils.py +356 -75
  22. itkdb_gtk/findComponent.py +242 -0
  23. itkdb_gtk/findVTRx.py +36 -0
  24. itkdb_gtk/readGoogleSheet.py +1 -2
  25. itkdb_gtk/untrash_component.py +35 -0
  26. {itkdb_gtk-0.0.3.dist-info → itkdb_gtk-0.20.1.dist-info}/METADATA +21 -12
  27. itkdb_gtk-0.20.1.dist-info/RECORD +30 -0
  28. {itkdb_gtk-0.0.3.dist-info → itkdb_gtk-0.20.1.dist-info}/WHEEL +1 -1
  29. itkdb_gtk-0.20.1.dist-info/entry_points.txt +12 -0
  30. itkdb_gtk/checkComponent.py +0 -131
  31. itkdb_gtk/groundingTest.py +0 -225
  32. itkdb_gtk/readAVSdata.py +0 -565
  33. itkdb_gtk/uploadPetalInformation.py +0 -604
  34. itkdb_gtk/uploadTest.py +0 -384
  35. itkdb_gtk-0.0.3.dist-info/RECORD +0 -19
  36. itkdb_gtk-0.0.3.dist-info/entry_points.txt +0 -7
  37. {itkdb_gtk-0.0.3.dist-info → itkdb_gtk-0.20.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,746 @@
1
+ #!/usr/bin/env python3
2
+ """GUI to upload tests."""
3
+ import fnmatch
4
+ import json
5
+ import os
6
+ import sys
7
+ from pathlib import Path
8
+
9
+ try:
10
+ import itkdb_gtk
11
+
12
+ except ImportError:
13
+ cwd = Path(__file__).parent.parent
14
+ sys.path.append(cwd.as_posix())
15
+
16
+ from itkdb_gtk import dbGtkUtils, ITkDBlogin, ITkDButils
17
+ from itkdb_gtk.ShowComments import ShowComments
18
+ from itkdb_gtk.ShowAttachments import ShowAttachments
19
+ from itkdb_gtk.ShowDefects import ShowDefects
20
+ from itkdb_gtk.UploadTest import create_json_data_editor
21
+
22
+ import gi
23
+ gi.require_version("Gtk", "3.0")
24
+ from gi.repository import Gtk, Gio, Gdk
25
+
26
+ # Check if Gtk can be open
27
+ gtk_runs, gtk_args = Gtk.init_check()
28
+
29
+
30
+ def handle_test_date(the_date):
31
+ """Edit date."""
32
+ the_date = the_date[:19].replace('T', ' ')
33
+ return the_date
34
+
35
+
36
+ def all_files(root, patterns='*', single_level=False, yield_folders=False):
37
+ """A generator that reruns all files in the given folder.
38
+
39
+ Args:
40
+ root (file path): The folder
41
+ patterns (str, optional): The pattern of the files. Defaults to '*'.
42
+ single_level (bool, optional): If true, do not go into sub folders. Defaults to False.
43
+ yield_folders (bool, optional): If True, return folders as well. Defaults to False.
44
+
45
+ Yields:
46
+ str: file path name
47
+
48
+ """
49
+ patterns = patterns.split(';')
50
+ for path, subdirs, files in os.walk(root):
51
+ if yield_folders:
52
+ files.extend(subdirs)
53
+
54
+ files.sort()
55
+ for name in files:
56
+ for pattern in patterns:
57
+ if fnmatch.fnmatch(name, pattern):
58
+ yield os.path.join(path, name)
59
+ break
60
+
61
+ if single_level:
62
+ break
63
+
64
+
65
+ class TestList(object):
66
+ """Enumeration with TreeView model columns."""
67
+ (
68
+ SN,
69
+ TestType,
70
+ RunNumber,
71
+ Date,
72
+ Institute,
73
+ Stage,
74
+ currentStage,
75
+ Path,
76
+ Json,
77
+ Nattch,
78
+ Attachments,
79
+ Ncomm,
80
+ Comments,
81
+ Ndef,
82
+ Defects,
83
+ Color,
84
+ ALL,
85
+ ) = range(17)
86
+
87
+
88
+ def check_data(data):
89
+ """Checks validity of JSon data.
90
+
91
+ Args:
92
+ data (): The json data
93
+
94
+ Returns:
95
+ -------
96
+ boolean: True if valid, False otherwise.
97
+
98
+ """
99
+ errors = []
100
+ missing = []
101
+ if "component" not in data:
102
+ errors.append("Need reference to component, hex string")
103
+ missing.append("component")
104
+
105
+ if "testType" not in data:
106
+ errors.append("Need to know test type, short code")
107
+ missing.append("testType")
108
+
109
+ if "institution" not in data:
110
+ errors.append("Need to know institution, short code")
111
+ missing.append("institution")
112
+
113
+ if "results" not in data:
114
+ errors.append("Need some test results")
115
+ missing.append("results")
116
+
117
+ return errors, missing
118
+
119
+
120
+ class UploadMultipleTests(dbGtkUtils.ITkDBWindow):
121
+ """Collects information to upload a test and its attachments."""
122
+
123
+ def __init__(self, session, help_link=None):
124
+ """Initialization.
125
+
126
+ Args:
127
+ session: ITkDB session
128
+
129
+ """
130
+ super().__init__(session=session, title="Upload Tests", gtk_runs=gtk_runs, help_link=help_link)
131
+ self.tests = []
132
+ self.data = None
133
+ self.tree = None
134
+ self.is_retroactive = False
135
+ self.def_color = None
136
+
137
+ self.init_window()
138
+
139
+ def init_window(self):
140
+ """Creates the Gtk window."""
141
+ # Initial tweaks
142
+ self.set_border_width(10)
143
+
144
+ # Prepare HeaderBar
145
+ self.hb.props.title = "Upload Multiple Tests"
146
+
147
+ # Active buttin in header
148
+ button = Gtk.Button()
149
+ icon = Gio.ThemedIcon(name="document-send-symbolic")
150
+ image = Gtk.Image.new_from_gicon(icon, Gtk.IconSize.BUTTON)
151
+ button.add(image)
152
+ button.set_tooltip_text("Click to upload test")
153
+ button.connect("clicked", self.upload_test_gui)
154
+ self.hb.pack_end(button)
155
+
156
+ # Data panel
157
+ grid = Gtk.Grid(column_spacing=5, row_spacing=1)
158
+ self.mainBox.pack_start(grid, False, False, 0)
159
+
160
+ # The test file widgets
161
+ lbl = Gtk.Label(label="Select Test Files: ")
162
+ lbl.set_xalign(0)
163
+ grid.attach(lbl, 0, 0, 1, 1)
164
+
165
+ btn = Gtk.Button()
166
+ icon = Gio.ThemedIcon(name="text-x-generic-symbolic")
167
+ image = Gtk.Image.new_from_gicon(icon, Gtk.IconSize.BUTTON)
168
+ btn.add(image)
169
+ btn.set_tooltip_text("Click to select multiple tests.")
170
+ btn.connect("clicked", self.on_select_test)
171
+ grid.attach(btn, 1, 0, 1, 1)
172
+
173
+ btn = Gtk.Button()
174
+ icon = Gio.ThemedIcon(name="folder-symbolic")
175
+ image = Gtk.Image.new_from_gicon(icon, Gtk.IconSize.BUTTON)
176
+ btn.add(image)
177
+ btn.set_tooltip_text("Click to select a folder to scan.")
178
+ btn.connect("clicked", self.on_select_folder)
179
+ grid.attach(btn, 2, 0, 1, 1)
180
+
181
+ # toggle = Gtk.ToggleButton("RetroActive")
182
+ # toggle.set_tooltip_text("Toggle to make all uploads retroactive.")
183
+ # toggle.connect("toggled", self.on_toggle_retroactive)
184
+ # grid.attach(toggle, 3, 0, 1, 1)
185
+
186
+ # Paned object
187
+ paned = Gtk.Paned(orientation=Gtk.Orientation.VERTICAL)
188
+ paned.set_size_request(-1, 200)
189
+ self.mainBox.pack_start(paned, True, True, 5)
190
+
191
+ # the list of attachments
192
+ tree_view = self.create_tree_view()
193
+ paned.add1(tree_view)
194
+
195
+ # The text view
196
+ paned.add2(self.message_panel.frame)
197
+
198
+ self.show_all()
199
+
200
+ def create_tree_view(self, size=150):
201
+ """Creates the tree vew with the attachments."""
202
+ model = Gtk.ListStore(str, # SN
203
+ str, # test type
204
+ str, # runNumber
205
+ str, # date
206
+ str, # institute
207
+ str, # stage
208
+ str, # stage
209
+ str, # ifile
210
+ object, # data
211
+ int, # num. attch.
212
+ object, # attachments
213
+ int, # num. comments
214
+ object, # comments
215
+ int, # num defects
216
+ object, # defects
217
+ str # color
218
+ )
219
+ self.tree = Gtk.TreeView(model=model)
220
+ self.tree.connect("button-press-event", self.button_pressed)
221
+ scrolled = Gtk.ScrolledWindow()
222
+ scrolled.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
223
+ scrolled.add(self.tree)
224
+ scrolled.set_size_request(-1, size)
225
+
226
+ renderer = Gtk.CellRendererText()
227
+ column = Gtk.TreeViewColumn("SN", renderer, text=TestList.SN)
228
+ self.tree.append_column(column)
229
+
230
+ renderer = Gtk.CellRendererText()
231
+ self.def_color = renderer.get_property("foreground-rgba").to_string()
232
+ column = Gtk.TreeViewColumn("Test Type", renderer, text=TestList.TestType, foreground=TestList.Color)
233
+ self.tree.append_column(column)
234
+
235
+ renderer = Gtk.CellRendererText()
236
+ column = Gtk.TreeViewColumn("Run", renderer, text=TestList.RunNumber)
237
+ self.tree.append_column(column)
238
+
239
+ renderer = Gtk.CellRendererText()
240
+ column = Gtk.TreeViewColumn("Institute", renderer, text=TestList.Institute)
241
+ self.tree.append_column(column)
242
+
243
+ renderer = Gtk.CellRendererText()
244
+ column = Gtk.TreeViewColumn("Stage", renderer, text=TestList.Stage)
245
+ self.tree.append_column(column)
246
+
247
+ renderer = Gtk.CellRendererText()
248
+ column = Gtk.TreeViewColumn("N. att.", renderer, text=TestList.Nattch)
249
+ self.tree.append_column(column)
250
+
251
+ renderer = Gtk.CellRendererText()
252
+ column = Gtk.TreeViewColumn("N. comm.", renderer, text=TestList.Ncomm)
253
+ self.tree.append_column(column)
254
+
255
+ renderer = Gtk.CellRendererText()
256
+ column = Gtk.TreeViewColumn("N. def.", renderer, text=TestList.Ndef)
257
+ self.tree.append_column(column)
258
+
259
+ renderer = Gtk.CellRendererText()
260
+ column = Gtk.TreeViewColumn("Date", renderer, text=TestList.Date)
261
+ self.tree.append_column(column)
262
+
263
+ return scrolled
264
+
265
+ def button_pressed(self, tree, event):
266
+ """Button pressed on tree view."""
267
+ # double click shows attachments
268
+ if event.button == 1 and event.type == Gdk.EventType.DOUBLE_BUTTON_PRESS:
269
+ select = self.tree.get_selection()
270
+ model, lv_iter = select.get_selected()
271
+ if not lv_iter:
272
+ return
273
+
274
+ self.on_show_json(None, (model, lv_iter, model[lv_iter]))
275
+ # self.on_show_attachments(None, (model, lv_iter, model[lv_iter]))
276
+ return
277
+
278
+ if event.button != 3:
279
+ return
280
+
281
+ # Create popup menu
282
+ select = self.tree.get_selection()
283
+ model, lv_iter = select.get_selected()
284
+ values = None
285
+ if lv_iter:
286
+ values = model[lv_iter]
287
+
288
+ if not lv_iter:
289
+ P = tree.get_path_at_pos(event.x, event.y)
290
+ if P:
291
+ print(P[0].to_string())
292
+ lv_iter = model.get_iter(P[0])
293
+ values = model[lv_iter]
294
+
295
+ if not values:
296
+ return
297
+
298
+ menu = Gtk.Menu()
299
+ item_show = Gtk.MenuItem(label="Show JSOn")
300
+ item_show.connect("activate", self.on_show_json, (model, lv_iter, values))
301
+ menu.append(item_show)
302
+
303
+ item_set_stage = Gtk.MenuItem(label="Set Stage")
304
+ item_set_stage.connect("activate", self.on_set_stage, (model, lv_iter, values))
305
+ menu.append(item_set_stage)
306
+
307
+ item_show_att = Gtk.MenuItem(label="Edit Attachments")
308
+ item_show_att.connect("activate", self.on_show_attachments, (model, lv_iter, values))
309
+ menu.append(item_show_att)
310
+
311
+ item_show_com = Gtk.MenuItem(label="Edit Comments")
312
+ item_show_com.connect("activate", self.on_show_comments, (model, lv_iter, values))
313
+ menu.append(item_show_com)
314
+
315
+ item_show_def = Gtk.MenuItem(label="Edit Defects")
316
+ item_show_def.connect("activate", self.on_show_defects, (model, lv_iter, values))
317
+ menu.append(item_show_def)
318
+
319
+ item_del = Gtk.MenuItem(label="Delete")
320
+ item_del.connect("activate", self.on_delete_tests, (model, lv_iter, values))
321
+ menu.append(item_del)
322
+ menu.show_all()
323
+
324
+ menu.popup_at_pointer(event)
325
+
326
+ def on_toggle_retroactive(self, toggle, *args):
327
+ """Called when retroactive button is toggled."""
328
+ self.is_retroactive = toggle.get_active()
329
+ print("Is retroactive", self.is_retroactive)
330
+
331
+ def on_show_json(self, item, data):
332
+ """Test JSon."""
333
+ model, lv_iter, val = data
334
+ payload = val[TestList.Json]
335
+ value, dlg = create_json_data_editor(payload)
336
+ rc = dlg.run()
337
+ if rc == Gtk.ResponseType.OK:
338
+ payload = value.values
339
+ model.set_value(lv_iter, TestList.Json, payload)
340
+ model.set_value(lv_iter, TestList.SN, payload["component"])
341
+ model.set_value(lv_iter, TestList.RunNumber, payload["runNumber"])
342
+ model.set_value(lv_iter, TestList.Date, handle_test_date(payload["date"]))
343
+ model.set_value(lv_iter, TestList.Institute, handle_test_date(payload["institution"]))
344
+
345
+ dlg.hide()
346
+ dlg.destroy()
347
+
348
+ def on_show_attachments(self, item, data):
349
+ """Show the attachmetns."""
350
+ model, lv_iter, val = data
351
+
352
+ SA = ShowAttachments("Test Attachments", self.session, val[TestList.Attachments], parent=self)
353
+ response = SA.run()
354
+ if response == Gtk.ResponseType.OK:
355
+ model.set_value(lv_iter, TestList.Attachments, SA.attachments)
356
+ model.set_value(lv_iter, TestList.Nattch, len(SA.attachments))
357
+
358
+ SA.hide()
359
+ SA.destroy()
360
+
361
+ def on_show_comments(self, item, data):
362
+ """Show comments"""
363
+ model, lv_iter, val = data
364
+ SC = ShowComments("Test Comments", val[TestList.Comments], self)
365
+ rc = SC.run()
366
+ if rc == Gtk.ResponseType.OK:
367
+ model.set_value(lv_iter, TestList.Comments, SC.comments)
368
+ model.set_value(lv_iter, TestList.Ncomm, len(SC.comments))
369
+
370
+ SC.hide()
371
+ SC.destroy()
372
+
373
+ def on_show_defects(self, item, data):
374
+ """Show comments"""
375
+ model, lv_iter, val = data
376
+ SD = ShowDefects("Test Defects", val[TestList.Defects], self)
377
+ rc = SD.run()
378
+ if rc == Gtk.ResponseType.OK:
379
+ model.set_value(lv_iter, TestList.Defects, SD.defects)
380
+ model.set_value(lv_iter, TestList.Ndef, len(SD.defects))
381
+
382
+ SD.hide()
383
+ SD.destroy()
384
+
385
+ def on_delete_tests(self, item, data):
386
+ """Test edit."""
387
+ model, lv_iter, val = data
388
+ rc = dbGtkUtils.ask_for_confirmation("Remove this test?",
389
+ "{} - {}".format(val[TestList.SN], val[TestList.TestType]))
390
+ if rc:
391
+ model.remove(lv_iter)
392
+
393
+ def get_test_institute(self):
394
+ """Select an institue."""
395
+ dlg = Gtk.Dialog(title="Select Institution.", flags=0)
396
+ dlg.add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
397
+ Gtk.STOCK_OK, Gtk.ResponseType.OK)
398
+ area = dlg.get_content_area()
399
+ box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
400
+ area.add(box)
401
+
402
+ box.pack_start(Gtk.Label(label="Select an Institute"), False, True, 0)
403
+
404
+ combo = self.create_institute_combo(only_user=True)
405
+ box.pack_start(combo, False, True, 5)
406
+
407
+ btn = Gtk.CheckButton(label="Use as default for other tests missing institute ?")
408
+ box.pack_start(btn, False, True, 5)
409
+ dlg.show_all()
410
+ rc = dlg.run()
411
+
412
+ out = None
413
+ if rc == Gtk.ResponseType.OK:
414
+ out = self.get_institute_from_combo(combo)
415
+
416
+ use_default = btn.get_active()
417
+ dlg.hide()
418
+ dlg.destroy()
419
+ return out, use_default
420
+
421
+ def on_set_stage(self, item, data):
422
+ """Set the test stage."""
423
+ model, lv_iter, val = data
424
+ SN = val[TestList.SN]
425
+ combo, _ = self.get_component_stages(SN)
426
+
427
+ dlg = Gtk.Dialog(title="Set object stage")
428
+
429
+ dlg.add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
430
+ Gtk.STOCK_OK, Gtk.ResponseType.OK)
431
+ area = dlg.get_content_area()
432
+ box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
433
+ area.add(box)
434
+
435
+ box.pack_start(Gtk.Label(label="Select Stage"), False, True, 0)
436
+ box.pack_start(combo, False, True, 0)
437
+ toggle = Gtk.ToggleButton("Retroactive")
438
+ box.pack_start(toggle, False, True, 0)
439
+
440
+ dlg.show_all()
441
+
442
+ rc = dlg.run()
443
+ if rc == Gtk.ResponseType.OK:
444
+ new_stage = combo.get_active_text()
445
+ model[lv_iter][TestList.Stage] = new_stage
446
+ data = model[lv_iter][TestList.Json]
447
+ if toggle.get_active():
448
+ data["isRetroactive"] = True
449
+ data["stage"] = new_stage
450
+
451
+ else:
452
+ changed = (new_stage != model[lv_iter][TestList.currentStage])
453
+ data["isRetroactive"] = changed
454
+ if changed:
455
+ data["stage"] = new_stage
456
+ else:
457
+ if "stage" in data:
458
+ del data["stage"]
459
+
460
+ model[lv_iter][TestList.Json] = data
461
+
462
+ dlg.hide()
463
+ dlg.destroy()
464
+
465
+ def get_component_stages(self, SN):
466
+ """Create a combo with the stages."""
467
+ try:
468
+ obj = ITkDButils.get_DB_component(self.session, SN)
469
+ currentStage = obj["currentStage"]["code"]
470
+
471
+ combo = Gtk.ComboBoxText.new_with_entry()
472
+ combo.remove_all()
473
+ indx = 0
474
+ for i, stg in enumerate(obj["stages"]):
475
+ S = stg["code"]
476
+ combo.append_text(S)
477
+ if S == currentStage:
478
+ indx = i
479
+
480
+ combo.set_active(indx)
481
+ return combo, currentStage
482
+
483
+ except Exception:
484
+ self.write_message("Something went wrong with the stages\n")
485
+ return [None, None]
486
+
487
+ def add_test_data_to_view(self, data, default_site=None, use_default=False, ifile=None, folder=None):
488
+ """Add a test data to the tree view."""
489
+ has_errors = False
490
+ errors, missing = check_data(data)
491
+ if len(missing) > 0:
492
+ self.write_message("Some keys are missing in the JSon file.\n")
493
+ self.write_message("{}\n".format("\n".join(['\t'+line for line in missing])))
494
+
495
+ if "institution" in missing and len(missing) == 1:
496
+ if default_site is None:
497
+ site, use_default = self.get_test_institute()
498
+ if use_default:
499
+ default_site = site
500
+ else:
501
+ site = default_site
502
+
503
+ if site:
504
+ data["institution"] = site
505
+ self.write_message("Setting Institution to {}\n".format(data["institution"]))
506
+
507
+ else:
508
+ has_errors = True
509
+ dbGtkUtils.complain("Invalid JSON file\n{}".format('\n'.join(errors)),"--")
510
+
511
+ if not has_errors:
512
+ attachments = []
513
+ if "attachments" in data:
514
+ for att in data["attachments"]:
515
+ path = Path(att["path"])
516
+ if path.exists():
517
+ path = path.expanduser().resolve()
518
+ else:
519
+ if folder is not None:
520
+ path = folder / path.name
521
+
522
+ if path.exists():
523
+ attachments.append(ITkDButils.Attachment(path=path,
524
+ title=att["title"],
525
+ desc=att["description"]))
526
+ else:
527
+ self.write_message("Ignoring atachment {}".format(data["path"]))
528
+
529
+ # We need to delete this, which is "unofficial"
530
+ del data["attachments"]
531
+
532
+ model = self.tree.get_model()
533
+ comments = data.get("comments", [])
534
+ defects = data.get("defects", [])
535
+ the_date = handle_test_date(data["date"])
536
+ combo, currentStage = self.get_component_stages(data["component"])
537
+ if data["passed"]:
538
+ if data["problems"]:
539
+ color = "orange"
540
+ else:
541
+ color = self.def_color
542
+ else:
543
+ color = "firebrick"
544
+
545
+ model.append([data["component"], data["testType"], data["runNumber"], the_date,
546
+ data["institution"], currentStage, currentStage,
547
+ ifile, data, len(attachments), attachments,
548
+ len(comments), comments, len(defects), defects, color])
549
+
550
+ return default_site, use_default
551
+
552
+ def add_tests_to_view(self, files):
553
+ """Add the input fiels to the treeview."""
554
+ default_site = None
555
+ use_default = False
556
+ for ifile in files:
557
+ try:
558
+ self.write_message("{}\n".format(Path(ifile).name))
559
+ folder = Path(ifile).parent
560
+
561
+ data = json.loads(open(ifile, "r", encoding="UTF-8").read())
562
+ default_site, use_default = self.add_test_data_to_view(
563
+ data,
564
+ default_site=default_site,
565
+ use_default=use_default,
566
+ ifile=ifile,
567
+ folder=folder,
568
+ )
569
+
570
+ except Exception as E:
571
+ self.write_message("Cannot load file {}\n".format(ifile))
572
+ self.write_message("{}\n".format(str(E)))
573
+
574
+ def on_select_folder(self, *args):
575
+ """Caalback for select folder button"""
576
+ fdlg = Gtk.FileChooserNative(action=Gtk.FileChooserAction.SELECT_FOLDER, accept_label="Select")
577
+ response = fdlg.run()
578
+ if response == Gtk.ResponseType.ACCEPT:
579
+ folder = fdlg.get_filename()
580
+ ifiles = [ipath for ipath in all_files(folder, '*.json')]
581
+ self.add_tests_to_view(ifiles)
582
+
583
+ fdlg.hide()
584
+ fdlg.destroy()
585
+
586
+ def on_select_test(self, *args):
587
+ """Test file browser clicked."""
588
+ fdlg = Gtk.FileChooserNative(action=Gtk.FileChooserAction.OPEN, accept_label="Select")
589
+
590
+ filter_js = Gtk.FileFilter()
591
+ filter_js.set_name("JSon files")
592
+ filter_js.add_mime_type("application/json")
593
+ fdlg.add_filter(filter_js)
594
+
595
+ filter_any = Gtk.FileFilter()
596
+ filter_any.set_name("Any files")
597
+ filter_any.add_pattern("*")
598
+ fdlg.add_filter(filter_any)
599
+
600
+ fdlg.set_select_multiple(True)
601
+
602
+ response = fdlg.run()
603
+ if response == Gtk.ResponseType.ACCEPT:
604
+ ifiles = [ipath for ipath in fdlg.get_filenames()]
605
+ self.add_tests_to_view(ifiles)
606
+
607
+ fdlg.hide()
608
+ fdlg.destroy()
609
+ return
610
+
611
+ def show_data(self, *args):
612
+ """Show data button clicked."""
613
+ if self.data is None:
614
+ return
615
+
616
+ dlg = Gtk.Dialog(title="Test Data")
617
+ dlg.add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
618
+ Gtk.STOCK_OK, Gtk.ResponseType.OK)
619
+
620
+ dlg.set_property("height-request", 500)
621
+ box = dlg.get_content_area()
622
+ value = dbGtkUtils.DictDialog(self.data)
623
+ scrolled = Gtk.ScrolledWindow()
624
+ scrolled.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
625
+ scrolled.add(value)
626
+ box.pack_start(scrolled, True, True, 10)
627
+
628
+ dlg.show_all()
629
+
630
+ rc = dlg.run()
631
+ if rc == Gtk.ResponseType.OK:
632
+ self.data = value.values
633
+
634
+ dlg.hide()
635
+ dlg.destroy()
636
+
637
+ def add_attachment_dialog(self):
638
+ """Create the add attachment dialog."""
639
+ dlg = Gtk.Dialog(title="Add Attachment")
640
+ dlg.add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
641
+ Gtk.STOCK_OK, Gtk.ResponseType.OK)
642
+ grid = Gtk.Grid(column_spacing=5, row_spacing=1)
643
+ box = dlg.get_content_area()
644
+ box.add(grid)
645
+
646
+ lbl = Gtk.Label(label="File")
647
+ lbl.set_xalign(0)
648
+ grid.attach(lbl, 0, 0, 1, 1)
649
+
650
+ lbl = Gtk.Label(label="Title")
651
+ lbl.set_xalign(0)
652
+ grid.attach(lbl, 0, 1, 1, 1)
653
+
654
+ lbl = Gtk.Label(label="Description")
655
+ lbl.set_xalign(0)
656
+ grid.attach(lbl, 0, 2, 1, 1)
657
+
658
+ dlg.fC = Gtk.FileChooserButton()
659
+ grid.attach(dlg.fC, 1, 0, 1, 1)
660
+
661
+ dlg.att_title = Gtk.Entry()
662
+ grid.attach(dlg.att_title, 1, 1, 1, 1)
663
+
664
+ dlg.att_desc = Gtk.Entry()
665
+ grid.attach(dlg.att_desc, 1, 2, 1, 1)
666
+
667
+ dlg.show_all()
668
+ return dlg
669
+
670
+ def upload_test_gui(self, *args):
671
+ """Uploads test and attachments."""
672
+ self.upload_test()
673
+
674
+ def upload_test(self):
675
+ """Uploads tests and attachments."""
676
+ model = self.tree.get_model()
677
+ lv_iter = model.get_iter_first()
678
+ ngood = 0
679
+ nbad = 0
680
+ while lv_iter:
681
+ past_iter = None
682
+ values = model[lv_iter]
683
+ payload = values[TestList.Json]
684
+ payload["comments"] = values[TestList.Comments]
685
+ payload["defects"] = values[TestList.Defects]
686
+
687
+ rc = ITkDButils.upload_test(self.session, payload, values[TestList.Attachments], check_runNumber=True)
688
+ if rc:
689
+ ipos = rc.find("The following details may help:")
690
+ if ipos>=0:
691
+ msg = rc[ipos:]
692
+ else:
693
+ msg = rc
694
+ dbGtkUtils.complain("Failed uploading test {}-{}\n".format(payload["component"], payload["testType"]), msg)
695
+ self.write_message("Failed uploading test {}-{}\n{}\n".format(payload["component"], payload["testType"], msg))
696
+ nbad += 1
697
+
698
+ else:
699
+ self.write_message("Upload {}-{} successfull\n".format(payload["component"], payload["testType"]))
700
+ past_iter = lv_iter
701
+ ngood += 1
702
+
703
+ lv_iter = model.iter_next(lv_iter)
704
+ if past_iter:
705
+ model.remove(past_iter)
706
+
707
+ if nbad>0:
708
+ dbGtkUtils.complain("Failed to upload some tests", "{}/{} tests had errors.\nThey are left in the ListView.".format(nbad, ngood))
709
+ else:
710
+ dbGtkUtils.complain("All {} tests uploaded succesfully".format(ngood))
711
+
712
+
713
+ def main():
714
+ """Main entry."""
715
+ HELP_LINK="https://itkdb-gtk.docs.cern.ch/uploadMultipleTests.html"
716
+ # DB login
717
+ dlg = ITkDBlogin.ITkDBlogin()
718
+ client = dlg.get_client()
719
+ if client is None:
720
+ print("Could not connect to DB with provided credentials.")
721
+ dlg.die()
722
+ sys.exit()
723
+
724
+ client.user_gui = dlg
725
+
726
+ # Start GUI
727
+ UpT = UploadMultipleTests(client, help_link=HELP_LINK)
728
+
729
+ if gtk_runs:
730
+ UpT.present()
731
+ UpT.connect("destroy", Gtk.main_quit)
732
+ try:
733
+ Gtk.main()
734
+
735
+ except KeyboardInterrupt:
736
+ print("Arrrgggg!!!")
737
+
738
+ else:
739
+ # Think
740
+ pass
741
+
742
+ dlg.die()
743
+
744
+
745
+ if __name__ == "__main__":
746
+ main()