import gtk, gobject import sys import os import inspect import logger import fluents import main def _workflow_classes(modname): """Returns a list of all subclasses of Workflow in a given module""" workflow_classes = [] __import__('workflows.%s' % modname) module = sys.modules['workflows.%s' % modname] d = module.__dict__ for wf in d.values(): try: if issubclass(wf, Workflow): workflow_classes.append(wf) except TypeError, e: pass return workflow_classes def workflow_list(): """Returns a list containing all new workflows""" retval = [] # List all .py files that can contain workflow classes wf_path = sys.modules['workflows'].__path__ wf_files = [] for dir in wf_path: for fn in os.listdir(dir): if fn.endswith('.py') and ('#' not in fn): wf_files.append(fn[:-3]) # Try to load each file and look for Workflow derived classes for fn in wf_files: try: for wf in _workflow_classes(fn): retval.append(wf) except Exception, e: logger.log('warning', 'Cannot load workflow: %s' % fn) logger.log('warning', e) return retval class Workflow: """Defines a workflow that contains a set of analysis stages. A Workflow is a set of analysis stages for a certain type of analysis. Each stage contains some possible operations to do accomplish that task. """ name = "Workflow" ident = None description = "Workflow Description" def __init__(self): self.stages = [] def get_data_file_name(self, filename): """Checks if a file with the given name exists in the data directory. Returns the file name if the file exists in the data directory, which is defined as datadir/workflowname. If the file does not exist, or the workflow does not have an identificator, this method returns None.""" print os.path.join(main.options.datadir, self.ident, filename) if self.ident == None: return None fn = os.path.join(main.options.datadir, self.ident, filename) if os.path.isfile(fn): return fn return None def add_stage(self, stage): self.stages.append(stage) #self.stages_by_id[stage.id] = stage def print_tree(self): print self.name for stage in self.stages: print ' %s' % stage.name for task in stage.tasks: print ' %s' % task.name class EmptyWorkflow(Workflow): name = 'Empty Workflow' def __init__(self): logger.log("debug", "initing empty workflow") Workflow.__init__(self) class Stage: """A stage is a part of the data analysis process. Each stage contains a set of tasks that can be used to accomplish the task. A typical early stage is 'preprocessing', which can be done in several ways, each represented by a task. """ def __init__(self, id, name): self.id = id self.name = name self.tasks = [] def add_task(self, task): self.tasks.append(task) class Task: """A Task object encapsulates a task on a data set. Each Task instance encapsulates some task that can be applied to one or more types of data. """ name = "" def __init__(self, input): self.input = input self.options = Options() self.datasets = {} self.arrays = {} self.plots = {} # just return a Validation object def validate_input(input): return Validation(True, "Validation Not Implemented") def run(self): pass def show_options_gui(self, editable=False): pass class Validation: def __init__(self,result, reason): self.succeeded = result self.reason = reason class WorkflowView (gtk.VBox): def __init__(self, wf): gtk.VBox.__init__(self) self.workflow = wf self.setup_workflow(wf) def setup_workflow(self, wf): # Add stage in the process for stage in wf.stages: exp = gtk.Expander(stage.name) btn_align = gtk.Alignment(xscale=0.9) btn_align.set_padding(0,4,20,0) btn_align.show() btn_box = gtk.VBox() btn_align.add(btn_box) btn_box.show() exp.add(btn_align) # Add tasks in each stage for task in stage.tasks: btn = gtk.Button(task.name) btn.connect('clicked', lambda button, t=task : self.run_task(t)) btn_box.add(btn) btn.show() exp.show() self.pack_start(exp, expand=False, fill=False) def remove_workflow(self): for c in self.get_children(): c.hide() self.remove(c) def set_workflow(self, workflow): self.workflow = workflow self.remove_workflow() self.setup_workflow(workflow) def run_task(self, task_class): logger.log('debug', 'Creating task: %s' % task_class.name) parent_data = main.project.current_data task = task_class(input=parent_data) validation = task.validate_input() if not validation.succeeded: logger.log('warning','Invalid Inputdata: ' + str(reason)) return task_result = task.run() if task_result != None: main.project.add_data(parent_data, task_result, task.name) else: logger.log('debug', 'Task gave no output: %s' % task.name) logger.log('debug', 'Task ended: %s' % task.name) class Options(dict): """Options base class. """ def __init__(self, *args,**kw): dict.__init__(self, *args, **kw) self['out_plots'] = [] self['out_data'] = [] self['all_plots'] = [] self['all_data'] = [] def _copy_from_list(self, key_list): """Returns suboptions (dictionary) from a list of keys. """ d = {} for key in key_list: d[key] = self.get(key, None) return d class OptionsDialog(gtk.Dialog): """The basic input/output dialog box. This defines the first page of the task options-gui. Any task that invokes a option-gui will inherit from this class. """ def __init__(self, data, options, input_names=['X','Y']): gtk.Dialog.__init__(self, 'Input-Output dialog', None, gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)) self._options = options self._data = data self._editable = True self.set_size_request(550,450) # create notebook self.nb = nb = gtk.Notebook() # 1. page: input/output #inputs input_frame = gtk.Frame("Input") hbox = gtk.HBox(True, 8) align = gtk.Alignment(1, 1, 1, 1) align.set_padding(8, 8, 8, 8) align.add(hbox) input_frame.add(align) for i, name in enumerate(input_names): frame = gtk.Frame(name) frame.set_label_align(0.5, 0.5) label = gtk.Label(data[i]._name + "\n" + str(data[i]._array.shape)) frame.add(label) hbox.add(frame) #outputs output_frame = gtk.Frame("Output") output_hbox = gtk.HBox(True,4) output_align = gtk.Alignment(1, 1, 1, 1) output_align.set_padding(8, 8, 8, 8) #left padding:8 output_align.add(output_hbox) output_frame.add(output_align) # plots plot_list = gtk.ListStore(str, 'gboolean', gtk.gdk.Pixbuf) plot_treeview = gtk.TreeView(plot_list) # Add plots plot_icon = fluents.icon_factory.get('line_plot') for plt, name, use in self._options['all_plots']: plot_list.append((name, use, plot_icon)) # Renderer for icon plot_icon = fluents.icon_factory.get('line_plot') icon_renderer = gtk.CellRendererPixbuf() icon_renderer.set_property('pixbuf', plot_icon) # Renderer for active toggle. active_renderer = gtk.CellRendererToggle() active_renderer.set_property('mode', gtk.CELL_RENDERER_MODE_ACTIVATABLE) active_renderer.connect('toggled', toggled, plot_list) active_column = gtk.TreeViewColumn('Use', active_renderer, active=1) # Renderer for plot title. title_renderer = gtk.CellRendererText() title_renderer.set_property('mode', gtk.CELL_RENDERER_MODE_EDITABLE) title_column = gtk.TreeViewColumn('Plot', title_renderer, text=0) title_column.pack_start(icon_renderer, expand=False) # Add columns to tree view. plot_treeview.append_column(active_column) plot_treeview.append_column(title_column) ## datasets dataset_list = gtk.ListStore(str, 'gboolean', gtk.gdk.Pixbuf) dataset_treeview = gtk.TreeView(dataset_list) # Add datasets data_icon = fluents.icon_factory.get('dataset') for dat, name, use in self._options['all_data']: dataset_list.append((name, use, data_icon)) # Renderer for icon icon_renderer = gtk.CellRendererPixbuf() icon_renderer.set_property('pixbuf', data_icon) # Renderer for active toggle. active_renderer = gtk.CellRendererToggle() active_renderer.set_property('mode', gtk.CELL_RENDERER_MODE_ACTIVATABLE) active_renderer.connect('toggled', toggled, dataset_list) active_column = gtk.TreeViewColumn('Use', active_renderer, active=1) # Renderer for dataset title. title_renderer = gtk.CellRendererText() title_renderer.set_property('mode', gtk.CELL_RENDERER_MODE_EDITABLE) title_column = gtk.TreeViewColumn('Dataset', title_renderer, text=0) title_column.pack_start(icon_renderer, expand=False) # Add columns to tree view. dataset_treeview.append_column(active_column) dataset_treeview.append_column(title_column) # add treeviews to output frame output_hbox.add(plot_treeview) output_hbox.add(dataset_treeview) # vbox for input/spacer/output vbox1 = gtk.VBox() vbox1.add(input_frame) vbox1.add(gtk.HSeparator()) vbox1.add(output_frame) # add vbox to notebook nb.insert_page(vbox1, gtk.Label("Input/Output"), 0) self.vbox.add(nb) #keep ref to liststores self.dataset_list = dataset_list self.plot_list = plot_list def run(self): self.vbox.show_all() return gtk.Dialog.run(self) def set_options(self, options): self._options = options def update_options(self, options): self._options.update(options) def set_output(self): # get toggled output data out_data = [item[0] for name, mark, ic in self.dataset_list for item in self._options['all_data'] if mark==True and name==item[1]] # get toggled plots out_plots = [item[0] for name, mark, ic in self.plot_list for item in self._options['all_plots'] if mark==True and name==item[1]] # update options self._options['out_data'] = out_data self._options['out_plots'] = out_plots def set_editable(self, editable): self._editable = True def set_data(self, data): self._data = data def get_data(self): return self._data def get_options(self): return self._options def add_page_from_glade(self, glade_file, widget_name, page_title): """Adds a new page(s) to the existing notebook. The input widget (added as a page in notebook) is defined in the glade file. input: glade_file -- path to glade file widget_name -- name of widget from glade file """ try: self.wTree = gtk.glade.XML(glade_file) except: logger.log('notice', 'Could not find glade file: %s' %glade_file) widget = self.wTree.get_widget(widget_name) win = widget.get_parent() win.hide() widget.unparent() self.nb.insert_page(widget, gtk.Label(page_title), -1) self.nb.set_current_page(0) def toggled(renderer, path, store): it = store.get_iter(path) old_value = store.get_value(it, 1) store.set_value(it, 1, not old_value) class WorkflowMenu (gtk.Menu): def __init__(self, workflow): gtk.Menu.__init__(self) self._workflow = workflow for stage in workflow.stages: self.append(self._create_stage_item(stage)) def _create_stage_item(self, stage): stage_menu_item = gtk.MenuItem(stage.name) stage_menu_item.show() stage_menu = gtk.Menu() stage_menu_item.set_submenu(stage_menu) for task in stage.tasks: stage_menu.append(self._create_task_item(task)) return stage_menu_item def _create_task_item(self, task): menuitem = gtk.MenuItem(task.name) menuitem.show() return menuitem class Options(): def __init__(self): pass