projectapp.py
Go to the documentation of this file.
1 #! /usr/bin/env python
2 ######################################################################
3 #
4 # Name: projectapp.py
5 #
6 # Purpose: Python class ProjectApp for project.py gui interface.
7 #
8 # Created: 16-Jan-2015 Herbert Greenlee
9 #
10 ######################################################################
11 
12 from __future__ import absolute_import
13 from __future__ import print_function
14 
15 # Standard imports
16 
17 import sys, os, subprocess, traceback
18 from project_modules.jobsuberror import JobsubError
19 from larbatch_utilities import convert_str
20 
21 # Import project.py as a module.
22 
23 import project
24 import project_utilities
25 from project_modules.batchstatus import BatchStatus
26 
27 # Import Tkinter GUI stuff
28 
29 try:
30  import tkinter as tk
31  import tkinter.filedialog as tkinter_filedialog
32  import tkinter.messagebox as tkinter_messagebox
33  import tkinter.font as tkinter_font
34 except ImportError:
35  import Tkinter as tk
36  import tkFileDialog as tkinter_filedialog
37  import tkMessageBox as tkinter_messagebox
38  import tkFont as tkinter_font
39 
40 from project_gui_modules.projectview import ProjectView
41 from project_gui_modules.textwindow import TextWindow
42 
43 ticket_ok = False
44 
45 # Main window class for this gui application.
46 
47 class ProjectApp(tk.Frame):
48 
49  # Constructor.
50 
51  def __init__(self, parent=None):
52 
53  # Root window.
54 
55  if parent == None:
56  self.root = tk.Tk()
57  else:
58  self.root = parent
59  self.root.title('project')
60  self.root.protocol('WM_DELETE_WINDOW', self.close)
61 
62  # Register our outermost frame in the parent window.
63 
64  tk.Frame.__init__(self, self.root)
65  self.pack(expand=1, fill=tk.BOTH)
66 
67  # Make widgets that belong to this app.
68 
69  self.make_widgets()
70 
71  # Current project and stage (menu settable).
72 
75  self.current_project_def = None
77  self.current_stage_def = None
78 
79  # Known projects (3-tuple: project_name, xml_path, project_defs)
80 
81  self.projects = []
82 
83  # Process command line arguments.
84 
85  for n in range(1, len(sys.argv)):
86  xmlpath = sys.argv[n]
87  self.open(xmlpath, choose=False)
88  if len(self.projects) > 0:
89  self.choose_project(self.projects[0][0])
90 
91  # Make widgets. Make and register all widgets in the application window.
92 
93  def make_widgets(self):
94 
95  self.rowconfigure(2, weight=1)
96  self.columnconfigure(0, weight=1)
97 
98  # Make menu bar (row 0).
99 
100  self.make_menubar()
101 
102  # Add project view widget (row 1).
103 
104  self.project_view = ProjectView(self)
105  self.project_view.grid(row=1, column=0, sticky=tk.E+tk.W)
106 
107  # Add console window widget (row 2).
108 
109  self.console = TextWindow(self)
110  self.console.grid(row=2, column=0, sticky=tk.N+tk.E+tk.W+tk.S)
111 
112  # From now on, send standard and diagnostic output to console window.
113 
114  sys.stdout = self.console
115  sys.stderr = self.console
116 
117  # Schedule the idle callback.
118 
119  self.after(120000, self.often)
120 
121  # Periodic callback.
122 
123  def often(self):
124  self.update_jobs()
125  self.after(120000, self.often)
126 
127  # Make a menubar widget.
128 
129  def make_menubar(self):
130 
131  # Put menu in its own frame.
132 
133  self.menubar = tk.Frame(self)
134  self.menubar.grid(row=0, column=0, sticky=tk.E+tk.W)
135 
136  # File menu.
137 
138  mbutton = tk.Menubutton(self.menubar, text='File', font=tkinter_font.Font(size=12))
139  mbutton.pack(side=tk.LEFT)
140  file_menu = tk.Menu(mbutton)
141  file_menu.add_command(label='Open Project', command=self.open)
142  file_menu.add_command(label='Quit', command=self.close)
143  mbutton['menu'] = file_menu
144 
145  # View menu.
146 
147  mbutton = tk.Menubutton(self.menubar, text='View', font=tkinter_font.Font(size=12))
148  mbutton.pack(side=tk.LEFT)
149  view_menu = tk.Menu(mbutton)
150  view_menu.add_command(label='XML', command=self.xml_display)
151  mbutton['menu'] = view_menu
152 
153  # Project menu.
154 
155  mbutton = tk.Menubutton(self.menubar, text='Project', font=tkinter_font.Font(size=12))
156  mbutton.pack(side=tk.LEFT)
157  self.project_menu = tk.Menu(mbutton)
158  self.project_menu.add_command(label='Next Project', command=self.next_project,
159  accelerator='PgUp')
160  self.project_menu.add_command(label='Previous Project', command=self.previous_project,
161  accelerator='PgDn')
162  self.project_menu.add_separator()
163  mbutton['menu'] = self.project_menu
164 
165  # Add project menu key bindings.
166 
167  self.project_menu.bind_all('<KeyPress-KP_Next>', self.next_project_handler)
168  self.project_menu.bind_all('<KeyPress-Next>', self.next_project_handler)
169  self.project_menu.bind_all('<KeyPress-KP_Prior>', self.previous_project_handler)
170  self.project_menu.bind_all('<KeyPress-Prior>', self.previous_project_handler)
171 
172  # Stage menu.
173 
174  mbutton = tk.Menubutton(self.menubar, text='Stage', font=tkinter_font.Font(size=12))
175  mbutton.pack(side=tk.LEFT)
176  self.stage_menu = tk.Menu(mbutton)
177  self.stage_menu.add_command(label='Next Stage', command=self.next_stage,
178  accelerator='Up')
179  self.stage_menu.add_command(label='Previous Stage', command=self.previous_stage,
180  accelerator='Down')
181  self.stage_menu.add_separator()
182  mbutton['menu'] = self.stage_menu
183 
184  # Add stage menu key bindings.
185 
186  self.stage_menu.bind_all('<KeyPress-KP_Up>', self.previous_stage_handler)
187  self.stage_menu.bind_all('<KeyPress-Up>', self.previous_stage_handler)
188  self.stage_menu.bind_all('<KeyPress-KP_Down>', self.next_stage_handler)
189  self.stage_menu.bind_all('<KeyPress-Down>', self.next_stage_handler)
190 
191  # Output menu.
192 
193  mbutton = tk.Menubutton(self.menubar, text='Output', font=tkinter_font.Font(size=12))
194  mbutton.pack(side=tk.LEFT)
195  self.output_menu = tk.Menu(mbutton)
196  self.output_menu.add_command(label='Check', command=self.check)
197  self.output_menu.add_command(label='Checkana', command=self.checkana)
198  self.output_menu.add_command(label='Fetchlog', command=self.fetchlog)
199  self.output_menu.add_command(label='Shorten', command=self.shorten)
200  self.output_menu.add_separator()
201  self.output_menu.add_command(label='Histogram merge', command=self.mergehist)
202  self.output_menu.add_command(label='Ntuple merge', command=self.mergentuple)
203  self.output_menu.add_command(label='Custom merge', command=self.merge)
204  self.output_menu.add_separator()
205  self.output_menu.add_command(label='Clean', command=self.clean)
206  mbutton['menu'] = self.output_menu
207 
208  # Batch menu.
209 
210  mbutton = tk.Menubutton(self.menubar, text='Batch', font=tkinter_font.Font(size=12))
211  mbutton.pack(side=tk.LEFT)
212  self.batch_menu = tk.Menu(mbutton)
213  self.batch_menu.add_command(label='Submit', command=self.submit)
214  self.batch_menu.add_command(label='Makeup', command=self.makeup)
215  self.batch_menu.add_command(label='Update', command=self.update_jobs)
216  self.batch_menu.add_command(label='Kill', command=self.kill_jobs)
217  mbutton['menu'] = self.batch_menu
218 
219  # SAM-art menu.
220 
221  mbutton = tk.Menubutton(self.menubar, text='SAM-art', font=tkinter_font.Font(size=12))
222  mbutton.pack(side=tk.LEFT)
223  self.sam_menu = tk.Menu(mbutton)
224  self.sam_menu.add_command(label='Check Declarations', command=self.check_declarations)
225  self.sam_menu.add_command(label='Declare Files', command=self.declare)
226  self.sam_menu.add_command(label='Test Declarations', command=self.test_declarations)
227  self.sam_menu.add_separator()
228  self.sam_menu.add_command(label='Check Dataset Definition', command=self.check_definition)
229  self.sam_menu.add_command(label='Create Dataset Definition', command=self.define)
230  self.sam_menu.add_command(label='Test Dataset Definition', command=self.test_definition)
231  self.sam_menu.add_separator()
232  self.sam_menu.add_command(label='Check Locations', command=self.check_locations)
233  self.sam_menu.add_command(label='Check Tape Locations', command=self.check_tape)
234  self.sam_menu.add_command(label='Add Disk Locations', command=self.add_locations)
235  self.sam_menu.add_command(label='Clean Disk Locations', command=self.clean_locations)
236  self.sam_menu.add_command(label='Remove Disk Locations', command=self.remove_locations)
237  self.sam_menu.add_command(label='Upload to Enstore', command=self.upload)
238  self.sam_menu.add_separator()
239  self.sam_menu.add_command(label='Audit', command=self.audit)
240  mbutton['menu'] = self.sam_menu
241 
242  # SAM-ana menu.
243 
244  mbutton = tk.Menubutton(self.menubar, text='SAM-ana', font=tkinter_font.Font(size=12))
245  mbutton.pack(side=tk.LEFT)
246  self.sam_menu = tk.Menu(mbutton)
247  self.sam_menu.add_command(label='Check Declarations', command=self.check_ana_declarations)
248  self.sam_menu.add_command(label='Declare Files', command=self.declare_ana)
249  self.sam_menu.add_command(label='Test Declarations', command=self.test_ana_declarations)
250  self.sam_menu.add_separator()
251  self.sam_menu.add_command(label='Check Dataset Definition',
252  command=self.check_ana_definition)
253  self.sam_menu.add_command(label='Create Dataset Definition', command=self.define_ana)
254  self.sam_menu.add_command(label='Test Dataset Definition',
255  command=self.test_ana_definition)
256  self.sam_menu.add_separator()
257  self.sam_menu.add_command(label='Check Locations', command=self.check_ana_locations)
258  self.sam_menu.add_command(label='Check Tape Locations', command=self.check_ana_tape)
259  self.sam_menu.add_command(label='Add Disk Locations', command=self.add_ana_locations)
260  self.sam_menu.add_command(label='Clean Disk Locations', command=self.clean_ana_locations)
261  self.sam_menu.add_command(label='Remove Disk Locations', command=self.remove_ana_locations)
262  self.sam_menu.add_command(label='Upload to Enstore', command=self.upload_ana)
263  #self.sam_menu.add_separator()
264  #self.sam_menu.add_command(label='Audit', command=self.audit_ana)
265  mbutton['menu'] = self.sam_menu
266 
267  # Help menu.
268 
269  mbutton = tk.Menubutton(self.menubar, text='Help', font=tkinter_font.Font(size=12))
270  mbutton.pack(side=tk.RIGHT)
271  self.help_menu = tk.Menu(mbutton)
272  self.help_menu.add_command(label='project.py help', command=self.help)
273  self.help_menu.add_command(label='XML help', command=self.xmlhelp)
274  mbutton['menu'] = self.help_menu
275 
276  return
277 
278  # Open project.
279 
280  def open(self, xml_path=None, choose=True):
281  if xml_path == None:
282  types = (('XML files', '*.xml'),
283  ('All files', '*'))
284  d = tkinter_filedialog.Open(filetypes=types, parent=self.root)
285  xml_path = d.show()
286 
287  # Parse xml into ProjectDef objects.
288  # This step can raise an exception for several reasons. In that case,
289  # display a message and return without opening the file.
290 
291  top=self.winfo_toplevel()
292  old_cursor = top['cursor']
293  project_defs = []
294  try:
295  top['cursor'] = 'watch'
296  top.update_idletasks()
297  new_project_defs = project.get_projects(xml_path)
298  if len(new_project_defs) > 0:
299  project_defs.extend(new_project_defs)
300  top['cursor'] = old_cursor
301  except:
302  top['cursor'] = old_cursor
303  e = sys.exc_info()
304  message = 'Error opening %s\n%s' % (xml_path, e[1])
305  traceback.print_tb(e[2])
306  tkinter_messagebox.showerror('', message)
307  return
308 
309  if len(project_defs) > 0:
310  project_name = project_defs[0].name
311  else:
312  xml_name = os.path.basename(xml_path)
313  n = xml_name.find('.xml')
314  if n > 0:
315  project_name = xml_name[0: n]
316  else:
317  project_name = xml_name
318 
319  # See if this project is already in the list of open projects.
320  # If so, just choose this project, but don't open it again.
321 
322  for project_tuple in self.projects:
323  if project_name == project_tuple[0]:
324  if choose:
325  self.choose_project(project_name)
326  return
327 
328  # Add this project to the list of known projects.
329 
330  self.projects.append((project_name, xml_path, project_defs))
331 
332  # Update project menu.
333 
334  callback = tk._setit(tk.StringVar(), project_name, callback=self.choose_project)
335  self.project_menu.add_command(label=project_name, command=callback)
336 
337  # Choose just-opened project.
338 
339  if choose:
340  self.choose_project(project_name)
341 
342  # Choose already-opened project.
343 
344  def choose_project(self, value):
345  self.current_project_name = ''
346  self.current_project_defs = []
347  self.current_project_def = None
348  self.current_stage_name = ''
349  self.current_stage_def = None
350  self.project_view.highlight_stage(self.current_stage_name)
351  for project_tuple in self.projects:
352  project_name = project_tuple[0]
353  xml_path = project_tuple[1]
354  project_defs = project_tuple[2]
355  if project_name == value:
356  self.current_project_name = value
357  self.current_project_defs = project_defs
358 
359  # Update project view widget.
360 
361  self.project_view.set_project(project_name, xml_path, project_defs)
362 
363  # Update stage menu.
364 
365  self.stage_menu.delete(3, tk.END)
366  self.stage_menu.add_separator()
367  for project_def in project_defs:
368  for stage in project_def.stages:
369  callback = tk._setit(tk.StringVar(), stage.name, callback=self.choose_stage)
370  self.stage_menu.add_command(label=stage.name, command=callback)
371 
372  return
373 
374  # It is an error if we fall out of the loop.
375 
376  raise 'No project: %s' % value
377 
378  # Choose stage.
379 
380  def choose_stage(self, value):
381  for project_def in self.current_project_defs:
382  for stage in project_def.stages:
383  if stage.name == value:
384  self.current_stage_name = value
385  self.current_stage_def = stage
386  self.current_project_def = project_def
387  self.project_view.highlight_stage(self.current_stage_name)
388 
389  # Key event handlers.
390 
391  def next_project_handler(self, event):
392  self.next_project()
393  def previous_project_handler(self, event):
394  self.previous_project()
395  def next_stage_handler(self, event):
396  self.next_stage()
397  def previous_stage_handler(self, event):
398  self.previous_stage()
399 
400  # Select next project.
401  def next_project(self):
402 
403  # Don't do anything if the project list is empty.
404 
405  if len(self.projects) == 0:
406  return
407 
408  # Cycle through list of known projects.
409 
410  found = False
411  for project_tuple in self.projects:
412  project_name = project_tuple[0]
413  if found:
414  self.choose_project(project_name)
415  return
416  if project_name == self.current_project_name:
417  found = True
418 
419  # Choose first project if we fell out of the loop.
420 
421  self.choose_project(self.projects[0][0])
422 
423  # Select previous project.
424 
425  def previous_project(self):
426 
427  # Don't do anything if the project list is empty.
428 
429  if len(self.projects) == 0:
430  return
431 
432  # Cycle through list of known projects.
433 
434  previous_project_name = self.projects[-1][0]
435  for project_tuple in self.projects:
436  project_name = project_tuple[0]
437  if project_name == self.current_project_name:
438  self.choose_project(previous_project_name)
439  return
440  previous_project_name = project_name
441 
442  # Choose the last project if we fell out of the loop.
443 
444  self.choose_project(self.projects[-1][0])
445 
446  # Select XML view.
447 
448  def xml_display(self):
449  self.project_view.make_xml_window()
450 
451  # Select next stage.
452 
453  def next_stage(self):
454 
456  circular=True)
457  self.choose_stage(stage.name)
458  return
459 
460 
461  # Select previous stage.
462 
463  def previous_stage(self):
464 
466  circular=True)
467  self.choose_stage(stage.name)
468  return
469 
470 
471  # Check action.
472 
473  def check(self):
474  if self.current_project_def == None:
475  tkinter_messagebox.showwarning('', 'No project selected.')
476  return
477  if self.current_stage_def == None:
478  tkinter_messagebox.showwarning('', 'No stage selected.')
479  return
480  top=self.winfo_toplevel()
481  old_cursor = top['cursor']
482  try:
483  top['cursor'] = 'watch'
484  top.update_idletasks()
486  quick=self.current_stage_def.validate_on_worker)
487  top['cursor'] = old_cursor
488  except:
489  top['cursor'] = old_cursor
490  e = sys.exc_info()
491  traceback.print_tb(e[2])
492  tkinter_messagebox.showerror('', e[1])
493  self.project_view.update_status()
494 
495  # Checkana action.
496 
497  def checkana(self):
498  if self.current_project_def == None:
499  tkinter_messagebox.showwarning('', 'No project selected.')
500  return
501  if self.current_stage_def == None:
502  tkinter_messagebox.showwarning('', 'No stage selected.')
503  return
504  top=self.winfo_toplevel()
505  old_cursor = top['cursor']
506  try:
507  top['cursor'] = 'watch'
508  top.update_idletasks()
510  top['cursor'] = old_cursor
511  except:
512  top['cursor'] = old_cursor
513  e = sys.exc_info()
514  traceback.print_tb(e[2])
515  tkinter_messagebox.showerror('', e[1])
516  self.project_view.update_status()
517 
518  # Fetchlog action.
519 
520  def fetchlog(self):
521  if self.current_project_def == None:
522  tkinter_messagebox.showwarning('', 'No project selected.')
523  return
524  if self.current_stage_def == None:
525  tkinter_messagebox.showwarning('', 'No stage selected.')
526  return
527  top=self.winfo_toplevel()
528  old_cursor = top['cursor']
529  try:
530  top['cursor'] = 'watch'
531  top.update_idletasks()
533  top['cursor'] = old_cursor
534  except:
535  top['cursor'] = old_cursor
536  e = sys.exc_info()
537  traceback.print_tb(e[2])
538  tkinter_messagebox.showerror('', e[1])
539 
540  # Shorten action.
541 
542  def shorten(self):
543  if self.current_project_def == None:
544  tkinter_messagebox.showwarning('', 'No project selected.')
545  return
546  if self.current_stage_def == None:
547  tkinter_messagebox.showwarning('', 'No stage selected.')
548  return
549  top=self.winfo_toplevel()
550  old_cursor = top['cursor']
551  try:
552  top['cursor'] = 'watch'
553  top.update_idletasks()
555  top['cursor'] = old_cursor
556  except:
557  top['cursor'] = old_cursor
558  e = sys.exc_info()
559  traceback.print_tb(e[2])
560  tkinter_messagebox.showerror('', e[1])
561  self.project_view.update_status()
562 
563  # Clean action.
564 
565  def clean(self):
566  if self.current_project_def == None:
567  tkinter_messagebox.showwarning('', 'No project selected.')
568  return
569  if self.current_stage_def == None:
570  tkinter_messagebox.showwarning('', 'No stage selected.')
571  return
572  top=self.winfo_toplevel()
573  old_cursor = top['cursor']
574  try:
575  top['cursor'] = 'watch'
576  top.update_idletasks()
577  project.docleanx(self.current_project_defs, self.current_project_def.name,
578  self.current_stage_name)
579  top['cursor'] = old_cursor
580  except:
581  top['cursor'] = old_cursor
582  e = sys.exc_info()
583  traceback.print_tb(e[2])
584  tkinter_messagebox.showerror('', e[1])
585  self.project_view.update_status()
586 
587  # Submit action.
588 
589  def submit(self):
590  if self.current_project_def == None:
591  tkinter_messagebox.showwarning('', 'No project selected.')
592  return
593  if self.current_stage_def == None:
594  tkinter_messagebox.showwarning('', 'No stage selected.')
595  return
596 
597  top=self.winfo_toplevel()
598  old_cursor = top['cursor']
599  try:
600  top['cursor'] = 'watch'
601  top.update_idletasks()
602  project.dosubmit(self.current_project_def, self.current_stage_def, makeup=False,
603  recur=self.current_stage_def.recur)
604  top['cursor'] = old_cursor
605  except:
606  top['cursor'] = old_cursor
607  e = sys.exc_info()
608  traceback.print_tb(e[2])
609  tkinter_messagebox.showerror('', e[1])
610  BatchStatus.update_jobs()
611  self.project_view.update_status()
612 
613  # Makeup action.
614 
615  def makeup(self):
616  if self.current_project_def == None:
617  tkinter_messagebox.showwarning('', 'No project selected.')
618  return
619  if self.current_stage_def == None:
620  tkinter_messagebox.showwarning('', 'No stage selected.')
621  return
622 
623  top=self.winfo_toplevel()
624  old_cursor = top['cursor']
625  try:
626  top['cursor'] = 'watch'
627  top.update_idletasks()
629  recur=self.current_stage_def.recur)
630  top['cursor'] = old_cursor
631  except:
632  top['cursor'] = old_cursor
633  e = sys.exc_info()
634  traceback.print_tb(e[2])
635  tkinter_messagebox.showerror('', e[1])
636  BatchStatus.update_jobs()
637  self.project_view.update_status()
638 
639  # Update jobs action.
640 
641  def update_jobs(self):
642  self.project_view.update_jobs()
643 
644  # Kill jobs action.
645 
646  def kill_jobs(self):
647  if self.current_project_def == None:
648  tkinter_messagebox.showwarning('', 'No project selected.')
649  return
650  if self.current_stage_def == None:
651  tkinter_messagebox.showwarning('', 'No stage selected.')
652  return
653 
654  top=self.winfo_toplevel()
655  old_cursor = top['cursor']
656  try:
657  top['cursor'] = 'watch'
658  top.update_idletasks()
659  BatchStatus.update_jobs()
660  jobs = BatchStatus.get_jobs()
661  top['cursor'] = old_cursor
662  except:
663  top['cursor'] = old_cursor
664  e = sys.exc_info()
665  traceback.print_tb(e[2])
666  tkinter_messagebox.showerror('', e[1])
667 
668  # Figure out which clusters to kill.
669 
670  cluster_ids = set()
671  for job in jobs:
672  words = job.split()
673  if len(words) >= 2:
674  jobid = words[0]
675  script = words[-1]
676  workscript = '%s-%s-%s.sh' % (self.current_stage_def.name,
677  self.current_project_def.name,
678  self.current_project_def.release_tag)
679  if script.find(workscript) == 0:
680  cp_server = jobid.split('@')
681  if len(cp_server) == 2:
682  clusproc = cp_server[0]
683  server = cp_server[1]
684  cp = clusproc.split('.')
685  if len(cp) == 2:
686  cluster = cp[0]
687  process = cp[1]
688  cluster_id = '%s@%s' % (cluster, server)
689  if not cluster_id in cluster_ids:
690  cluster_ids.add(cluster_id)
691 
692  # Actually issue kill commands.
693 
694  for cluster_id in cluster_ids:
695  print('Kill cluster id %s' % cluster_id)
696  command = ['jobsub_rm']
697  if self.current_project_def.server != '-' and self.current_project_def.server != '':
698  command.append('--jobsub-server=%s' % self.current_project_def.server)
699  command.append('--jobid=%s' % cluster_id)
700  command.append('--role=%s' % project_utilities.get_role())
701  jobinfo = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
702  jobout, joberr = jobinfo.communicate()
703  jobout = convert_str(jobout)
704  joberr = convert_str(joberr)
705  rc = jobinfo.poll()
706  if rc != 0:
707  raise JobsubError(command, rc, jobout, joberr)
708 
709  self.update_jobs()
710 
711 
712  # Histogram merge.
713 
714  def mergehist(self):
715  if self.current_project_def == None:
716  tkinter_messagebox.showwarning('', 'No project selected.')
717  return
718  if self.current_stage_def == None:
719  tkinter_messagebox.showwarning('', 'No stage selected.')
720  return
721  top=self.winfo_toplevel()
722  old_cursor = top['cursor']
723  try:
724  top['cursor'] = 'watch'
725  top.update_idletasks()
726  project.domerge(self.current_stage_def, mergehist=True, mergentuple=False)
727  top['cursor'] = old_cursor
728  except:
729  top['cursor'] = old_cursor
730  e = sys.exc_info()
731  traceback.print_tb(e[2])
732  tkinter_messagebox.showerror('', e[1])
733 
734  # Ntuple merge.
735 
736  def mergentuple(self):
737  if self.current_project_def == None:
738  tkinter_messagebox.showwarning('', 'No project selected.')
739  return
740  if self.current_stage_def == None:
741  tkinter_messagebox.showwarning('', 'No stage selected.')
742  return
743  top=self.winfo_toplevel()
744  old_cursor = top['cursor']
745  try:
746  top['cursor'] = 'watch'
747  top.update_idletasks()
748  project.domerge(self.current_stage_def, mergehist=False, mergentuple=True)
749  top['cursor'] = old_cursor
750  except:
751  top['cursor'] = old_cursor
752  e = sys.exc_info()
753  traceback.print_tb(e[2])
754  tkinter_messagebox.showerror('', e[1])
755 
756  # Custom merge.
757 
758  def merge(self):
759  if self.current_project_def == None:
760  tkinter_messagebox.showwarning('', 'No project selected.')
761  return
762  if self.current_stage_def == None:
763  tkinter_messagebox.showwarning('', 'No stage selected.')
764  return
765  top=self.winfo_toplevel()
766  old_cursor = top['cursor']
767  try:
768  top['cursor'] = 'watch'
769  top.update_idletasks()
770  project.domerge(self.current_stage_def, mergehist=False, mergentuple=False)
771  top['cursor'] = old_cursor
772  except:
773  top['cursor'] = old_cursor
774  e = sys.exc_info()
775  traceback.print_tb(e[2])
776  tkinter_messagebox.showerror('', e[1])
777 
778  # Declare files to sam.
779 
780  def declare(self, ana=False):
781  if self.current_project_def == None:
782  tkinter_messagebox.showwarning('', 'No project selected.')
783  return
784  if self.current_stage_def == None:
785  tkinter_messagebox.showwarning('', 'No stage selected.')
786  return
787  top=self.winfo_toplevel()
788  old_cursor = top['cursor']
789  try:
790  top['cursor'] = 'watch'
791  top.update_idletasks()
792  project.docheck_declarations(self.current_stage_def.logdir,
793  self.current_stage_def.outdir, declare=True, ana=ana)
794  top['cursor'] = old_cursor
795  except:
796  top['cursor'] = old_cursor
797  e = sys.exc_info()
798  traceback.print_tb(e[2])
799  tkinter_messagebox.showerror('', e[1])
800 
801  # Declare analysis files to sam.
802 
803  def declare_ana(self):
804  self.declare(ana=True)
805 
806  # Check sam declarations.
807 
808  def check_declarations(self, ana=False):
809  if self.current_project_def == None:
810  tkinter_messagebox.showwarning('', 'No project selected.')
811  return
812  if self.current_stage_def == None:
813  tkinter_messagebox.showwarning('', 'No stage selected.')
814  return
815  top=self.winfo_toplevel()
816  old_cursor = top['cursor']
817  try:
818  top['cursor'] = 'watch'
819  top.update_idletasks()
820  project.docheck_declarations(self.current_stage_def.logdir,
821  self.current_stage_def.outdir, declare=False, ana=ana)
822  top['cursor'] = old_cursor
823  except:
824  top['cursor'] = old_cursor
825  e = sys.exc_info()
826  traceback.print_tb(e[2])
827  tkinter_messagebox.showerror('', e[1])
828 
829  # Check sam analysis file declarations.
830 
832  self.check_declarations(ana=True)
833 
834  # Test sam declarations.
835 
836  def test_declarations(self, ana=False):
837  if self.current_project_def == None:
838  tkinter_messagebox.showwarning('', 'No project selected.')
839  return
840  if self.current_stage_def == None:
841  tkinter_messagebox.showwarning('', 'No stage selected.')
842  return
843  top=self.winfo_toplevel()
844  old_cursor = top['cursor']
845  try:
846  top['cursor'] = 'watch'
847  top.update_idletasks()
848  dim = project_utilities.dimensions_datastream(self.current_project_def,
849  self.current_stage_def,
850  ana=ana)
852  top['cursor'] = old_cursor
853  except:
854  top['cursor'] = old_cursor
855  e = sys.exc_info()
856  traceback.print_tb(e[2])
857  tkinter_messagebox.showerror('', e[1])
858 
859  # Test sam analysis file declarations.
860 
862  self.test_declarations(ana=True)
863 
864  # Create sam dataset definition.
865 
866  def define(self, ana=False):
867  if self.current_project_def == None:
868  tkinter_messagebox.showwarning('', 'No project selected.')
869  return
870  if self.current_stage_def == None:
871  tkinter_messagebox.showwarning('', 'No stage selected.')
872  return
873  top=self.winfo_toplevel()
874  old_cursor = top['cursor']
875 
876  defname = ''
877  if ana:
878  defname = self.current_stage_def.ana_defname
879  else:
880  defname = self.current_stage_def.defname
881 
882  try:
883  top['cursor'] = 'watch'
884  top.update_idletasks()
885  dim = project_utilities.dimensions_datastream(self.current_project_def,
886  self.current_stage_def,
887  ana=ana)
888  project.docheck_definition(defname, dim, define=True)
889  top['cursor'] = old_cursor
890  except:
891  top['cursor'] = old_cursor
892  e = sys.exc_info()
893  traceback.print_tb(e[2])
894  tkinter_messagebox.showerror('', e[1])
895 
896  # Create sam dataset definition for analysis files.
897 
898  def define_ana(self):
899  self.define(ana=True)
900 
901  # Check whether sam dataset definition exists.
902 
903  def check_definition(self, ana=False):
904  if self.current_project_def == None:
905  tkinter_messagebox.showwarning('', 'No project selected.')
906  return
907  if self.current_stage_def == None:
908  tkinter_messagebox.showwarning('', 'No stage selected.')
909  return
910  top=self.winfo_toplevel()
911  old_cursor = top['cursor']
912 
913  defname = ''
914  if ana:
915  defname = self.current_stage_def.ana_defname
916  else:
917  defname = self.current_stage_def.defname
918 
919  try:
920  top['cursor'] = 'watch'
921  top.update_idletasks()
922  dim = project_utilities.dimensions_datastream(self.current_project_def,
923  self.current_stage_def,
924  ana=ana)
925  project.docheck_definition(defname, dim, define=False)
926  top['cursor'] = old_cursor
927  except:
928  top['cursor'] = old_cursor
929  e = sys.exc_info()
930  traceback.print_tb(e[2])
931  tkinter_messagebox.showerror('', e[1])
932 
933  # Check whether sam analysis dataset definition exists.
934 
936  self.check_definition(ana=True)
937 
938  # Test sam dataset definition (list files).
939 
940  def test_definition(self, ana=False):
941  if self.current_project_def == None:
942  tkinter_messagebox.showwarning('', 'No project selected.')
943  return
944  if self.current_stage_def == None:
945  tkinter_messagebox.showwarning('', 'No stage selected.')
946  return
947 
948  defname = ''
949  if ana:
950  defname = self.current_stage_def.ana_defname
951  else:
952  defname = self.current_stage_def.defname
953  if defname == '':
954  tkinter_messagebox.showwarning('No sam dataset definition specified.')
955  return
956 
957  top=self.winfo_toplevel()
958  old_cursor = top['cursor']
959  try:
960  top['cursor'] = 'watch'
961  top.update_idletasks()
963  top['cursor'] = old_cursor
964  except:
965  top['cursor'] = old_cursor
966  e = sys.exc_info()
967  traceback.print_tb(e[2])
968  tkinter_messagebox.showerror('', e[1])
969 
970  # Test sam analysis dataset definition (list files).
971 
973  self.test_definition(ana=True)
974 
975  # Check locations.
976 
977  def check_locations(self, ana=False):
978  if self.current_project_def == None:
979  tkinter_messagebox.showwarning('', 'No project selected.')
980  return
981  if self.current_stage_def == None:
982  tkinter_messagebox.showwarning('', 'No stage selected.')
983  return
984  top=self.winfo_toplevel()
985  old_cursor = top['cursor']
986  try:
987  top['cursor'] = 'watch'
988  top.update_idletasks()
989  dim = project_utilities.dimensions_datastream(self.current_project_def,
990  self.current_stage_def,
991  ana=ana)
992  project.docheck_locations(dim, self.current_stage_def.logdir,
993  add=False,
994  clean=False,
995  remove=False,
996  upload=False)
997  top['cursor'] = old_cursor
998  except:
999  top['cursor'] = old_cursor
1000  e = sys.exc_info()
1001  traceback.print_tb(e[2])
1002  tkinter_messagebox.showerror('', e[1])
1003 
1004  # Check locations for analysis files.
1005 
1007  self.check_locations(ana=True)
1008 
1009  # Check tape locations.
1010 
1011  def check_tape(self, ana=False):
1012  if self.current_project_def == None:
1013  tkinter_messagebox.showwarning('', 'No project selected.')
1014  return
1015  if self.current_stage_def == None:
1016  tkinter_messagebox.showwarning('', 'No stage selected.')
1017  return
1018  top=self.winfo_toplevel()
1019  old_cursor = top['cursor']
1020  try:
1021  top['cursor'] = 'watch'
1022  top.update_idletasks()
1023  dim = project_utilities.dimensions_datastream(self.current_project_def,
1024  self.current_stage_def,
1025  ana=ana)
1027  top['cursor'] = old_cursor
1028  except:
1029  top['cursor'] = old_cursor
1030  e = sys.exc_info()
1031  traceback.print_tb(e[2])
1032  tkinter_messagebox.showerror('', e[1])
1033 
1034  # Check tape locations for analysis files.
1035 
1036  def check_ana_tape(self):
1037  self.check_tape(ana=True)
1038 
1039  # Add disk locations.
1040 
1041  def add_locations(self, ana=False):
1042  if self.current_project_def == None:
1043  tkinter_messagebox.showwarning('', 'No project selected.')
1044  return
1045  if self.current_stage_def == None:
1046  tkinter_messagebox.showwarning('', 'No stage selected.')
1047  return
1048  top=self.winfo_toplevel()
1049  old_cursor = top['cursor']
1050  try:
1051  top['cursor'] = 'watch'
1052  top.update_idletasks()
1053  dim = project_utilities.dimensions_datastream(self.current_project_def,
1054  self.current_stage_def,
1055  ana=ana)
1056  project.docheck_locations(dim, self.current_stage_def.outdir,
1057  add=True,
1058  clean=False,
1059  remove=False,
1060  upload=False)
1061  top['cursor'] = old_cursor
1062  except:
1063  top['cursor'] = old_cursor
1064  e = sys.exc_info()
1065  traceback.print_tb(e[2])
1066  tkinter_messagebox.showerror('', e[1])
1067 
1068  # Add disk locations for analysis files.
1069 
1071  self.add_locations(ana=True)
1072 
1073  # Clean disk locations.
1074 
1075  def clean_locations(self, ana):
1076  if self.current_project_def == None:
1077  tkinter_messagebox.showwarning('', 'No project selected.')
1078  return
1079  if self.current_stage_def == None:
1080  tkinter_messagebox.showwarning('', 'No stage selected.')
1081  return
1082  top=self.winfo_toplevel()
1083  old_cursor = top['cursor']
1084  try:
1085  top['cursor'] = 'watch'
1086  top.update_idletasks()
1087  dim = project_utilities.dimensions_datastream(self.current_project_def,
1088  self.current_stage_def,
1089  ana=ana)
1090  project.docheck_locations(dim, self.current_stage_def.outdir,
1091  add=False,
1092  clean=True,
1093  remove=False,
1094  upload=False)
1095  top['cursor'] = old_cursor
1096  except:
1097  top['cursor'] = old_cursor
1098  e = sys.exc_info()
1099  traceback.print_tb(e[2])
1100  tkinter_messagebox.showerror('', e[1])
1101 
1102  # Clean disk locations for analysis files.
1103 
1105  self.clean_locations(ana=True)
1106 
1107  # Remove disk locations.
1108 
1109  def remove_locations(self, ana=False):
1110  if self.current_project_def == None:
1111  tkinter_messagebox.showwarning('', 'No project selected.')
1112  return
1113  if self.current_stage_def == None:
1114  tkinter_messagebox.showwarning('', 'No stage selected.')
1115  return
1116  top=self.winfo_toplevel()
1117  old_cursor = top['cursor']
1118  try:
1119  top['cursor'] = 'watch'
1120  top.update_idletasks()
1121  dim = project_utilities.dimensions_datastream(self.current_project_def,
1122  self.current_stage_def,
1123  ana=ana)
1124  project.docheck_locations(dim, self.current_stage_def.outdir,
1125  add=False,
1126  clean=False,
1127  remove=True,
1128  upload=False)
1129  top['cursor'] = old_cursor
1130  except:
1131  top['cursor'] = old_cursor
1132  e = sys.exc_info()
1133  traceback.print_tb(e[2])
1134  tkinter_messagebox.showerror('', e[1])
1135 
1136  # Remove disk locations for analysis files.
1137 
1139  self.remove_locations(ana=True)
1140 
1141  # Upload.
1142 
1143  def upload(self, ana=False):
1144  if self.current_project_def == None:
1145  tkinter_messagebox.showwarning('', 'No project selected.')
1146  return
1147  if self.current_stage_def == None:
1148  tkinter_messagebox.showwarning('', 'No stage selected.')
1149  return
1150  top=self.winfo_toplevel()
1151  old_cursor = top['cursor']
1152  try:
1153  top['cursor'] = 'watch'
1154  top.update_idletasks()
1155  dim = project_utilities.dimensions_datastream(self.current_project_def,
1156  self.current_stage_def,
1157  ana=ana)
1158  project.docheck_locations(dim, self.current_stage_def.outdir,
1159  add=False,
1160  clean=False,
1161  remove=False,
1162  upload=True)
1163  top['cursor'] = old_cursor
1164  except:
1165  top['cursor'] = old_cursor
1166  e = sys.exc_info()
1167  traceback.print_tb(e[2])
1168  tkinter_messagebox.showerror('', e[1])
1169 
1170  # Upload analysis files.
1171 
1172  def upload_ana(self):
1173  self.upload(ana=True)
1174 
1175  # Do a SAM audit.
1176 
1177  def audit(self):
1178  if self.current_project_def == None:
1179  tkinter_messagebox.showwarning('', 'No project selected.')
1180  return
1181  if self.current_stage_def == None:
1182  tkinter_messagebox.showwarning('', 'No stage selected.')
1183  return
1184  top=self.winfo_toplevel()
1185  old_cursor = top['cursor']
1186  try:
1187  top['cursor'] = 'watch'
1188  top.update_idletasks()
1190  top['cursor'] = old_cursor
1191  except:
1192  top['cursor'] = old_cursor
1193  e = sys.exc_info()
1194  traceback.print_tb(e[2])
1195  tkinter_messagebox.showerror('', e[1])
1196 
1197  # Help method.
1198 
1199  def help(self):
1200 
1201  # Capture output from project.py --help.
1202  # Because of the way this command is implemented in project.py, we have
1203  # to run in a separate process, not just call method help of project module.
1204 
1205  command = ['project.py', '--help']
1206  helptext = convert_str(subprocess.check_output(command))
1207  w = TextWindow()
1208  w.append(helptext)
1209 
1210  # XML help method.
1211 
1212  def xmlhelp(self):
1213 
1214  # Capture output from project.py --xmlhelp.
1215  # Because of the way this command is implemented in project.py, we have
1216  # to run in a separate process, not just call method xmlhelp of project module.
1217 
1218  command = ['project.py', '--xmlhelp']
1219  helptext = convert_str(subprocess.check_output(command))
1220  w = TextWindow()
1221  w.append(helptext)
1222 
1223  # Close window.
1224 
1225  def close(self):
1226  self.root.destroy()
def next_stage(projects, stagename, circular=False)
Definition: project.py:762
def choose_project(self, value)
Definition: projectapp.py:344
def next_stage_handler(self, event)
Definition: projectapp.py:395
def upload(self, ana=False)
Definition: projectapp.py:1143
def docleanx(projects, projectname, stagename, clean_descendants=True)
Definition: project.py:519
def choose_stage(self, value)
Definition: projectapp.py:380
def dotest_declarations(dim)
Definition: project.py:2158
def __init__(self, parent=None)
Definition: projectapp.py:51
def dotest_definition(defname)
Definition: project.py:2217
def previous_stage(projects, stagename, circular=False)
Definition: project.py:788
def remove_locations(self, ana=False)
Definition: projectapp.py:1109
def previous_project_handler(self, event)
Definition: projectapp.py:393
def doaudit(stage)
Definition: project.py:3778
def dofetchlog(project, stage)
Definition: project.py:1946
def clean_locations(self, ana)
Definition: projectapp.py:1075
def check_declarations(self, ana=False)
Definition: projectapp.py:808
def docheck_definition(defname, dim, define)
Definition: project.py:2176
def check_definition(self, ana=False)
Definition: projectapp.py:903
def domerge(stage, mergehist, mergentuple)
Definition: project.py:3721
def previous_stage_handler(self, event)
Definition: projectapp.py:397
def dosubmit(project, stage, makeup=False, recur=False, dryrun=False)
Definition: project.py:3634
def docheck_declarations(logdir, outdir, declare, ana=False)
Definition: project.py:2071
def open(self, xml_path=None, choose=True)
Definition: projectapp.py:280
def declare(self, ana=False)
Definition: projectapp.py:780
def docheck_locations(dim, outdir, add, clean, remove, upload)
Definition: project.py:2265
def doshorten(stage)
Definition: project.py:970
def add_locations(self, ana=False)
Definition: projectapp.py:1041
def test_declarations(self, ana=False)
Definition: projectapp.py:836
def test_definition(self, ana=False)
Definition: projectapp.py:940
def docheck_tape(dim)
Definition: project.py:2432
def define(self, ana=False)
Definition: projectapp.py:866
def docheck(project, stage, ana, quick=False)
Definition: project.py:1087
def check_locations(self, ana=False)
Definition: projectapp.py:977
def next_project_handler(self, event)
Definition: projectapp.py:391
def check_tape(self, ana=False)
Definition: projectapp.py:1011
def get_projects(xmlfile, check=True)
Definition: project.py:700