Beispiel #1
0
 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')))
Beispiel #2
0
    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)
Beispiel #3
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)
Beispiel #4
0
    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)
Beispiel #5
0
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()
Beispiel #6
0
    def testCreate(self):

        s = WorkflowScene(DumbManager())
        self.assertTrue(s != None)
Beispiel #7
0
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()