Added main.py that now contains the One & Only Singleton instance of these classes:
- Navigator - Aplication - Workflow - Project - Options Corresponding changes have been added in lots of other files to account for this, but the access to these objects should now be a lot easier.
This commit is contained in:
parent
91abf12f51
commit
a45743c31e
15
bin/fluents
15
bin/fluents
@ -3,7 +3,7 @@
|
||||
from getopt import getopt
|
||||
import os
|
||||
import sys
|
||||
from fluents import fluents, project, workflow
|
||||
from fluents import fluents, project, workflow, main
|
||||
import workflows
|
||||
import cfgparse, optparse
|
||||
|
||||
@ -68,11 +68,16 @@ if __name__ == '__main__':
|
||||
if wf.ident == options.workflow:
|
||||
selected_wf = wf
|
||||
|
||||
app = fluents.FluentApp(selected_wf)
|
||||
app.options = options
|
||||
fluents.app = app
|
||||
|
||||
app.set_project(project.Project())
|
||||
main.set_workflow(selected_wf())
|
||||
main.set_options(options)
|
||||
app = fluents.FluentApp()
|
||||
|
||||
main.set_application(app)
|
||||
main.set_project(project.Project())
|
||||
|
||||
|
||||
app.set_project(main.project)
|
||||
app.show()
|
||||
gtk.main()
|
||||
|
||||
|
@ -0,0 +1,3 @@
|
||||
|
||||
import main
|
||||
|
@ -17,9 +17,8 @@ class CreateProjectDruid(gtk.Window):
|
||||
Workflow, and asks the user to select one of these. A new project of
|
||||
the selected class is added to the application."""
|
||||
|
||||
def __init__(self, app):
|
||||
def __init__(self):
|
||||
gtk.Window.__init__(self)
|
||||
self.app = app
|
||||
self.widget_tree = gtk.glade.XML(GLADEFILENAME, 'new_project_druid')
|
||||
self.workflows = self.make_workflow_list()
|
||||
self.selected = None
|
||||
@ -63,10 +62,12 @@ class CreateProjectDruid(gtk.Window):
|
||||
|
||||
def finish(self, *rest):
|
||||
tree, it = self['workflow_list'].get_selection().get_selected()
|
||||
wf = self.workflows.get_value(it, 1)
|
||||
wf_class = self.workflows.get_value(it, 1)
|
||||
proj = project.Project()
|
||||
self.app.set_workflow(wf(self.app))
|
||||
self.app.set_project(proj)
|
||||
main.set_workflow(wf_class())
|
||||
# self.app.set_workflow(wf(self.app))
|
||||
# self.app.set_project(proj)
|
||||
main.set_project(proj)
|
||||
self.hide()
|
||||
self.destroy()
|
||||
|
||||
|
@ -13,7 +13,7 @@ import gnome
|
||||
import gnome.ui
|
||||
import scipy
|
||||
import pango
|
||||
import project, workflow, dataset, logger, view, navigator, dialogs, selections
|
||||
import project, workflow, dataset, logger, view, navigator, dialogs, selections, main
|
||||
|
||||
|
||||
PROGRAM_NAME = 'fluents'
|
||||
@ -142,8 +142,8 @@ class ViewFrameToolButton (gtk.ToolItem):
|
||||
|
||||
class FluentApp:
|
||||
|
||||
def __init__(self, wf): # Application variables
|
||||
self.project = None
|
||||
def __init__(self): # Application variables
|
||||
# self.project = None
|
||||
self.current_data = None
|
||||
self._last_view = None
|
||||
self._plot_toolbar = None
|
||||
@ -151,7 +151,7 @@ class FluentApp:
|
||||
|
||||
gtk.glade.set_custom_handler(self.custom_object_factory)
|
||||
self.widget_tree = gtk.glade.XML(GLADEFILENAME, 'appwindow')
|
||||
self.workflow = wf(self)
|
||||
# self.workflow = wf
|
||||
|
||||
self.idlist_crt = selections.IdListController(self['identifier_list'])
|
||||
self.sellist_crt = selections.SelectionListController(self['selection_tree'],
|
||||
@ -164,11 +164,11 @@ class FluentApp:
|
||||
self['appwindow'].set_size_request(800, 600)
|
||||
|
||||
# Set up workflow
|
||||
self.wf_view = workflow.WorkflowView(self.workflow)
|
||||
self.wf_view = workflow.WorkflowView(main.workflow)
|
||||
self.wf_view.show()
|
||||
self['workflow_vbox'].pack_end(self.wf_view)
|
||||
|
||||
self._wf_menu = workflow.WorkflowMenu(self.workflow)
|
||||
self._wf_menu = workflow.WorkflowMenu(main.workflow)
|
||||
self._wf_menu.show()
|
||||
wf_menuitem = gtk.MenuItem('Fu_nctions')
|
||||
wf_menuitem.set_submenu(self._wf_menu)
|
||||
@ -208,16 +208,16 @@ class FluentApp:
|
||||
|
||||
def set_project(self, proj):
|
||||
logger.log('notice', 'Creating a new project')
|
||||
self.project = proj
|
||||
project.project = proj
|
||||
self.workflow.add_project(proj)
|
||||
# self.project = proj
|
||||
# project.project = proj
|
||||
# main.workflow.add_project(proj)
|
||||
self.navigator_view.add_project(proj)
|
||||
self.dimlist_crt.set_project(proj)
|
||||
self.sellist_crt.set_project(proj)
|
||||
|
||||
def set_workflow(self, workflow):
|
||||
self.workflow = workflow
|
||||
self.wf_view.set_workflow(self.workflow)
|
||||
main.workflow = workflow
|
||||
self.wf_view.set_workflow(main.workflow)
|
||||
|
||||
def show(self):
|
||||
self.init_gui()
|
||||
@ -226,7 +226,7 @@ class FluentApp:
|
||||
"""Sets the plot in the currently active ViewFrame. If the plot is
|
||||
already shown in another ViewFrame it will be moved from there."""
|
||||
# Set current selection in the plot before showing it.
|
||||
plot.selection_changed(None, self.project.get_selection())
|
||||
plot.selection_changed(None, main.project.get_selection())
|
||||
|
||||
self['main_view'].insert_view(plot)
|
||||
self._update_toolbar(plot)
|
||||
@ -287,7 +287,7 @@ class FluentApp:
|
||||
return self.main_view
|
||||
|
||||
def create_navigator_view(self, str1, str2, int1, int2):
|
||||
self.navigator_view = navigator.NavigatorView(None, self)
|
||||
self.navigator_view = navigator.NavigatorView()
|
||||
self.navigator_view.show()
|
||||
return self.navigator_view
|
||||
|
||||
@ -336,7 +336,7 @@ class FluentApp:
|
||||
|
||||
def on_workflow_refresh_clicked(self, *ignored):
|
||||
try:
|
||||
reload(sys.modules[self.workflow.__class__.__module__])
|
||||
reload(sys.modules[main.workflow.__class__.__module__])
|
||||
except Exception, e:
|
||||
logger.log('warning', 'Cannot reload workflow')
|
||||
logger.log('warning', e)
|
||||
|
90
fluents/main.py
Normal file
90
fluents/main.py
Normal file
@ -0,0 +1,90 @@
|
||||
|
||||
import sys
|
||||
|
||||
#: Dictionary of observers
|
||||
_observers = {}
|
||||
|
||||
#: The current Navigator object.
|
||||
navigator = None
|
||||
|
||||
#: The current application
|
||||
application = None
|
||||
|
||||
#: The current project
|
||||
project = None
|
||||
|
||||
#: The current workflow
|
||||
workflow = None
|
||||
|
||||
#: A cfgparse/optparse options object.
|
||||
options = None
|
||||
|
||||
def notify_observers(name):
|
||||
call = "%s_changed" % name
|
||||
for s in _observers.get(name, []):
|
||||
getattr(s, call)(getattr(sys.modules[__name__], name))
|
||||
|
||||
def _add_observer(name, observer):
|
||||
"""Adds observer as an observer of the named object."""
|
||||
if not _observers.has_key(name):
|
||||
_observers[name] = []
|
||||
_observers[name].append(observer)
|
||||
|
||||
def _remove_observer(name, observer):
|
||||
"""Removes observer as an observer of the named object."""
|
||||
if not _observers.has_key(name):
|
||||
return
|
||||
_observers.remove(observer)
|
||||
|
||||
def add_navigator_observer(observer):
|
||||
_add_observer('navigator', observer)
|
||||
|
||||
def add_project_observer(observer):
|
||||
_add_observer('project', observer)
|
||||
|
||||
def add_workflow_observer(observer):
|
||||
_add_observer('workflow', observer)
|
||||
|
||||
def add_application_observer(observer):
|
||||
_add_observer('application', observer)
|
||||
|
||||
def remove_navigator_observer(observer):
|
||||
_remove_observer('navigator', observer)
|
||||
|
||||
def remove_project_observer(observer):
|
||||
_remove_observer('project', observer)
|
||||
|
||||
def remove_workflow_observer(observer):
|
||||
_remove_observer('workflow', observer)
|
||||
|
||||
def remove_application_observer(observer):
|
||||
_remove_observer('application', observer)
|
||||
|
||||
def remove_options_observer(observer):
|
||||
_remove_observer('options', observer)
|
||||
|
||||
def set_navigator(nav):
|
||||
global navigator
|
||||
navigator = nav
|
||||
notify_observers('navigator')
|
||||
|
||||
def set_application(app):
|
||||
global application
|
||||
application = app
|
||||
notify_observers('application')
|
||||
|
||||
def set_project(p):
|
||||
global project
|
||||
project = p
|
||||
notify_observers('project')
|
||||
|
||||
def set_workflow(wf):
|
||||
global workflow
|
||||
workflow = wf
|
||||
notify_observers('workflow')
|
||||
|
||||
def set_options(opt):
|
||||
global options
|
||||
options = opt
|
||||
notify_observers('options')
|
||||
|
@ -4,14 +4,14 @@ import gobject
|
||||
import plots
|
||||
import time
|
||||
import fluents
|
||||
import dataset, logger, plots, project, workflow
|
||||
import dataset, logger, plots, project, workflow, main
|
||||
|
||||
class NavigatorView (gtk.TreeView):
|
||||
def __init__(self, project, app):
|
||||
self.project = project
|
||||
self.app = app
|
||||
if project:
|
||||
self.data_tree = project.data_tree
|
||||
def __init__(self):
|
||||
# self.project = project
|
||||
# self.app = app
|
||||
if main.project:
|
||||
self.data_tree = main.project.data_tree
|
||||
else:
|
||||
self.data_tree = None
|
||||
|
||||
@ -65,7 +65,7 @@ class NavigatorView (gtk.TreeView):
|
||||
self.data_tree.drag_data_get(paths[0], selection)
|
||||
|
||||
def add_project(self, project):
|
||||
self.project = project
|
||||
# self.project = project
|
||||
self.data_tree = project.data_tree
|
||||
self.set_model(project.data_tree)
|
||||
self.data_tree.connect('row-changed',self.row_changed_handler)
|
||||
@ -101,10 +101,10 @@ class NavigatorView (gtk.TreeView):
|
||||
|
||||
if objs and isinstance(objs[0], dataset.Dataset):
|
||||
logger.log('debug', 'Selecting dataset')
|
||||
self.project.set_current_data(objs)
|
||||
main.project.set_current_data(objs)
|
||||
else:
|
||||
logger.log('debug', 'Deselecting dataset')
|
||||
self.project.set_current_data([])
|
||||
main.project.set_current_data([])
|
||||
|
||||
|
||||
# TreeView changed. Set correct focus and colours
|
||||
@ -142,7 +142,7 @@ class NavigatorView (gtk.TreeView):
|
||||
|
||||
if isinstance(obj, plots.Plot):
|
||||
logger.log('debug', 'Activating plot')
|
||||
self.app.change_plot(obj)
|
||||
main.application.change_plot(obj)
|
||||
elif isinstance(obj, dataset.Dataset):
|
||||
self.display_data_info(obj)
|
||||
elif obj == None:
|
||||
@ -153,7 +153,7 @@ class NavigatorView (gtk.TreeView):
|
||||
if isinstance(child, plots.Plot):
|
||||
children.append(child)
|
||||
i = self.data_tree.iter_next(i)
|
||||
self.app.change_plots(children)
|
||||
main.application.change_plots(children)
|
||||
else:
|
||||
t = type(obj)
|
||||
logger.log('debug', 'Activated datatype was %s. Don\'t know what to do.' % t)
|
||||
@ -248,9 +248,8 @@ class NavigatorMenu(gtk.Menu):
|
||||
else:
|
||||
icon = fluents.icon_factory.get("dataset")
|
||||
|
||||
project = navigator.project
|
||||
project.add_dataset(ds)
|
||||
project.data_tree_insert(None, ds.get_name(), ds, None, "black", icon)
|
||||
main.project.add_dataset(ds)
|
||||
main.project.data_tree_insert(None, ds.get_name(), ds, None, "black", icon)
|
||||
else:
|
||||
print "unknown; ", retval
|
||||
dialog.destroy()
|
||||
@ -273,10 +272,9 @@ class NavigatorMenu(gtk.Menu):
|
||||
dialog.destroy()
|
||||
|
||||
def on_plot_image(self, item, navigator):
|
||||
project = navigator.project
|
||||
plot = plots.ImagePlot(self.dataset, name='Image Plot')
|
||||
icon = fluents.icon_factory.get("line_plot")
|
||||
project.data_tree_insert(self.tree_iter, 'Image Plot', plot, None, "black", icon)
|
||||
main.project.data_tree_insert(self.tree_iter, 'Image Plot', plot, None, "black", icon)
|
||||
# fixme: image plot selections are not well defined
|
||||
#plot.set_selection_listener(project.set_selection)
|
||||
#project._selection_observers.append(plot)
|
||||
|
@ -136,7 +136,3 @@ class Project:
|
||||
self.current_data = obj
|
||||
|
||||
|
||||
## Singleton project.
|
||||
## This is the current and only project in the application.
|
||||
project = None
|
||||
|
||||
|
@ -6,7 +6,7 @@ import gnome
|
||||
import gnome.ui
|
||||
import gobject
|
||||
|
||||
import logger, dataset
|
||||
import logger, dataset, main
|
||||
import annotations
|
||||
from lib import hypergeom
|
||||
|
||||
@ -243,8 +243,7 @@ class SelectionListController:
|
||||
|
||||
def set_project(self, project):
|
||||
"""Dependency injection."""
|
||||
self.project = project
|
||||
project.add_selection_observer(self)
|
||||
main.project.add_selection_observer(self)
|
||||
|
||||
def set_dimlist_controller(self, dimlist_controller):
|
||||
"""Dependency injection of the dimension list controller."""
|
||||
@ -292,7 +291,7 @@ class SelectionListController:
|
||||
di = self._get_dataset_iter(dataset)
|
||||
if not di:
|
||||
n_tot = dataset.shape[0]
|
||||
selection = self.project.get_selection().get(dim_name)
|
||||
selection = main.project.get_selection().get(dim_name)
|
||||
ds_idents = dataset.get_identifiers(dim_name)
|
||||
n_cs = len(selection.intersection(ds_idents))
|
||||
values = (dataset.get_name(), dataset, dim_name, n_cs, n_tot, 2)
|
||||
@ -363,7 +362,7 @@ class SelectionListController:
|
||||
"""
|
||||
dim_name = dataset.get_dim_name(0)
|
||||
sel_store = self._sel_stores[dim_name]
|
||||
selection_obj = self.project.get_selection()
|
||||
selection_obj = main.project.get_selection()
|
||||
current_selection = selection_obj.get(dim_name)
|
||||
if current_selection==None: return
|
||||
|
||||
@ -427,7 +426,7 @@ class SelectionListController:
|
||||
else:
|
||||
seltree.expand_row(path, True)
|
||||
elif isinstance(obj, dataset.Selection):
|
||||
self.project.set_selection(self._dimension,
|
||||
main.project.set_selection(self._dimension,
|
||||
obj[self._dimension])
|
||||
|
||||
def _on_button_pressed(self, widget, event):
|
||||
@ -486,7 +485,7 @@ class DimListController:
|
||||
##
|
||||
def set_project(self, project):
|
||||
"""Dependency injection."""
|
||||
self.project = project
|
||||
# self.project = project
|
||||
self.dim_names = project.dim_names
|
||||
self.update_dims()
|
||||
project.add_dataset_observer(self)
|
||||
|
@ -4,6 +4,7 @@ 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"""
|
||||
@ -58,20 +59,20 @@ class Workflow:
|
||||
ident = None
|
||||
description = "Workflow Description"
|
||||
|
||||
def __init__(self, app):
|
||||
def __init__(self):
|
||||
print "Setting stages"
|
||||
self.stages = []
|
||||
self.stages_by_id = {}
|
||||
self.app = app
|
||||
|
||||
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(self.app.options.datadir, self.ident, filename)
|
||||
print os.path.join(main.options.datadir, self.ident, filename)
|
||||
if self.ident == None:
|
||||
return None
|
||||
fn = os.path.join(self.app.options.datadir, self.ident, filename)
|
||||
fn = os.path.join(main.options.datadir, self.ident, filename)
|
||||
if os.path.isfile(fn):
|
||||
return fn
|
||||
return None
|
||||
@ -87,18 +88,19 @@ class Workflow:
|
||||
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
|
||||
# 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)
|
||||
def __init__(self):
|
||||
print "initing empty workflow"
|
||||
Workflow.__init__(self)
|
||||
|
||||
|
||||
class Stage:
|
||||
@ -188,8 +190,7 @@ class WorkflowView (gtk.VBox):
|
||||
|
||||
def run_function(self, function):
|
||||
logger.log('debug', 'Starting function: %s' % function.name)
|
||||
project = self.workflow.app.project
|
||||
parent_data = project.current_data
|
||||
parent_data = main.project.current_data
|
||||
|
||||
validation = function.validate_input()
|
||||
|
||||
@ -226,12 +227,12 @@ class WorkflowView (gtk.VBox):
|
||||
if pass_selection:
|
||||
# if the function has a 'selection' argument, we pass in
|
||||
# the selection
|
||||
new_data = function.run(selection=project.get_selection(), *data)
|
||||
new_data = function.run(selection=main.project.get_selection(), *data)
|
||||
else:
|
||||
new_data = function.run(*data)
|
||||
|
||||
if new_data != None:
|
||||
project.add_data(parent_data, new_data, function.name)
|
||||
main.project.add_data(parent_data, new_data, function.name)
|
||||
|
||||
logger.log('debug', 'Function ended: %s' % function.name)
|
||||
|
||||
|
@ -164,17 +164,12 @@ def read_gene_ontology(fd):
|
||||
section = s
|
||||
if s == 'Term':
|
||||
term = GOTerm()
|
||||
# print "[Term]"
|
||||
else:
|
||||
term = None
|
||||
#print "ignoring: %s" %s
|
||||
print "ignoring: %s" %s
|
||||
else:
|
||||
if term:
|
||||
_add_term_attribute(term, k, v, c)
|
||||
# print " %s: %s" % (k, v)
|
||||
# else:
|
||||
# print "no term: ignoring: %s" %line
|
||||
# print '.',
|
||||
line = fd.readline()
|
||||
|
||||
if term:
|
||||
@ -182,6 +177,18 @@ def read_gene_ontology(fd):
|
||||
|
||||
return go
|
||||
|
||||
|
||||
def pickle_gene_ontology(go, fn):
|
||||
fd = open(fn, 'wb')
|
||||
pickle.dump(go, fd)
|
||||
fd.close()
|
||||
|
||||
def load_pickled_ontology(fn):
|
||||
fd = open(fn, 'rb')
|
||||
go = pickle.load(fd)
|
||||
fd.close()
|
||||
return go
|
||||
|
||||
def read_default_go():
|
||||
f = open("/usr/share/gene-ontology/gene_ontology.obo")
|
||||
go = read_gene_ontology(f)
|
||||
|
@ -37,7 +37,7 @@ class GoTermView (gtk.Frame):
|
||||
|
||||
def __init__(self):
|
||||
gtk.Frame.__init__(self)
|
||||
tab = gtk.Table(2, 2, False)
|
||||
tab = gtk.Table(2, 3, False)
|
||||
self._table = tab
|
||||
|
||||
self._name = gtk.Label('')
|
||||
@ -48,6 +48,11 @@ class GoTermView (gtk.Frame):
|
||||
tab.attach(name_label, 0, 1, 0, 1, gtk.FILL, gtk.FILL, 5, 5)
|
||||
tab.attach(self._name, 1, 2, 0, 1, gtk.FILL|gtk.EXPAND, gtk.FILL, 5, 5)
|
||||
|
||||
self._isa_parents = gtk.HBox()
|
||||
isa_parents_label = gtk.Label('Is a:')
|
||||
tab.attach(isa_parents_label, 0, 1, 1, 2, gtk.FILL, gtk.FILL, 5, 5)
|
||||
tab.attach(self._isa_parents, 1, 2, 1, 2, gtk.FILL, gtk.FILL, 5, 5)
|
||||
|
||||
self._def = gtk.TextBuffer()
|
||||
textview = gtk.TextView(self._def)
|
||||
textview.set_wrap_mode(gtk.WRAP_WORD)
|
||||
@ -55,9 +60,10 @@ class GoTermView (gtk.Frame):
|
||||
scrolled_window.add(textview)
|
||||
def_label = gtk.Label('Def:')
|
||||
def_label.set_alignment(0.0, 0.0)
|
||||
tab.attach(def_label, 0, 1, 1, 2, gtk.FILL, gtk.FILL, 5, 5)
|
||||
tab.attach(scrolled_window, 1, 2, 1, 2, gtk.FILL|gtk.EXPAND, gtk.FILL|gtk.EXPAND, 5, 5)
|
||||
tab.attach(def_label, 0, 1, 2, 3, gtk.FILL, gtk.FILL, 5, 5)
|
||||
tab.attach(scrolled_window, 1, 2, 2, 3, gtk.FILL|gtk.EXPAND, gtk.FILL|gtk.EXPAND, 5, 5)
|
||||
|
||||
self._tab = tab
|
||||
self.add(tab)
|
||||
self.set_go_term(None)
|
||||
|
||||
@ -66,16 +72,28 @@ class GoTermView (gtk.Frame):
|
||||
self.set_label(term['id'])
|
||||
self._name.set_text(term['name'])
|
||||
self._def.set_text(term['def'])
|
||||
self._tab.remove(self._isa_parents)
|
||||
self._isa_parents = gtk.HBox()
|
||||
for p in term['is_a']:
|
||||
btn = gtk.Button(p)
|
||||
btn.show()
|
||||
self._isa_parents.add(btn)
|
||||
self._isa_parents.show()
|
||||
self._tab.attach(self._isa_parents, 1, 2, 1, 2, gtk.FILL, gtk.FILL, 5, 5)
|
||||
else:
|
||||
self.set_label('GO Term')
|
||||
self._name.set_text('')
|
||||
self._def.set_text('')
|
||||
|
||||
self._tab.remove(self._isa_parents)
|
||||
self._isa_parents = gtk.HBox()
|
||||
self._tab.attach(self._isa_parents, 1, 2, 1, 2, gtk.FILL, gtk.FILL, 5, 5)
|
||||
|
||||
|
||||
class GeneOntologyTree (gtk.HPaned):
|
||||
|
||||
def __init__(self, network):
|
||||
gtk.HPaned.__init__(self)
|
||||
self.set_position(400)
|
||||
|
||||
treemodel = geneontology.get_go_treestore(network)
|
||||
self._treemodel = treemodel
|
||||
|
@ -13,8 +13,8 @@ class SmallTestWorkflow(workflow.Workflow):
|
||||
ident = 'smokers'
|
||||
description = 'A small test workflow for gene expression analysis.'
|
||||
|
||||
def __init__(self, app):
|
||||
workflow.Workflow.__init__(self, app)
|
||||
def __init__(self):
|
||||
workflow.Workflow.__init__(self)
|
||||
|
||||
# DATA IMPORT
|
||||
load = workflow.Stage('load', 'Data')
|
||||
|
Reference in New Issue
Block a user