def add_to_persistent_pipeline(self, pipeline): """add_to_persistent_pipeline(pipeline): (module_id_map, connection_id_map, modules_added) Adds a pipeline to the persistent pipeline of the cached interpreter and adds current logging object to each existing module. Returns four things: two dictionaries describing the mapping of ids from the passed pipeline to the persistent one (the first one has the module id mapping, the second one has the connection id mapping), a set of all module ids added to the persistent pipeline, and a set of all connection ids added to the persistent pipeline.""" module_id_map = Bidict() connection_id_map = Bidict() modules_added = set() connections_added = set() pipeline.refresh_signatures() # we must traverse vertices in topological sort order verts = pipeline.graph.vertices_topological_sort() for new_module_id in verts: new_sig = pipeline.subpipeline_signature(new_module_id) if not self._persistent_pipeline.has_subpipeline_signature( new_sig): # Must add module to persistent pipeline persistent_module = copy.copy(pipeline.modules[new_module_id]) persistent_id = self._persistent_pipeline.fresh_module_id() persistent_module.id = persistent_id self._persistent_pipeline.add_module(persistent_module) self._persistent_pipeline.modules[persistent_id]._signature = \ base64.b16encode(new_sig).lower() module_id_map[new_module_id] = persistent_id modules_added.add(new_module_id) else: i = self._persistent_pipeline \ .subpipeline_id_from_signature(new_sig) module_id_map[new_module_id] = i for connection in pipeline.connections.itervalues(): new_sig = pipeline.connection_signature(connection.id) if not self._persistent_pipeline.has_connection_signature(new_sig): # Must add connection to persistent pipeline persistent_connection = copy.copy(connection) persistent_id = self._persistent_pipeline.fresh_connection_id() persistent_connection.id = persistent_id persistent_connection.sourceId = module_id_map[ connection.sourceId] persistent_connection.destinationId = module_id_map[ connection.destinationId] self._persistent_pipeline.add_connection(persistent_connection) connection_id_map[connection.id] = persistent_id connections_added.add(connection.id) else: i = self._persistent_pipeline \ .connection_id_from_signature(new_sig) connection_id_map[connection.id] = i # update persistent signatures self._persistent_pipeline.compute_signatures() return (module_id_map, connection_id_map, modules_added, connections_added)
def __init__(self, controller, panel, parent=None): """ QAliasList(parent: QWidget) -> QAliasTable """ QtGui.QTreeWidget.__init__(self, parent) self.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) self.setRootIsDecorated(False) self.panel = panel self.aliases = Bidict() self.alias_widgets = {} self.controller = controller self.header().setStretchLastSection(True) self.setHeaderLabels(["Position", "Name", "Type"]) self.itemSelectionChanged.connect(self.setPreviousSelected) self.connect(self, QtCore.SIGNAL("currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)"), self.currentAliasChanged) self.previousSelected = -1
def build_widget(self): layout = QtGui.QVBoxLayout() layout.setMargin(4) layout.setSpacing(2) self.searchBox = QSearchBox(True, False, self) layout.addWidget(self.searchBox) options_layout = QtGui.QHBoxLayout() options_layout.setSpacing(5) options_layout.setAlignment(QtCore.Qt.AlignLeft) options_layout.addWidget(QtGui.QLabel("Search:")) searchAll = QtGui.QRadioButton("Open Vistrails") searchCurrent = QtGui.QRadioButton("Current Vistrail") searchWorkflow = QtGui.QRadioButton("Current Workflow") useRegex = QtGui.QCheckBox("Regular expression") self.level_group = QtGui.QButtonGroup() self.level_group.addButton(searchAll) self.level_group.addButton(searchCurrent) self.level_group.addButton(searchWorkflow) self.level_map = \ Bidict([(QueryController.LEVEL_ALL, searchAll), (QueryController.LEVEL_VISTRAIL, searchCurrent), (QueryController.LEVEL_WORKFLOW, searchWorkflow)]) options_layout.addWidget(searchAll) options_layout.addWidget(searchCurrent) options_layout.addWidget(searchWorkflow) options_layout.addWidget(useRegex) searchCurrent.setChecked(True) self.editButton = QtGui.QPushButton("Edit") self.editButton.setEnabled(False) self.backButton = QtGui.QPushButton("Back to Search") self.backButton.setEnabled(False) options_layout.addStretch(1) options_layout.addWidget(self.editButton, 0, QtCore.Qt.AlignRight) options_layout.addWidget(self.backButton, 0, QtCore.Qt.AlignRight) layout.addLayout(options_layout) self.setLayout(layout) self.connect(self.searchBox, QtCore.SIGNAL('resetSearch()'), self.resetSearch) self.connect(self.searchBox, QtCore.SIGNAL('executeSearch(QString)'), self.executeSearch) self.connect(self.searchBox, QtCore.SIGNAL('refineMode(bool)'), self.refineMode) self.connect(self.backButton, QtCore.SIGNAL('clicked()'), self.backToSearch) self.connect(self.editButton, QtCore.SIGNAL('clicked()'), self.doEdit) self.connect(self.level_group, QtCore.SIGNAL('buttonClicked(QAbstractButton*)'), self.levelChanged) self.connect(useRegex, QtCore.SIGNAL('stateChanged(int)'), self.useRegexChanged)
class QQueryView(QtGui.QWidget, BaseView): VISUAL_SEARCH_VIEW = 0 GLOBAL_RESULT_VIEW = 1 VERSION_RESULT_VIEW = 2 WORKFLOW_RESULT_VIEW = 3 RESULT_LEVEL_MAP = \ Bidict([(QueryController.LEVEL_ALL, GLOBAL_RESULT_VIEW), (QueryController.LEVEL_VISTRAIL, VERSION_RESULT_VIEW), (QueryController.LEVEL_WORKFLOW, WORKFLOW_RESULT_VIEW)]) def __init__(self, parent=None): QtGui.QWidget.__init__(self, parent) BaseView.__init__(self) self.build_widget() self.set_title("Search") def set_controller(self, controller=None): if self.controller: self.disconnect(self.controller, QtCore.SIGNAL('stateChanged'), self.update_controller) self.controller = controller if controller: self.connect(self.controller, QtCore.SIGNAL('stateChanged'), self.update_controller) self.vt_controller.vistrail_view = self.version_result_view self.vt_controller.current_pipeline_view = \ self.workflow_result_view # self.vt_controller.vistrail_view.set_controller(self.vt_controller) # FIXME Need to figure out how to deal with this !!! self.vt_controller.set_vistrail(controller.vistrail, None, set_log_on_vt=False) hide_upgrades = not getattr(get_vistrails_configuration(), 'hideUpgrades', True) self.vt_controller.change_selected_version(controller.current_version, hide_upgrades, hide_upgrades) self.version_result_view.set_controller(self.vt_controller) self.workflow_result_view.set_controller(self.vt_controller) self.query_controller.set_vistrail_controller(controller) def update_controller(self): # FIXME Need to figure out how to deal with this !!! self.vt_controller.set_vistrail(self.controller.vistrail, None, set_log_on_vt=False) hide_upgrades = getattr(get_vistrails_configuration(), 'hideUpgrades', True) self.vt_controller.change_selected_version( self.controller.current_version, hide_upgrades, hide_upgrades) def build_widget(self): layout = QtGui.QVBoxLayout() layout.setMargin(0) layout.setSpacing(0) self.query_controller = QueryController(self) self.vt_controller = VistrailController(auto_save=False) self.p_controller = VistrailController(Vistrail(), auto_save=False) self.connect(self.p_controller, QtCore.SIGNAL('vistrailChanged()'), self.vistrailChanged) self.query_box = QQueryBox() self.query_box.set_controller(self.query_controller) layout.addWidget(self.query_box) self.stacked_widget = QtGui.QStackedWidget() self.pipeline_view = QQueryPipelineView() self.p_controller.current_pipeline_view = self.pipeline_view self.pipeline_view.set_controller(self.p_controller) self.pipeline_view.set_query_controller(self.query_controller) QQueryView.VISUAL_SEARCH_VIEW = \ self.stacked_widget.addWidget(self.pipeline_view) self.global_result_view = QQueryResultGlobalView() QQueryView.GLOBAL_RESULT_VIEW = \ self.stacked_widget.addWidget(self.global_result_view) self.version_result_view = QQueryResultVersionView() self.connect(self.version_result_view.scene(), QtCore.SIGNAL('versionSelected(int,bool,bool,bool,bool)'), self.result_version_selected) # self.version_result_view.set_controller(self.vt_controller) QQueryView.VERSION_RESULT_VIEW = \ self.stacked_widget.addWidget(self.version_result_view) self.workflow_result_view = QQueryResultWorkflowView() # self.workflow_result_view.set_controller(self.vt_controller) QQueryView.WORKFLOW_RESULT_VIEW = \ self.stacked_widget.addWidget(self.workflow_result_view) self.stacked_widget.setCurrentWidget(self.pipeline_view) layout.addWidget(self.stacked_widget) self.setLayout(layout) self.current_display = QQueryView.VISUAL_SEARCH_VIEW self.current_result_view = QQueryView.VERSION_RESULT_VIEW def set_default_layout(self): from vistrails.gui.module_palette import QModulePalette from vistrails.gui.module_info import QModuleInfo self.set_palette_layout({ QtCore.Qt.LeftDockWidgetArea: QModulePalette, QtCore.Qt.RightDockWidgetArea: QModuleInfo, }) def set_action_links(self): self.action_links = \ { 'execute': ('query_pipeline_changed', self.set_execute_action) } # also add other notification here... from vistrails.gui.vistrails_window import _app _app.register_notification('query_pipeline_changed', self.set_reset_button) def set_reset_button(self, pipeline): self.query_box.setManualResetEnabled(self.pipeline_non_empty(pipeline)) def set_result_level(self, level): view_idx = QQueryView.RESULT_LEVEL_MAP[level] if self.current_display != QQueryView.VISUAL_SEARCH_VIEW: self.set_display_view(view_idx) self.current_result_view = view_idx self.query_controller.update_results() def set_to_search_mode(self): self.set_display_view(QQueryView.VISUAL_SEARCH_VIEW) self.query_box.backButton.setEnabled(False) self.query_box.editButton.setEnabled(False) self.set_reset_button(self.p_controller.current_pipeline) from vistrails.gui.vistrails_window import _app _app.notify('query_pipeline_changed', self.p_controller.current_pipeline) def set_to_result_mode(self): self.set_display_view(self.current_result_view) self.query_box.backButton.setEnabled(True) if self.query_controller.level >= QueryController.LEVEL_VISTRAIL: self.query_box.editButton.setEnabled(True) self.query_box.setManualResetEnabled(True) from vistrails.gui.vistrails_window import _app _app.notify('query_pipeline_changed', self.p_controller.current_pipeline) def set_display_view(self, view_type): self.current_display = view_type self.stacked_widget.setCurrentIndex(view_type) def get_current_view(self): return self.stacked_widget.currentWidget() def set_action_defaults(self): self.action_defaults = \ { 'execute': [('setEnabled', True, self.set_execute_action), ('setIcon', False, CurrentTheme.VISUAL_QUERY_ICON), ('setToolTip', False, 'Execute a visual query')], 'publishWeb': [('setEnabled', False, False)], 'publishPaper': [('setEnabled', False, False)], } def set_execute_action(self, pipeline=None): if not self.vt_controller: return False if pipeline is None: pipeline = self.p_controller.current_pipeline if self.current_display == QQueryView.VISUAL_SEARCH_VIEW: return self.pipeline_non_empty(pipeline) return False def pipeline_non_empty(self, pipeline): return pipeline is not None and len(pipeline.modules) > 0 def vistrailChanged(self): from vistrails.gui.vistrails_window import _app self.p_controller.current_pipeline.ensure_connection_specs() _app.notify('query_pipeline_changed', self.p_controller.current_pipeline) def query_changed(self, query=None): if query is None: self.query_controller.reset_search() # FIXME add support for changing the query to something specific # DAK: removed this call as the query view maintains its own # "current version" # def version_changed(self, version_id): # self.vt_controller.change_selected_version(version_id) # self.version_result_view.select_current_version() # self.query_controller.update_results() def result_version_selected(self, version_id, by_click, do_validate=True, from_root=False, double_click=False): if by_click: hide_upgrades = getattr(get_vistrails_configuration(), 'hideUpgrades', True) self.query_controller.search.setCurrentController( self.vt_controller) self.vt_controller.change_selected_version(version_id, hide_upgrades, hide_upgrades, from_root) if double_click: self.query_controller.set_level(QueryController.LEVEL_WORKFLOW) self.query_controller.show_workflow_matches()
def get_vertex_map(g): return Bidict([(v, k) for (k, v) in enumerate(g.iter_vertices())])
def get_edge_map(g): itor = enumerate(imap(lambda x: x[2], g.iter_all_edges())) return Bidict([(v, k) for (k, v) in itor])
class QAliasList(QtGui.QTreeWidget): """ QAliasList just inherits from QListView to have a customized list and items """ #signals aliasUpdated = pyqtSignal(Alias) aliasRemoved = pyqtSignal(str) highlightModule = pyqtSignal(int) def __init__(self, controller, panel, parent=None): """ QAliasList(parent: QWidget) -> QAliasTable """ QtGui.QTreeWidget.__init__(self, parent) self.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) self.setRootIsDecorated(False) self.panel = panel self.aliases = Bidict() self.alias_widgets = {} self.controller = controller self.header().setStretchLastSection(True) self.setHeaderLabels(["Position", "Name", "Type"]) self.itemSelectionChanged.connect(self.setPreviousSelected) self.connect( self, QtCore.SIGNAL( "currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)"), self.currentAliasChanged) self.previousSelected = -1 @pyqtSlot() def setPreviousSelected(self): if len(self.selectedItems()) == 1: item = self.selectedItems()[0] self.previousSelected = self.indexOfTopLevelItem(item) else: self.previousSelected = -1 def processCellChanges(self, row, col): """ processCellChanges(row: int, col: int) -> None Event handler for capturing when the contents in a cell changes """ item = self.item(row, col) if col == 0: old_alias = item.alias.alias new_alias = str(item.text()) if new_alias in self.aliases.keys(): QtGui.QMessageBox.warning( self, "VisMashup", """Label name %s already exists. Please type a different name. """ % new_alias) item.setText(old_alias) return elif new_alias == '': del self.aliases[old_alias] wdgt = self.cellWidget(row, 1) del self.alias_widgets[wdgt] item.alias.alias = '' self.removeRow(row) wdgt.deleteLater() self.updateRowNumbers() else: self.aliases[new_alias] = self.aliases[old_alias] del self.aliases[old_alias] item.alias.alias = new_alias elif col == 1: wdgt = self.cellWidget(row, col) if wdgt is not None: item.alias.value = wdgt.contents() self.aliasUpdated.emit(item.alias) def currentAliasChanged(self, current, previous): if current: if ((previous is not None and current.alias != previous.alias) or previous is None): self.highlightModule.emit(current.alias.component.vtmid) else: self.highlightModule.emit(-1) def _getOtherParameterInfo(self, pipeline, id, ptype): parameter = pipeline.db_get_object(ptype, id) return (parameter.type, parameter.strValue, 1, parameter.pos) def createAliasItem(self, alias): """ createAliasRow( alias: core.mashup.Alias) -> AliasItem Creates a row in the list """ alias.pos = self.topLevelItemCount() labels = [str(alias.component.pos), str(alias.name), \ str(alias.component.type)] item = QAliasListItem(self, alias, labels) item.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable) return alias def populateFromMashup(self, mashupController): #print "populateFromMashup ", self , self.previousSelected if self.controller != mashupController: self.controller = mashupController self.itemSelectionChanged.disconnect(self.setPreviousSelected) self.aliases = {} self.alias_cache = {} self.alias_widgets = {} self.clear() mashup = self.controller.currentMashup if len(mashup.alias_list) > 0: for alias in mashup.alias_list: alias = self.createAliasItem(copy.copy(alias)) self.aliases[alias.name] = alias if self.previousSelected > -1: if self.previousSelected >= self.topLevelItemCount(): self.previousSelected = self.topLevelItemCount() - 1 item = self.topLevelItem(self.previousSelected) self.setItemSelected(item, True) self.setCurrentItem(item) self.itemSelectionChanged.connect(self.setPreviousSelected) def updatePosNumbers(self): new_order = [] for idx in range(self.topLevelItemCount()): item = self.topLevelItem(idx) new_order.append(item.alias.component.pos) item.setText(0, str(idx)) return new_order def moveItemToNewPos(self, old, new): """moveItemToNewPos(old:int, new:int) -> None Move item from pos old to pos new """ self.itemSelectionChanged.disconnect(self.panel.updateInspector) item = self.takeTopLevelItem(old) self.insertTopLevelItem(new, item) self.clearSelection() new_order = self.updatePosNumbers() self.setItemSelected(item, True) self.itemSelectionChanged.connect(self.panel.updateInspector) self.controller.reorderAliases(new_order) def keyPressEvent(self, event): """ keyPressEvent(event: QKeyEvent) -> None Capture 'Del', 'Backspace' for deleting aliases """ if (event.key() in [QtCore.Qt.Key_Backspace, QtCore.Qt.Key_Delete]): self.removeCurrentAlias() @pyqtSlot(bool) def removeCurrentAlias(self, checked=False): item = self.currentItem() if not item: return name = item.alias.name # item will get recreated after question dialog shows so keep only index pos = self.indexOfTopLevelItem(item) res = show_question( "Mashups", "Are you sure do you want to remove '%s' from the mashup?" % name, [YES_BUTTON, NO_BUTTON], NO_BUTTON) if res == YES_BUTTON: self.previousSelected = pos self.takeTopLevelItem(pos) del self.aliases[name] self.updatePosNumbers() if pos >= self.topLevelItemCount() - 1: pos = self.topLevelItemCount() - 1 self.previousSelected = pos if pos != -1: new_item = self.topLevelItem(pos) self.setCurrentItem(new_item) self.setItemSelected(new_item, True) self.aliasRemoved.emit(name)
class QAliasList(QtGui.QTreeWidget): """ QAliasList just inherits from QListView to have a customized list and items """ #signals aliasUpdated = pyqtSignal(Alias) aliasRemoved = pyqtSignal(str) highlightModule = pyqtSignal(int) def __init__(self, controller, panel, parent=None): """ QAliasList(parent: QWidget) -> QAliasTable """ QtGui.QTreeWidget.__init__(self, parent) self.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) self.setRootIsDecorated(False) self.panel = panel self.aliases = Bidict() self.alias_widgets = {} self.controller = controller self.header().setStretchLastSection(True) self.setHeaderLabels(["Position", "Name", "Type"]) self.itemSelectionChanged.connect(self.setPreviousSelected) self.connect(self, QtCore.SIGNAL("currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)"), self.currentAliasChanged) self.previousSelected = -1 @pyqtSlot() def setPreviousSelected(self): if len(self.selectedItems()) == 1: item = self.selectedItems()[0] self.previousSelected = self.indexOfTopLevelItem(item) else: self.previousSelected = -1 def processCellChanges(self, row, col): """ processCellChanges(row: int, col: int) -> None Event handler for capturing when the contents in a cell changes """ item = self.item(row, col) if col == 0: old_alias = item.alias.alias new_alias = str(item.text()) if new_alias in self.aliases.keys(): QtGui.QMessageBox.warning(self, "VisMashup", """Label name %s already exists. Please type a different name. """ % new_alias) item.setText(old_alias) return elif new_alias == '': del self.aliases[old_alias] wdgt = self.cellWidget(row, 1) del self.alias_widgets[wdgt] item.alias.alias = '' self.removeRow(row) wdgt.deleteLater() self.updateRowNumbers() else: self.aliases[new_alias] = self.aliases[old_alias] del self.aliases[old_alias] item.alias.alias = new_alias elif col == 1: wdgt = self.cellWidget(row,col) if wdgt is not None: item.alias.value = wdgt.contents() self.aliasUpdated.emit(item.alias) def currentAliasChanged(self, current, previous): if current: if ((previous is not None and current.alias != previous.alias) or previous is None): self.highlightModule.emit(current.alias.component.vtmid) else: self.highlightModule.emit(-1) def _getOtherParameterInfo(self, pipeline, id, ptype): parameter = pipeline.db_get_object(ptype,id) return (parameter.type, parameter.strValue, 1, parameter.pos) def createAliasItem(self, alias): """ createAliasRow( alias: core.mashup.Alias) -> AliasItem Creates a row in the list """ alias.pos = self.topLevelItemCount() labels = [str(alias.component.pos), str(alias.name), \ str(alias.component.type)] item = QAliasListItem(self, alias, labels) item.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable ) return alias def populateFromMashup(self, mashupController): #print "populateFromMashup ", self , self.previousSelected if self.controller != mashupController: self.controller = mashupController self.itemSelectionChanged.disconnect(self.setPreviousSelected) self.aliases = {} self.alias_cache = {} self.alias_widgets = {} self.clear() mashup = self.controller.currentMashup if len(mashup.alias_list) > 0: for alias in mashup.alias_list: alias = self.createAliasItem(copy.copy(alias)) self.aliases[alias.name] = alias if self.previousSelected > -1: if self.previousSelected >= self.topLevelItemCount(): self.previousSelected = self.topLevelItemCount()-1 item = self.topLevelItem(self.previousSelected) self.setItemSelected(item, True) self.setCurrentItem(item) self.itemSelectionChanged.connect(self.setPreviousSelected) def updatePosNumbers(self): new_order = [] for idx in range(self.topLevelItemCount()): item = self.topLevelItem(idx) new_order.append(item.alias.component.pos) item.setText(0,str(idx)) return new_order def moveItemToNewPos(self, old, new): """moveItemToNewPos(old:int, new:int) -> None Move item from pos old to pos new """ self.itemSelectionChanged.disconnect(self.panel.updateInspector) item = self.takeTopLevelItem(old) self.insertTopLevelItem(new,item) self.clearSelection() new_order = self.updatePosNumbers() self.setItemSelected(item, True) self.itemSelectionChanged.connect(self.panel.updateInspector) self.controller.reorderAliases(new_order) def keyPressEvent(self, event): """ keyPressEvent(event: QKeyEvent) -> None Capture 'Del', 'Backspace' for deleting aliases """ if (event.key() in [QtCore.Qt.Key_Backspace, QtCore.Qt.Key_Delete]): self.removeCurrentAlias() @pyqtSlot(bool) def removeCurrentAlias(self, checked=False): item = self.currentItem() if not item: return name = item.alias.name # item will get recreated after question dialog shows so keep only index pos = self.indexOfTopLevelItem(item) res = show_question("Mashups", "Are you sure do you want to remove '%s' from the mashup?"%name, [YES_BUTTON, NO_BUTTON], NO_BUTTON) if res == YES_BUTTON: self.previousSelected = pos self.takeTopLevelItem(pos) del self.aliases[name] self.updatePosNumbers() if pos >= self.topLevelItemCount() - 1: pos = self.topLevelItemCount() - 1 self.previousSelected = pos if pos != -1: new_item = self.topLevelItem(pos) self.setCurrentItem(new_item) self.setItemSelected(new_item, True) self.aliasRemoved.emit(name)
class PortSpec(DBPortSpec): port_type_map = Bidict([('input', 'destination'), ('output', 'source'), ('invalid', 'invalid')]) end_point_map = Bidict([('source', PortEndPoint.Source), ('destination', PortEndPoint.Destination), ('invalid', PortEndPoint.Invalid)]) ########################################################################## # Constructors and copy def __init__(self, *args, **kwargs): signature = None if 'signature' in kwargs: signature = kwargs['signature'] del kwargs['signature'] sigstring = None if 'sigstring' in kwargs: sigstring = kwargs['sigstring'] del kwargs['sigstring'] defaults = None if 'defaults' in kwargs: defaults = kwargs['defaults'] del kwargs['defaults'] labels = None if 'labels' in kwargs: labels = kwargs['labels'] del kwargs['labels'] values = None if 'values' in kwargs: values = kwargs['values'] del kwargs['values'] entry_types = None if 'entry_types' in kwargs: entry_types = kwargs['entry_types'] del kwargs['entry_types'] if 'items' in kwargs and 'portSpecItems' not in kwargs: kwargs['portSpecItems'] = kwargs['items'] del kwargs['items'] if 'optional' not in kwargs: kwargs['optional'] = 0 # False elif not isinstance(kwargs['optional'], (int, long)): if isinstance(kwargs['optional'], bool): if kwargs['optional']: kwargs['optional'] = 1 else: kwargs['optional'] = 0 else: raise VistrailsInternalError("Cannot parse 'optional' kw " "-- must be an int or bool") if 'min_conns' not in kwargs: kwargs['min_conns'] = 0 elif kwargs['optional'] == 1 and kwargs['min_conns'] > 0: raise VistrailsInternalError("A mandatory port cannot be set " "to optional") if 'max_conns' not in kwargs: kwargs['max_conns'] = -1 if kwargs['min_conns'] >= 0 and kwargs['max_conns'] >= 0 and \ kwargs['min_conns'] > kwargs['max_conns']: raise VistrailsInternalError("Minimum number of connections " "cannot be greater than maximum " "number of connections") if 'sort_key' not in kwargs: kwargs['sort_key'] = -1 if 'depth' not in kwargs: kwargs['depth'] = 0 if 'id' not in kwargs: kwargs['id'] = -1 if 'tooltip' in kwargs: self._tooltip = kwargs['tooltip'] del kwargs['tooltip'] else: self._tooltip = None if 'docstring' in kwargs: self._docstring = kwargs['docstring'] del kwargs['docstring'] else: self._docstring = None if 'shape' in kwargs: self._shape = kwargs['shape'] del kwargs['shape'] else: self._shape = None DBPortSpec.__init__(self, *args, **kwargs) if sum(1 for container in (self.port_spec_items, signature, sigstring) if container) > 1: raise ValueError("Please specify only one of portSpecItems," " signature, or sigstring kwargs.") self.create_spec_items(self.port_spec_items, signature, sigstring, defaults, labels, values, entry_types) self._short_sigstring = None # if signature is not None: # self.create_entries(signature) # if not self.sigstring and self._entries is not None: # # create sigstring from entries # self.create_sigstring_and_descriptors() # DAKOOP: removed this---we will check in module_registry and pipeline # validation, this way, we can let errors go all the way up # elif self._entries is None and self.sigstring: # # create entries from sigstring # self.create_entries_and_descriptors() # else: # raise VistrailsInternalError("Need to specify signature or " # "sigstring to create PortSpec") # if self._entries is not None and self._tooltip is None: # self.create_tooltip() self.is_valid = True def __copy__(self): return PortSpec.do_copy(self) def do_copy(self, new_ids=False, id_scope=None, id_remap=None): cp = DBPortSpec.do_copy(self, new_ids, id_scope, id_remap) cp._short_sigstring = self._short_sigstring cp._tooltip = self._tooltip cp._shape = self._shape cp._docstring = self._docstring cp.is_valid = self.is_valid cp.__class__ = PortSpec # if cp._entries is not None: # cp.create_tooltip() return cp @staticmethod def convert(_port_spec): if _port_spec.__class__ == PortSpec: return _port_spec.__class__ = PortSpec for _port_spec_item in _port_spec.db_portSpecItems: PortSpecItem.convert(_port_spec_item) _port_spec._short_sigstring = None _port_spec._tooltip = None _port_spec._shape = None _port_spec._docstring = None _port_spec.is_valid = True _port_spec.port_spec_items.sort(key=operator.attrgetter('db_pos')) @staticmethod def from_sigstring(sigstring): """from_sig(sigstring: string) -> PortSpec Returns a portspec from the given sigstring. """ return PortSpec(sigstring=sigstring) ########################################################################## # Properties id = DBPortSpec.db_id name = DBPortSpec.db_name type = DBPortSpec.db_type optional = DBPortSpec.db_optional sort_key = DBPortSpec.db_sort_key min_conns = DBPortSpec.db_min_conns max_conns = DBPortSpec.db_max_conns _depth = DBPortSpec.db_depth port_spec_items = DBPortSpec.db_portSpecItems items = DBPortSpec.db_portSpecItems def _get_sigstring(self): return create_port_spec_string( [i.spec_tuple for i in self.port_spec_items]) sigstring = property(_get_sigstring) def is_mandatory(self): return (self.min_conns > 0) def _get_labels(self): return [i.label for i in self.port_spec_items] labels = property(_get_labels) def _get_defaults(self): return [i.default for i in self.port_spec_items] defaults = property(_get_defaults) def _get_short_sigstring(self): if self._short_sigstring is None: self.create_tooltip() return self._short_sigstring short_sigstring = property(_get_short_sigstring) def _get_signature(self): signature = [] for i in self.port_spec_items: signature.append((i.descriptor.module, i.label)) return signature signature = property(_get_signature) def _get_depth(self): return self._depth or 0 def _set_depth(self, depth): self._depth = depth depth = property(_get_depth, _set_depth) def toolTip(self): if self._tooltip is None: self.create_tooltip() return self._tooltip def shape(self): return self._shape def docstring(self): return self._docstring def descriptors(self): return [i.descriptor for i in self.port_spec_items] ########################################################################## # Methods def _resize_attrs(self, target, *lists): for rlist in lists: if len(target) > len(rlist): rlist.extend(None for i in xrange(len(target) - len(rlist))) def _set_attrs(self, item, *attrs): attr_order = ['default', 'label', 'values', 'entry_type'] if item is None: kwargs = dict(izip(attr_order, attrs)) return kwargs else: for (attr_key, attr) in izip(attr_order, attrs): if attr is not None: setattr(item, attr_key, attr) def create_spec_items(self, items=None, signature=None, sigstring=None, defaults=None, labels=None, values=None, entry_types=None): if defaults is None: defaults = [] elif isinstance(defaults, basestring): defaults = literal_eval(defaults) if labels is None: labels = [] elif isinstance(labels, basestring): labels = literal_eval(labels) if values is None: values = [] elif isinstance(values, basestring): values = literal_eval(values) if entry_types is None: entry_types = [] elif isinstance(entry_types, basestring): entry_types = literal_eval(entry_types) attrs = [defaults, labels, values, entry_types] if items: self.set_items(items, *attrs) elif signature is not None: items = self.get_items_from_entries(signature, *attrs) elif sigstring is not None: items = self.get_items_from_sigstring(sigstring, *attrs) self.port_spec_items = items def set_items(self, items, *attrs): self._resize_attrs(items, *attrs) for i, item_tuple in enumerate(izip(items, *attrs)): item_tuple[0].pos = i self._set_attrs(*item_tuple) def get_items_from_entries(self, signature, *attrs): # This is reasonably messy code. The intent is that a # signature given by the user in a call like this # add_input_port(module, name, signature) should be one of the # following: # type only: add_input_port(_, _, Float) # type plus description: add_input_port(_, _, (Float, 'radius')) # multiple parameters, where each parameter can be either of the above: # add_input_port(_, _, [Float, (Integer, 'count')]) registry = get_module_registry() entries = [] def canonicalize(sig_item): if isinstance(sig_item, tuple): # assert len(sig_item) == 2 # assert isinstance(sig_item[0], type) # assert isinstance(sig_item[1], str) descriptor = registry.get_descriptor(sig_item[0]) label = sig_item[1] return (descriptor, label) elif isinstance(sig_item, list): descriptor = registry.get_descriptor_by_name( get_vistrails_basic_pkg_id(), 'List') return (descriptor, None) else: # isinstance(sig_item, type): return (registry.get_descriptor(sig_item), None) # def _add_entry(sig_item): ps_items = [] if not isinstance(signature, list): signature = [signature] self._resize_attrs(signature, *attrs) for i, item_tuple in enumerate(izip(signature, *attrs)): descriptor, item_label = canonicalize(item_tuple[0]) kwargs = self._set_attrs(None, *item_tuple[1:]) if not kwargs['label']: if item_label != "<no description>": kwargs['label'] = item_label ps_item = PortSpecItem(pos=i, package=descriptor.identifier, module=descriptor.name, namespace=descriptor.namespace, **kwargs) ps_items.append(ps_item) return ps_items def get_items_from_sigstring(self, sigstring, *attrs): ps_items = [] specs_list = parse_port_spec_string(sigstring) if len(specs_list) == 0: return ps_items self._resize_attrs(specs_list, *attrs) for i, item_tuple in enumerate(izip(specs_list, *attrs)): kwargs = self._set_attrs(None, *item_tuple[1:]) ps_item = PortSpecItem(pos=i, package=item_tuple[0][0], module=item_tuple[0][1], namespace=item_tuple[0][2], **kwargs) ps_items.append(ps_item) return ps_items def create_tooltip(self): """Creates a short_sigstring that does not include package names for use with the tooltip. Note, however, that such sigstrings can't be used to reconstruct a spec. They should only be used for human-readable purposes. """ self._short_sigstring = \ "(" + ",".join(d.name for d in self.descriptors()) + ")" if self.type in ['input', 'output']: port_string = self.type.capitalize() else: port_string = 'Invalid' _depth = " (depth %s)" % self.depth if self.depth else '' self._tooltip = "%s port %s\n%s%s" % (port_string, self.name, self._short_sigstring, _depth) ########################################################################## # Operators def __str__(self): """__str__() -> str - Returns a string representation of an PortSpec object. """ rep = "<portSpec id=%s name=%s type=%s signature=%s depth=%s />" return rep % (str(self.id), str(self.name), str( self.type), str(self.sigstring), str(self.depth)) def __eq__(self, other): """ __eq__(other: PortSpec) -> boolean Returns True if self and other have the same attributes. Used by == operator. """ if self is None and other is None: return True if type(self) != type(other) or \ self.name != other.name or \ self.type != other.type: return False if len(self.descriptors()) != len(other.descriptors()): return False for (mine, their) in izip(self.descriptors(), other.descriptors()): if mine != their: return False return True def __ne__(self, other): return not self.__eq__(other) def type_equals(self, other): """type_equals(other: PortSpec) -> Bool Checks equality ignoring description strings. Only cares about types. Does not do subtyping or supertyping: match must be perfect. """ if self is None and other is None: return True if len(self.descriptors()) != len(other.descriptors()): return False for (mine, their) in izip(self.descriptors(), other.descriptors()): if mine != their: return False return True def key_no_id(self): """key_no_id(): tuple. returns a tuple that identifies the port without caring about ids. Used for sorting port lists.""" return (self.type, self.name, self.signature)