updating for the last version of Spiffworkflow which deprecates the use of task.STATE values, in favor of TaskState.STATE, for example TaskState.READY

This commit is contained in:
Dan 2022-05-10 12:28:55 -04:00
parent a78bb46682
commit 063da419d0
6 changed files with 61 additions and 36 deletions

View File

@ -53,7 +53,7 @@ dateparser = "*"
# pipenv install --editable ../SpiffWorkflow (but fix things back before commiting!) # pipenv install --editable ../SpiffWorkflow (but fix things back before commiting!)
# Merged Commit https://github.com/sartography/SpiffWorkflow/pull/178 broke usage of SpiffWorkflow # Merged Commit https://github.com/sartography/SpiffWorkflow/pull/178 broke usage of SpiffWorkflow
# References to task states will need to be updated to allow using newest version # References to task states will need to be updated to allow using newest version
spiffworkflow = {git = "https://github.com/sartography/SpiffWorkflow", ref = "e47072ff88d7121c01861b08851e5b6f6fbf6609"} spiffworkflow = {git = "https://github.com/sartography/SpiffWorkflow"}
[requires] [requires]
python_version = "3.9" python_version = "3.9"

48
Pipfile.lock generated
View File

@ -1,7 +1,7 @@
{ {
"_meta": { "_meta": {
"hash": { "hash": {
"sha256": "9f340919423c7c2d75664173de3132b3925a0e0bc28216951f188010e3a1e1f1" "sha256": "c2fd582e7167dd91efba5115ea49717313e8bc5cf0589e5469b6e641326cfc8b"
}, },
"pipfile-spec": 6, "pipfile-spec": 6,
"requires": { "requires": {
@ -70,6 +70,28 @@
"markers": "python_version >= '3.6'", "markers": "python_version >= '3.6'",
"version": "==2.10.1" "version": "==2.10.1"
}, },
"backports.zoneinfo": {
"hashes": [
"sha256:17746bd546106fa389c51dbea67c8b7c8f0d14b5526a579ca6ccf5ed72c526cf",
"sha256:1b13e654a55cd45672cb54ed12148cd33628f672548f373963b0bff67b217328",
"sha256:1c5742112073a563c81f786e77514969acb58649bcdf6cdf0b4ed31a348d4546",
"sha256:4a0f800587060bf8880f954dbef70de6c11bbe59c673c3d818921f042f9954a6",
"sha256:5c144945a7752ca544b4b78c8c41544cdfaf9786f25fe5ffb10e838e19a27570",
"sha256:7b0a64cda4145548fed9efc10322770f929b944ce5cee6c0dfe0c87bf4c0c8c9",
"sha256:8439c030a11780786a2002261569bdf362264f605dfa4d65090b64b05c9f79a7",
"sha256:8961c0f32cd0336fb8e8ead11a1f8cd99ec07145ec2931122faaac1c8f7fd987",
"sha256:89a48c0d158a3cc3f654da4c2de1ceba85263fafb861b98b59040a5086259722",
"sha256:a76b38c52400b762e48131494ba26be363491ac4f9a04c1b7e92483d169f6582",
"sha256:da6013fd84a690242c310d77ddb8441a559e9cb3d3d59ebac9aca1a57b2e18bc",
"sha256:e55b384612d93be96506932a786bbcde5a2db7a9e6a4bb4bffe8b733f5b9036b",
"sha256:e81b76cace8eda1fca50e345242ba977f9be6ae3945af8d46326d776b4cf78d1",
"sha256:e8236383a20872c0cdf5a62b554b27538db7fa1bbec52429d8d106effbaeca08",
"sha256:f04e857b59d9d1ccc39ce2da1021d196e47234873820cbeaad210724b1ee28ac",
"sha256:fadbfe37f74051d024037f223b8e001611eac868b5c5b06144ef4d8b799862f2"
],
"markers": "python_version >= '3.6' and python_version < '3.9'",
"version": "==0.2.1"
},
"bcrypt": { "bcrypt": {
"hashes": [ "hashes": [
"sha256:2b02d6bfc6336d1094276f3f588aa1225a598e27f8e3388f4db9948cb707b521", "sha256:2b02d6bfc6336d1094276f3f588aa1225a598e27f8e3388f4db9948cb707b521",
@ -199,7 +221,7 @@
"sha256:a0713dc7a1de3f06bc0df5a9567ad19ead2d3d5689b434768a6145bff77c0667", "sha256:a0713dc7a1de3f06bc0df5a9567ad19ead2d3d5689b434768a6145bff77c0667",
"sha256:f184f0d851d96b6d29297354ed981b7dd71df7ff500d82fa6d11f0856bee8035" "sha256:f184f0d851d96b6d29297354ed981b7dd71df7ff500d82fa6d11f0856bee8035"
], ],
"markers": "python_full_version >= '3.6.2' and python_full_version < '4.0.0'", "markers": "python_version < '4' and python_full_version >= '3.6.2'",
"version": "==0.3.0" "version": "==0.3.0"
}, },
"click-plugins": { "click-plugins": {
@ -528,6 +550,14 @@
"markers": "python_version < '3.10'", "markers": "python_version < '3.10'",
"version": "==4.11.3" "version": "==4.11.3"
}, },
"importlib-resources": {
"hashes": [
"sha256:b6062987dfc51f0fcb809187cffbd60f35df7acb4589091f154214af6d0d49d3",
"sha256:e447dc01619b1e951286f3929be820029d48c75eb25d265c28b92a16548212b8"
],
"markers": "python_version < '3.9'",
"version": "==5.7.1"
},
"inflection": { "inflection": {
"hashes": [ "hashes": [
"sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417", "sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417",
@ -1147,14 +1177,6 @@
"index": "pypi", "index": "pypi",
"version": "==0.14.4" "version": "==0.14.4"
}, },
"setuptools": {
"hashes": [
"sha256:26ead7d1f93efc0f8c804d9fafafbe4a44b179580a7105754b245155f9af05a8",
"sha256:47c7b0c0f8fc10eec4cf1e71c6fdadf8decaa74ffa087e68cd1c20db7ad6a592"
],
"markers": "python_version >= '3.7'",
"version": "==62.1.0"
},
"six": { "six": {
"hashes": [ "hashes": [
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
@ -1244,7 +1266,7 @@
}, },
"spiffworkflow": { "spiffworkflow": {
"git": "https://github.com/sartography/SpiffWorkflow", "git": "https://github.com/sartography/SpiffWorkflow",
"ref": "e47072ff88d7121c01861b08851e5b6f6fbf6609" "ref": "2617ef4cb82b85db9c756a38632c66290f3e1007"
}, },
"sqlalchemy": { "sqlalchemy": {
"hashes": [ "hashes": [
@ -1317,7 +1339,7 @@
"sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14", "sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14",
"sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e" "sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e"
], ],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_full_version < '4.0.0'", "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'",
"version": "==1.26.9" "version": "==1.26.9"
}, },
"vine": { "vine": {
@ -1466,7 +1488,7 @@
"sha256:56bf8aadb83c24db6c4b577e13de374ccfb67da2078beba1d037c17980bf43ad", "sha256:56bf8aadb83c24db6c4b577e13de374ccfb67da2078beba1d037c17980bf43ad",
"sha256:c4f6e5bbf48e74f7a38e7cc5b0480ff42b0ae5178957d564d18932525d5cf099" "sha256:c4f6e5bbf48e74f7a38e7cc5b0480ff42b0ae5178957d564d18932525d5cf099"
], ],
"markers": "python_version >= '3.7'", "markers": "python_version < '3.10'",
"version": "==3.8.0" "version": "==3.8.0"
} }
}, },

View File

@ -1,5 +1,6 @@
import uuid import uuid
from SpiffWorkflow import TaskState
from flask import g from flask import g
from crc import session from crc import session
@ -16,7 +17,6 @@ from crc.services.workflow_processor import WorkflowProcessor
from crc.services.workflow_service import WorkflowService from crc.services.workflow_service import WorkflowService
from crc.services.workflow_spec_service import WorkflowSpecService from crc.services.workflow_spec_service import WorkflowSpecService
def all_specifications(libraries=False,standalone=False): def all_specifications(libraries=False,standalone=False):
spec_service = WorkflowSpecService() spec_service = WorkflowSpecService()
if libraries and standalone: if libraries and standalone:
@ -255,14 +255,15 @@ def set_current_task(workflow_id, task_id):
processor = WorkflowProcessor(workflow_model) processor = WorkflowProcessor(workflow_model)
task_id = uuid.UUID(task_id) task_id = uuid.UUID(task_id)
spiff_task = processor.bpmn_workflow.get_task(task_id) spiff_task = processor.bpmn_workflow.get_task(task_id)
cancel_notify = (spiff_task.state == spiff_task.COMPLETED and cancel_notify = (spiff_task.state == TaskState.COMPLETED and
spiff_task.task_spec.__class__.__name__ != 'EndEvent') spiff_task.task_spec.__class__.__name__ != 'EndEvent')
if not spiff_task: if not spiff_task:
# An invalid task_id was requested. # An invalid task_id was requested.
raise ApiError("invalid_task", "The Task you requested no longer exists as a part of this workflow.") raise ApiError("invalid_task", "The Task you requested no longer exists as a part of this workflow.")
_verify_user_and_role(processor, spiff_task) _verify_user_and_role(processor, spiff_task)
user_uid = UserService.current_user(allow_admin_impersonate=True).uid user_uid = UserService.current_user(allow_admin_impersonate=True).uid
if spiff_task.state != spiff_task.COMPLETED and spiff_task.state != spiff_task.READY:
if spiff_task.state != TaskState.COMPLETED and spiff_task.state != TaskState.READY:
raise ApiError("invalid_state", "You may not move the token to a task who's state is not " raise ApiError("invalid_state", "You may not move the token to a task who's state is not "
"currently set to COMPLETE or READY.") "currently set to COMPLETE or READY.")
@ -295,7 +296,7 @@ def update_task(workflow_id, task_id, body, terminate_loop=None, update_all=Fals
if not spiff_task: if not spiff_task:
raise ApiError("empty_task", "Processor failed to obtain task.", status_code=404) raise ApiError("empty_task", "Processor failed to obtain task.", status_code=404)
if spiff_task.state != spiff_task.READY: if spiff_task.state != TaskState.READY:
raise ApiError("invalid_state", "You may not update a task unless it is in the READY state. " raise ApiError("invalid_state", "You may not update a task unless it is in the READY state. "
"Consider calling a token reset to make this task Ready.") "Consider calling a token reset to make this task Ready.")

View File

@ -10,7 +10,7 @@ from SpiffWorkflow.serializer.exceptions import MissingSpecError
from lxml import etree from lxml import etree
from datetime import datetime from datetime import datetime
from SpiffWorkflow import Task as SpiffTask, WorkflowException, Task from SpiffWorkflow import Task as SpiffTask, WorkflowException, Task, TaskState
from SpiffWorkflow.bpmn.parser.ValidationException import ValidationException from SpiffWorkflow.bpmn.parser.ValidationException import ValidationException
from SpiffWorkflow.bpmn.serializer.BpmnSerializer import BpmnSerializer from SpiffWorkflow.bpmn.serializer.BpmnSerializer import BpmnSerializer
from SpiffWorkflow.bpmn.workflow import BpmnWorkflow from SpiffWorkflow.bpmn.workflow import BpmnWorkflow
@ -172,7 +172,7 @@ class WorkflowProcessor(object):
if UserService.has_user(): if UserService.has_user():
current_user = UserService.current_user(allow_admin_impersonate=True) current_user = UserService.current_user(allow_admin_impersonate=True)
current_user_data = UserModelSchema().dump(current_user) current_user_data = UserModelSchema().dump(current_user)
tasks = bpmn_workflow.get_tasks(SpiffTask.READY) tasks = bpmn_workflow.get_tasks(TaskState.READY)
for task in tasks: for task in tasks:
task.data['current_user'] = current_user_data task.data['current_user'] = current_user_data
@ -236,7 +236,7 @@ class WorkflowProcessor(object):
def save(self): def save(self):
"""Saves the current state of this processor to the database """ """Saves the current state of this processor to the database """
self.workflow_model.bpmn_workflow_json = self.serialize() self.workflow_model.bpmn_workflow_json = self.serialize()
complete_states = [SpiffTask.CANCELLED, SpiffTask.COMPLETED] complete_states = [TaskState.CANCELLED, TaskState.COMPLETED]
tasks = list(self.get_all_user_tasks()) tasks = list(self.get_all_user_tasks())
self.workflow_model.status = self.get_status() self.workflow_model.status = self.get_status()
self.workflow_model.total_tasks = len(tasks) self.workflow_model.total_tasks = len(tasks)
@ -304,7 +304,7 @@ class WorkflowProcessor(object):
if bpmn_workflow.is_completed(): if bpmn_workflow.is_completed():
return WorkflowStatus.complete return WorkflowStatus.complete
user_tasks = bpmn_workflow.get_ready_user_tasks() user_tasks = bpmn_workflow.get_ready_user_tasks()
waiting_tasks = bpmn_workflow.get_tasks(Task.WAITING) waiting_tasks = bpmn_workflow.get_tasks(TaskState.WAITING)
if len(waiting_tasks) > 0: if len(waiting_tasks) > 0:
return WorkflowStatus.waiting return WorkflowStatus.waiting
if len(user_tasks) > 0: if len(user_tasks) > 0:
@ -355,7 +355,7 @@ class WorkflowProcessor(object):
endtasks = [] endtasks = []
if self.bpmn_workflow.is_completed(): if self.bpmn_workflow.is_completed():
for task in SpiffTask.Iterator(self.bpmn_workflow.task_tree, SpiffTask.ANY_MASK): for task in SpiffTask.Iterator(self.bpmn_workflow.task_tree, TaskState.ANY_MASK):
# Assure that we find the end event for this workflow, and not for any sub-workflows. # Assure that we find the end event for this workflow, and not for any sub-workflows.
if isinstance(task.task_spec, EndEvent) and task.workflow == self.bpmn_workflow: if isinstance(task.task_spec, EndEvent) and task.workflow == self.bpmn_workflow:
endtasks.append(task) endtasks.append(task)
@ -366,11 +366,11 @@ class WorkflowProcessor(object):
# a parallel gateway with multiple tasks, so prefer ones that share a parent. # a parallel gateway with multiple tasks, so prefer ones that share a parent.
# Get a list of all ready tasks # Get a list of all ready tasks
ready_tasks = self.bpmn_workflow.get_tasks(SpiffTask.READY) ready_tasks = self.bpmn_workflow.get_tasks(TaskState.READY)
if len(ready_tasks) == 0: if len(ready_tasks) == 0:
# If no ready tasks exist, check for a waiting task. # If no ready tasks exist, check for a waiting task.
waiting_tasks = self.bpmn_workflow.get_tasks(SpiffTask.WAITING) waiting_tasks = self.bpmn_workflow.get_tasks(TaskState.WAITING)
if len(waiting_tasks) > 0: if len(waiting_tasks) > 0:
return waiting_tasks[0] return waiting_tasks[0]
else: else:
@ -398,12 +398,12 @@ class WorkflowProcessor(object):
# If there are no ready tasks, but the thing isn't complete yet, find the first non-complete task # If there are no ready tasks, but the thing isn't complete yet, find the first non-complete task
# and return that # and return that
next_task = None next_task = None
for task in SpiffTask.Iterator(self.bpmn_workflow.task_tree, SpiffTask.NOT_FINISHED_MASK): for task in SpiffTask.Iterator(self.bpmn_workflow.task_tree, TaskState.NOT_FINISHED_MASK):
next_task = task next_task = task
return next_task return next_task
def completed_user_tasks(self): def completed_user_tasks(self):
completed_user_tasks = self.bpmn_workflow.get_tasks(SpiffTask.COMPLETED) completed_user_tasks = self.bpmn_workflow.get_tasks(TaskState.COMPLETED)
completed_user_tasks.reverse() completed_user_tasks.reverse()
completed_user_tasks = list( completed_user_tasks = list(
filter(lambda task: not self.bpmn_workflow._is_engine_task(task.task_spec), completed_user_tasks)) filter(lambda task: not self.bpmn_workflow._is_engine_task(task.task_spec), completed_user_tasks))
@ -445,18 +445,19 @@ class WorkflowProcessor(object):
additional_tasks = [] additional_tasks = []
if len(ready_tasks) > 0: if len(ready_tasks) > 0:
for child in ready_tasks[0].parent.children: for child in ready_tasks[0].parent.children:
if child.state == SpiffTask.COMPLETED: if child.state == TaskState.COMPLETED:
additional_tasks.append(child) additional_tasks.append(child)
return ready_tasks + additional_tasks return ready_tasks + additional_tasks
def get_all_user_tasks(self): def get_all_user_tasks(self):
all_tasks = self.bpmn_workflow.get_tasks(SpiffTask.ANY_MASK) all_tasks = self.bpmn_workflow.get_tasks(TaskState.ANY_MASK)
return [t for t in all_tasks if not self.bpmn_workflow._is_engine_task(t.task_spec)] return [t for t in all_tasks if not self.bpmn_workflow._is_engine_task(t.task_spec)]
def get_all_completed_tasks(self): def get_all_completed_tasks(self):
all_tasks = self.bpmn_workflow.get_tasks(SpiffTask.ANY_MASK) all_tasks = self.bpmn_workflow.get_tasks(TaskState.ANY_MASK)
return [t for t in all_tasks return [t for t in all_tasks
if not self.bpmn_workflow._is_engine_task(t.task_spec) and t.state in [t.COMPLETED, t.CANCELLED]] if not self.bpmn_workflow._is_engine_task(t.task_spec) and
t.state in [TaskState.COMPLETED, TaskState.CANCELLED]]
def get_nav_item(self, task): def get_nav_item(self, task):
for nav_item in self.bpmn_workflow.get_nav_list(): for nav_item in self.bpmn_workflow.get_nav_list():

View File

@ -8,7 +8,7 @@ from datetime import datetime
from typing import List from typing import List
import jinja2 import jinja2
from SpiffWorkflow import Task as SpiffTask, WorkflowException, NavItem from SpiffWorkflow import Task as SpiffTask, WorkflowException, NavItem, TaskState
from SpiffWorkflow.bpmn.PythonScriptEngine import Box from SpiffWorkflow.bpmn.PythonScriptEngine import Box
from SpiffWorkflow.bpmn.specs.ManualTask import ManualTask from SpiffWorkflow.bpmn.specs.ManualTask import ManualTask
from SpiffWorkflow.bpmn.specs.ScriptTask import ScriptTask from SpiffWorkflow.bpmn.specs.ScriptTask import ScriptTask
@ -188,7 +188,7 @@ class WorkflowService(object):
f"The validation has been exited early on task '{exit_task.task_spec.id}' " f"The validation has been exited early on task '{exit_task.task_spec.id}' "
f"and was parented by ", f"and was parented by ",
exit_task.parent) exit_task.parent)
tasks = processor.bpmn_workflow.get_tasks(SpiffTask.READY) tasks = processor.bpmn_workflow.get_tasks(TaskState.READY)
for task in tasks: for task in tasks:
if task.task_spec.lane is not None and task.task_spec.lane not in task.data: if task.task_spec.lane is not None and task.task_spec.lane not in task.data:
raise ApiError.from_task("invalid_role", raise ApiError.from_task("invalid_role",
@ -805,7 +805,7 @@ class WorkflowService(object):
# All ready tasks should have a valid name, and this can be computed for # All ready tasks should have a valid name, and this can be computed for
# some tasks, particularly multi-instance tasks that all have the same spec # some tasks, particularly multi-instance tasks that all have the same spec
# but need different labels. # but need different labels.
if spiff_task.state == SpiffTask.READY: if spiff_task.state == TaskState.READY:
task.properties = WorkflowService._process_properties(spiff_task, props) task.properties = WorkflowService._process_properties(spiff_task, props)
task.title = WorkflowService.__calculate_title(spiff_task) task.title = WorkflowService.__calculate_title(spiff_task)
@ -838,7 +838,7 @@ class WorkflowService(object):
# if the task is ready, we should raise an error, but if it is in the future or the past, we may not # if the task is ready, we should raise an error, but if it is in the future or the past, we may not
# have the information we need to properly set the title, so don't error out, and just use what is # have the information we need to properly set the title, so don't error out, and just use what is
# provided. # provided.
if spiff_task.state == spiff_task.READY: if spiff_task.state == TaskState.READY:
raise ApiError.from_task(code="task_title_error", raise ApiError.from_task(code="task_title_error",
message="Could not set task title on task %s with '%s' property because %s" % message="Could not set task title on task %s with '%s' property because %s" %
(spiff_task.task_spec.name, Task.PROP_EXTENSIONS_TITLE, str(e)), (spiff_task.task_spec.name, Task.PROP_EXTENSIONS_TITLE, str(e)),

View File

@ -1,5 +1,6 @@
import os import os
from SpiffWorkflow import TaskState
from SpiffWorkflow.bpmn.serializer.BpmnSerializer import BpmnSerializer from SpiffWorkflow.bpmn.serializer.BpmnSerializer import BpmnSerializer
from tests.base_test import BaseTest from tests.base_test import BaseTest
@ -177,7 +178,7 @@ class TestWorkflowProcessor(BaseTest):
processor.do_engine_steps() processor.do_engine_steps()
task = processor.next_task() task = processor.next_task()
self.assertIsNotNone(task) self.assertIsNotNone(task)
self.assertEqual(task.state, task.WAITING) self.assertEqual(task.state, TaskState.WAITING)
def test_workflow_validation_error_is_properly_raised(self): def test_workflow_validation_error_is_properly_raised(self):