Projects/laydi
Archived
7
0
This repository has been archived on 2024-07-04. You can view files and clone it, but cannot push or open issues or pull requests.

216 lines
6.2 KiB
Python

import gtk
import sys
import os
import inspect
from system import logger
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 ListStore 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, app):
self.stages = []
self.stages_by_id = {}
self.app = app
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 fun in stage.functions:
print ' %s' % fun.name
def add_project(self,project):
if project == None:
logger.log('notice','Proejct is empty')
logger.log('notice','Project added in : %s' %self.name)
self.project = project
class EmptyWorkflow(Workflow):
name = 'Empty Workflow'
def __init__(self, app):
Workflow.__init__(self, None)
class Stage:
"""A stage is a part of the data analysis process.
Each stage contains a set of functions 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 function.
"""
def __init__(self, id, name):
self.id = id
self.name = name
self.functions = []
self.functions_by_id = {}
def add_function(self, fun):
self.functions.append(fun)
self.functions_by_id[fun.id] = fun
class Function:
"""A Function object encapsulates a function on a data set.
Each Function instance encapsulates some function that can be applied
to one or more types of data.
"""
def __init__(self, id, name):
self.id = id
self.name = name
# ,ust return a Validation object
def validate_input(input):
return Validation(True,"Validation Not Implemented")
def run(self):
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_box = gtk.VBox()
btn_box.show()
exp.add(btn_box)
# Add functions in each stage
for fun in stage.functions:
btn = gtk.Button(fun.name)
btn.connect('clicked',
lambda button, f=fun : self.run_function(f))
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_function(self, function):
logger.log('debug', 'Starting function: %s' % function.name)
project = self.workflow.app.project
parent_data = project.current_data
validation = function.validate_input()
if not validation.succeeded:
logger.log('warning','Invalid Inputdata: ' + str(reason))
return
args, varargs, varkw, defaults = inspect.getargspec(function.run)
# first argument is 'self' and second should be the selection
# and we don't care about those...
args.remove('self')
if "selection" in args:
pass_selection = True
args.remove('selection')
else:
pass_selection = False
if varargs and len(parent_data) < len(args):
logger.log('warning', "Function requires minimum %d datasets selected." % len(args))
return
elif not varargs and args and len(args) != len(parent_data):
# functions requiring datasets have to have the right number
logger.log('warning', "Function requires %d datasets, but only %d selected." % (len(args), len(parent_data)))
return
if not args:
# we allow functions requiring no data to be run even if a
# dataset is is selected
data = []
else:
data = parent_data
if pass_selection:
# if the function has a 'selection' argument, we pass in
# the selection
new_data = function.run(selection=project.get_selection(), *data)
else:
new_data = function.run(*data)
if new_data != None:
project.add_data(parent_data, new_data, function.name)
logger.log('debug', 'Function ended: %s' % function.name)