def get_values(self, count): """ get_values(count) -> [] Convert the list values into a list count should be an integer with the expected size of the list (given by the dimension 'size' in the exploration) """ param_info = self._param_info module = registry.get_module_by_name(param_info.identifier, param_info.type, param_info.namespace) result = [module.translate_to_python(m) for m in self._str_values] if len(result) != count: show_warning('Inconsistent Size', 'One of the <i>%s</i>\'s list ' 'interpolated ' 'values has a different ' 'size from the step count. ' 'Expected %d, got %d instead. ' 'Parameter Exploration aborted.' % (self.type, count, len(result))) return None return result
def updateCurrentTag(self, name): if BaseController.updateCurrentTag(self, name) == False: show_warning('Name Exists', "There is already another version named '%s'.\n" "Please enter a different one." % name) return False else: return True
def compute(self): # if server, grab local file using checksum id if self.is_server: self.checkInputPort("checksum") self.checksum = self.getInputFromPort("checksum") # get file path path_url = "%s/datasets/path/%s/" % (self.base_url, self.checksum) try: dataset_path_request = urllib2.urlopen(url=path_url) dataset_path = dataset_path_request.read() except urllib2.HTTPError: pass if os.path.isfile(dataset_path): out_file = core.modules.basic_modules.File() out_file.name = dataset_path self.setResult("file", out_file) else: # is client self.checkInputPort("file") self.in_file = self.getInputFromPort("file") if os.path.isfile(self.in_file.name): # do size check size = os.path.getsize(self.in_file.name) if size > 26214400: show_warning( "File is too large", ("file is larger than 25MB, " "unable to sync with web repository") ) self.setResult("file", self.in_file) else: # compute checksum f = open(self.in_file.name, "r") self.checksum = hashlib.sha1() block = 1 while block: block = f.read(128) self.checksum.update(block) f.close() self.checksum = self.checksum.hexdigest() # upload/download file self.data_sync() # set checksum param in module if not self.hasInputFromPort("checksum"): self.change_parameter("checksum", [self.checksum]) else: # local file not present if self.hasInputFromPort("checksum"): self.checksum = self.getInputFromPort("checksum") # download file self.data_sync()
def compute(self): # if server, grab local file using checksum id if self.is_server: self.checkInputPort('checksum') self.checksum = self.getInputFromPort("checksum") # get file path path_url = "%s/datasets/path/%s/" % (self.base_url, self.checksum) try: dataset_path_request = urllib2.urlopen(url=path_url) dataset_path = dataset_path_request.read() except urllib2.HTTPError: pass if os.path.isfile(dataset_path): out_file = core.modules.basic_modules.File() out_file.name = dataset_path self.setResult("file", out_file) else: # is client self.checkInputPort('file') self.in_file = self.getInputFromPort("file") if os.path.isfile(self.in_file.name): # do size check size = os.path.getsize(self.in_file.name) if size > 26214400: show_warning("File is too large", ("file is larger than 25MB, " "unable to sync with web repository")) self.setResult("file", self.in_file) else: # compute checksum f = open(self.in_file.name, 'r') self.checksum = hashlib.sha1() block = 1 while block: block = f.read(128) self.checksum.update(block) f.close() self.checksum = self.checksum.hexdigest() # upload/download file self.data_sync() # set checksum param in module if not self.hasInputFromPort('checksum'): self.change_parameter('checksum', [self.checksum]) else: # local file not present if self.hasInputFromPort('checksum'): self.checksum = self.getInputFromPort("checksum") # download file self.data_sync()
def thumbs_cache_directory_changed(self): """ thumbs_cache_changed(v: int) -> None """ value = str(self._thumbs_cache_directory_edt.text()) old_folder = self._configuration.thumbs.cacheDirectory if os.path.exists(value): self._configuration.thumbs.cacheDirectory = value self._temp_configuration.thumbs.cacheDirectory = value self.emit(QtCore.SIGNAL("configuration_changed"), None, value) self._cache.move_cache_directory(old_folder, value) else: show_warning("VisTrails", "The directory specified does not exist.") self._thumbs_cache_directory_edt.setText(old_folder)
def thumbs_cache_directory_changed(self): """ thumbs_cache_changed(v: int) -> None """ value = str(self._thumbs_cache_directory_edt.text()) old_folder = self._configuration.thumbs.cacheDirectory if os.path.exists(value): self._configuration.thumbs.cacheDirectory = value self._temp_configuration.thumbs.cacheDirectory = value self.emit(QtCore.SIGNAL('configuration_changed'), None, value) self._cache.move_cache_directory(old_folder, value) else: show_warning('VisTrails', 'The directory specified does not exist.') self._thumbs_cache_directory_edt.setText(old_folder)
def exportMashupGUI(self): if self.controller: dialog = QMashupExportDialog(self) if dialog.exec_() == QtGui.QDialog.Accepted: result = dialog.btnPressed fileName = QtGui.QFileDialog.getSaveFileName(self, "Export Mashup...", core.system.vistrails_file_directory(), "VisTrail link files (*.vtl)", None) if not fileName.isEmpty(): filename = str(fileName) res = MashupsManager.exportMashup(filename, self.controller.originalController, self.controller.mshptrail, self.controller.currentVersion, result) if not res: show_warning('VisTrails - Exporting Mashup', 'There was an error and the mashup could not be exported.')
def exportMashupGUI(self): if self.controller: dialog = QMashupExportDialog(self) if dialog.exec_() == QtGui.QDialog.Accepted: result = dialog.btnPressed fileName = QtGui.QFileDialog.getSaveFileName( self, "Export Mashup...", core.system.vistrails_file_directory(), "VisTrail link files (*.vtl)", None) if not fileName.isEmpty(): filename = str(fileName) res = MashupsManager.exportMashup( filename, self.controller.originalController, self.controller.mshptrail, self.controller.currentVersion, result) if not res: show_warning( 'VisTrails - Exporting Mashup', 'There was an error and the mashup could not be exported.' )
def addParameter(self, paramInfo): """ addParameter(paramInfo: (str, [ParameterInfo]) -> None Add a parameter to the table. The parameter info is specified in QParameterTreeWidgetItem """ # Check to see paramInfo is not a subset of some other parameter set params = paramInfo[1] for i in xrange(self.layout().count()): pEditor = self.layout().itemAt(i).widget() if pEditor and type(pEditor)==QParameterSetEditor: subset = True for p in params: if not (p in pEditor.info[1]): subset = False break if subset: show_warning('Parameter Exists', 'The parameter you are trying to add is ' 'already in the list.') return self.showPrompt(False) newEditor = QParameterSetEditor(paramInfo, self) # Make sure to disable all duplicated parameter for p in xrange(len(params)): for i in xrange(self.layout().count()): pEditor = self.layout().itemAt(i).widget() if pEditor and type(pEditor)==QParameterSetEditor: if params[p] in pEditor.info[1]: widget = newEditor.paramWidgets[p] widget.setDimension(4) widget.setDuplicate(True) widget.setEnabled(False) break self.layout().addWidget(newEditor) newEditor.show() self.setMinimumHeight(self.layout().minimumSize().height()) self.emit(QtCore.SIGNAL('exploreChange(bool)'), self.layout().count() > 3) return newEditor
def nameChanged(self): old_alias = self.alias.name new_alias = str(self.name_edit.text()) if old_alias == new_alias: return if new_alias in self.table.aliases.keys(): show_warning("Mashup", """Label name %s already exists. Please type a different name. """ % new_alias) self.name_edit.setText(old_alias) self.name_edit.setFocus() elif new_alias == '': show_warning("Mashup", """Variables with empty name are not allowed. Please type a unique name. """ % new_alias) self.name_edit.setText(old_alias) self.name_edit.setFocus() else: self.table.aliases[new_alias] = self.table.aliases[old_alias] #self.table.alias_cache[new_alias] = self.table.alias_cache[old_alias] del self.table.aliases[old_alias] #del self.table.alias_cache[old_alias] self.alias.name = new_alias self.aliasChanged.emit(self.alias)
def data_sync(self): """ downloads/uploads/uses the local file depending on availability """ self.checksum_lookup() # local file not on repository, so upload if not self.on_server and os.path.isfile(self.in_file.name): cookiejar = gui.repository.QRepositoryDialog.cookiejar if cookiejar: register_openers(cookiejar=cookiejar) params = { 'dataset_file': open(self.in_file.name, 'rb'), 'name': self.in_file.name.split('/')[-1], 'origin': 'vistrails', 'checksum': self.checksum } upload_url = "%s/datasets/upload/" % self.base_url datagen, headers = multipart_encode(params) request = urllib2.Request(upload_url, datagen, headers) try: result = urllib2.urlopen(request) if result.code != 200: show_warning("Upload Failure", "Data failed to upload to repository") # make temporarily uncachable self.is_cacheable = self.invalidate_cache else: debug.warning("Push to repository was successful") # make sure module caches self.is_cacheable = self.validate_cache except Exception, e: show_warning("Upload Failure", "Data failed to upload to repository") # make temporarily uncachable self.is_cacheable = self.invalidate_cache debug.warning('RepoSync uploaded %s to the repository' % \ self.in_file.name) else: show_warning("Please login", ("You must be logged into the web" " repository in order to upload " "data. No data was synced")) # make temporarily uncachable self.is_cacheable = self.invalidate_cache # use local data self.setResult("file", self.in_file)
def data_sync(self): """ downloads/uploads/uses the local file depending on availability """ self.checksum_lookup() # local file not on repository, so upload if not self.on_server and os.path.isfile(self.in_file.name): cookiejar = gui.repository.QRepositoryDialog.cookiejar if cookiejar: register_openers(cookiejar=cookiejar) params = { "dataset_file": open(self.in_file.name, "rb"), "name": self.in_file.name.split("/")[-1], "origin": "vistrails", "checksum": self.checksum, } upload_url = "%s/datasets/upload/" % self.base_url datagen, headers = multipart_encode(params) request = urllib2.Request(upload_url, datagen, headers) try: result = urllib2.urlopen(request) if result.code != 200: show_warning("Upload Failure", "Data failed to upload to repository") # make temporarily uncachable self.is_cacheable = self.invalidate_cache else: debug.warning("Push to repository was successful") # make sure module caches self.is_cacheable = self.validate_cache except Exception, e: show_warning("Upload Failure", "Data failed to upload to repository") # make temporarily uncachable self.is_cacheable = self.invalidate_cache debug.warning("RepoSync uploaded %s to the repository" % self.in_file.name) else: show_warning( "Please login", ("You must be logged into the web" " repository in order to upload " "data. No data was synced"), ) # make temporarily uncachable self.is_cacheable = self.invalidate_cache # use local data self.setResult("file", self.in_file)
def evaluate(i): try: v = d['value'](i) if v == None: return module.default_value return v except Exception, e: return str(e) return [evaluate(i) for i in xrange(self.size)] result = get() if not all(result, module.validate): show_warning('Failed Validation', 'One of the <i>%s</i>\'s user defined ' 'functions has failed validation, ' 'which usually means it generated a ' 'value of a type different ' 'than that specified by the ' 'parameter. Parameter Exploration ' 'aborted.' % param_info.type) return None return result def getValuesString(self): """ getValuesString() -> str Return a string representation of the parameter list """ r = self.get_values(self.size) if r is None: return '{ERROR}'
def __init__(self, parent=None, vistrail_view=None, dumpcells=False, controller=None, version=-1): """ QMashupAppMainWindow() Initialize an app window from a mashup. """ # Constructing the main widget QtGui.QMainWindow.__init__(self, parent) self.vtkCells = [] self.setStatusBar(QtGui.QStatusBar(self)) # Central widget centralWidget = QtGui.QWidget() self.mainLayout = QtGui.QVBoxLayout() self.mainLayout.setMargin(0) self.mainLayout.setSpacing(5) centralWidget.setLayout(self.mainLayout) self.setCentralWidget(centralWidget) self.numberOfCells = 0 self.is_executing = False #self.resize(100,100) self.dumpcells = dumpcells self.view = vistrail_view if controller: self.controller = controller self.mshptrail = controller.mshptrail if version == -1: self.currentMashup = self.controller.currentMashup else: self.currentMashup = self.mshptrail.getMashup(version) self.setWindowTitle('%s Mashup'%self.controller.getMashupName(version)) else: self.setWindowTitle('Mashup') # Assign "hidden" shortcut self.editingModeAct = QtGui.QAction("Chang&e Layout", self, shortcut="Ctrl+E", statusTip="Change the layout of the widgets", triggered=self.toggleEditingMode) #self.editingModeShortcut = QtGui.QShortcut(QtGui.QKeySequence('Ctrl+E'), self) #self.connect(self.editingModeShortcut, QtCore.SIGNAL('activated()'), # self.toggleEditingMode) self.editing = False # Constructing alias controls self.controlDocks = [] # Show here to make sure XDisplay info is correct (for VTKCell) self.show() spreadsheetController.setEchoMode(True) #will run to get Spreadsheet Cell events (cellEvents, errors) = self.runAndGetCellEvents(useDefaultValues=True) if cellEvents: self.numberOfCells = len(cellEvents) self.initCells(cellEvents) if len(errors) > 0: show_warning("VisTrails::Mashup Preview", "There was a problem executing the pipeline: %s."%errors) # Construct the controllers for aliases self.controlDocks = {} self.cellControls = {} self.aliasWidgets = {} self.initControls() if self.currentMashup.layout != None: self.restoreState(QtCore.QByteArray.fromPercentEncoding( QtCore.QByteArray(self.currentMashup.layout))) if self.currentMashup.geometry != None: self.restoreGeometry(QtCore.QByteArray.fromPercentEncoding( QtCore.QByteArray(self.currentMashup.geometry))) else: self.resize(self.sizeHint()) # Constructing buttons buttonDock = QCustomDockWidget('Control Buttons', self) buttonWidget = QtGui.QWidget(buttonDock) buttonWidget.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred) buttonLayout = QtGui.QGridLayout() buttonWidget.setLayout(buttonLayout) buttonLayout.setMargin(5) self.cb_auto_update = QtGui.QCheckBox("Turn on auto-update", self.centralWidget()) self.cb_auto_update.setChecked(False) self.cb_keep_camera = QtGui.QCheckBox("Keep camera position", self.centralWidget()) self.cb_keep_camera.setChecked(True) self.connect(self.cb_auto_update, QtCore.SIGNAL("stateChanged(int)"), self.auto_update_changed) self.updateButton = QtGui.QPushButton("&Update", self.centralWidget()) if self.dumpcells: self.quitButton = QtGui.QPushButton("&Save", self.centralWidget()) self.connect(self.quitButton, QtCore.SIGNAL('clicked(bool)'), self.saveAndExport) else: self.quitButton = QtGui.QPushButton("&Quit", self.centralWidget()) self.connect(self.quitButton, QtCore.SIGNAL('clicked(bool)'), self.close) buttonLayout.setColumnStretch(0, 1) buttonLayout.addWidget(self.cb_auto_update, 0, 1, QtCore.Qt.AlignLeft) buttonLayout.addWidget(self.cb_keep_camera, 0, 2, 1, 2, QtCore.Qt.AlignLeft) buttonLayout.addWidget(self.updateButton, 1, 2, QtCore.Qt.AlignRight) buttonLayout.addWidget(self.quitButton, 1, 3, QtCore.Qt.AlignRight) self.connect(self.updateButton, QtCore.SIGNAL('clicked(bool)'), self.updateButtonClick) buttonDock.setWidget(buttonWidget) self.addDockWidget(QtCore.Qt.BottomDockWidgetArea, buttonDock) self.controlDocks["__buttons__"] = buttonDock self.saveAllAct = QtGui.QAction("S&ave Combined", self, shortcut=QtGui.QKeySequence.SelectAll, statusTip="Save combined images to disk", triggered=self.saveAllEvent) self.saveAct = QtGui.QAction("&Save Each", self, shortcut=QtGui.QKeySequence.Save, statusTip="Save separate images to disk", triggered=self.saveEventAction) self.showBuilderAct = QtGui.QAction("VisTrails Main Window", self, statusTip="Show VisTrails Main Window", triggered=self.showBuilderWindow) self.createMenus() self.lastExportPath = ''
def __init__(self, parent=None, vistrail_view=None, dumpcells=False, controller=None, version=-1): """ QMashupAppMainWindow() Initialize an app window from a mashup. """ # Constructing the main widget QtGui.QMainWindow.__init__(self, parent) self.vtkCells = [] self.setStatusBar(QtGui.QStatusBar(self)) # Central widget centralWidget = QtGui.QWidget() self.mainLayout = QtGui.QVBoxLayout() self.mainLayout.setMargin(0) self.mainLayout.setSpacing(5) centralWidget.setLayout(self.mainLayout) self.setCentralWidget(centralWidget) self.numberOfCells = 0 self.is_executing = False #self.resize(100,100) self.dumpcells = dumpcells self.view = vistrail_view if controller: self.controller = controller self.mshptrail = controller.mshptrail if version == -1: self.currentMashup = self.controller.currentMashup else: self.currentMashup = self.mshptrail.getMashup(version) self.setWindowTitle('%s Mashup' % self.controller.getMashupName(version)) else: self.setWindowTitle('Mashup') # Assign "hidden" shortcut self.editingModeAct = QtGui.QAction( "Chang&e Layout", self, shortcut="Ctrl+E", statusTip="Change the layout of the widgets", triggered=self.toggleEditingMode) #self.editingModeShortcut = QtGui.QShortcut(QtGui.QKeySequence('Ctrl+E'), self) #self.connect(self.editingModeShortcut, QtCore.SIGNAL('activated()'), # self.toggleEditingMode) self.editing = False # Constructing alias controls self.controlDocks = [] # Show here to make sure XDisplay info is correct (for VTKCell) self.show() spreadsheetController.setEchoMode(True) #will run to get Spreadsheet Cell events (cellEvents, errors) = self.runAndGetCellEvents(useDefaultValues=True) if cellEvents: self.numberOfCells = len(cellEvents) self.initCells(cellEvents) if len(errors) > 0: show_warning( "VisTrails::Mashup Preview", "There was a problem executing the pipeline: %s." % errors) # Construct the controllers for aliases self.controlDocks = {} self.cellControls = {} self.aliasWidgets = {} self.initControls() if self.currentMashup.layout != None: self.restoreState( QtCore.QByteArray.fromPercentEncoding( QtCore.QByteArray(self.currentMashup.layout))) if self.currentMashup.geometry != None: self.restoreGeometry( QtCore.QByteArray.fromPercentEncoding( QtCore.QByteArray(self.currentMashup.geometry))) else: self.resize(self.sizeHint()) # Constructing buttons buttonDock = QCustomDockWidget('Control Buttons', self) buttonWidget = QtGui.QWidget(buttonDock) buttonWidget.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred) buttonLayout = QtGui.QGridLayout() buttonWidget.setLayout(buttonLayout) buttonLayout.setMargin(5) self.cb_auto_update = QtGui.QCheckBox("Turn on auto-update", self.centralWidget()) self.cb_auto_update.setChecked(False) self.cb_keep_camera = QtGui.QCheckBox("Keep camera position", self.centralWidget()) self.cb_keep_camera.setChecked(True) self.connect(self.cb_auto_update, QtCore.SIGNAL("stateChanged(int)"), self.auto_update_changed) self.updateButton = QtGui.QPushButton("&Update", self.centralWidget()) if self.dumpcells: self.quitButton = QtGui.QPushButton("&Save", self.centralWidget()) self.connect(self.quitButton, QtCore.SIGNAL('clicked(bool)'), self.saveAndExport) else: self.quitButton = QtGui.QPushButton("&Quit", self.centralWidget()) self.connect(self.quitButton, QtCore.SIGNAL('clicked(bool)'), self.close) buttonLayout.setColumnStretch(0, 1) buttonLayout.addWidget(self.cb_auto_update, 0, 1, QtCore.Qt.AlignLeft) buttonLayout.addWidget(self.cb_keep_camera, 0, 2, 1, 2, QtCore.Qt.AlignLeft) buttonLayout.addWidget(self.updateButton, 1, 2, QtCore.Qt.AlignRight) buttonLayout.addWidget(self.quitButton, 1, 3, QtCore.Qt.AlignRight) self.connect(self.updateButton, QtCore.SIGNAL('clicked(bool)'), self.updateButtonClick) buttonDock.setWidget(buttonWidget) self.addDockWidget(QtCore.Qt.BottomDockWidgetArea, buttonDock) self.controlDocks["__buttons__"] = buttonDock self.saveAllAct = QtGui.QAction( "S&ave Combined", self, shortcut=QtGui.QKeySequence.SelectAll, statusTip="Save combined images to disk", triggered=self.saveAllEvent) self.saveAct = QtGui.QAction("&Save Each", self, shortcut=QtGui.QKeySequence.Save, statusTip="Save separate images to disk", triggered=self.saveEventAction) self.showBuilderAct = QtGui.QAction( "VisTrails Main Window", self, statusTip="Show VisTrails Main Window", triggered=self.showBuilderWindow) self.createMenus() self.lastExportPath = ''
def saveSpreadsheet(self, fileName=None): """ saveSpreadsheet(fileName: str) -> None Save the current spreadsheet to a file if fileName is not None. Else, pop up a dialog to ask for a file name. """ def serialize_locator(locator): wrapper = XMLWrapper() dom = wrapper.create_document('spreadsheet_locator') root = dom.documentElement root.setAttribute("version", "1.0") locator.serialize(dom,root) return dom.toxml() def need_save(): from gui.vistrails_window import _app need_save_vt = False for t in self.tabWidgets: dim = t.getDimension() for r in xrange(dim[0]): for c in xrange(dim[1]): info = t.getCellPipelineInfo(r,c) if info: locator = info[0]['locator'] view = _app.ensureVistrail(locator) if view: controller = view.get_controller() if controller.changed: need_save_vt = True return need_save_vt if need_save(): show_warning('Save Spreadsheet', 'Please save your vistrails and try again.') return if fileName==None: fileName = self.spreadsheetFileName if fileName: indexFile = open(fileName, 'w') indexFile.write(str(len(self.tabWidgets))+'\n') for t in self.tabWidgets: dim = t.getDimension() sheet = spreadsheetRegistry.getSheetByType(type(t)) indexFile.write('%s\n'%str((str(t.windowTitle()), sheet, dim[0], dim[1]))) for r in xrange(dim[0]): for c in xrange(dim[1]): info = t.getCellPipelineInfo(r,c) if info: newinfo0 = copy.copy(info[0]) newinfo0['pipeline'] = None newinfo0['actions'] = [] newinfo0['locator'] = \ serialize_locator(newinfo0['locator']) indexFile.write('%s\n' %str((r, c, newinfo0, info[1], info[2]))) indexFile.write('---\n') indexFile.write(str(len(self.executedPipelines[0]))+'\n') for vistrail in self.executedPipelines[0]: indexFile.write('%s\n'%str((serialize_locator(vistrail[0]), vistrail[1]))) self.changeSpreadsheetFileName(fileName) indexFile.close() else: self.saveSpreadsheetAs()
def saveSpreadsheet(self, fileName=None): """ saveSpreadsheet(fileName: str) -> None Save the current spreadsheet to a file if fileName is not None. Else, pop up a dialog to ask for a file name. """ def serialize_locator(locator): wrapper = XMLWrapper() dom = wrapper.create_document('spreadsheet_locator') root = dom.documentElement root.setAttribute("version", "1.0") locator.serialize(dom, root) return dom.toxml() def need_save(): from gui.vistrails_window import _app need_save_vt = False for t in self.tabWidgets: dim = t.getDimension() for r in xrange(dim[0]): for c in xrange(dim[1]): info = t.getCellPipelineInfo(r, c) if info: locator = info[0]['locator'] view = _app.ensureVistrail(locator) if view: controller = view.get_controller() if controller.changed: need_save_vt = True return need_save_vt if need_save(): show_warning('Save Spreadsheet', 'Please save your vistrails and try again.') return if fileName == None: fileName = self.spreadsheetFileName if fileName: indexFile = open(fileName, 'w') indexFile.write(str(len(self.tabWidgets)) + '\n') for t in self.tabWidgets: dim = t.getDimension() sheet = spreadsheetRegistry.getSheetByType(type(t)) indexFile.write('%s\n' % str( (str(t.windowTitle()), sheet, dim[0], dim[1]))) for r in xrange(dim[0]): for c in xrange(dim[1]): info = t.getCellPipelineInfo(r, c) if info: newinfo0 = copy.copy(info[0]) newinfo0['pipeline'] = None newinfo0['actions'] = [] newinfo0['locator'] = \ serialize_locator(newinfo0['locator']) indexFile.write('%s\n' % str( (r, c, newinfo0, info[1], info[2]))) indexFile.write('---\n') indexFile.write(str(len(self.executedPipelines[0])) + '\n') for vistrail in self.executedPipelines[0]: indexFile.write('%s\n' % str( (serialize_locator(vistrail[0]), vistrail[1]))) self.changeSpreadsheetFileName(fileName) indexFile.close() else: self.saveSpreadsheetAs()