From a45743c31e2f9ecce5454dacb0037716c9a65948 Mon Sep 17 00:00:00 2001 From: einarr Date: Thu, 26 Jul 2007 12:35:59 +0000 Subject: [PATCH] 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. --- bin/fluents | 15 ++++--- fluents/__init__.py | 3 ++ fluents/dialogs.py | 11 ++--- fluents/fluents.py | 28 ++++++------ fluents/main.py | 90 +++++++++++++++++++++++++++++++++++++++ fluents/navigator.py | 30 ++++++------- fluents/project.py | 4 -- fluents/selections.py | 13 +++--- fluents/workflow.py | 31 +++++++------- workflows/geneontology.py | 19 ++++++--- workflows/gobrowser.py | 26 +++++++++-- workflows/smokers.py | 4 +- 12 files changed, 196 insertions(+), 78 deletions(-) create mode 100644 fluents/main.py diff --git a/bin/fluents b/bin/fluents index df82c13..00b359a 100755 --- a/bin/fluents +++ b/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() diff --git a/fluents/__init__.py b/fluents/__init__.py index e69de29..1cd1c90 100644 --- a/fluents/__init__.py +++ b/fluents/__init__.py @@ -0,0 +1,3 @@ + +import main + diff --git a/fluents/dialogs.py b/fluents/dialogs.py index 8250755..cfcf500 100644 --- a/fluents/dialogs.py +++ b/fluents/dialogs.py @@ -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() diff --git a/fluents/fluents.py b/fluents/fluents.py index 3bd2284..116dfdc 100644 --- a/fluents/fluents.py +++ b/fluents/fluents.py @@ -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) diff --git a/fluents/main.py b/fluents/main.py new file mode 100644 index 0000000..9ed81ef --- /dev/null +++ b/fluents/main.py @@ -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') + diff --git a/fluents/navigator.py b/fluents/navigator.py index 9f670be..1d02331 100644 --- a/fluents/navigator.py +++ b/fluents/navigator.py @@ -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) diff --git a/fluents/project.py b/fluents/project.py index 2fc8398..efd4e26 100644 --- a/fluents/project.py +++ b/fluents/project.py @@ -136,7 +136,3 @@ class Project: self.current_data = obj -## Singleton project. -## This is the current and only project in the application. -project = None - diff --git a/fluents/selections.py b/fluents/selections.py index 898394d..3ae7a27 100644 --- a/fluents/selections.py +++ b/fluents/selections.py @@ -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) diff --git a/fluents/workflow.py b/fluents/workflow.py index 747c675..d21fcbf 100644 --- a/fluents/workflow.py +++ b/fluents/workflow.py @@ -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) diff --git a/workflows/geneontology.py b/workflows/geneontology.py index 355016c..c6bb411 100644 --- a/workflows/geneontology.py +++ b/workflows/geneontology.py @@ -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) diff --git a/workflows/gobrowser.py b/workflows/gobrowser.py index 3f135a8..d3a2f0a 100644 --- a/workflows/gobrowser.py +++ b/workflows/gobrowser.py @@ -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 diff --git a/workflows/smokers.py b/workflows/smokers.py index 7844eac..01c3848 100644 --- a/workflows/smokers.py +++ b/workflows/smokers.py @@ -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')