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.
- itkdb_gtk/{sendShipments.py → CreateShipments.py} +74 -78
- itkdb_gtk/{getShipments.py → GetShipments.py} +99 -106
- itkdb_gtk/GlueWeight.py +45 -66
- itkdb_gtk/ITkDB.desktop +8 -0
- itkdb_gtk/ITkDB.svg +380 -0
- itkdb_gtk/ITkDBlogin.py +10 -6
- itkdb_gtk/ITkDButils.py +295 -57
- itkdb_gtk/PanelVisualInspection.py +590 -0
- itkdb_gtk/QRScanner.py +120 -0
- itkdb_gtk/SensorUtils.py +492 -0
- itkdb_gtk/ShowAttachments.py +267 -0
- itkdb_gtk/ShowComments.py +94 -0
- itkdb_gtk/ShowDefects.py +103 -0
- itkdb_gtk/UploadModuleIV.py +566 -0
- itkdb_gtk/UploadMultipleTests.py +746 -0
- itkdb_gtk/UploadTest.py +509 -0
- itkdb_gtk/VisualInspection.py +297 -0
- itkdb_gtk/WireBondGui.py +1304 -0
- itkdb_gtk/__init__.py +38 -12
- itkdb_gtk/dashBoard.py +292 -33
- itkdb_gtk/dbGtkUtils.py +356 -75
- itkdb_gtk/findComponent.py +242 -0
- itkdb_gtk/findVTRx.py +36 -0
- itkdb_gtk/readGoogleSheet.py +1 -2
- itkdb_gtk/untrash_component.py +35 -0
- {itkdb_gtk-0.0.3.dist-info → itkdb_gtk-0.20.1.dist-info}/METADATA +21 -12
- itkdb_gtk-0.20.1.dist-info/RECORD +30 -0
- {itkdb_gtk-0.0.3.dist-info → itkdb_gtk-0.20.1.dist-info}/WHEEL +1 -1
- itkdb_gtk-0.20.1.dist-info/entry_points.txt +12 -0
- itkdb_gtk/checkComponent.py +0 -131
- itkdb_gtk/groundingTest.py +0 -225
- itkdb_gtk/readAVSdata.py +0 -565
- itkdb_gtk/uploadPetalInformation.py +0 -604
- itkdb_gtk/uploadTest.py +0 -384
- itkdb_gtk-0.0.3.dist-info/RECORD +0 -19
- itkdb_gtk-0.0.3.dist-info/entry_points.txt +0 -7
- {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()
|