def setUp(self): self._s = WorkflowScene(DumbManager()) self._nodes = [] self._nodes.append(MetaStep(DumbStep('nowhere'))) self._nodes.append(MetaStep(DumbStep('nowhere'))) self._nodes.append(MetaStep(DumbStep('nowhere'))) self._nodes.append(MetaStep(DumbStep('nowhere'))) self._nodes.append(MetaStep(DumbStep('nowhere'))) self._nodes.append(MetaStep(DumbStep('nowhere'))) self._nodes.append(MetaStep(DumbStep('nowhere')))
def testItemAPI(self): item = MetaStep(DumbStep('nowhere')) s = WorkflowScene(DumbManager()) s.addItem(item) self.assertEqual(len(s._items), 1) s.setItemPos(item, QtCore.QPoint(344, 404)) self.assertEqual(s._items[item]._pos.x(), 344) self.assertEqual(s._items[item]._pos.y(), 404) s.setItemSelected(item, False) self.assertFalse(s._items[item]._selected) s.removeItem(item) self.assertEqual(len(s._items), 0)
def __init__(self, parent): self.name = 'WorkflowManager' self._parent = parent self._location = '' self._conf_filename = None self._previousLocation = None self._saveStateIndex = 0 self._currentStateIndex = 0 self._title = None self._scene = WorkflowScene(self) self._steps = WorkflowSteps(self) self._filtered_steps = WorkflowStepsFilter() self._filtered_steps.setSourceModel(self._steps)
def testSaveLoad(self): test_conf = os.path.join(test_path, 'test.conf') dm = DumbManager() dm._location = test_path s = WorkflowScene(dm) ws = QtCore.QSettings(test_conf, QtCore.QSettings.IniFormat) ds1 = DumbStep('nowhere') ds1._identifier = '1' ds1._name = 'a' ds2 = DumbStep('nowhere') ds2._identifier = '2' ds2._name = 'b' item1 = MetaStep(ds1) item2 = MetaStep(ds2) s.addItem(item1) s.addItem(item2) s.saveState(ws) del ws self.assertTrue(os.path.exists(test_conf)) file_content = open(test_conf).read() self.assertIn('Point(0 0)', file_content) self.assertIn('name=a', file_content) self.assertIn('name=b', file_content) self.assertNotIn('selected=false', file_content) os.remove(test_conf)
class WorkflowManager(object): """ This class manages (models?) the workflow. """ def __init__(self, parent): self.name = 'WorkflowManager' self._parent = parent self._location = '' self._conf_filename = None self._previousLocation = None self._saveStateIndex = 0 self._currentStateIndex = 0 self._title = None self._scene = WorkflowScene(self) self._steps = WorkflowSteps(self) self._filtered_steps = WorkflowStepsFilter() self._filtered_steps.setSourceModel(self._steps) def title(self): self._title = info.APPLICATION_NAME if self._location: if get_configuration(DISPLAY_FULL_PATH): self._title = self._title + ' - ' + self._location else: self._title = self._title + ' - ' + os.path.basename( self._location) if self._saveStateIndex != self._currentStateIndex: self._title = self._title + ' *' return self._title def updateLocation(self, location): self._location = location return self._scene.updateWorkflowLocation(location) def setLocation(self, location): self._location = location def location(self): return self._location def setPreviousLocation(self, location): self._previousLocation = location def previousLocation(self): return self._previousLocation def scene(self): return self._scene def getStepModel(self): return self._steps def getFilteredStepModel(self): return self._filtered_steps def updateAvailableSteps(self): self._steps.reload() self._filtered_steps.sort(QtCore.Qt.AscendingOrder) def undoStackIndexChanged(self, index): self._currentStateIndex = index def identifierOccursCount(self, identifier): return self._scene.identifierOccursCount(identifier) def register_finished_workflow_callback(self, callback): self._scene.register_finished_workflow_callback(callback) def execute(self): self._scene.execute() def canExecute(self): return self._scene.canExecute() def registerDoneExecutionForAll(self, callback): self._scene.registerDoneExecutionForAll(callback) def isModified(self): return self._saveStateIndex != self._currentStateIndex def changeIdentifier(self, old_identifier, new_identifier): old_config = get_configuration_file(self._location, old_identifier) new_config = get_configuration_file(self._location, new_identifier) try: os.rename(old_config, new_config) except OSError: pass def _checkRequirements(self): requirements_file = _getWorkflowRequirementsAbsoluteFilename( self._location) def new(self, location): """ Create a new workflow at the given location. The location is a directory, it must exist it will not be created. A file is created in the directory at 'location' which holds information describing the workflow. """ if location is None: raise WorkflowError('No location given to create new Workflow.') if not os.path.exists(location): raise WorkflowError('Location %s does not exist.' % location) self._location = location wf = _getWorkflowConfiguration(location) wf.setValue('version', info.VERSION_STRING) self._scene.clear() def exists(self, location): """ Determines whether a workflow exists in the given location. Returns True if a valid workflow exists, False otherwise. """ if location is None: return False if not os.path.exists(location): return False wf = _getWorkflowConfiguration(location) if wf.contains('version'): return True return False def is_restricted(self, location): if location is None or not os.path.exists( location) or not os.path.isdir(location): return False wf = _getWorkflowConfiguration(location) if not wf.contains('version'): return False return self._scene.is_restricted(wf) def load(self, location): """ Open a workflow from the given location. :param location: """ if location is None: raise WorkflowError('No location given to open Workflow.') if not os.path.exists(location): raise WorkflowError('Given location %s does not exist' % location) if os.path.isfile(location): location = os.path.dirname(location) wf = _getWorkflowConfiguration(location) if not wf.contains('version'): raise WorkflowError( 'The given Workflow configuration file is not valid.') workflow_version = version.parse(wf.value('version')) application_version = version.parse(info.VERSION_STRING) if not _compatible_versions(workflow_version, application_version): pass # should already have thrown an exception self._location = location if self._scene.is_loadable(wf): self._scene.restrict_plugins(wf) self._scene.load_state(wf) else: report = self._scene.doStepReport(wf) new_packages = False not_found = [] for name in report: reason = report[name] if reason.startswith('Not Found'): not_found.append(name) logger.warning( 'Workflow not loadable due to missing plugin "{0}"'. format(name)) elif reason.startswith('Broken'): not_found.append(name) logger.warning( 'Workflow not loadable due to broken plugin "{0}"'. format(name)) elif reason.startswith('Found'): pass else: new_packages = True self._parent.installPackage(reason) if self._scene.is_loadable(wf): self._scene.restrict_plugins(wf) self._scene.load_state(wf) elif new_packages: logger.warning( 'Unable to load workflow. You may need to restart the application.' ) raise WorkflowError( 'The given Workflow configuration file was not loaded. ' 'You may need to restart the application to pick up newly installed Python modules' ) else: error_text = 'The given Workflow configuration file was not loaded. ' \ 'A required plugin was not found (or had an error when loading).' \ ' The missing plugin(s) are: \n' for nf in not_found: error_text += '\n {0}'.format(nf) raise WorkflowError(error_text) self._saveStateIndex = self._currentStateIndex = 0 def save(self): wf = _getWorkflowConfiguration(self._location) if 'version' not in wf.allKeys(): wf.setValue('version', info.VERSION_STRING) workflow_version = version.parse(wf.value('version')) application_version = version.parse(info.VERSION_STRING) if workflow_version < application_version: wf.setValue('version', info.VERSION_STRING) self._scene.saveState(wf) self._saveStateIndex = self._currentStateIndex af = _getWorkflowMetaAbsoluteFilename(self._location) try: annotation = serializeWorkflowAnnotation().decode('utf-8') except AttributeError: annotation = serializeWorkflowAnnotation() with open(af, 'w') as f: f.write(annotation) self._scene.saveAnnotation(f) def close(self): """ Close the current workflow """ self._location = '' self._saveStateIndex = self._currentStateIndex = 0 def isWorkflowOpen(self): return True # not self._location == None def isWorkflowTracked(self): markers = ['.git', '.hg'] for marker in markers: target = os.path.join(self._location, marker) logger.debug('checking isdir: %s', target) return os.path.isdir(target) return False def writeSettings(self, settings): settings.beginGroup(self.name) settings.setValue(_PREVIOUS_LOCATION_STRING, self._previousLocation) settings.endGroup() def readSettings(self, settings): settings.beginGroup(self.name) self._previousLocation = settings.value(_PREVIOUS_LOCATION_STRING, '') settings.endGroup()
def testCreate(self): s = WorkflowScene(DumbManager()) self.assertTrue(s != None)
class WorkflowDependencyGraphTestCase(unittest.TestCase): def assertIn(self, a, b, *args, **kwargs): """'Python < v2.7 compatibility. Assert "a" in "b"""" try: f = super(WorkflowDependencyGraphTestCase, self).assertIn except AttributeError: self.assertTrue(a in b, *args, **kwargs) else: f(a, b, *args, **kwargs) def assertNotIn(self, a, b, *args, **kwargs): """'Python < v2.7 compatibility. Assert "a" NOT in "b"""" try: f = super(WorkflowDependencyGraphTestCase, self).assertNotIn except AttributeError: self.assertFalse(a in b, *args, **kwargs) else: f(a, b, *args, **kwargs) def assertLess(self, a, b, *args, **kwargs): """'Python < v2.7 compatibility. Assert "a" less "b"""" try: f = super(WorkflowDependencyGraphTestCase, self).assertLess except AttributeError: self.assertTrue(a < b, *args, **kwargs) else: f(a, b, *args, **kwargs) def setUp(self): self._s = WorkflowScene(DumbManager()) self._nodes = [] self._nodes.append(MetaStep(DumbStep('nowhere'))) self._nodes.append(MetaStep(DumbStep('nowhere'))) self._nodes.append(MetaStep(DumbStep('nowhere'))) self._nodes.append(MetaStep(DumbStep('nowhere'))) self._nodes.append(MetaStep(DumbStep('nowhere'))) self._nodes.append(MetaStep(DumbStep('nowhere'))) self._nodes.append(MetaStep(DumbStep('nowhere'))) def tearDown(self): self._s.clear() self._nodes = [] def testCreate(self): g = WorkflowDependencyGraph(self._s) self.assertTrue(g != None) def testGraph1(self): g = WorkflowDependencyGraph(self._s) c1 = Connection(self._nodes[0], 0, self._nodes[1], 0) self._s.addItem(self._nodes[0]) self._s.addItem(self._nodes[1]) self._s.addItem(c1) self.assertTrue(g.canExecute()) self.assertEqual(len(g._topologicalOrder), 2) self.assertEqual(g._topologicalOrder[0], self._nodes[0]) self.assertEqual(g._topologicalOrder[1], self._nodes[1]) def testGraph2(self): g = WorkflowDependencyGraph(self._s) c1 = Connection(self._nodes[0], 0, self._nodes[1], 0) c2 = Connection(self._nodes[1], 0, self._nodes[2], 0) self._s.addItem(self._nodes[0]) self._s.addItem(self._nodes[1]) self._s.addItem(self._nodes[2]) self._s.addItem(c1) self._s.addItem(c2) self.assertTrue(g.canExecute()) self.assertEqual(len(g._topologicalOrder), 3) self.assertEqual(g._topologicalOrder[0], self._nodes[0]) self.assertEqual(g._topologicalOrder[1], self._nodes[1]) self.assertEqual(g._topologicalOrder[2], self._nodes[2]) def testGraph3(self): g = WorkflowDependencyGraph(self._s) c1 = Connection(self._nodes[0], 0, self._nodes[1], 0) c2 = Connection(self._nodes[1], 0, self._nodes[2], 0) c3 = Connection(self._nodes[2], 0, self._nodes[3], 0) self._s.addItem(self._nodes[0]) self._s.addItem(self._nodes[1]) self._s.addItem(self._nodes[2]) self._s.addItem(self._nodes[3]) self._s.addItem(c3) self._s.addItem(c1) self._s.addItem(c2) self.assertTrue(g.canExecute()) self.assertEqual(len(g._topologicalOrder), 4) self.assertEqual(g._topologicalOrder[0], self._nodes[0]) self.assertEqual(g._topologicalOrder[1], self._nodes[1]) self.assertEqual(g._topologicalOrder[2], self._nodes[2]) self.assertEqual(g._topologicalOrder[3], self._nodes[3]) def testGraph4(self): g = WorkflowDependencyGraph(self._s) c1 = Connection(self._nodes[0], 0, self._nodes[1], 0) c2 = Connection(self._nodes[1], 0, self._nodes[2], 0) c3 = Connection(self._nodes[2], 0, self._nodes[3], 0) self._s.addItem(self._nodes[0]) self._s.addItem(self._nodes[1]) self._s.addItem(self._nodes[2]) self._s.addItem(self._nodes[3]) self._s.addItem(self._nodes[4]) self._s.addItem(self._nodes[5]) self._s.addItem(c3) self._s.addItem(c1) self._s.addItem(c2) nodes = g._findAllConnectedNodes() self.assertEqual(4, len(nodes)) self.assertIn(self._nodes[0], nodes) self.assertIn(self._nodes[1], nodes) self.assertIn(self._nodes[2], nodes) self.assertIn(self._nodes[3], nodes) self.assertNotIn(self._nodes[4], nodes) self.assertNotIn(self._nodes[5], nodes) def testGraph5(self): g = WorkflowDependencyGraph(self._s) c1 = Connection(self._nodes[0], 0, self._nodes[2], 0) c2 = Connection(self._nodes[1], 0, self._nodes[2], 0) c3 = Connection(self._nodes[2], 0, self._nodes[3], 0) c4 = Connection(self._nodes[2], 0, self._nodes[4], 0) self._s.addItem(self._nodes[0]) self._s.addItem(self._nodes[1]) self._s.addItem(self._nodes[2]) self._s.addItem(self._nodes[3]) self._s.addItem(self._nodes[4]) self._s.addItem(self._nodes[5]) self._s.addItem(c1) self._s.addItem(c2) self._s.addItem(c3) self._s.addItem(c4) nodes = g._findAllConnectedNodes() self.assertEqual(5, len(nodes)) self.assertIn(self._nodes[0], nodes) self.assertIn(self._nodes[1], nodes) self.assertIn(self._nodes[2], nodes) self.assertIn(self._nodes[3], nodes) self.assertIn(self._nodes[4], nodes) self.assertNotIn(self._nodes[5], nodes) graph = g._calculateDependencyGraph() self.assertFalse(g._nodeIsDestination(graph, self._nodes[0])) self.assertFalse(g._nodeIsDestination(graph, self._nodes[1])) self.assertTrue(g._nodeIsDestination(graph, self._nodes[2])) self.assertTrue(g._nodeIsDestination(graph, self._nodes[3])) self.assertTrue(g._nodeIsDestination(graph, self._nodes[4])) self.assertFalse(g._nodeIsDestination(graph, self._nodes[5])) starting_set = g._findStartingSet(graph, nodes) self.assertEqual(2, len(starting_set)) self.assertIn(self._nodes[0], starting_set) self.assertIn(self._nodes[1], starting_set) self.assertNotIn(self._nodes[2], starting_set) self.assertNotIn(self._nodes[3], starting_set) self.assertNotIn(self._nodes[4], starting_set) self.assertNotIn(self._nodes[5], starting_set) order = g._determineTopologicalOrder(graph, starting_set) self.assertEqual(5, len(order)) index0 = order.index(self._nodes[0]) index1 = order.index(self._nodes[1]) index2 = order.index(self._nodes[2]) index3 = order.index(self._nodes[3]) index4 = order.index(self._nodes[4]) self.assertLess(index1, index2) self.assertLess(index0, index2) self.assertLess(index2, index3) self.assertLess(index2, index4) def testGraph6(self): g = WorkflowDependencyGraph(self._s) c1 = Connection(self._nodes[0], 0, self._nodes[2], 0) c2 = Connection(self._nodes[1], 0, self._nodes[2], 0) c3 = Connection(self._nodes[2], 0, self._nodes[3], 0) c4 = Connection(self._nodes[2], 0, self._nodes[4], 0) c5 = Connection(self._nodes[6], 0, self._nodes[0], 0) c6 = Connection(self._nodes[6], 0, self._nodes[1], 0) self._s.addItem(self._nodes[0]) self._s.addItem(self._nodes[1]) self._s.addItem(self._nodes[2]) self._s.addItem(self._nodes[3]) self._s.addItem(self._nodes[4]) self._s.addItem(self._nodes[5]) self._s.addItem(self._nodes[6]) self._s.addItem(c1) self._s.addItem(c2) self._s.addItem(c3) self._s.addItem(c4) self._s.addItem(c5) self._s.addItem(c6) nodes = g._findAllConnectedNodes() self.assertEqual(6, len(nodes)) graph = g._calculateDependencyGraph() starting_set = g._findStartingSet(graph, nodes) self.assertEqual(1, len(starting_set)) order = g._determineTopologicalOrder(graph, starting_set) self.assertEqual(6, len(order)) index0 = order.index(self._nodes[6]) index1 = order.index(self._nodes[1]) self.assertLess(index0, index1) def testGraph7(self): """ Testing independent graphs """ g = WorkflowDependencyGraph(self._s) c1 = Connection(self._nodes[0], 0, self._nodes[2], 0) c2 = Connection(self._nodes[1], 0, self._nodes[2], 0) c3 = Connection(self._nodes[2], 0, self._nodes[3], 0) c4 = Connection(self._nodes[2], 0, self._nodes[4], 0) c5 = Connection(self._nodes[6], 0, self._nodes[5], 0) self._s.addItem(self._nodes[0]) self._s.addItem(self._nodes[1]) self._s.addItem(self._nodes[2]) self._s.addItem(self._nodes[3]) self._s.addItem(self._nodes[4]) self._s.addItem(self._nodes[5]) self._s.addItem(self._nodes[6]) self._s.addItem(c1) self._s.addItem(c2) self._s.addItem(c3) self._s.addItem(c4) self._s.addItem(c5) nodes = g._findAllConnectedNodes() self.assertEqual(7, len(nodes)) graph = g._calculateDependencyGraph() starting_set = g._findStartingSet(graph, nodes) self.assertEqual(3, len(starting_set)) order = g._determineTopologicalOrder(graph, starting_set) self.assertEqual(7, len(order)) def testGraph8(self): """ Testing graph with loop """ g = WorkflowDependencyGraph(self._s) c1 = Connection(self._nodes[0], 0, self._nodes[1], 0) c2 = Connection(self._nodes[1], 0, self._nodes[2], 0) c3 = Connection(self._nodes[2], 0, self._nodes[3], 0) c4 = Connection(self._nodes[3], 0, self._nodes[4], 0) c5 = Connection(self._nodes[3], 0, self._nodes[5], 0) c6 = Connection(self._nodes[5], 0, self._nodes[6], 0) c7 = Connection(self._nodes[6], 0, self._nodes[2], 0) self._s.addItem(self._nodes[0]) self._s.addItem(self._nodes[1]) self._s.addItem(self._nodes[2]) self._s.addItem(self._nodes[3]) self._s.addItem(self._nodes[4]) self._s.addItem(self._nodes[5]) self._s.addItem(self._nodes[6]) self._s.addItem(c1) self._s.addItem(c2) self._s.addItem(c3) self._s.addItem(c4) self._s.addItem(c5) self._s.addItem(c6) self._s.addItem(c7) nodes = g._findAllConnectedNodes() self.assertEqual(7, len(nodes)) graph = g._calculateDependencyGraph() starting_set = g._findStartingSet(graph, nodes) self.assertEqual(1, len(starting_set)) order = g._determineTopologicalOrder(graph, starting_set) self.assertEqual(0, len(order)) def testExecute(self): g = WorkflowDependencyGraph(self._s) c1 = Connection(self._nodes[0], 0, self._nodes[2], 0) c2 = Connection(self._nodes[1], 0, self._nodes[2], 1) c3 = Connection(self._nodes[1], 1, self._nodes[2], 2) c4 = Connection(self._nodes[2], 0, self._nodes[3], 0) self._s.addItem(self._nodes[0]) self._s.addItem(self._nodes[1]) self._s.addItem(self._nodes[2]) self._s.addItem(self._nodes[3]) self._s.addItem(c1) self._s.addItem(c2) self._s.addItem(c3) self._s.addItem(c4) g.canExecute() for _ in range(len(g._topologicalOrder)): g.execute()