From 76fac5fb6dbfc83a617232395844b6b4d3c45ac5 Mon Sep 17 00:00:00 2001 From: jbirddog <100367399+jbirddog@users.noreply.github.com> Date: Wed, 2 Nov 2022 14:34:59 -0400 Subject: [PATCH 01/12] From the logs, allow viewing a diagram in a previous state (#15) Co-authored-by: Elizabeth Esswein --- .../{bdd1d64689db_.py => b1647eff45c9_.py} | 20 +++++- .../src/spiffworkflow_backend/api.yml | 6 ++ .../load_database_models.py | 3 + .../models/process_instance.py | 2 + .../models/spiff_logging.py | 1 + .../models/spiff_step_details.py | 23 +++++++ .../routes/process_api_blueprint.py | 17 ++++- .../services/logging_service.py | 8 +++ .../services/process_instance_processor.py | 62 ++++++++++++++++--- .../unit/test_spiff_logging.py | 1 + .../src/routes/AdminRoutes.tsx | 4 ++ .../src/routes/ProcessInstanceLogList.tsx | 11 +++- .../src/routes/ProcessInstanceShow.tsx | 14 +++-- 13 files changed, 155 insertions(+), 17 deletions(-) rename spiffworkflow-backend/migrations/versions/{bdd1d64689db_.py => b1647eff45c9_.py} (95%) create mode 100644 spiffworkflow-backend/src/spiffworkflow_backend/models/spiff_step_details.py diff --git a/spiffworkflow-backend/migrations/versions/bdd1d64689db_.py b/spiffworkflow-backend/migrations/versions/b1647eff45c9_.py similarity index 95% rename from spiffworkflow-backend/migrations/versions/bdd1d64689db_.py rename to spiffworkflow-backend/migrations/versions/b1647eff45c9_.py index 555661497..d6ff25e3b 100644 --- a/spiffworkflow-backend/migrations/versions/bdd1d64689db_.py +++ b/spiffworkflow-backend/migrations/versions/b1647eff45c9_.py @@ -1,8 +1,8 @@ """empty message -Revision ID: bdd1d64689db +Revision ID: b1647eff45c9 Revises: -Create Date: 2022-11-02 11:31:50.606843 +Create Date: 2022-11-02 14:25:09.992800 """ from alembic import op @@ -10,7 +10,7 @@ import sqlalchemy as sa # revision identifiers, used by Alembic. -revision = 'bdd1d64689db' +revision = 'b1647eff45c9' down_revision = None branch_labels = None depends_on = None @@ -106,6 +106,7 @@ def upgrade(): sa.Column('status', sa.String(length=50), nullable=True), sa.Column('bpmn_version_control_type', sa.String(length=50), nullable=True), sa.Column('bpmn_version_control_identifier', sa.String(length=255), nullable=True), + sa.Column('spiff_step', sa.Integer(), nullable=True), sa.ForeignKeyConstraint(['process_initiator_id'], ['user.id'], ), sa.PrimaryKeyConstraint('id') ) @@ -229,10 +230,22 @@ def upgrade(): sa.Column('timestamp', sa.DECIMAL(precision=17, scale=6), nullable=False), sa.Column('message', sa.String(length=255), nullable=True), sa.Column('current_user_id', sa.Integer(), nullable=True), + sa.Column('spiff_step', sa.Integer(), nullable=False), sa.ForeignKeyConstraint(['current_user_id'], ['user.id'], ), sa.ForeignKeyConstraint(['process_instance_id'], ['process_instance.id'], ), sa.PrimaryKeyConstraint('id') ) + op.create_table('spiff_step_details', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('process_instance_id', sa.Integer(), nullable=False), + sa.Column('spiff_step', sa.Integer(), nullable=False), + sa.Column('task_json', sa.JSON(), nullable=False), + sa.Column('timestamp', sa.DECIMAL(precision=17, scale=6), nullable=False), + sa.Column('completed_by_user_id', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['completed_by_user_id'], ['user.id'], ), + sa.ForeignKeyConstraint(['process_instance_id'], ['process_instance.id'], ), + sa.PrimaryKeyConstraint('id') + ) op.create_table('active_task_user', sa.Column('id', sa.Integer(), nullable=False), sa.Column('active_task_id', sa.Integer(), nullable=False), @@ -266,6 +279,7 @@ def downgrade(): op.drop_index(op.f('ix_active_task_user_user_id'), table_name='active_task_user') op.drop_index(op.f('ix_active_task_user_active_task_id'), table_name='active_task_user') op.drop_table('active_task_user') + op.drop_table('spiff_step_details') op.drop_table('spiff_logging') op.drop_table('permission_assignment') op.drop_table('message_instance') diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/api.yml b/spiffworkflow-backend/src/spiffworkflow_backend/api.yml index 614d4f26c..0f0a49c24 100755 --- a/spiffworkflow-backend/src/spiffworkflow_backend/api.yml +++ b/spiffworkflow-backend/src/spiffworkflow_backend/api.yml @@ -1000,6 +1000,12 @@ paths: description: If true, this wil return all tasks associated with the process instance and not just user tasks. schema: type: boolean + - name: spiff_step + in: query + required: false + description: If set will return the tasks as they were during a specific step of execution. + schema: + type: integer get: tags: - Process Instances diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/load_database_models.py b/spiffworkflow-backend/src/spiffworkflow_backend/load_database_models.py index 7283b19b1..14dcac0dc 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/load_database_models.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/load_database_models.py @@ -46,6 +46,9 @@ from spiffworkflow_backend.models.process_instance_report import ( from spiffworkflow_backend.models.refresh_token import RefreshTokenModel # noqa: F401 from spiffworkflow_backend.models.secret_model import SecretModel # noqa: F401 from spiffworkflow_backend.models.spiff_logging import SpiffLoggingModel # noqa: F401 +from spiffworkflow_backend.models.spiff_step_details import ( + SpiffStepDetailsModel, +) # noqa: F401 from spiffworkflow_backend.models.user import UserModel # noqa: F401 from spiffworkflow_backend.models.group import GroupModel # noqa: F401 diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/models/process_instance.py b/spiffworkflow-backend/src/spiffworkflow_backend/models/process_instance.py index 1c2098e91..0e4112d6a 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/models/process_instance.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/models/process_instance.py @@ -81,6 +81,7 @@ class ProcessInstanceModel(SpiffworkflowBaseDBModel): spiff_logs = relationship("SpiffLoggingModel", cascade="delete") # type: ignore message_instances = relationship("MessageInstanceModel", cascade="delete") # type: ignore message_correlations = relationship("MessageCorrelationModel", cascade="delete") # type: ignore + spiff_step_details = relationship("SpiffStepDetailsModel", cascade="delete") # type: ignore bpmn_json: str | None = deferred(db.Column(db.JSON)) # type: ignore start_in_seconds: int | None = db.Column(db.Integer) @@ -92,6 +93,7 @@ class ProcessInstanceModel(SpiffworkflowBaseDBModel): bpmn_xml_file_contents: bytes | None = None bpmn_version_control_type: str = db.Column(db.String(50)) bpmn_version_control_identifier: str = db.Column(db.String(255)) + spiff_step: int = db.Column(db.Integer) @property def serialized(self) -> dict[str, Any]: diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/models/spiff_logging.py b/spiffworkflow-backend/src/spiffworkflow_backend/models/spiff_logging.py index a655ec513..58f13cd4e 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/models/spiff_logging.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/models/spiff_logging.py @@ -25,3 +25,4 @@ class SpiffLoggingModel(SpiffworkflowBaseDBModel): timestamp: float = db.Column(db.DECIMAL(17, 6), nullable=False) message: Optional[str] = db.Column(db.String(255), nullable=True) current_user_id: int = db.Column(ForeignKey(UserModel.id), nullable=True) + spiff_step: int = db.Column(db.Integer, nullable=False) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/models/spiff_step_details.py b/spiffworkflow-backend/src/spiffworkflow_backend/models/spiff_step_details.py new file mode 100644 index 000000000..1706c2e91 --- /dev/null +++ b/spiffworkflow-backend/src/spiffworkflow_backend/models/spiff_step_details.py @@ -0,0 +1,23 @@ +"""Spiff_step_details.""" +from dataclasses import dataclass + +from flask_bpmn.models.db import db +from flask_bpmn.models.db import SpiffworkflowBaseDBModel +from sqlalchemy import ForeignKey +from sqlalchemy.orm import deferred + +from spiffworkflow_backend.models.process_instance import ProcessInstanceModel +from spiffworkflow_backend.models.user import UserModel + + +@dataclass +class SpiffStepDetailsModel(SpiffworkflowBaseDBModel): + """SpiffStepDetailsModel.""" + + __tablename__ = "spiff_step_details" + id: int = db.Column(db.Integer, primary_key=True) + process_instance_id: int = db.Column(ForeignKey(ProcessInstanceModel.id), nullable=False) # type: ignore + spiff_step: int = db.Column(db.Integer, nullable=False) + task_json: str | None = deferred(db.Column(db.JSON, nullable=False)) # type: ignore + timestamp: float = db.Column(db.DECIMAL(17, 6), nullable=False) + completed_by_user_id: int = db.Column(ForeignKey(UserModel.id), nullable=True) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_api_blueprint.py b/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_api_blueprint.py index 0523ad255..41cd9d996 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_api_blueprint.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_api_blueprint.py @@ -56,6 +56,7 @@ from spiffworkflow_backend.models.process_model import ProcessModelInfoSchema from spiffworkflow_backend.models.secret_model import SecretModel from spiffworkflow_backend.models.secret_model import SecretModelSchema from spiffworkflow_backend.models.spiff_logging import SpiffLoggingModel +from spiffworkflow_backend.models.spiff_step_details import SpiffStepDetailsModel from spiffworkflow_backend.models.user import UserModel from spiffworkflow_backend.routes.user import verify_token from spiffworkflow_backend.services.authorization_service import AuthorizationService @@ -954,10 +955,23 @@ def task_list_my_tasks(page: int = 1, per_page: int = 100) -> flask.wrappers.Res def process_instance_task_list( - process_instance_id: int, all_tasks: bool = False + process_instance_id: int, all_tasks: bool = False, spiff_step: int = 0 ) -> flask.wrappers.Response: """Process_instance_task_list.""" process_instance = find_process_instance_by_id_or_raise(process_instance_id) + + if spiff_step > 0: + step_detail = ( + db.session.query(SpiffStepDetailsModel) + .filter( + SpiffStepDetailsModel.process_instance_id == process_instance.id, + SpiffStepDetailsModel.spiff_step == spiff_step, + ) + .first() + ) + if step_detail is not None: + process_instance.bpmn_json = json.dumps(step_detail.task_json) + processor = ProcessInstanceProcessor(process_instance) spiff_tasks = None @@ -1233,6 +1247,7 @@ def script_unit_test_run( """Script_unit_test_run.""" # FIXME: We should probably clear this somewhere else but this works current_app.config["THREAD_LOCAL_DATA"].process_instance_id = None + current_app.config["THREAD_LOCAL_DATA"].spiff_step = None python_script = _get_required_parameter_or_raise("python_script", body) input_json = _get_required_parameter_or_raise("input_json", body) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/logging_service.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/logging_service.py index ce30e8b92..13f66e00d 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/logging_service.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/logging_service.py @@ -108,6 +108,8 @@ class SpiffFilter(logging.Filter): if hasattr(tld, "process_instance_id"): process_instance_id = tld.process_instance_id setattr(record, "process_instance_id", process_instance_id) # noqa: B010 + if hasattr(tld, "spiff_step"): + setattr(record, "spiff_step", tld.spiff_step) # noqa: 8010 if hasattr(g, "user") and g.user: setattr(record, "current_user_id", g.user.id) # noqa: B010 return True @@ -204,6 +206,11 @@ class DBHandler(logging.Handler): timestamp = record.created message = record.msg if hasattr(record, "msg") else None current_user_id = record.current_user_id if hasattr(record, "current_user_id") else None # type: ignore + spiff_step = ( + record.spiff_step # type: ignore + if hasattr(record, "spiff_step") and record.spiff_step is not None # type: ignore + else 1 + ) spiff_log = SpiffLoggingModel( process_instance_id=record.process_instance_id, # type: ignore bpmn_process_identifier=bpmn_process_identifier, @@ -214,6 +221,7 @@ class DBHandler(logging.Handler): message=message, timestamp=timestamp, current_user_id=current_user_id, + spiff_step=spiff_step, ) db.session.add(spiff_log) db.session.commit() diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py index fecde1b90..aa94704c1 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py @@ -79,6 +79,7 @@ from spiffworkflow_backend.models.process_model import ProcessModelInfo from spiffworkflow_backend.models.script_attributes_context import ( ScriptAttributesContext, ) +from spiffworkflow_backend.models.spiff_step_details import SpiffStepDetailsModel from spiffworkflow_backend.models.user import UserModel from spiffworkflow_backend.models.user import UserModelSchema from spiffworkflow_backend.scripts.script import Script @@ -276,9 +277,9 @@ class ProcessInstanceProcessor: self, process_instance_model: ProcessInstanceModel, validate_only: bool = False ) -> None: """Create a Workflow Processor based on the serialized information available in the process_instance model.""" - current_app.config[ - "THREAD_LOCAL_DATA" - ].process_instance_id = process_instance_model.id + tld = current_app.config["THREAD_LOCAL_DATA"] + tld.process_instance_id = process_instance_model.id + tld.spiff_step = process_instance_model.spiff_step # we want this to be the fully qualified path to the process model including all group subcomponents current_app.config["THREAD_LOCAL_DATA"].process_model_identifier = ( @@ -411,10 +412,8 @@ class ProcessInstanceProcessor: bpmn_process_spec, subprocesses ) - def add_user_info_to_process_instance( - self, bpmn_process_instance: BpmnWorkflow - ) -> None: - """Add_user_info_to_process_instance.""" + def current_user(self) -> Any: + """Current_user.""" current_user = None if UserService.has_user(): current_user = UserService.current_user() @@ -425,6 +424,14 @@ class ProcessInstanceProcessor: elif self.process_instance_model.process_initiator_id: current_user = self.process_instance_model.process_initiator + return current_user + + def add_user_info_to_process_instance( + self, bpmn_process_instance: BpmnWorkflow + ) -> None: + """Add_user_info_to_process_instance.""" + current_user = self.current_user() + if current_user: current_user_data = UserModelSchema().dump(current_user) tasks = bpmn_process_instance.get_tasks(TaskState.READY) @@ -542,9 +549,32 @@ class ProcessInstanceProcessor: "lane_assignment_id": lane_assignment_id, } + def save_spiff_step_details(self, bpmn_json: Optional[str]) -> None: + """SaveSpiffStepDetails.""" + if bpmn_json is None: + return + wf_json = json.loads(bpmn_json) + task_json = "{}" + if "tasks" in wf_json: + task_json = json.dumps(wf_json["tasks"]) + + # TODO want to just save the tasks, something wasn't immediately working + # so after the flow works with the full wf_json revisit this + task_json = wf_json + details_model = SpiffStepDetailsModel( + process_instance_id=self.process_instance_model.id, + spiff_step=self.process_instance_model.spiff_step or 1, + task_json=task_json, + timestamp=round(time.time()), + completed_by_user_id=self.current_user().id, + ) + db.session.add(details_model) + db.session.commit() + def save(self) -> None: """Saves the current state of this processor to the database.""" self.process_instance_model.bpmn_json = self.serialize() + complete_states = [TaskState.CANCELLED, TaskState.COMPLETED] user_tasks = list(self.get_all_user_tasks()) self.process_instance_model.status = self.get_status().value @@ -930,8 +960,19 @@ class ProcessInstanceProcessor: db.session.commit() + def increment_spiff_step(self) -> None: + """Spiff_step++.""" + spiff_step = self.process_instance_model.spiff_step or 0 + spiff_step += 1 + self.process_instance_model.spiff_step = spiff_step + current_app.config["THREAD_LOCAL_DATA"].spiff_step = spiff_step + db.session.add(self.process_instance_model) + db.session.commit() + def do_engine_steps(self, exit_at: None = None, save: bool = False) -> None: """Do_engine_steps.""" + self.increment_spiff_step() + try: self.bpmn_process_instance.refresh_waiting_tasks() self.bpmn_process_instance.do_engine_steps(exit_at=exit_at) @@ -944,6 +985,10 @@ class ProcessInstanceProcessor: finally: if save: self.save() + bpmn_json = self.process_instance_model.bpmn_json + else: + bpmn_json = self.serialize() + self.save_spiff_step_details(bpmn_json) def cancel_notify(self) -> None: """Cancel_notify.""" @@ -1054,7 +1099,10 @@ class ProcessInstanceProcessor: def complete_task(self, task: SpiffTask) -> None: """Complete_task.""" + self.increment_spiff_step() self.bpmn_process_instance.complete_task_from_id(task.id) + bpmn_json = self.serialize() + self.save_spiff_step_details(bpmn_json) def get_data(self) -> dict[str, Any]: """Get_data.""" diff --git a/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_spiff_logging.py b/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_spiff_logging.py index c4a5984f1..d8680b719 100644 --- a/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_spiff_logging.py +++ b/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_spiff_logging.py @@ -36,6 +36,7 @@ class TestSpiffLogging(BaseTest): bpmn_task_identifier=bpmn_task_identifier, message=message, timestamp=timestamp, + spiff_step=1, ) assert spiff_log.timestamp == timestamp diff --git a/spiffworkflow-frontend/src/routes/AdminRoutes.tsx b/spiffworkflow-frontend/src/routes/AdminRoutes.tsx index c3e39e16e..776a5f341 100644 --- a/spiffworkflow-frontend/src/routes/AdminRoutes.tsx +++ b/spiffworkflow-frontend/src/routes/AdminRoutes.tsx @@ -76,6 +76,10 @@ export default function AdminRoutes() { path="process-models/:process_group_id/:process_model_id/process-instances/:process_instance_id" element={} /> + } + /> } diff --git a/spiffworkflow-frontend/src/routes/ProcessInstanceLogList.tsx b/spiffworkflow-frontend/src/routes/ProcessInstanceLogList.tsx index f2d297f02..83e56ac54 100644 --- a/spiffworkflow-frontend/src/routes/ProcessInstanceLogList.tsx +++ b/spiffworkflow-frontend/src/routes/ProcessInstanceLogList.tsx @@ -1,6 +1,6 @@ import { useEffect, useState } from 'react'; import { Table } from 'react-bootstrap'; -import { useParams, useSearchParams } from 'react-router-dom'; +import { useParams, useSearchParams, Link } from 'react-router-dom'; import PaginationForTable from '../components/PaginationForTable'; import ProcessBreadcrumb from '../components/ProcessBreadcrumb'; import { @@ -39,7 +39,14 @@ export default function ProcessInstanceLogList() { {rowToUse.bpmn_task_name} {rowToUse.bpmn_task_type} {rowToUse.username} - {convertSecondsToFormattedDate(rowToUse.timestamp)} + + + {convertSecondsToFormattedDate(rowToUse.timestamp)} + + ); }); diff --git a/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx b/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx index f5336df8f..010a7f48e 100644 --- a/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx +++ b/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx @@ -32,10 +32,16 @@ export default function ProcessInstanceShow() { path: `/process-models/${params.process_group_id}/${params.process_model_id}/process-instances/${params.process_instance_id}`, successCallback: setProcessInstance, }); - HttpService.makeCallToBackend({ - path: `/process-instance/${params.process_instance_id}/tasks?all_tasks=true`, - successCallback: setTasks, - }); + if (typeof params.spiff_step === 'undefined') + HttpService.makeCallToBackend({ + path: `/process-instance/${params.process_instance_id}/tasks?all_tasks=true`, + successCallback: setTasks, + }); + else + HttpService.makeCallToBackend({ + path: `/process-instance/${params.process_instance_id}/tasks?all_tasks=true&spiff_step=${params.spiff_step}`, + successCallback: setTasks, + }); }, [params]); const deleteProcessInstance = () => { From 48d211ab8fc544fa05643a7e382ef1985ed797f4 Mon Sep 17 00:00:00 2001 From: Jon Herron Date: Wed, 2 Nov 2022 15:21:51 -0400 Subject: [PATCH 02/12] Prettier --- spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx b/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx index 010a7f48e..677e5b09a 100644 --- a/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx +++ b/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx @@ -36,12 +36,12 @@ export default function ProcessInstanceShow() { HttpService.makeCallToBackend({ path: `/process-instance/${params.process_instance_id}/tasks?all_tasks=true`, successCallback: setTasks, - }); + }); else HttpService.makeCallToBackend({ path: `/process-instance/${params.process_instance_id}/tasks?all_tasks=true&spiff_step=${params.spiff_step}`, successCallback: setTasks, - }); + }); }, [params]); const deleteProcessInstance = () => { From 04172f2c10dce36a9492f82027958e5c05a11e40 Mon Sep 17 00:00:00 2001 From: jbirddog <100367399+jbirddog@users.noreply.github.com> Date: Thu, 3 Nov 2022 11:11:32 -0400 Subject: [PATCH 03/12] Fix FutureWarning in SpiffWorkflow (#16) --- SpiffWorkflow/SpiffWorkflow/bpmn/parser/node_parser.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/SpiffWorkflow/SpiffWorkflow/bpmn/parser/node_parser.py b/SpiffWorkflow/SpiffWorkflow/bpmn/parser/node_parser.py index b76ccfbb6..0b1c8ed46 100644 --- a/SpiffWorkflow/SpiffWorkflow/bpmn/parser/node_parser.py +++ b/SpiffWorkflow/SpiffWorkflow/bpmn/parser/node_parser.py @@ -35,7 +35,8 @@ class NodeParser: return expression.text if expression is not None else None def parse_documentation(self, sequence_flow=None): - documentation_node = first(self._xpath(sequence_flow or self.node, './/bpmn:documentation')) + node = sequence_flow if sequence_flow is not None else self.node + documentation_node = first(self._xpath(node, './/bpmn:documentation')) return None if documentation_node is None else documentation_node.text def parse_incoming_data_references(self): From 55cb9f4fd07b3a72af1cb029655eaae1bc266525 Mon Sep 17 00:00:00 2001 From: jbirddog <100367399+jbirddog@users.noreply.github.com> Date: Thu, 3 Nov 2022 11:12:00 -0400 Subject: [PATCH 04/12] Clear the remaining __init__.py imports in SpiffWorkflow (#14) --- .../SpiffWorkflow/bpmn/parser/BpmnParser.py | 6 +- .../SpiffWorkflow/bpmn/parser/TaskParser.py | 3 +- .../bpmn/parser/event_parsers.py | 2 +- .../serializer/CompactWorkflowSerializer.py | 2 +- .../SpiffWorkflow/bpmn/serializer/__init__.py | 3 - .../bpmn/serializer/bpmn_converters.py | 6 +- .../bpmn/serializer/task_spec_converters.py | 6 +- .../SpiffWorkflow/bpmn/specs/BpmnSpecMixin.py | 2 +- .../bpmn/specs/ExclusiveGateway.py | 2 +- .../SpiffWorkflow/bpmn/specs/ManualTask.py | 4 +- .../bpmn/specs/MultiInstanceTask.py | 2 +- .../SpiffWorkflow/bpmn/specs/NoneTask.py | 2 +- .../bpmn/specs/SubWorkflowTask.py | 2 +- .../bpmn/specs/events/__init__.py | 5 -- .../camunda/parser/CamundaParser.py | 4 +- .../camunda/serializer/__init__.py | 2 - .../serializer/task_spec_converters.py | 4 +- .../SpiffWorkflow/dmn/serializer/__init__.py | 1 - .../dmn/specs/BusinessRuleTask.py | 2 +- .../SpiffWorkflow/serializer/base.py | 65 +++++++++++++++++++ .../SpiffWorkflow/serializer/dict.py | 29 +++++++-- .../SpiffWorkflow/serializer/prettyxml.py | 26 +++----- SpiffWorkflow/SpiffWorkflow/serializer/xml.py | 46 +++++++------ .../SpiffWorkflow/signavio/parser/__init__.py | 1 - .../SpiffWorkflow/specs/SubWorkflow.py | 4 +- .../SpiffWorkflow/specs/ThreadMerge.py | 2 +- .../SpiffWorkflow/specs/WorkflowSpec.py | 4 +- SpiffWorkflow/SpiffWorkflow/specs/__init__.py | 31 --------- .../SpiffWorkflow/spiff/parser/__init__.py | 1 - .../SpiffWorkflow/spiff/parser/process.py | 11 +++- .../spiff/serializer/__init__.py | 4 -- .../spiff/serializer/task_spec_converters.py | 13 +++- .../SpiffWorkflow/spiff/specs/__init__.py | 6 -- .../spiff/specs/events/__init__.py | 1 - SpiffWorkflow/SpiffWorkflow/workflow.py | 4 +- SpiffWorkflow/doc/non-bpmn/tutorial/start.py | 2 +- .../tests/SpiffWorkflow/PatternTest.py | 2 +- .../SpiffWorkflow/PersistSmallWorkflowTest.py | 4 +- SpiffWorkflow/tests/SpiffWorkflow/TaskTest.py | 3 +- .../tests/SpiffWorkflow/WorkflowTest.py | 4 +- .../tests/SpiffWorkflow/bpmn/ApprovalsTest.py | 2 +- .../SpiffWorkflow/bpmn/BpmnLoaderForTests.py | 2 +- .../bpmn/BpmnWorkflowSerializerTest.py | 2 +- .../bpmn/BpmnWorkflowTestCase.py | 2 +- .../bpmn/ProcessDependencyTest.py | 2 +- .../bpmn/events/MultipleEventsTest.py | 2 +- .../events/TimerDurationBoundaryOnTaskTest.py | 2 +- .../SpiffWorkflow/camunda/BaseTestCase.py | 6 +- .../camunda/specs/UserTaskSpecTest.py | 3 +- .../SpiffWorkflow/data/spiff/workflow1.py | 7 +- .../SpiffWorkflow/serializer/baseTest.py | 2 +- .../tests/SpiffWorkflow/specs/CeleryTest.py | 3 +- .../tests/SpiffWorkflow/specs/ExecuteTest.py | 2 +- .../tests/SpiffWorkflow/specs/JoinTest.py | 2 +- .../tests/SpiffWorkflow/specs/MergeTest.py | 4 +- .../SpiffWorkflow/specs/SubWorkflowTest.py | 2 +- .../tests/SpiffWorkflow/specs/TaskSpecTest.py | 6 +- .../SpiffWorkflow/specs/TransformTest.py | 3 +- .../SpiffWorkflow/specs/WorkflowSpecTest.py | 3 +- .../tests/SpiffWorkflow/spiff/BaseTestCase.py | 6 +- .../services/process_instance_processor.py | 46 +++++++------ 61 files changed, 253 insertions(+), 179 deletions(-) diff --git a/SpiffWorkflow/SpiffWorkflow/bpmn/parser/BpmnParser.py b/SpiffWorkflow/SpiffWorkflow/bpmn/parser/BpmnParser.py index c6ed81bbd..e6783e052 100644 --- a/SpiffWorkflow/SpiffWorkflow/bpmn/parser/BpmnParser.py +++ b/SpiffWorkflow/SpiffWorkflow/bpmn/parser/BpmnParser.py @@ -27,8 +27,10 @@ from SpiffWorkflow.bpmn.specs.events.event_definitions import NoneEventDefinitio from .ValidationException import ValidationException from ..specs.BpmnProcessSpec import BpmnProcessSpec -from ..specs.events import StartEvent, EndEvent, BoundaryEvent, IntermediateCatchEvent, IntermediateThrowEvent -from ..specs.events import SendTask, ReceiveTask +from ..specs.events.EndEvent import EndEvent +from ..specs.events.StartEvent import StartEvent +from ..specs.events.IntermediateEvent import BoundaryEvent, IntermediateCatchEvent, IntermediateThrowEvent +from ..specs.events.IntermediateEvent import SendTask, ReceiveTask from ..specs.SubWorkflowTask import CallActivity, SubWorkflowTask, TransactionSubprocess from ..specs.ExclusiveGateway import ExclusiveGateway from ..specs.InclusiveGateway import InclusiveGateway diff --git a/SpiffWorkflow/SpiffWorkflow/bpmn/parser/TaskParser.py b/SpiffWorkflow/SpiffWorkflow/bpmn/parser/TaskParser.py index afbd19720..5291b1623 100644 --- a/SpiffWorkflow/SpiffWorkflow/bpmn/parser/TaskParser.py +++ b/SpiffWorkflow/SpiffWorkflow/bpmn/parser/TaskParser.py @@ -23,7 +23,8 @@ from .ValidationException import ValidationException from ..specs.NoneTask import NoneTask from ..specs.ScriptTask import ScriptTask from ..specs.UserTask import UserTask -from ..specs.events import _BoundaryEventParent, CancelEventDefinition +from ..specs.events.IntermediateEvent import _BoundaryEventParent +from ..specs.events.event_definitions import CancelEventDefinition from ..specs.MultiInstanceTask import getDynamicMIClass from ..specs.SubWorkflowTask import CallActivity, TransactionSubprocess, SubWorkflowTask from ..specs.ExclusiveGateway import ExclusiveGateway diff --git a/SpiffWorkflow/SpiffWorkflow/bpmn/parser/event_parsers.py b/SpiffWorkflow/SpiffWorkflow/bpmn/parser/event_parsers.py index d007fde8b..07cef338e 100644 --- a/SpiffWorkflow/SpiffWorkflow/bpmn/parser/event_parsers.py +++ b/SpiffWorkflow/SpiffWorkflow/bpmn/parser/event_parsers.py @@ -5,7 +5,7 @@ from SpiffWorkflow.bpmn.specs.events.event_definitions import CorrelationPropert from .ValidationException import ValidationException from .TaskParser import TaskParser from .util import first, one -from ..specs.events import (TimerEventDefinition, MessageEventDefinition, +from ..specs.events.event_definitions import (TimerEventDefinition, MessageEventDefinition, ErrorEventDefinition, EscalationEventDefinition, SignalEventDefinition, CancelEventDefinition, CycleTimerEventDefinition, diff --git a/SpiffWorkflow/SpiffWorkflow/bpmn/serializer/CompactWorkflowSerializer.py b/SpiffWorkflow/SpiffWorkflow/bpmn/serializer/CompactWorkflowSerializer.py index ac38dc6bc..9ed543fbf 100644 --- a/SpiffWorkflow/SpiffWorkflow/bpmn/serializer/CompactWorkflowSerializer.py +++ b/SpiffWorkflow/SpiffWorkflow/bpmn/serializer/CompactWorkflowSerializer.py @@ -23,7 +23,7 @@ from builtins import object from collections import deque import json from ...task import TaskState -from ...specs import SubWorkflow +from ...specs.Subworkflow import SubWorkflow from ...serializer.base import Serializer from ..workflow import BpmnWorkflow diff --git a/SpiffWorkflow/SpiffWorkflow/bpmn/serializer/__init__.py b/SpiffWorkflow/SpiffWorkflow/bpmn/serializer/__init__.py index 507b6257b..9a31a4077 100644 --- a/SpiffWorkflow/SpiffWorkflow/bpmn/serializer/__init__.py +++ b/SpiffWorkflow/SpiffWorkflow/bpmn/serializer/__init__.py @@ -15,6 +15,3 @@ # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301 USA - -from .workflow import BpmnWorkflowSerializer -from .bpmn_converters import BpmnDataConverter \ No newline at end of file diff --git a/SpiffWorkflow/SpiffWorkflow/bpmn/serializer/bpmn_converters.py b/SpiffWorkflow/SpiffWorkflow/bpmn/serializer/bpmn_converters.py index 99666b344..1e274c21f 100644 --- a/SpiffWorkflow/SpiffWorkflow/bpmn/serializer/bpmn_converters.py +++ b/SpiffWorkflow/SpiffWorkflow/bpmn/serializer/bpmn_converters.py @@ -7,9 +7,9 @@ from SpiffWorkflow.bpmn.specs.BpmnProcessSpec import BpmnDataSpecification from .dictionary import DictionaryConverter -from ..specs.events import SignalEventDefinition, MessageEventDefinition, NoneEventDefinition -from ..specs.events import TimerEventDefinition, CycleTimerEventDefinition, TerminateEventDefinition -from ..specs.events import ErrorEventDefinition, EscalationEventDefinition, CancelEventDefinition +from ..specs.events.event_definitions import SignalEventDefinition, MessageEventDefinition, NoneEventDefinition +from ..specs.events.event_definitions import TimerEventDefinition, CycleTimerEventDefinition, TerminateEventDefinition +from ..specs.events.event_definitions import ErrorEventDefinition, EscalationEventDefinition, CancelEventDefinition from ..specs.events.event_definitions import CorrelationProperty, NamedEventDefinition from ..specs.BpmnSpecMixin import BpmnSpecMixin, SequenceFlow diff --git a/SpiffWorkflow/SpiffWorkflow/bpmn/serializer/task_spec_converters.py b/SpiffWorkflow/SpiffWorkflow/bpmn/serializer/task_spec_converters.py index e2af6b321..852ebe4de 100644 --- a/SpiffWorkflow/SpiffWorkflow/bpmn/serializer/task_spec_converters.py +++ b/SpiffWorkflow/SpiffWorkflow/bpmn/serializer/task_spec_converters.py @@ -2,7 +2,7 @@ from uuid import UUID from .bpmn_converters import BpmnTaskSpecConverter -from ...specs import StartTask +from ...specs.StartTask import StartTask from ...specs.Simple import Simple from ...specs.LoopResetTask import LoopResetTask @@ -19,7 +19,9 @@ from ..specs.ExclusiveGateway import ExclusiveGateway from ..specs.InclusiveGateway import InclusiveGateway from ..specs.ParallelGateway import ParallelGateway -from ..specs.events import StartEvent, EndEvent, BoundaryEvent, IntermediateCatchEvent, IntermediateThrowEvent +from ..specs.events.StartEvent import StartEvent +from ..specs.events.EndEvent import EndEvent +from ..specs.events.IntermediateEvent import BoundaryEvent, IntermediateCatchEvent, IntermediateThrowEvent from ..specs.events.IntermediateEvent import _BoundaryEventParent, SendTask, ReceiveTask from ..workflow import BpmnWorkflow diff --git a/SpiffWorkflow/SpiffWorkflow/bpmn/specs/BpmnSpecMixin.py b/SpiffWorkflow/SpiffWorkflow/bpmn/specs/BpmnSpecMixin.py index 3b8f4b26f..459a38828 100644 --- a/SpiffWorkflow/SpiffWorkflow/bpmn/specs/BpmnSpecMixin.py +++ b/SpiffWorkflow/SpiffWorkflow/bpmn/specs/BpmnSpecMixin.py @@ -19,7 +19,7 @@ from ...task import TaskState from ...operators import Operator -from ...specs import TaskSpec +from ...specs.base import TaskSpec class _BpmnCondition(Operator): diff --git a/SpiffWorkflow/SpiffWorkflow/bpmn/specs/ExclusiveGateway.py b/SpiffWorkflow/SpiffWorkflow/bpmn/specs/ExclusiveGateway.py index 391a29325..89a1445ff 100644 --- a/SpiffWorkflow/SpiffWorkflow/bpmn/specs/ExclusiveGateway.py +++ b/SpiffWorkflow/SpiffWorkflow/bpmn/specs/ExclusiveGateway.py @@ -19,7 +19,7 @@ from ...exceptions import WorkflowException from .BpmnSpecMixin import BpmnSpecMixin -from ...specs import TaskSpec +from ...specs.base import TaskSpec from ...specs.ExclusiveChoice import ExclusiveChoice diff --git a/SpiffWorkflow/SpiffWorkflow/bpmn/specs/ManualTask.py b/SpiffWorkflow/SpiffWorkflow/bpmn/specs/ManualTask.py index a02834457..c8d4e7c25 100644 --- a/SpiffWorkflow/SpiffWorkflow/bpmn/specs/ManualTask.py +++ b/SpiffWorkflow/SpiffWorkflow/bpmn/specs/ManualTask.py @@ -18,7 +18,7 @@ # 02110-1301 USA from ...bpmn.specs.BpmnSpecMixin import BpmnSpecMixin -from ...specs import Simple +from ...specs.Simple import Simple class ManualTask(Simple, BpmnSpecMixin): @@ -32,4 +32,4 @@ class ManualTask(Simple, BpmnSpecMixin): @property def spec_type(self): - return 'Manual Task' \ No newline at end of file + return 'Manual Task' diff --git a/SpiffWorkflow/SpiffWorkflow/bpmn/specs/MultiInstanceTask.py b/SpiffWorkflow/SpiffWorkflow/bpmn/specs/MultiInstanceTask.py index 77886d547..f0ceb3dea 100644 --- a/SpiffWorkflow/SpiffWorkflow/bpmn/specs/MultiInstanceTask.py +++ b/SpiffWorkflow/SpiffWorkflow/bpmn/specs/MultiInstanceTask.py @@ -29,7 +29,7 @@ from .ScriptTask import ScriptTask from .ExclusiveGateway import ExclusiveGateway from ...dmn.specs.BusinessRuleTask import BusinessRuleTask from ...operators import valueof, is_number -from ...specs import SubWorkflow +from ...specs.SubWorkflow import SubWorkflow from ...specs.base import TaskSpec from ...util.impl import get_class from ...task import Task, TaskState diff --git a/SpiffWorkflow/SpiffWorkflow/bpmn/specs/NoneTask.py b/SpiffWorkflow/SpiffWorkflow/bpmn/specs/NoneTask.py index 28abc80cc..5c844e90f 100644 --- a/SpiffWorkflow/SpiffWorkflow/bpmn/specs/NoneTask.py +++ b/SpiffWorkflow/SpiffWorkflow/bpmn/specs/NoneTask.py @@ -16,7 +16,7 @@ # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301 USA -from ...specs import Simple +from ...specs.Simple import Simple from ...bpmn.specs.BpmnSpecMixin import BpmnSpecMixin diff --git a/SpiffWorkflow/SpiffWorkflow/bpmn/specs/SubWorkflowTask.py b/SpiffWorkflow/SpiffWorkflow/bpmn/specs/SubWorkflowTask.py index c8b4409e7..6f616f1d3 100644 --- a/SpiffWorkflow/SpiffWorkflow/bpmn/specs/SubWorkflowTask.py +++ b/SpiffWorkflow/SpiffWorkflow/bpmn/specs/SubWorkflowTask.py @@ -3,7 +3,7 @@ from copy import deepcopy from SpiffWorkflow.task import TaskState from .BpmnSpecMixin import BpmnSpecMixin -from ...specs import TaskSpec +from ...specs.base import TaskSpec class SubWorkflowTask(BpmnSpecMixin): diff --git a/SpiffWorkflow/SpiffWorkflow/bpmn/specs/events/__init__.py b/SpiffWorkflow/SpiffWorkflow/bpmn/specs/events/__init__.py index b4d526658..e69de29bb 100644 --- a/SpiffWorkflow/SpiffWorkflow/bpmn/specs/events/__init__.py +++ b/SpiffWorkflow/SpiffWorkflow/bpmn/specs/events/__init__.py @@ -1,5 +0,0 @@ -from .StartEvent import StartEvent -from .EndEvent import EndEvent -from .IntermediateEvent import IntermediateCatchEvent, IntermediateThrowEvent, BoundaryEvent, _BoundaryEventParent, SendTask, ReceiveTask -from .event_definitions import (NoneEventDefinition, CancelEventDefinition, ErrorEventDefinition, EscalationEventDefinition, MessageEventDefinition, - SignalEventDefinition, TimerEventDefinition, CycleTimerEventDefinition, TerminateEventDefinition) \ No newline at end of file diff --git a/SpiffWorkflow/SpiffWorkflow/camunda/parser/CamundaParser.py b/SpiffWorkflow/SpiffWorkflow/camunda/parser/CamundaParser.py index b9d0dc268..e91be639a 100644 --- a/SpiffWorkflow/SpiffWorkflow/camunda/parser/CamundaParser.py +++ b/SpiffWorkflow/SpiffWorkflow/camunda/parser/CamundaParser.py @@ -6,7 +6,9 @@ from SpiffWorkflow.dmn.parser.BpmnDmnParser import BpmnDmnParser from SpiffWorkflow.dmn.specs.BusinessRuleTask import BusinessRuleTask from SpiffWorkflow.camunda.parser.task_spec import BusinessRuleTaskParser -from SpiffWorkflow.bpmn.specs.events import EndEvent, IntermediateThrowEvent, StartEvent, IntermediateCatchEvent, BoundaryEvent +from SpiffWorkflow.bpmn.specs.events.StartEvent import StartEvent +from SpiffWorkflow.bpmn.specs.events.EndEvent import EndEvent +from SpiffWorkflow.bpmn.specs.events.IntermediateEvent import IntermediateThrowEvent, IntermediateCatchEvent, BoundaryEvent from .event_parsers import CamundaStartEventParser, CamundaEndEventParser, \ CamundaIntermediateCatchEventParser, CamundaIntermediateThrowEventParser, CamundaBoundaryEventParser diff --git a/SpiffWorkflow/SpiffWorkflow/camunda/serializer/__init__.py b/SpiffWorkflow/SpiffWorkflow/camunda/serializer/__init__.py index 62e56488a..e69de29bb 100644 --- a/SpiffWorkflow/SpiffWorkflow/camunda/serializer/__init__.py +++ b/SpiffWorkflow/SpiffWorkflow/camunda/serializer/__init__.py @@ -1,2 +0,0 @@ -from .task_spec_converters import UserTaskConverter, StartEventConverter, EndEventConverter, \ - BoundaryEventConverter, IntermediateCatchEventConverter, IntermediateThrowEventConverter diff --git a/SpiffWorkflow/SpiffWorkflow/camunda/serializer/task_spec_converters.py b/SpiffWorkflow/SpiffWorkflow/camunda/serializer/task_spec_converters.py index bb247e33a..3f997a0e3 100644 --- a/SpiffWorkflow/SpiffWorkflow/camunda/serializer/task_spec_converters.py +++ b/SpiffWorkflow/SpiffWorkflow/camunda/serializer/task_spec_converters.py @@ -1,6 +1,8 @@ from functools import partial -from SpiffWorkflow.bpmn.specs.events import EndEvent, IntermediateThrowEvent, StartEvent, IntermediateCatchEvent, BoundaryEvent +from SpiffWorkflow.bpmn.specs.events.StartEvent import StartEvent +from SpiffWorkflow.bpmn.specs.events.EndEvent import EndEvent +from SpiffWorkflow.bpmn.specs.events.IntermediateEvent import IntermediateThrowEvent, IntermediateCatchEvent, BoundaryEvent from ..specs.events.event_definitions import MessageEventDefinition from ...bpmn.serializer.bpmn_converters import BpmnTaskSpecConverter diff --git a/SpiffWorkflow/SpiffWorkflow/dmn/serializer/__init__.py b/SpiffWorkflow/SpiffWorkflow/dmn/serializer/__init__.py index 9f493c9d7..e69de29bb 100644 --- a/SpiffWorkflow/SpiffWorkflow/dmn/serializer/__init__.py +++ b/SpiffWorkflow/SpiffWorkflow/dmn/serializer/__init__.py @@ -1 +0,0 @@ -from .task_spec_converters import BusinessRuleTaskConverter \ No newline at end of file diff --git a/SpiffWorkflow/SpiffWorkflow/dmn/specs/BusinessRuleTask.py b/SpiffWorkflow/SpiffWorkflow/dmn/specs/BusinessRuleTask.py index 4a9684f25..5825c0232 100644 --- a/SpiffWorkflow/SpiffWorkflow/dmn/specs/BusinessRuleTask.py +++ b/SpiffWorkflow/SpiffWorkflow/dmn/specs/BusinessRuleTask.py @@ -1,6 +1,6 @@ from SpiffWorkflow.bpmn.exceptions import WorkflowTaskExecException -from ...specs import Simple +from ...specs.Simple import Simple from ...bpmn.specs.BpmnSpecMixin import BpmnSpecMixin from ...util.deep_merge import DeepMerge diff --git a/SpiffWorkflow/SpiffWorkflow/serializer/base.py b/SpiffWorkflow/SpiffWorkflow/serializer/base.py index 28b2e60ab..bbf4cc251 100644 --- a/SpiffWorkflow/SpiffWorkflow/serializer/base.py +++ b/SpiffWorkflow/SpiffWorkflow/serializer/base.py @@ -16,6 +16,71 @@ from builtins import object # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301 USA +import re +from .. import operators +from .. import specs +from ..specs.AcquireMutex import AcquireMutex +from ..specs.Cancel import Cancel +from ..specs.CancelTask import CancelTask +from ..specs.Celery import Celery +from ..specs.Choose import Choose +from ..specs.ExclusiveChoice import ExclusiveChoice +from ..specs.Execute import Execute +from ..specs.Gate import Gate +from ..specs.Join import Join +from ..specs.Merge import Merge +from ..specs.MultiChoice import MultiChoice +from ..specs.MultiInstance import MultiInstance +from ..specs.ReleaseMutex import ReleaseMutex +from ..specs.Simple import Simple +from ..specs.StartTask import StartTask +from ..specs.SubWorkflow import SubWorkflow +from ..specs.ThreadStart import ThreadStart +from ..specs.ThreadMerge import ThreadMerge +from ..specs.ThreadSplit import ThreadSplit +from ..specs.Transform import Transform +from ..specs.Trigger import Trigger +from ..specs.WorkflowSpec import WorkflowSpec +from ..specs.LoopResetTask import LoopResetTask + +# Create a list of tag names out of the spec names. +def spec_map(): + return { + 'acquire-mutex': AcquireMutex, + 'cancel': Cancel, + 'cancel-task': CancelTask, + 'celery': Celery, + 'choose': Choose, + 'exclusive-choice': ExclusiveChoice, + 'execute': Execute, + 'gate': Gate, + 'join': Join, + 'merge': Merge, + 'multi-choice': MultiChoice, + 'multi-instance': MultiInstance, + 'release-mutex': ReleaseMutex, + 'simple': Simple, + 'start-task': StartTask, + 'sub-workflow': SubWorkflow, + 'thread-start': ThreadStart, + 'thread-merge': ThreadMerge, + 'thread-split': ThreadSplit, + 'transform': Transform, + 'trigger': Trigger, + 'workflow-spec': WorkflowSpec, + 'loop-reset-task': LoopResetTask, + 'task': Simple, + } + +def op_map(): + return { + 'equals': operators.Equal, + 'not-equals': operators.NotEqual, + 'less-than': operators.LessThan, + 'greater-than': operators.GreaterThan, + 'matches': operators.Match + } + class Serializer(object): diff --git a/SpiffWorkflow/SpiffWorkflow/serializer/dict.py b/SpiffWorkflow/SpiffWorkflow/serializer/dict.py index 5688b5877..8d1e3ad42 100644 --- a/SpiffWorkflow/SpiffWorkflow/serializer/dict.py +++ b/SpiffWorkflow/SpiffWorkflow/serializer/dict.py @@ -24,11 +24,30 @@ from ..util.impl import get_class from ..task import Task from ..operators import (Attrib, PathAttrib, Equal, NotEqual, Operator, GreaterThan, LessThan, Match) -from ..specs import (Cancel, AcquireMutex, CancelTask, Celery, Choose, - ExclusiveChoice, Execute, Gate, Join, MultiChoice, - MultiInstance, ReleaseMutex, Simple, WorkflowSpec, - TaskSpec, SubWorkflow, StartTask, ThreadMerge, - ThreadSplit, ThreadStart, Merge, Trigger, LoopResetTask) +from ..specs.base import TaskSpec +from ..specs.AcquireMutex import AcquireMutex +from ..specs.Cancel import Cancel +from ..specs.CancelTask import CancelTask +from ..specs.Celery import Celery +from ..specs.Choose import Choose +from ..specs.ExclusiveChoice import ExclusiveChoice +from ..specs.Execute import Execute +from ..specs.Gate import Gate +from ..specs.Join import Join +from ..specs.Merge import Merge +from ..specs.MultiChoice import MultiChoice +from ..specs.MultiInstance import MultiInstance +from ..specs.ReleaseMutex import ReleaseMutex +from ..specs.Simple import Simple +from ..specs.StartTask import StartTask +from ..specs.SubWorkflow import SubWorkflow +from ..specs.ThreadStart import ThreadStart +from ..specs.ThreadMerge import ThreadMerge +from ..specs.ThreadSplit import ThreadSplit +from ..specs.Transform import Transform +from ..specs.Trigger import Trigger +from ..specs.WorkflowSpec import WorkflowSpec +from ..specs.LoopResetTask import LoopResetTask from .base import Serializer from .exceptions import TaskNotSupportedError, MissingSpecError import warnings diff --git a/SpiffWorkflow/SpiffWorkflow/serializer/prettyxml.py b/SpiffWorkflow/SpiffWorkflow/serializer/prettyxml.py index 25bec80e4..9bd189c52 100644 --- a/SpiffWorkflow/SpiffWorkflow/serializer/prettyxml.py +++ b/SpiffWorkflow/SpiffWorkflow/serializer/prettyxml.py @@ -18,25 +18,15 @@ # 02110-1301 USA import re import xml.dom.minidom as minidom -from .. import operators, specs +from .. import operators +from ..specs.Simple import Simple +from ..specs.WorkflowSpec import WorkflowSpec from ..exceptions import StorageException -from .base import Serializer +from .base import Serializer, spec_map, op_map # Create a list of tag names out of the spec names. -_spec_map = dict() -for name in dir(specs): - if name.startswith('_'): - continue - module = specs.__dict__[name] - name = re.sub(r'(.)([A-Z])', r'\1-\2', name).lower() - _spec_map[name] = module -_spec_map['task'] = specs.Simple - -_op_map = {'equals': operators.Equal, - 'not-equals': operators.NotEqual, - 'less-than': operators.LessThan, - 'greater-than': operators.GreaterThan, - 'matches': operators.Match} +_spec_map = spec_map() +_op_map = op_map() _exc = StorageException @@ -299,9 +289,9 @@ class XmlSerializer(Serializer): _exc('%s without a name attribute' % node.nodeName) # Read all task specs and create a list of successors. - workflow_spec = specs.WorkflowSpec(name, filename) + workflow_spec = WorkflowSpec(name, filename) del workflow_spec.task_specs['Start'] - end = specs.Simple(workflow_spec, 'End'), [] + end = Simple(workflow_spec, 'End'), [] read_specs = dict(end=end) for child_node in node.childNodes: if child_node.nodeType != minidom.Node.ELEMENT_NODE: diff --git a/SpiffWorkflow/SpiffWorkflow/serializer/xml.py b/SpiffWorkflow/SpiffWorkflow/serializer/xml.py index f4b18b6cc..c0d0572d7 100644 --- a/SpiffWorkflow/SpiffWorkflow/serializer/xml.py +++ b/SpiffWorkflow/SpiffWorkflow/serializer/xml.py @@ -24,29 +24,35 @@ from .. import specs, operators from ..task import Task, TaskStateNames from ..operators import (Attrib, Assign, PathAttrib, Equal, NotEqual, GreaterThan, LessThan, Match) -from ..specs import (Cancel, AcquireMutex, CancelTask, Celery, Choose, - ExclusiveChoice, Execute, Gate, Join, MultiChoice, - MultiInstance, ReleaseMutex, Simple, WorkflowSpec, - SubWorkflow, StartTask, ThreadMerge, - ThreadSplit, ThreadStart, Merge, Trigger, LoopResetTask) -from .base import Serializer +from ..specs.AcquireMutex import AcquireMutex +from ..specs.Cancel import Cancel +from ..specs.CancelTask import CancelTask +from ..specs.Celery import Celery +from ..specs.Choose import Choose +from ..specs.ExclusiveChoice import ExclusiveChoice +from ..specs.Execute import Execute +from ..specs.Gate import Gate +from ..specs.Join import Join +from ..specs.Merge import Merge +from ..specs.MultiChoice import MultiChoice +from ..specs.MultiInstance import MultiInstance +from ..specs.ReleaseMutex import ReleaseMutex +from ..specs.Simple import Simple +from ..specs.StartTask import StartTask +from ..specs.SubWorkflow import SubWorkflow +from ..specs.ThreadStart import ThreadStart +from ..specs.ThreadMerge import ThreadMerge +from ..specs.ThreadSplit import ThreadSplit +from ..specs.Transform import Transform +from ..specs.Trigger import Trigger +from ..specs.WorkflowSpec import WorkflowSpec +from ..specs.LoopResetTask import LoopResetTask +from .base import Serializer, spec_map, op_map from .exceptions import TaskNotSupportedError # Create a list of tag names out of the spec names. -_spec_map = dict() -for name in dir(specs): - if name.startswith('_'): - continue - module = specs.__dict__[name] - name = re.sub(r'(.)([A-Z])', r'\1-\2', name).lower() - _spec_map[name] = module -_spec_map['task'] = specs.Simple - -_op_map = {'equals': operators.Equal, - 'not-equals': operators.NotEqual, - 'less-than': operators.LessThan, - 'greater-than': operators.GreaterThan, - 'matches': operators.Match} +_spec_map = spec_map() +_op_map = op_map() class XmlSerializer(Serializer): diff --git a/SpiffWorkflow/SpiffWorkflow/signavio/parser/__init__.py b/SpiffWorkflow/SpiffWorkflow/signavio/parser/__init__.py index 477cb987b..e69de29bb 100644 --- a/SpiffWorkflow/SpiffWorkflow/signavio/parser/__init__.py +++ b/SpiffWorkflow/SpiffWorkflow/signavio/parser/__init__.py @@ -1 +0,0 @@ -from .tasks import CallActivityParser \ No newline at end of file diff --git a/SpiffWorkflow/SpiffWorkflow/specs/SubWorkflow.py b/SpiffWorkflow/SpiffWorkflow/specs/SubWorkflow.py index 58d9f779d..197a69125 100644 --- a/SpiffWorkflow/SpiffWorkflow/specs/SubWorkflow.py +++ b/SpiffWorkflow/SpiffWorkflow/specs/SubWorkflow.py @@ -18,7 +18,7 @@ # 02110-1301 USA import os -from . import StartTask +from .StartTask import StartTask from .base import TaskSpec from ..task import TaskState from ..exceptions import WorkflowException @@ -87,7 +87,7 @@ class SubWorkflow(TaskSpec): def _create_subworkflow(self, my_task): from ..serializer.prettyxml import XmlSerializer - from ..specs import WorkflowSpec + from ..specs.WorkflowSpec import WorkflowSpec from ..workflow import Workflow file_name = valueof(my_task, self.file) serializer = XmlSerializer() diff --git a/SpiffWorkflow/SpiffWorkflow/specs/ThreadMerge.py b/SpiffWorkflow/SpiffWorkflow/specs/ThreadMerge.py index 56e3a4c33..ddbd0d712 100644 --- a/SpiffWorkflow/SpiffWorkflow/specs/ThreadMerge.py +++ b/SpiffWorkflow/SpiffWorkflow/specs/ThreadMerge.py @@ -19,7 +19,7 @@ from ..task import TaskState from ..exceptions import WorkflowException from ..operators import valueof -from ..specs import Join +from ..specs.Join import Join class ThreadMerge(Join): diff --git a/SpiffWorkflow/SpiffWorkflow/specs/WorkflowSpec.py b/SpiffWorkflow/SpiffWorkflow/specs/WorkflowSpec.py index 8ea12710b..7f084cb3f 100644 --- a/SpiffWorkflow/SpiffWorkflow/specs/WorkflowSpec.py +++ b/SpiffWorkflow/SpiffWorkflow/specs/WorkflowSpec.py @@ -17,7 +17,7 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301 USA -from ..specs import StartTask +from ..specs.StartTask import StartTask class WorkflowSpec(object): @@ -82,7 +82,7 @@ class WorkflowSpec(object): :returns: empty list if valid, a list of errors if not """ results = [] - from ..specs import Join + from ..specs.Join import Join def recursive_find_loop(task, history): current = history[:] diff --git a/SpiffWorkflow/SpiffWorkflow/specs/__init__.py b/SpiffWorkflow/SpiffWorkflow/specs/__init__.py index 1b10f8195..e69de29bb 100644 --- a/SpiffWorkflow/SpiffWorkflow/specs/__init__.py +++ b/SpiffWorkflow/SpiffWorkflow/specs/__init__.py @@ -1,31 +0,0 @@ -# -*- coding: utf-8 -*- -# flake8: noqa - -from .base import TaskSpec -from .AcquireMutex import AcquireMutex -from .Cancel import Cancel -from .CancelTask import CancelTask -from .Celery import Celery -from .Choose import Choose -from .ExclusiveChoice import ExclusiveChoice -from .Execute import Execute -from .Gate import Gate -from .Join import Join -from .Merge import Merge -from .MultiChoice import MultiChoice -from .MultiInstance import MultiInstance -from .ReleaseMutex import ReleaseMutex -from .Simple import Simple -from .StartTask import StartTask -from .SubWorkflow import SubWorkflow -from .ThreadStart import ThreadStart -from .ThreadMerge import ThreadMerge -from .ThreadSplit import ThreadSplit -from .Transform import Transform -from .Trigger import Trigger -from .WorkflowSpec import WorkflowSpec -from .LoopResetTask import LoopResetTask - -import inspect -__all__ = [name for name, obj in list(locals().items()) - if not (name.startswith('_') or inspect.ismodule(obj))] diff --git a/SpiffWorkflow/SpiffWorkflow/spiff/parser/__init__.py b/SpiffWorkflow/SpiffWorkflow/spiff/parser/__init__.py index 6b38b3623..e69de29bb 100644 --- a/SpiffWorkflow/SpiffWorkflow/spiff/parser/__init__.py +++ b/SpiffWorkflow/SpiffWorkflow/spiff/parser/__init__.py @@ -1 +0,0 @@ -from .process import SpiffBpmnParser, VALIDATOR \ No newline at end of file diff --git a/SpiffWorkflow/SpiffWorkflow/spiff/parser/process.py b/SpiffWorkflow/SpiffWorkflow/spiff/parser/process.py index 7e3dd1691..a8238b6bb 100644 --- a/SpiffWorkflow/SpiffWorkflow/spiff/parser/process.py +++ b/SpiffWorkflow/SpiffWorkflow/spiff/parser/process.py @@ -3,8 +3,15 @@ import os from SpiffWorkflow.dmn.parser.BpmnDmnParser import BpmnDmnParser from SpiffWorkflow.bpmn.parser.BpmnParser import BpmnValidator, full_tag -from SpiffWorkflow.bpmn.specs.events import StartEvent, EndEvent, IntermediateThrowEvent, BoundaryEvent, IntermediateCatchEvent -from SpiffWorkflow.spiff.specs import NoneTask, ManualTask, UserTask, ScriptTask, SubWorkflowTask, TransactionSubprocess, CallActivity, ServiceTask +from SpiffWorkflow.bpmn.specs.events.EndEvent import EndEvent +from SpiffWorkflow.bpmn.specs.events.StartEvent import StartEvent +from SpiffWorkflow.bpmn.specs.events.IntermediateEvent import IntermediateThrowEvent, BoundaryEvent, IntermediateCatchEvent +from SpiffWorkflow.spiff.specs.none_task import NoneTask +from SpiffWorkflow.spiff.specs.manual_task import ManualTask +from SpiffWorkflow.spiff.specs.user_task import UserTask +from SpiffWorkflow.spiff.specs.script_task import ScriptTask +from SpiffWorkflow.spiff.specs.subworkflow_task import SubWorkflowTask, TransactionSubprocess, CallActivity +from SpiffWorkflow.spiff.specs.service_task import ServiceTask from SpiffWorkflow.spiff.specs.events.event_types import SendTask, ReceiveTask from SpiffWorkflow.spiff.parser.task_spec import SpiffTaskParser, SubWorkflowParser, CallActivityParser, ServiceTaskParser, ScriptTaskParser from SpiffWorkflow.spiff.parser.event_parsers import (SpiffStartEventParser, SpiffEndEventParser, SpiffBoundaryEventParser, diff --git a/SpiffWorkflow/SpiffWorkflow/spiff/serializer/__init__.py b/SpiffWorkflow/SpiffWorkflow/spiff/serializer/__init__.py index 364c3ebfc..e69de29bb 100644 --- a/SpiffWorkflow/SpiffWorkflow/spiff/serializer/__init__.py +++ b/SpiffWorkflow/SpiffWorkflow/spiff/serializer/__init__.py @@ -1,4 +0,0 @@ -from .task_spec_converters import NoneTaskConverter, ManualTaskConverter, UserTaskConverter, ScriptTaskConverter -from .task_spec_converters import TransactionSubprocessConverter, CallActivityTaskConverter, SubWorkflowTaskConverter -from .task_spec_converters import StartEventConverter, EndEventConverter, IntermediateCatchEventConverter, IntermediateThrowEventConverter, \ - BoundaryEventConverter, SendTaskConverter, ReceiveTaskConverter, ServiceTaskConverter diff --git a/SpiffWorkflow/SpiffWorkflow/spiff/serializer/task_spec_converters.py b/SpiffWorkflow/SpiffWorkflow/spiff/serializer/task_spec_converters.py index 5b6769685..a1c0525c2 100644 --- a/SpiffWorkflow/SpiffWorkflow/spiff/serializer/task_spec_converters.py +++ b/SpiffWorkflow/SpiffWorkflow/spiff/serializer/task_spec_converters.py @@ -1,9 +1,16 @@ from functools import partial from SpiffWorkflow.bpmn.serializer.bpmn_converters import BpmnTaskSpecConverter -from SpiffWorkflow.bpmn.specs.events import EndEvent, StartEvent, IntermediateThrowEvent, IntermediateCatchEvent, BoundaryEvent -from SpiffWorkflow.spiff.specs import NoneTask, ManualTask, UserTask, ScriptTask, ServiceTask, SubWorkflowTask, TransactionSubprocess, CallActivity -from SpiffWorkflow.spiff.specs.events import SendTask, ReceiveTask +from SpiffWorkflow.bpmn.specs.events.StartEvent import StartEvent +from SpiffWorkflow.bpmn.specs.events.EndEvent import EndEvent +from SpiffWorkflow.bpmn.specs.events.IntermediateEvent import IntermediateThrowEvent, IntermediateCatchEvent, BoundaryEvent +from SpiffWorkflow.spiff.specs.none_task import NoneTask +from SpiffWorkflow.spiff.specs.manual_task import ManualTask +from SpiffWorkflow.spiff.specs.user_task import UserTask +from SpiffWorkflow.spiff.specs.script_task import ScriptTask +from SpiffWorkflow.spiff.specs.service_task import ServiceTask +from SpiffWorkflow.spiff.specs.subworkflow_task import SubWorkflowTask, TransactionSubprocess, CallActivity +from SpiffWorkflow.spiff.specs.events.event_types import SendTask, ReceiveTask from SpiffWorkflow.spiff.specs.events.event_definitions import MessageEventDefinition diff --git a/SpiffWorkflow/SpiffWorkflow/spiff/specs/__init__.py b/SpiffWorkflow/SpiffWorkflow/spiff/specs/__init__.py index 1e18b634a..e69de29bb 100644 --- a/SpiffWorkflow/SpiffWorkflow/spiff/specs/__init__.py +++ b/SpiffWorkflow/SpiffWorkflow/spiff/specs/__init__.py @@ -1,6 +0,0 @@ -from .manual_task import ManualTask -from .none_task import NoneTask -from .subworkflow_task import SubWorkflowTask, TransactionSubprocess, CallActivity -from .user_task import UserTask -from .script_task import ScriptTask -from .service_task import ServiceTask diff --git a/SpiffWorkflow/SpiffWorkflow/spiff/specs/events/__init__.py b/SpiffWorkflow/SpiffWorkflow/spiff/specs/events/__init__.py index 2fc0bc117..e69de29bb 100644 --- a/SpiffWorkflow/SpiffWorkflow/spiff/specs/events/__init__.py +++ b/SpiffWorkflow/SpiffWorkflow/spiff/specs/events/__init__.py @@ -1 +0,0 @@ -from .event_types import SendTask, ReceiveTask \ No newline at end of file diff --git a/SpiffWorkflow/SpiffWorkflow/workflow.py b/SpiffWorkflow/SpiffWorkflow/workflow.py index 376f2a019..906cfa5c0 100644 --- a/SpiffWorkflow/SpiffWorkflow/workflow.py +++ b/SpiffWorkflow/SpiffWorkflow/workflow.py @@ -19,7 +19,7 @@ import logging -from . import specs +from .specs.Simple import Simple from .specs.LoopResetTask import LoopResetTask from .task import Task, TaskState from .util.compat import mutex @@ -61,7 +61,7 @@ class Workflow(object): if 'Root' in workflow_spec.task_specs: root = workflow_spec.task_specs['Root'] else: - root = specs.Simple(workflow_spec, 'Root') + root = Simple(workflow_spec, 'Root') logger.info('Initialize', extra=self.log_info()) # Setting TaskState.COMPLETED prevents the root task from being executed. diff --git a/SpiffWorkflow/doc/non-bpmn/tutorial/start.py b/SpiffWorkflow/doc/non-bpmn/tutorial/start.py index e52b66c63..4090384cc 100644 --- a/SpiffWorkflow/doc/non-bpmn/tutorial/start.py +++ b/SpiffWorkflow/doc/non-bpmn/tutorial/start.py @@ -1,6 +1,6 @@ import json from SpiffWorkflow.workflow import Workflow -from SpiffWorkflow.specs import WorkflowSpec +from SpiffWorkflow.specs.WorkflowSpec import WorkflowSpec from SpiffWorkflow.serializer.json import JSONSerializer # Load from JSON diff --git a/SpiffWorkflow/tests/SpiffWorkflow/PatternTest.py b/SpiffWorkflow/tests/SpiffWorkflow/PatternTest.py index 8d11528fd..f0d013ce0 100644 --- a/SpiffWorkflow/tests/SpiffWorkflow/PatternTest.py +++ b/SpiffWorkflow/tests/SpiffWorkflow/PatternTest.py @@ -6,7 +6,7 @@ import unittest import os sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..')) -from SpiffWorkflow.specs import WorkflowSpec +from SpiffWorkflow.specs.WorkflowSpec import WorkflowSpec from SpiffWorkflow.task import Task from SpiffWorkflow.serializer.prettyxml import XmlSerializer from tests.SpiffWorkflow.util import run_workflow diff --git a/SpiffWorkflow/tests/SpiffWorkflow/PersistSmallWorkflowTest.py b/SpiffWorkflow/tests/SpiffWorkflow/PersistSmallWorkflowTest.py index c580c87d7..b554be189 100644 --- a/SpiffWorkflow/tests/SpiffWorkflow/PersistSmallWorkflowTest.py +++ b/SpiffWorkflow/tests/SpiffWorkflow/PersistSmallWorkflowTest.py @@ -6,7 +6,9 @@ import os.path sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..')) from SpiffWorkflow.workflow import Workflow -from SpiffWorkflow.specs import Join, MultiChoice, WorkflowSpec +from SpiffWorkflow.specs.Join import Join +from SpiffWorkflow.specs.MultiChoice import MultiChoice +from SpiffWorkflow.specs.WorkflowSpec import WorkflowSpec from SpiffWorkflow.operators import Attrib, Equal, PathAttrib from SpiffWorkflow.task import TaskState from SpiffWorkflow.specs.Simple import Simple diff --git a/SpiffWorkflow/tests/SpiffWorkflow/TaskTest.py b/SpiffWorkflow/tests/SpiffWorkflow/TaskTest.py index af4f28e33..e44f68e6f 100644 --- a/SpiffWorkflow/tests/SpiffWorkflow/TaskTest.py +++ b/SpiffWorkflow/tests/SpiffWorkflow/TaskTest.py @@ -7,7 +7,8 @@ import os.path sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..')) from SpiffWorkflow.task import Task, TaskState, updateDotDict -from SpiffWorkflow.specs import WorkflowSpec, Simple +from SpiffWorkflow.specs.WorkflowSpec import WorkflowSpec +from SpiffWorkflow.specs.Simple import Simple class MockWorkflow(object): diff --git a/SpiffWorkflow/tests/SpiffWorkflow/WorkflowTest.py b/SpiffWorkflow/tests/SpiffWorkflow/WorkflowTest.py index e47f069da..0d2b0b3d0 100644 --- a/SpiffWorkflow/tests/SpiffWorkflow/WorkflowTest.py +++ b/SpiffWorkflow/tests/SpiffWorkflow/WorkflowTest.py @@ -7,7 +7,9 @@ data_dir = os.path.join(os.path.dirname(__file__), 'data') sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..')) from SpiffWorkflow.workflow import Workflow -from SpiffWorkflow.specs import Cancel, Simple, WorkflowSpec +from SpiffWorkflow.specs.Cancel import Cancel +from SpiffWorkflow.specs.Simple import Simple +from SpiffWorkflow.specs.WorkflowSpec import WorkflowSpec from SpiffWorkflow.task import TaskState from SpiffWorkflow.serializer.prettyxml import XmlSerializer diff --git a/SpiffWorkflow/tests/SpiffWorkflow/bpmn/ApprovalsTest.py b/SpiffWorkflow/tests/SpiffWorkflow/bpmn/ApprovalsTest.py index 19f493806..7576a23fe 100644 --- a/SpiffWorkflow/tests/SpiffWorkflow/bpmn/ApprovalsTest.py +++ b/SpiffWorkflow/tests/SpiffWorkflow/bpmn/ApprovalsTest.py @@ -2,7 +2,7 @@ import unittest from SpiffWorkflow.bpmn.workflow import BpmnWorkflow -from SpiffWorkflow.bpmn.specs.events import MessageEventDefinition +from SpiffWorkflow.bpmn.specs.events.event_definitions import MessageEventDefinition from tests.SpiffWorkflow.bpmn.BpmnWorkflowTestCase import BpmnWorkflowTestCase __author__ = 'matth' diff --git a/SpiffWorkflow/tests/SpiffWorkflow/bpmn/BpmnLoaderForTests.py b/SpiffWorkflow/tests/SpiffWorkflow/bpmn/BpmnLoaderForTests.py index 7a407cc7f..54c18709f 100644 --- a/SpiffWorkflow/tests/SpiffWorkflow/bpmn/BpmnLoaderForTests.py +++ b/SpiffWorkflow/tests/SpiffWorkflow/bpmn/BpmnLoaderForTests.py @@ -10,7 +10,7 @@ from SpiffWorkflow.bpmn.serializer.bpmn_converters import BpmnTaskSpecConverter # Many of our tests relied on the Packager to set the calledElement attribute on # Call Activities. I've moved that code to a customized parser. -from SpiffWorkflow.signavio.parser import CallActivityParser +from SpiffWorkflow.signavio.parser.tasks import CallActivityParser from SpiffWorkflow.bpmn.specs.SubWorkflowTask import CallActivity __author__ = 'matth' diff --git a/SpiffWorkflow/tests/SpiffWorkflow/bpmn/BpmnWorkflowSerializerTest.py b/SpiffWorkflow/tests/SpiffWorkflow/bpmn/BpmnWorkflowSerializerTest.py index d0d1a9479..ac2ae463c 100644 --- a/SpiffWorkflow/tests/SpiffWorkflow/bpmn/BpmnWorkflowSerializerTest.py +++ b/SpiffWorkflow/tests/SpiffWorkflow/bpmn/BpmnWorkflowSerializerTest.py @@ -6,7 +6,7 @@ from uuid import uuid4 from SpiffWorkflow.task import TaskState from SpiffWorkflow.bpmn.PythonScriptEngine import PythonScriptEngine from SpiffWorkflow.bpmn.parser.BpmnParser import BpmnParser -from SpiffWorkflow.bpmn.serializer import BpmnWorkflowSerializer +from SpiffWorkflow.bpmn.serializer.workflow import BpmnWorkflowSerializer from SpiffWorkflow.bpmn.serializer.BpmnSerializer import BpmnSerializer from SpiffWorkflow.bpmn.workflow import BpmnWorkflow from tests.SpiffWorkflow.bpmn.BpmnLoaderForTests import TestUserTaskConverter diff --git a/SpiffWorkflow/tests/SpiffWorkflow/bpmn/BpmnWorkflowTestCase.py b/SpiffWorkflow/tests/SpiffWorkflow/bpmn/BpmnWorkflowTestCase.py index 5a341188b..e2864919e 100644 --- a/SpiffWorkflow/tests/SpiffWorkflow/bpmn/BpmnWorkflowTestCase.py +++ b/SpiffWorkflow/tests/SpiffWorkflow/bpmn/BpmnWorkflowTestCase.py @@ -7,7 +7,7 @@ from SpiffWorkflow.bpmn.parser.BpmnParser import BpmnValidator from SpiffWorkflow.task import TaskState -from SpiffWorkflow.bpmn.serializer import BpmnWorkflowSerializer +from SpiffWorkflow.bpmn.serializer.workflow import BpmnWorkflowSerializer from .BpmnLoaderForTests import TestUserTaskConverter, TestBpmnParser __author__ = 'matth' diff --git a/SpiffWorkflow/tests/SpiffWorkflow/bpmn/ProcessDependencyTest.py b/SpiffWorkflow/tests/SpiffWorkflow/bpmn/ProcessDependencyTest.py index b3a795196..86514a034 100644 --- a/SpiffWorkflow/tests/SpiffWorkflow/bpmn/ProcessDependencyTest.py +++ b/SpiffWorkflow/tests/SpiffWorkflow/bpmn/ProcessDependencyTest.py @@ -3,7 +3,7 @@ import os import unittest from SpiffWorkflow.camunda.parser.CamundaParser import CamundaParser -from SpiffWorkflow.spiff.parser import SpiffBpmnParser +from SpiffWorkflow.spiff.parser.process import SpiffBpmnParser from tests.SpiffWorkflow.bpmn.BpmnWorkflowTestCase import BpmnWorkflowTestCase diff --git a/SpiffWorkflow/tests/SpiffWorkflow/bpmn/events/MultipleEventsTest.py b/SpiffWorkflow/tests/SpiffWorkflow/bpmn/events/MultipleEventsTest.py index b1e2a24d5..86c552358 100644 --- a/SpiffWorkflow/tests/SpiffWorkflow/bpmn/events/MultipleEventsTest.py +++ b/SpiffWorkflow/tests/SpiffWorkflow/bpmn/events/MultipleEventsTest.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- import unittest -from SpiffWorkflow.bpmn.specs.events import CancelEventDefinition, SignalEventDefinition +from SpiffWorkflow.bpmn.specs.events.event_definitions import CancelEventDefinition, SignalEventDefinition from SpiffWorkflow.task import TaskState from SpiffWorkflow.bpmn.workflow import BpmnWorkflow from tests.SpiffWorkflow.bpmn.BpmnWorkflowTestCase import BpmnWorkflowTestCase diff --git a/SpiffWorkflow/tests/SpiffWorkflow/bpmn/events/TimerDurationBoundaryOnTaskTest.py b/SpiffWorkflow/tests/SpiffWorkflow/bpmn/events/TimerDurationBoundaryOnTaskTest.py index e87de251e..9bd1f322b 100644 --- a/SpiffWorkflow/tests/SpiffWorkflow/bpmn/events/TimerDurationBoundaryOnTaskTest.py +++ b/SpiffWorkflow/tests/SpiffWorkflow/bpmn/events/TimerDurationBoundaryOnTaskTest.py @@ -5,7 +5,7 @@ import datetime import time from datetime import timedelta -from SpiffWorkflow.bpmn.specs.events import EndEvent +from SpiffWorkflow.bpmn.specs.events.EndEvent import EndEvent from SpiffWorkflow.task import TaskState from SpiffWorkflow.bpmn.workflow import BpmnWorkflow from SpiffWorkflow.bpmn.PythonScriptEngine import PythonScriptEngine diff --git a/SpiffWorkflow/tests/SpiffWorkflow/camunda/BaseTestCase.py b/SpiffWorkflow/tests/SpiffWorkflow/camunda/BaseTestCase.py index 6ea39d0ac..b41a8aab7 100644 --- a/SpiffWorkflow/tests/SpiffWorkflow/camunda/BaseTestCase.py +++ b/SpiffWorkflow/tests/SpiffWorkflow/camunda/BaseTestCase.py @@ -1,12 +1,12 @@ # -*- coding: utf-8 -*- import os -from SpiffWorkflow.bpmn.serializer import BpmnWorkflowSerializer +from SpiffWorkflow.bpmn.serializer.workflow import BpmnWorkflowSerializer from SpiffWorkflow.camunda.parser.CamundaParser import CamundaParser -from SpiffWorkflow.camunda.serializer import UserTaskConverter, StartEventConverter, EndEventConverter, \ +from SpiffWorkflow.camunda.serializer.task_spec_converters import UserTaskConverter, StartEventConverter, EndEventConverter, \ IntermediateCatchEventConverter, IntermediateThrowEventConverter, BoundaryEventConverter -from SpiffWorkflow.dmn.serializer import BusinessRuleTaskConverter +from SpiffWorkflow.dmn.serializer.task_spec_converters import BusinessRuleTaskConverter from tests.SpiffWorkflow.bpmn.BpmnWorkflowTestCase import BpmnWorkflowTestCase diff --git a/SpiffWorkflow/tests/SpiffWorkflow/camunda/specs/UserTaskSpecTest.py b/SpiffWorkflow/tests/SpiffWorkflow/camunda/specs/UserTaskSpecTest.py index 2d3c16d7f..33f621912 100644 --- a/SpiffWorkflow/tests/SpiffWorkflow/camunda/specs/UserTaskSpecTest.py +++ b/SpiffWorkflow/tests/SpiffWorkflow/camunda/specs/UserTaskSpecTest.py @@ -3,7 +3,8 @@ import unittest from SpiffWorkflow.camunda.specs.UserTask import FormField, UserTask, Form, \ EnumFormField -from SpiffWorkflow.specs import WorkflowSpec, TaskSpec +from SpiffWorkflow.specs.base import TaskSpec +from SpiffWorkflow.specs.WorkflowSpec import WorkflowSpec class UserTaskSpecTest(unittest.TestCase): diff --git a/SpiffWorkflow/tests/SpiffWorkflow/data/spiff/workflow1.py b/SpiffWorkflow/tests/SpiffWorkflow/data/spiff/workflow1.py index fba204bd6..bc963fea1 100644 --- a/SpiffWorkflow/tests/SpiffWorkflow/data/spiff/workflow1.py +++ b/SpiffWorkflow/tests/SpiffWorkflow/data/spiff/workflow1.py @@ -1,6 +1,11 @@ # -*- coding: utf-8 -*- -from SpiffWorkflow.specs import ExclusiveChoice, Join, MultiChoice, MultiInstance, Simple, WorkflowSpec +from SpiffWorkflow.specs.ExclusiveChoice import ExclusiveChoice +from SpiffWorkflow.specs.Join import Join +from SpiffWorkflow.specs.MultiChoice import MultiChoice +from SpiffWorkflow.specs.MultiInstance import MultiInstance +from SpiffWorkflow.specs.Simple import Simple +from SpiffWorkflow.specs.WorkflowSpec import WorkflowSpec from SpiffWorkflow.operators import Attrib, Equal, NotEqual diff --git a/SpiffWorkflow/tests/SpiffWorkflow/serializer/baseTest.py b/SpiffWorkflow/tests/SpiffWorkflow/serializer/baseTest.py index 9bb79b137..7ac41f3c7 100644 --- a/SpiffWorkflow/tests/SpiffWorkflow/serializer/baseTest.py +++ b/SpiffWorkflow/tests/SpiffWorkflow/serializer/baseTest.py @@ -11,7 +11,7 @@ sys.path.insert(0, os.path.join(dirname, '..')) from PatternTest import run_workflow, PatternTest from SpiffWorkflow.serializer.base import Serializer -from SpiffWorkflow.specs import WorkflowSpec +from SpiffWorkflow.specs.WorkflowSpec import WorkflowSpec from SpiffWorkflow.workflow import Workflow from SpiffWorkflow.serializer.exceptions import TaskNotSupportedError diff --git a/SpiffWorkflow/tests/SpiffWorkflow/specs/CeleryTest.py b/SpiffWorkflow/tests/SpiffWorkflow/specs/CeleryTest.py index 9190dd33f..ac8116881 100644 --- a/SpiffWorkflow/tests/SpiffWorkflow/specs/CeleryTest.py +++ b/SpiffWorkflow/tests/SpiffWorkflow/specs/CeleryTest.py @@ -6,7 +6,8 @@ import unittest import pickle sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..')) from .TaskSpecTest import TaskSpecTest -from SpiffWorkflow.specs import Celery, WorkflowSpec +from SpiffWorkflow.specs.Celery import Celery +from SpiffWorkflow.specs.WorkflowSpec import WorkflowSpec from SpiffWorkflow.operators import Attrib from SpiffWorkflow.serializer.dict import DictionarySerializer from base64 import b64encode diff --git a/SpiffWorkflow/tests/SpiffWorkflow/specs/ExecuteTest.py b/SpiffWorkflow/tests/SpiffWorkflow/specs/ExecuteTest.py index bd3b06fd5..fc16db931 100644 --- a/SpiffWorkflow/tests/SpiffWorkflow/specs/ExecuteTest.py +++ b/SpiffWorkflow/tests/SpiffWorkflow/specs/ExecuteTest.py @@ -10,7 +10,7 @@ sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..')) from tests.SpiffWorkflow.util import run_workflow from .TaskSpecTest import TaskSpecTest from SpiffWorkflow.task import TaskState -from SpiffWorkflow.specs import Execute +from SpiffWorkflow.specs.Execute import Execute class ExecuteTest(TaskSpecTest): diff --git a/SpiffWorkflow/tests/SpiffWorkflow/specs/JoinTest.py b/SpiffWorkflow/tests/SpiffWorkflow/specs/JoinTest.py index 3eeb92866..7224701f5 100644 --- a/SpiffWorkflow/tests/SpiffWorkflow/specs/JoinTest.py +++ b/SpiffWorkflow/tests/SpiffWorkflow/specs/JoinTest.py @@ -8,7 +8,7 @@ import unittest sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..')) from .TaskSpecTest import TaskSpecTest -from SpiffWorkflow.specs import Join +from SpiffWorkflow.specs.Join import Join class JoinTest(TaskSpecTest): diff --git a/SpiffWorkflow/tests/SpiffWorkflow/specs/MergeTest.py b/SpiffWorkflow/tests/SpiffWorkflow/specs/MergeTest.py index 68f028d90..6fc692a66 100644 --- a/SpiffWorkflow/tests/SpiffWorkflow/specs/MergeTest.py +++ b/SpiffWorkflow/tests/SpiffWorkflow/specs/MergeTest.py @@ -8,7 +8,9 @@ import unittest sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..')) from .JoinTest import JoinTest -from SpiffWorkflow.specs import Merge, WorkflowSpec, Simple +from SpiffWorkflow.specs.Merge import Merge +from SpiffWorkflow.specs.WorkflowSpec import WorkflowSpec +from SpiffWorkflow.specs.Simple import Simple from SpiffWorkflow.workflow import Workflow diff --git a/SpiffWorkflow/tests/SpiffWorkflow/specs/SubWorkflowTest.py b/SpiffWorkflow/tests/SpiffWorkflow/specs/SubWorkflowTest.py index aed09fc27..5baacf99e 100644 --- a/SpiffWorkflow/tests/SpiffWorkflow/specs/SubWorkflowTest.py +++ b/SpiffWorkflow/tests/SpiffWorkflow/specs/SubWorkflowTest.py @@ -6,7 +6,7 @@ import os sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..')) -from SpiffWorkflow.specs import WorkflowSpec +from SpiffWorkflow.specs.WorkflowSpec import WorkflowSpec from SpiffWorkflow.specs.SubWorkflow import SubWorkflow from SpiffWorkflow.serializer.prettyxml import XmlSerializer from SpiffWorkflow.task import TaskState diff --git a/SpiffWorkflow/tests/SpiffWorkflow/specs/TaskSpecTest.py b/SpiffWorkflow/tests/SpiffWorkflow/specs/TaskSpecTest.py index 2b213b4af..2509d6184 100644 --- a/SpiffWorkflow/tests/SpiffWorkflow/specs/TaskSpecTest.py +++ b/SpiffWorkflow/tests/SpiffWorkflow/specs/TaskSpecTest.py @@ -5,9 +5,11 @@ import unittest import os sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..')) -from SpiffWorkflow.specs import WorkflowSpec, Simple, Join +from SpiffWorkflow.specs.Join import Join +from SpiffWorkflow.specs.Simple import Simple +from SpiffWorkflow.specs.WorkflowSpec import WorkflowSpec from SpiffWorkflow.exceptions import WorkflowException -from SpiffWorkflow.specs import TaskSpec +from SpiffWorkflow.specs.base import TaskSpec from SpiffWorkflow.serializer.dict import DictionarySerializer diff --git a/SpiffWorkflow/tests/SpiffWorkflow/specs/TransformTest.py b/SpiffWorkflow/tests/SpiffWorkflow/specs/TransformTest.py index ca2aaf1c3..228a038ec 100644 --- a/SpiffWorkflow/tests/SpiffWorkflow/specs/TransformTest.py +++ b/SpiffWorkflow/tests/SpiffWorkflow/specs/TransformTest.py @@ -9,7 +9,8 @@ sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..')) from tests.SpiffWorkflow.util import run_workflow from .TaskSpecTest import TaskSpecTest -from SpiffWorkflow.specs import Transform, Simple +from SpiffWorkflow.specs.Transform import Transform +from SpiffWorkflow.specs.Simple import Simple class TransformTest(TaskSpecTest): diff --git a/SpiffWorkflow/tests/SpiffWorkflow/specs/WorkflowSpecTest.py b/SpiffWorkflow/tests/SpiffWorkflow/specs/WorkflowSpecTest.py index 8b0289b8d..9b4c0d322 100644 --- a/SpiffWorkflow/tests/SpiffWorkflow/specs/WorkflowSpecTest.py +++ b/SpiffWorkflow/tests/SpiffWorkflow/specs/WorkflowSpecTest.py @@ -15,7 +15,8 @@ try: except ImportError as e: from tests.SpiffWorkflow.util import track_workflow from SpiffWorkflow.workflow import Workflow -from SpiffWorkflow.specs import Join, WorkflowSpec +from SpiffWorkflow.specs.Join import Join +from SpiffWorkflow.specs.WorkflowSpec import WorkflowSpec from SpiffWorkflow.serializer.prettyxml import XmlSerializer serializer = XmlSerializer() diff --git a/SpiffWorkflow/tests/SpiffWorkflow/spiff/BaseTestCase.py b/SpiffWorkflow/tests/SpiffWorkflow/spiff/BaseTestCase.py index 9e882fcb9..b085d1f76 100644 --- a/SpiffWorkflow/tests/SpiffWorkflow/spiff/BaseTestCase.py +++ b/SpiffWorkflow/tests/SpiffWorkflow/spiff/BaseTestCase.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- import os -from SpiffWorkflow.spiff.parser import SpiffBpmnParser, VALIDATOR -from SpiffWorkflow.spiff.serializer import NoneTaskConverter, \ +from SpiffWorkflow.spiff.parser.process import SpiffBpmnParser, VALIDATOR +from SpiffWorkflow.spiff.serializer.task_spec_converters import NoneTaskConverter, \ ManualTaskConverter, UserTaskConverter, ScriptTaskConverter, \ SubWorkflowTaskConverter, TransactionSubprocessConverter, \ CallActivityTaskConverter, \ @@ -11,7 +11,7 @@ from SpiffWorkflow.spiff.serializer import NoneTaskConverter, \ IntermediateCatchEventConverter, IntermediateThrowEventConverter, \ ServiceTaskConverter from SpiffWorkflow.dmn.serializer.task_spec_converters import BusinessRuleTaskConverter -from SpiffWorkflow.bpmn.serializer import BpmnWorkflowSerializer +from SpiffWorkflow.bpmn.serializer.workflow import BpmnWorkflowSerializer from tests.SpiffWorkflow.bpmn.BpmnWorkflowTestCase import BpmnWorkflowTestCase diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py index aa94704c1..99c58beff 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py @@ -29,31 +29,39 @@ from SpiffWorkflow.bpmn.exceptions import WorkflowTaskExecException # type: ign from SpiffWorkflow.bpmn.parser.ValidationException import ValidationException # type: ignore from SpiffWorkflow.bpmn.PythonScriptEngine import Box # type: ignore from SpiffWorkflow.bpmn.PythonScriptEngine import PythonScriptEngine -from SpiffWorkflow.bpmn.serializer import BpmnWorkflowSerializer # type: ignore +from SpiffWorkflow.bpmn.serializer.workflow import BpmnWorkflowSerializer # type: ignore from SpiffWorkflow.bpmn.specs.BpmnProcessSpec import BpmnProcessSpec # type: ignore -from SpiffWorkflow.bpmn.specs.events import CancelEventDefinition # type: ignore -from SpiffWorkflow.bpmn.specs.events import EndEvent +from SpiffWorkflow.bpmn.specs.events.EndEvent import EndEvent # type: ignore +from SpiffWorkflow.bpmn.specs.events.event_definitions import CancelEventDefinition # type: ignore from SpiffWorkflow.bpmn.workflow import BpmnWorkflow # type: ignore from SpiffWorkflow.dmn.parser.BpmnDmnParser import BpmnDmnParser # type: ignore -from SpiffWorkflow.dmn.serializer import BusinessRuleTaskConverter # type: ignore +from SpiffWorkflow.dmn.serializer.task_spec_converters import BusinessRuleTaskConverter # type: ignore from SpiffWorkflow.exceptions import WorkflowException # type: ignore from SpiffWorkflow.serializer.exceptions import MissingSpecError # type: ignore from SpiffWorkflow.spiff.parser.process import SpiffBpmnParser # type: ignore -from SpiffWorkflow.spiff.serializer import BoundaryEventConverter # type: ignore -from SpiffWorkflow.spiff.serializer import CallActivityTaskConverter -from SpiffWorkflow.spiff.serializer import EndEventConverter -from SpiffWorkflow.spiff.serializer import IntermediateCatchEventConverter -from SpiffWorkflow.spiff.serializer import IntermediateThrowEventConverter -from SpiffWorkflow.spiff.serializer import ManualTaskConverter -from SpiffWorkflow.spiff.serializer import NoneTaskConverter -from SpiffWorkflow.spiff.serializer import ReceiveTaskConverter -from SpiffWorkflow.spiff.serializer import ScriptTaskConverter -from SpiffWorkflow.spiff.serializer import SendTaskConverter -from SpiffWorkflow.spiff.serializer import ServiceTaskConverter -from SpiffWorkflow.spiff.serializer import StartEventConverter -from SpiffWorkflow.spiff.serializer import SubWorkflowTaskConverter -from SpiffWorkflow.spiff.serializer import TransactionSubprocessConverter -from SpiffWorkflow.spiff.serializer import UserTaskConverter +from SpiffWorkflow.spiff.serializer.task_spec_converters import BoundaryEventConverter # type: ignore +from SpiffWorkflow.spiff.serializer.task_spec_converters import ( + CallActivityTaskConverter, +) +from SpiffWorkflow.spiff.serializer.task_spec_converters import EndEventConverter +from SpiffWorkflow.spiff.serializer.task_spec_converters import ( + IntermediateCatchEventConverter, +) +from SpiffWorkflow.spiff.serializer.task_spec_converters import ( + IntermediateThrowEventConverter, +) +from SpiffWorkflow.spiff.serializer.task_spec_converters import ManualTaskConverter +from SpiffWorkflow.spiff.serializer.task_spec_converters import NoneTaskConverter +from SpiffWorkflow.spiff.serializer.task_spec_converters import ReceiveTaskConverter +from SpiffWorkflow.spiff.serializer.task_spec_converters import ScriptTaskConverter +from SpiffWorkflow.spiff.serializer.task_spec_converters import SendTaskConverter +from SpiffWorkflow.spiff.serializer.task_spec_converters import ServiceTaskConverter +from SpiffWorkflow.spiff.serializer.task_spec_converters import StartEventConverter +from SpiffWorkflow.spiff.serializer.task_spec_converters import SubWorkflowTaskConverter +from SpiffWorkflow.spiff.serializer.task_spec_converters import ( + TransactionSubprocessConverter, +) +from SpiffWorkflow.spiff.serializer.task_spec_converters import UserTaskConverter from SpiffWorkflow.task import Task as SpiffTask # type: ignore from SpiffWorkflow.task import TaskState from SpiffWorkflow.util.deep_merge import DeepMerge # type: ignore From a8e904c6b8f0d570b7454751ec3745facde846a5 Mon Sep 17 00:00:00 2001 From: jbirddog <100367399+jbirddog@users.noreply.github.com> Date: Thu, 3 Nov 2022 15:07:46 -0400 Subject: [PATCH 05/12] Track spiff step details more granularly (#17) --- SpiffWorkflow/SpiffWorkflow/bpmn/workflow.py | 21 ++++++++++++-- spiffworkflow-backend/poetry.lock | 27 ++++++++++-------- spiffworkflow-backend/pyproject.toml | 4 +-- .../services/process_instance_processor.py | 28 ++++++++++--------- 4 files changed, 51 insertions(+), 29 deletions(-) diff --git a/SpiffWorkflow/SpiffWorkflow/bpmn/workflow.py b/SpiffWorkflow/SpiffWorkflow/bpmn/workflow.py index 39c265f9d..d9b3994b2 100644 --- a/SpiffWorkflow/SpiffWorkflow/bpmn/workflow.py +++ b/SpiffWorkflow/SpiffWorkflow/bpmn/workflow.py @@ -161,7 +161,9 @@ class BpmnWorkflow(Workflow): event_definition.payload = payload self.catch(event_definition, correlations=correlations) - def do_engine_steps(self, exit_at = None): + def do_engine_steps(self, exit_at = None, + will_complete_task=None, + did_complete_task=None): """ Execute any READY tasks that are engine specific (for example, gateways or script tasks). This is done in a loop, so it will keep completing @@ -169,6 +171,8 @@ class BpmnWorkflow(Workflow): left. :param exit_at: After executing a task with a name matching this param return the task object + :param will_complete_task: Callback that will be called prior to completing a task + :param did_complete_task: Callback that will be called after completing a task """ assert not self.read_only engine_steps = list( @@ -176,21 +180,34 @@ class BpmnWorkflow(Workflow): if self._is_engine_task(t.task_spec)]) while engine_steps: for task in engine_steps: + if will_complete_task is not None: + will_complete_task(task) task.complete() + if did_complete_task is not None: + did_complete_task(task) if task.task_spec.name == exit_at: return task engine_steps = list( [t for t in self.get_tasks(TaskState.READY) if self._is_engine_task(t.task_spec)]) - def refresh_waiting_tasks(self): + def refresh_waiting_tasks(self, + will_refresh_task=None, + did_refresh_task=None): """ Refresh the state of all WAITING tasks. This will, for example, update Catching Timer Events whose waiting time has passed. + + :param will_refresh_task: Callback that will be called prior to refreshing a task + :param did_refresh_task: Callback that will be called after refreshing a task """ assert not self.read_only for my_task in self.get_tasks(TaskState.WAITING): + if will_refresh_task is not None: + will_refresh_task(my_task) my_task.task_spec._update(my_task) + if did_refresh_task is not None: + did_refresh_task(my_task) def get_tasks_from_spec_name(self, name, workflow=None): return [t for t in self.get_tasks(workflow=workflow) if t.task_spec.name == name] diff --git a/spiffworkflow-backend/poetry.lock b/spiffworkflow-backend/poetry.lock index c474c696d..7c18c6027 100644 --- a/spiffworkflow-backend/poetry.lock +++ b/spiffworkflow-backend/poetry.lock @@ -1860,20 +1860,16 @@ description = "A workflow framework and BPMN/DMN Processor" category = "main" optional = false python-versions = "*" -develop = false +develop = true [package.dependencies] celery = "*" configparser = "*" -dateparser = "*" lxml = "*" -pytz = "*" [package.source] -type = "git" -url = "https://github.com/sartography/SpiffWorkflow" -reference = "main" -resolved_reference = "a6392d19061f623394f5705fb78af23673d3940d" +type = "directory" +url = "../SpiffWorkflow" [[package]] name = "SQLAlchemy" @@ -2256,7 +2252,7 @@ testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools" [metadata] lock-version = "1.1" python-versions = ">=3.9,<3.11" -content-hash = "995be3a9a60b515b281f017ff32ff27a52ca178b1980611b348dccac6afb6b89" +content-hash = "9562df87977dc1c9273401fa150dd26742a6786d5162ec3e71844482207b4fba" [metadata.files] alabaster = [ @@ -2621,7 +2617,6 @@ greenlet = [ {file = "greenlet-1.1.3.post0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0a954002064ee919b444b19c1185e8cce307a1f20600f47d6f4b6d336972c809"}, {file = "greenlet-1.1.3.post0-cp39-cp39-win32.whl", hash = "sha256:2ccdc818cc106cc238ff7eba0d71b9c77be868fdca31d6c3b1347a54c9b187b2"}, {file = "greenlet-1.1.3.post0-cp39-cp39-win_amd64.whl", hash = "sha256:91a84faf718e6f8b888ca63d0b2d6d185c8e2a198d2a7322d75c303e7097c8b7"}, - {file = "greenlet-1.1.3.post0.tar.gz", hash = "sha256:f5e09dc5c6e1796969fd4b775ea1417d70e49a5df29aaa8e5d10675d9e11872c"}, ] gunicorn = [ {file = "gunicorn-20.1.0-py3-none-any.whl", hash = "sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e"}, @@ -2946,10 +2941,7 @@ orjson = [ {file = "orjson-3.8.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b68a42a31f8429728183c21fb440c21de1b62e5378d0d73f280e2d894ef8942e"}, {file = "orjson-3.8.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ff13410ddbdda5d4197a4a4c09969cb78c722a67550f0a63c02c07aadc624833"}, {file = "orjson-3.8.0-cp310-none-win_amd64.whl", hash = "sha256:2d81e6e56bbea44be0222fb53f7b255b4e7426290516771592738ca01dbd053b"}, - {file = "orjson-3.8.0-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:200eae21c33f1f8b02a11f5d88d76950cd6fd986d88f1afe497a8ae2627c49aa"}, - {file = "orjson-3.8.0-cp311-cp311-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:9529990f3eab54b976d327360aa1ff244a4b12cb5e4c5b3712fcdd96e8fe56d4"}, {file = "orjson-3.8.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:e2defd9527651ad39ec20ae03c812adf47ef7662bdd6bc07dabb10888d70dc62"}, - {file = "orjson-3.8.0-cp311-none-win_amd64.whl", hash = "sha256:b21c7af0ff6228ca7105f54f0800636eb49201133e15ddb80ac20c1ce973ef07"}, {file = "orjson-3.8.0-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:9e6ac22cec72d5b39035b566e4b86c74b84866f12b5b0b6541506a080fb67d6d"}, {file = "orjson-3.8.0-cp37-cp37m-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:e2f4a5542f50e3d336a18cb224fc757245ca66b1fd0b70b5dd4471b8ff5f2b0e"}, {file = "orjson-3.8.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1418feeb8b698b9224b1f024555895169d481604d5d884498c1838d7412794c"}, @@ -3062,7 +3054,18 @@ py = [ {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, ] pyasn1 = [ + {file = "pyasn1-0.4.8-py2.4.egg", hash = "sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3"}, + {file = "pyasn1-0.4.8-py2.5.egg", hash = "sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf"}, + {file = "pyasn1-0.4.8-py2.6.egg", hash = "sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00"}, + {file = "pyasn1-0.4.8-py2.7.egg", hash = "sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8"}, {file = "pyasn1-0.4.8-py2.py3-none-any.whl", hash = "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d"}, + {file = "pyasn1-0.4.8-py3.1.egg", hash = "sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86"}, + {file = "pyasn1-0.4.8-py3.2.egg", hash = "sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7"}, + {file = "pyasn1-0.4.8-py3.3.egg", hash = "sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576"}, + {file = "pyasn1-0.4.8-py3.4.egg", hash = "sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12"}, + {file = "pyasn1-0.4.8-py3.5.egg", hash = "sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2"}, + {file = "pyasn1-0.4.8-py3.6.egg", hash = "sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359"}, + {file = "pyasn1-0.4.8-py3.7.egg", hash = "sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776"}, {file = "pyasn1-0.4.8.tar.gz", hash = "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba"}, ] pycodestyle = [ diff --git a/spiffworkflow-backend/pyproject.toml b/spiffworkflow-backend/pyproject.toml index 7f2d09a40..764cebcf4 100644 --- a/spiffworkflow-backend/pyproject.toml +++ b/spiffworkflow-backend/pyproject.toml @@ -27,8 +27,8 @@ flask-marshmallow = "*" flask-migrate = "*" flask-restful = "*" werkzeug = "*" -SpiffWorkflow = {git = "https://github.com/sartography/SpiffWorkflow", rev = "main"} -#SpiffWorkflow = {develop = true, path = "../SpiffWorkflow" } +#SpiffWorkflow = {git = "https://github.com/sartography/SpiffWorkflow", rev = "main"} +SpiffWorkflow = {develop = true, path = "../SpiffWorkflow" } sentry-sdk = "^1.10" sphinx-autoapi = "^2.0" flask-bpmn = {git = "https://github.com/sartography/flask-bpmn", rev = "main"} diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py index 99c58beff..0795bc365 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py @@ -557,10 +557,9 @@ class ProcessInstanceProcessor: "lane_assignment_id": lane_assignment_id, } - def save_spiff_step_details(self, bpmn_json: Optional[str]) -> None: + def save_spiff_step_details(self) -> None: """SaveSpiffStepDetails.""" - if bpmn_json is None: - return + bpmn_json = self.serialize() wf_json = json.loads(bpmn_json) task_json = "{}" if "tasks" in wf_json: @@ -979,11 +978,18 @@ class ProcessInstanceProcessor: def do_engine_steps(self, exit_at: None = None, save: bool = False) -> None: """Do_engine_steps.""" - self.increment_spiff_step() - try: - self.bpmn_process_instance.refresh_waiting_tasks() - self.bpmn_process_instance.do_engine_steps(exit_at=exit_at) + self.bpmn_process_instance.refresh_waiting_tasks( + will_refresh_task=lambda t: self.increment_spiff_step(), + did_refresh_task=lambda t: self.save_spiff_step_details(), + ) + + self.bpmn_process_instance.do_engine_steps( + exit_at=exit_at, + will_complete_task=lambda t: self.increment_spiff_step(), + did_complete_task=lambda t: self.save_spiff_step_details(), + ) + self.process_bpmn_messages() self.queue_waiting_receive_messages() @@ -993,10 +999,6 @@ class ProcessInstanceProcessor: finally: if save: self.save() - bpmn_json = self.process_instance_model.bpmn_json - else: - bpmn_json = self.serialize() - self.save_spiff_step_details(bpmn_json) def cancel_notify(self) -> None: """Cancel_notify.""" @@ -1009,6 +1011,7 @@ class ProcessInstanceProcessor: # A little hackly, but make the bpmn_process_instance catch a cancel event. bpmn_process_instance.signal("cancel") # generate a cancel signal. bpmn_process_instance.catch(CancelEventDefinition()) + # Due to this being static, can't save granular step details in this case bpmn_process_instance.do_engine_steps() except WorkflowTaskExecException as we: raise ApiError.from_workflow_exception("task_error", str(we), we) from we @@ -1109,8 +1112,7 @@ class ProcessInstanceProcessor: """Complete_task.""" self.increment_spiff_step() self.bpmn_process_instance.complete_task_from_id(task.id) - bpmn_json = self.serialize() - self.save_spiff_step_details(bpmn_json) + self.save_spiff_step_details() def get_data(self) -> dict[str, Any]: """Get_data.""" From 2420cbf80f9880e5820dae139abadf5646da9078 Mon Sep 17 00:00:00 2001 From: jbirddog <100367399+jbirddog@users.noreply.github.com> Date: Thu, 3 Nov 2022 15:58:06 -0400 Subject: [PATCH 06/12] Point back to spiff main (#19) --- spiffworkflow-backend/poetry.lock | 10 ++++++---- spiffworkflow-backend/pyproject.toml | 4 ++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/spiffworkflow-backend/poetry.lock b/spiffworkflow-backend/poetry.lock index 7c18c6027..fdc27f61b 100644 --- a/spiffworkflow-backend/poetry.lock +++ b/spiffworkflow-backend/poetry.lock @@ -1860,7 +1860,7 @@ description = "A workflow framework and BPMN/DMN Processor" category = "main" optional = false python-versions = "*" -develop = true +develop = false [package.dependencies] celery = "*" @@ -1868,8 +1868,10 @@ configparser = "*" lxml = "*" [package.source] -type = "directory" -url = "../SpiffWorkflow" +type = "git" +url = "https://github.com/sartography/SpiffWorkflow" +reference = "main" +resolved_reference = "8d820dce1f439bb76bc07e39629832d998d6f634" [[package]] name = "SQLAlchemy" @@ -2252,7 +2254,7 @@ testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools" [metadata] lock-version = "1.1" python-versions = ">=3.9,<3.11" -content-hash = "9562df87977dc1c9273401fa150dd26742a6786d5162ec3e71844482207b4fba" +content-hash = "995be3a9a60b515b281f017ff32ff27a52ca178b1980611b348dccac6afb6b89" [metadata.files] alabaster = [ diff --git a/spiffworkflow-backend/pyproject.toml b/spiffworkflow-backend/pyproject.toml index 764cebcf4..7f2d09a40 100644 --- a/spiffworkflow-backend/pyproject.toml +++ b/spiffworkflow-backend/pyproject.toml @@ -27,8 +27,8 @@ flask-marshmallow = "*" flask-migrate = "*" flask-restful = "*" werkzeug = "*" -#SpiffWorkflow = {git = "https://github.com/sartography/SpiffWorkflow", rev = "main"} -SpiffWorkflow = {develop = true, path = "../SpiffWorkflow" } +SpiffWorkflow = {git = "https://github.com/sartography/SpiffWorkflow", rev = "main"} +#SpiffWorkflow = {develop = true, path = "../SpiffWorkflow" } sentry-sdk = "^1.10" sphinx-autoapi = "^2.0" flask-bpmn = {git = "https://github.com/sartography/flask-bpmn", rev = "main"} From 88e58865fb22b175e22c6fcc2b307a6825f2cf75 Mon Sep 17 00:00:00 2001 From: burnettk Date: Thu, 3 Nov 2022 16:23:15 -0400 Subject: [PATCH 07/12] work around parser.get_process_dependencies returning a set containing the element None --- .../src/spiffworkflow_backend/scripts/get_current_user.py | 4 ++-- .../src/spiffworkflow_backend/scripts/get_process_info.py | 2 +- .../services/process_instance_processor.py | 4 ++++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_current_user.py b/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_current_user.py index b8c314c0e..a1a1b47e9 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_current_user.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_current_user.py @@ -9,8 +9,8 @@ from spiffworkflow_backend.models.script_attributes_context import ( from spiffworkflow_backend.scripts.script import Script -class GetUser(Script): - """GetUser.""" +class GetCurrentUser(Script): + """GetCurrentUser.""" def get_description(self) -> str: """Get_description.""" diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_process_info.py b/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_process_info.py index b8ad3d687..45c70d6ba 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_process_info.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_process_info.py @@ -8,7 +8,7 @@ from spiffworkflow_backend.scripts.script import Script class GetProcessInfo(Script): - """GetUser.""" + """GetProcessInfo.""" def get_description(self) -> str: """Get_description.""" diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py index 0795bc365..dd80aa85a 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py @@ -732,6 +732,10 @@ class ProcessInstanceProcessor: if processed_identifiers is None: processed_identifiers = set() processor_dependencies = parser.get_process_dependencies() + + # since get_process_dependencies() returns a set with None sometimes, we need to remove it + processor_dependencies = processor_dependencies - {None} + processor_dependencies_new = processor_dependencies - processed_identifiers bpmn_process_identifiers_in_parser = parser.get_process_ids() From 7d2f18bd42ef639b24dd5de43329d935d9a07bba Mon Sep 17 00:00:00 2001 From: burnettk Date: Thu, 3 Nov 2022 16:55:10 -0400 Subject: [PATCH 08/12] prevent backfill from exploding when a primary file name on another model does not exist --- .../services/process_instance_processor.py | 20 +++++++++++++++---- .../services/spec_file_service.py | 9 ++++++--- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py index dd80aa85a..35320f652 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py @@ -94,6 +94,9 @@ from spiffworkflow_backend.scripts.script import Script from spiffworkflow_backend.services.file_system_service import FileSystemService from spiffworkflow_backend.services.process_model_service import ProcessModelService from spiffworkflow_backend.services.service_task_service import ServiceTaskDelegate +from spiffworkflow_backend.services.spec_file_service import ( + ProcessModelFileNotFoundError, +) from spiffworkflow_backend.services.spec_file_service import SpecFileService from spiffworkflow_backend.services.user_service import UserService @@ -669,10 +672,14 @@ class ProcessInstanceProcessor: process_models = ProcessModelService().get_process_models() for process_model in process_models: if process_model.primary_file_name: - etree_element = SpecFileService.get_etree_element_from_file_name( - process_model, process_model.primary_file_name - ) - bpmn_process_identifiers = [] + try: + etree_element = SpecFileService.get_etree_element_from_file_name( + process_model, process_model.primary_file_name + ) + bpmn_process_identifiers = [] + except ProcessModelFileNotFoundError: + # if primary_file_name doesn't actually exist on disk, then just go on to the next process_model + continue try: bpmn_process_identifiers = ( @@ -700,6 +707,11 @@ class ProcessInstanceProcessor: bpmn_process_identifier: str, ) -> str: """Bpmn_file_full_path_from_bpmn_process_identifier.""" + if bpmn_process_identifier is None: + raise ValueError( + "bpmn_file_full_path_from_bpmn_process_identifier: bpmn_process_identifier is unexpectedly None" + ) + bpmn_process_id_lookup = BpmnProcessIdLookup.query.filter_by( bpmn_process_identifier=bpmn_process_identifier ).first() diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/spec_file_service.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/spec_file_service.py index 4e1e30e2f..eb2a322f9 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/spec_file_service.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/spec_file_service.py @@ -27,6 +27,10 @@ from spiffworkflow_backend.services.file_system_service import FileSystemService from spiffworkflow_backend.services.process_model_service import ProcessModelService +class ProcessModelFileNotFoundError(Exception): + """ProcessModelFileNotFoundError.""" + + class SpecFileService(FileSystemService): """SpecFileService.""" @@ -90,9 +94,8 @@ class SpecFileService(FileSystemService): """Get_data.""" file_path = SpecFileService.file_path(process_model_info, file_name) if not os.path.exists(file_path): - raise ApiError( - "unknown_file", - f"No file found with name {file_name} in {process_model_info.display_name}", + raise ProcessModelFileNotFoundError( + f"No file found with name {file_name} in {process_model_info.display_name}" ) with open(file_path, "rb") as f_handle: spec_file_data = f_handle.read() From ecf2b7c9419c2753cc04a874cb2c288b555d1c45 Mon Sep 17 00:00:00 2001 From: jbirddog <100367399+jbirddog@users.noreply.github.com> Date: Thu, 3 Nov 2022 18:57:26 -0400 Subject: [PATCH 09/12] Change steps when viewing a process instance model (#18) --- .../models/process_instance.py | 1 + .../src/routes/ProcessInstanceShow.tsx | 66 ++++++++++++++++++- 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/models/process_instance.py b/spiffworkflow-backend/src/spiffworkflow_backend/models/process_instance.py index 0e4112d6a..50c3c9f76 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/models/process_instance.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/models/process_instance.py @@ -112,6 +112,7 @@ class ProcessInstanceModel(SpiffworkflowBaseDBModel): "end_in_seconds": self.end_in_seconds, "process_initiator_id": self.process_initiator_id, "bpmn_xml_file_contents": local_bpmn_xml_file_contents, + "spiff_step": self.spiff_step, } @property diff --git a/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx b/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx index 677e5b09a..642c7d657 100644 --- a/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx +++ b/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx @@ -96,6 +96,62 @@ export default function ProcessInstanceShow() { return taskIds; }; + const currentSpiffStep = (processInstanceToUse: any) => { + if (typeof params.spiff_step === 'undefined') { + return processInstanceToUse.spiff_step; + } + + return Number(params.spiff_step); + }; + + const showingFirstSpiffStep = (processInstanceToUse: any) => { + return currentSpiffStep(processInstanceToUse) === 1; + }; + + const showingLastSpiffStep = (processInstanceToUse: any) => { + return ( + currentSpiffStep(processInstanceToUse) === processInstanceToUse.spiff_step + ); + }; + + const spiffStepLink = ( + processInstanceToUse: any, + label: string, + distance: number + ) => { + return ( +
  • + + {label} + +
  • + ); + }; + + const previousStepLink = (processInstanceToUse: any) => { + if (showingFirstSpiffStep(processInstanceToUse)) { + return null; + } + + return spiffStepLink(processInstanceToUse, 'Previous Step', -1); + }; + + const nextStepLink = (processInstanceToUse: any) => { + if (showingLastSpiffStep(processInstanceToUse)) { + return null; + } + + return spiffStepLink(processInstanceToUse, 'Next Step', 1); + }; + const getInfoTag = (processInstanceToUse: any) => { const currentEndDate = convertSecondsToFormattedDate( processInstanceToUse.end_in_seconds @@ -135,6 +191,12 @@ export default function ProcessInstanceShow() { Messages +
  • + Step {currentSpiffStep(processInstanceToUse)} of{' '} + {processInstanceToUse.spiff_step} +
  • + {previousStepLink(processInstanceToUse)} + {nextStepLink(processInstanceToUse)} ); }; @@ -234,7 +296,9 @@ export default function ProcessInstanceShow() { }; const canEditTaskData = (task: any) => { - return task.state === 'READY'; + return ( + task.state === 'READY' && showingLastSpiffStep(processInstance as any) + ); }; const cancelEditingTaskData = () => { From 7ac4b51c6a607fdd43524307db08070b4d2c1db0 Mon Sep 17 00:00:00 2001 From: burnettk Date: Fri, 4 Nov 2022 09:33:42 -0400 Subject: [PATCH 10/12] Squashed 'SpiffWorkflow/' changes from a6392d1906..8d820dce1f 8d820dce1f Track spiff step details more granularly (#17) 426da26d8f Clear the remaining __init__.py imports in SpiffWorkflow (#14) 9a1d1c484a Fix FutureWarning in SpiffWorkflow (#16) git-subtree-dir: SpiffWorkflow git-subtree-split: 8d820dce1f439bb76bc07e39629832d998d6f634 --- SpiffWorkflow/bpmn/parser/BpmnParser.py | 6 +- SpiffWorkflow/bpmn/parser/TaskParser.py | 3 +- SpiffWorkflow/bpmn/parser/event_parsers.py | 2 +- SpiffWorkflow/bpmn/parser/node_parser.py | 3 +- .../serializer/CompactWorkflowSerializer.py | 2 +- SpiffWorkflow/bpmn/serializer/__init__.py | 3 - .../bpmn/serializer/bpmn_converters.py | 6 +- .../bpmn/serializer/task_spec_converters.py | 6 +- SpiffWorkflow/bpmn/specs/BpmnSpecMixin.py | 2 +- SpiffWorkflow/bpmn/specs/ExclusiveGateway.py | 2 +- SpiffWorkflow/bpmn/specs/ManualTask.py | 4 +- SpiffWorkflow/bpmn/specs/MultiInstanceTask.py | 2 +- SpiffWorkflow/bpmn/specs/NoneTask.py | 2 +- SpiffWorkflow/bpmn/specs/SubWorkflowTask.py | 2 +- SpiffWorkflow/bpmn/specs/events/__init__.py | 5 -- SpiffWorkflow/bpmn/workflow.py | 21 +++++- SpiffWorkflow/camunda/parser/CamundaParser.py | 4 +- SpiffWorkflow/camunda/serializer/__init__.py | 2 - .../serializer/task_spec_converters.py | 4 +- SpiffWorkflow/dmn/serializer/__init__.py | 1 - SpiffWorkflow/dmn/specs/BusinessRuleTask.py | 2 +- SpiffWorkflow/serializer/base.py | 65 +++++++++++++++++++ SpiffWorkflow/serializer/dict.py | 29 +++++++-- SpiffWorkflow/serializer/prettyxml.py | 26 +++----- SpiffWorkflow/serializer/xml.py | 46 +++++++------ SpiffWorkflow/signavio/parser/__init__.py | 1 - SpiffWorkflow/specs/SubWorkflow.py | 4 +- SpiffWorkflow/specs/ThreadMerge.py | 2 +- SpiffWorkflow/specs/WorkflowSpec.py | 4 +- SpiffWorkflow/specs/__init__.py | 31 --------- SpiffWorkflow/spiff/parser/__init__.py | 1 - SpiffWorkflow/spiff/parser/process.py | 11 +++- SpiffWorkflow/spiff/serializer/__init__.py | 4 -- .../spiff/serializer/task_spec_converters.py | 13 +++- SpiffWorkflow/spiff/specs/__init__.py | 6 -- SpiffWorkflow/spiff/specs/events/__init__.py | 1 - SpiffWorkflow/workflow.py | 4 +- doc/non-bpmn/tutorial/start.py | 2 +- tests/SpiffWorkflow/PatternTest.py | 2 +- .../SpiffWorkflow/PersistSmallWorkflowTest.py | 4 +- tests/SpiffWorkflow/TaskTest.py | 3 +- tests/SpiffWorkflow/WorkflowTest.py | 4 +- tests/SpiffWorkflow/bpmn/ApprovalsTest.py | 2 +- .../SpiffWorkflow/bpmn/BpmnLoaderForTests.py | 2 +- .../bpmn/BpmnWorkflowSerializerTest.py | 2 +- .../bpmn/BpmnWorkflowTestCase.py | 2 +- .../bpmn/ProcessDependencyTest.py | 2 +- .../bpmn/events/MultipleEventsTest.py | 2 +- .../events/TimerDurationBoundaryOnTaskTest.py | 2 +- tests/SpiffWorkflow/camunda/BaseTestCase.py | 6 +- .../camunda/specs/UserTaskSpecTest.py | 3 +- tests/SpiffWorkflow/data/spiff/workflow1.py | 7 +- tests/SpiffWorkflow/serializer/baseTest.py | 2 +- tests/SpiffWorkflow/specs/CeleryTest.py | 3 +- tests/SpiffWorkflow/specs/ExecuteTest.py | 2 +- tests/SpiffWorkflow/specs/JoinTest.py | 2 +- tests/SpiffWorkflow/specs/MergeTest.py | 4 +- tests/SpiffWorkflow/specs/SubWorkflowTest.py | 2 +- tests/SpiffWorkflow/specs/TaskSpecTest.py | 6 +- tests/SpiffWorkflow/specs/TransformTest.py | 3 +- tests/SpiffWorkflow/specs/WorkflowSpecTest.py | 3 +- tests/SpiffWorkflow/spiff/BaseTestCase.py | 6 +- 62 files changed, 247 insertions(+), 163 deletions(-) diff --git a/SpiffWorkflow/bpmn/parser/BpmnParser.py b/SpiffWorkflow/bpmn/parser/BpmnParser.py index c6ed81bbd..e6783e052 100644 --- a/SpiffWorkflow/bpmn/parser/BpmnParser.py +++ b/SpiffWorkflow/bpmn/parser/BpmnParser.py @@ -27,8 +27,10 @@ from SpiffWorkflow.bpmn.specs.events.event_definitions import NoneEventDefinitio from .ValidationException import ValidationException from ..specs.BpmnProcessSpec import BpmnProcessSpec -from ..specs.events import StartEvent, EndEvent, BoundaryEvent, IntermediateCatchEvent, IntermediateThrowEvent -from ..specs.events import SendTask, ReceiveTask +from ..specs.events.EndEvent import EndEvent +from ..specs.events.StartEvent import StartEvent +from ..specs.events.IntermediateEvent import BoundaryEvent, IntermediateCatchEvent, IntermediateThrowEvent +from ..specs.events.IntermediateEvent import SendTask, ReceiveTask from ..specs.SubWorkflowTask import CallActivity, SubWorkflowTask, TransactionSubprocess from ..specs.ExclusiveGateway import ExclusiveGateway from ..specs.InclusiveGateway import InclusiveGateway diff --git a/SpiffWorkflow/bpmn/parser/TaskParser.py b/SpiffWorkflow/bpmn/parser/TaskParser.py index afbd19720..5291b1623 100644 --- a/SpiffWorkflow/bpmn/parser/TaskParser.py +++ b/SpiffWorkflow/bpmn/parser/TaskParser.py @@ -23,7 +23,8 @@ from .ValidationException import ValidationException from ..specs.NoneTask import NoneTask from ..specs.ScriptTask import ScriptTask from ..specs.UserTask import UserTask -from ..specs.events import _BoundaryEventParent, CancelEventDefinition +from ..specs.events.IntermediateEvent import _BoundaryEventParent +from ..specs.events.event_definitions import CancelEventDefinition from ..specs.MultiInstanceTask import getDynamicMIClass from ..specs.SubWorkflowTask import CallActivity, TransactionSubprocess, SubWorkflowTask from ..specs.ExclusiveGateway import ExclusiveGateway diff --git a/SpiffWorkflow/bpmn/parser/event_parsers.py b/SpiffWorkflow/bpmn/parser/event_parsers.py index d007fde8b..07cef338e 100644 --- a/SpiffWorkflow/bpmn/parser/event_parsers.py +++ b/SpiffWorkflow/bpmn/parser/event_parsers.py @@ -5,7 +5,7 @@ from SpiffWorkflow.bpmn.specs.events.event_definitions import CorrelationPropert from .ValidationException import ValidationException from .TaskParser import TaskParser from .util import first, one -from ..specs.events import (TimerEventDefinition, MessageEventDefinition, +from ..specs.events.event_definitions import (TimerEventDefinition, MessageEventDefinition, ErrorEventDefinition, EscalationEventDefinition, SignalEventDefinition, CancelEventDefinition, CycleTimerEventDefinition, diff --git a/SpiffWorkflow/bpmn/parser/node_parser.py b/SpiffWorkflow/bpmn/parser/node_parser.py index b76ccfbb6..0b1c8ed46 100644 --- a/SpiffWorkflow/bpmn/parser/node_parser.py +++ b/SpiffWorkflow/bpmn/parser/node_parser.py @@ -35,7 +35,8 @@ class NodeParser: return expression.text if expression is not None else None def parse_documentation(self, sequence_flow=None): - documentation_node = first(self._xpath(sequence_flow or self.node, './/bpmn:documentation')) + node = sequence_flow if sequence_flow is not None else self.node + documentation_node = first(self._xpath(node, './/bpmn:documentation')) return None if documentation_node is None else documentation_node.text def parse_incoming_data_references(self): diff --git a/SpiffWorkflow/bpmn/serializer/CompactWorkflowSerializer.py b/SpiffWorkflow/bpmn/serializer/CompactWorkflowSerializer.py index ac38dc6bc..9ed543fbf 100644 --- a/SpiffWorkflow/bpmn/serializer/CompactWorkflowSerializer.py +++ b/SpiffWorkflow/bpmn/serializer/CompactWorkflowSerializer.py @@ -23,7 +23,7 @@ from builtins import object from collections import deque import json from ...task import TaskState -from ...specs import SubWorkflow +from ...specs.Subworkflow import SubWorkflow from ...serializer.base import Serializer from ..workflow import BpmnWorkflow diff --git a/SpiffWorkflow/bpmn/serializer/__init__.py b/SpiffWorkflow/bpmn/serializer/__init__.py index 507b6257b..9a31a4077 100644 --- a/SpiffWorkflow/bpmn/serializer/__init__.py +++ b/SpiffWorkflow/bpmn/serializer/__init__.py @@ -15,6 +15,3 @@ # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301 USA - -from .workflow import BpmnWorkflowSerializer -from .bpmn_converters import BpmnDataConverter \ No newline at end of file diff --git a/SpiffWorkflow/bpmn/serializer/bpmn_converters.py b/SpiffWorkflow/bpmn/serializer/bpmn_converters.py index 99666b344..1e274c21f 100644 --- a/SpiffWorkflow/bpmn/serializer/bpmn_converters.py +++ b/SpiffWorkflow/bpmn/serializer/bpmn_converters.py @@ -7,9 +7,9 @@ from SpiffWorkflow.bpmn.specs.BpmnProcessSpec import BpmnDataSpecification from .dictionary import DictionaryConverter -from ..specs.events import SignalEventDefinition, MessageEventDefinition, NoneEventDefinition -from ..specs.events import TimerEventDefinition, CycleTimerEventDefinition, TerminateEventDefinition -from ..specs.events import ErrorEventDefinition, EscalationEventDefinition, CancelEventDefinition +from ..specs.events.event_definitions import SignalEventDefinition, MessageEventDefinition, NoneEventDefinition +from ..specs.events.event_definitions import TimerEventDefinition, CycleTimerEventDefinition, TerminateEventDefinition +from ..specs.events.event_definitions import ErrorEventDefinition, EscalationEventDefinition, CancelEventDefinition from ..specs.events.event_definitions import CorrelationProperty, NamedEventDefinition from ..specs.BpmnSpecMixin import BpmnSpecMixin, SequenceFlow diff --git a/SpiffWorkflow/bpmn/serializer/task_spec_converters.py b/SpiffWorkflow/bpmn/serializer/task_spec_converters.py index e2af6b321..852ebe4de 100644 --- a/SpiffWorkflow/bpmn/serializer/task_spec_converters.py +++ b/SpiffWorkflow/bpmn/serializer/task_spec_converters.py @@ -2,7 +2,7 @@ from uuid import UUID from .bpmn_converters import BpmnTaskSpecConverter -from ...specs import StartTask +from ...specs.StartTask import StartTask from ...specs.Simple import Simple from ...specs.LoopResetTask import LoopResetTask @@ -19,7 +19,9 @@ from ..specs.ExclusiveGateway import ExclusiveGateway from ..specs.InclusiveGateway import InclusiveGateway from ..specs.ParallelGateway import ParallelGateway -from ..specs.events import StartEvent, EndEvent, BoundaryEvent, IntermediateCatchEvent, IntermediateThrowEvent +from ..specs.events.StartEvent import StartEvent +from ..specs.events.EndEvent import EndEvent +from ..specs.events.IntermediateEvent import BoundaryEvent, IntermediateCatchEvent, IntermediateThrowEvent from ..specs.events.IntermediateEvent import _BoundaryEventParent, SendTask, ReceiveTask from ..workflow import BpmnWorkflow diff --git a/SpiffWorkflow/bpmn/specs/BpmnSpecMixin.py b/SpiffWorkflow/bpmn/specs/BpmnSpecMixin.py index 3b8f4b26f..459a38828 100644 --- a/SpiffWorkflow/bpmn/specs/BpmnSpecMixin.py +++ b/SpiffWorkflow/bpmn/specs/BpmnSpecMixin.py @@ -19,7 +19,7 @@ from ...task import TaskState from ...operators import Operator -from ...specs import TaskSpec +from ...specs.base import TaskSpec class _BpmnCondition(Operator): diff --git a/SpiffWorkflow/bpmn/specs/ExclusiveGateway.py b/SpiffWorkflow/bpmn/specs/ExclusiveGateway.py index 391a29325..89a1445ff 100644 --- a/SpiffWorkflow/bpmn/specs/ExclusiveGateway.py +++ b/SpiffWorkflow/bpmn/specs/ExclusiveGateway.py @@ -19,7 +19,7 @@ from ...exceptions import WorkflowException from .BpmnSpecMixin import BpmnSpecMixin -from ...specs import TaskSpec +from ...specs.base import TaskSpec from ...specs.ExclusiveChoice import ExclusiveChoice diff --git a/SpiffWorkflow/bpmn/specs/ManualTask.py b/SpiffWorkflow/bpmn/specs/ManualTask.py index a02834457..c8d4e7c25 100644 --- a/SpiffWorkflow/bpmn/specs/ManualTask.py +++ b/SpiffWorkflow/bpmn/specs/ManualTask.py @@ -18,7 +18,7 @@ # 02110-1301 USA from ...bpmn.specs.BpmnSpecMixin import BpmnSpecMixin -from ...specs import Simple +from ...specs.Simple import Simple class ManualTask(Simple, BpmnSpecMixin): @@ -32,4 +32,4 @@ class ManualTask(Simple, BpmnSpecMixin): @property def spec_type(self): - return 'Manual Task' \ No newline at end of file + return 'Manual Task' diff --git a/SpiffWorkflow/bpmn/specs/MultiInstanceTask.py b/SpiffWorkflow/bpmn/specs/MultiInstanceTask.py index 77886d547..f0ceb3dea 100644 --- a/SpiffWorkflow/bpmn/specs/MultiInstanceTask.py +++ b/SpiffWorkflow/bpmn/specs/MultiInstanceTask.py @@ -29,7 +29,7 @@ from .ScriptTask import ScriptTask from .ExclusiveGateway import ExclusiveGateway from ...dmn.specs.BusinessRuleTask import BusinessRuleTask from ...operators import valueof, is_number -from ...specs import SubWorkflow +from ...specs.SubWorkflow import SubWorkflow from ...specs.base import TaskSpec from ...util.impl import get_class from ...task import Task, TaskState diff --git a/SpiffWorkflow/bpmn/specs/NoneTask.py b/SpiffWorkflow/bpmn/specs/NoneTask.py index 28abc80cc..5c844e90f 100644 --- a/SpiffWorkflow/bpmn/specs/NoneTask.py +++ b/SpiffWorkflow/bpmn/specs/NoneTask.py @@ -16,7 +16,7 @@ # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301 USA -from ...specs import Simple +from ...specs.Simple import Simple from ...bpmn.specs.BpmnSpecMixin import BpmnSpecMixin diff --git a/SpiffWorkflow/bpmn/specs/SubWorkflowTask.py b/SpiffWorkflow/bpmn/specs/SubWorkflowTask.py index c8b4409e7..6f616f1d3 100644 --- a/SpiffWorkflow/bpmn/specs/SubWorkflowTask.py +++ b/SpiffWorkflow/bpmn/specs/SubWorkflowTask.py @@ -3,7 +3,7 @@ from copy import deepcopy from SpiffWorkflow.task import TaskState from .BpmnSpecMixin import BpmnSpecMixin -from ...specs import TaskSpec +from ...specs.base import TaskSpec class SubWorkflowTask(BpmnSpecMixin): diff --git a/SpiffWorkflow/bpmn/specs/events/__init__.py b/SpiffWorkflow/bpmn/specs/events/__init__.py index b4d526658..e69de29bb 100644 --- a/SpiffWorkflow/bpmn/specs/events/__init__.py +++ b/SpiffWorkflow/bpmn/specs/events/__init__.py @@ -1,5 +0,0 @@ -from .StartEvent import StartEvent -from .EndEvent import EndEvent -from .IntermediateEvent import IntermediateCatchEvent, IntermediateThrowEvent, BoundaryEvent, _BoundaryEventParent, SendTask, ReceiveTask -from .event_definitions import (NoneEventDefinition, CancelEventDefinition, ErrorEventDefinition, EscalationEventDefinition, MessageEventDefinition, - SignalEventDefinition, TimerEventDefinition, CycleTimerEventDefinition, TerminateEventDefinition) \ No newline at end of file diff --git a/SpiffWorkflow/bpmn/workflow.py b/SpiffWorkflow/bpmn/workflow.py index 39c265f9d..d9b3994b2 100644 --- a/SpiffWorkflow/bpmn/workflow.py +++ b/SpiffWorkflow/bpmn/workflow.py @@ -161,7 +161,9 @@ class BpmnWorkflow(Workflow): event_definition.payload = payload self.catch(event_definition, correlations=correlations) - def do_engine_steps(self, exit_at = None): + def do_engine_steps(self, exit_at = None, + will_complete_task=None, + did_complete_task=None): """ Execute any READY tasks that are engine specific (for example, gateways or script tasks). This is done in a loop, so it will keep completing @@ -169,6 +171,8 @@ class BpmnWorkflow(Workflow): left. :param exit_at: After executing a task with a name matching this param return the task object + :param will_complete_task: Callback that will be called prior to completing a task + :param did_complete_task: Callback that will be called after completing a task """ assert not self.read_only engine_steps = list( @@ -176,21 +180,34 @@ class BpmnWorkflow(Workflow): if self._is_engine_task(t.task_spec)]) while engine_steps: for task in engine_steps: + if will_complete_task is not None: + will_complete_task(task) task.complete() + if did_complete_task is not None: + did_complete_task(task) if task.task_spec.name == exit_at: return task engine_steps = list( [t for t in self.get_tasks(TaskState.READY) if self._is_engine_task(t.task_spec)]) - def refresh_waiting_tasks(self): + def refresh_waiting_tasks(self, + will_refresh_task=None, + did_refresh_task=None): """ Refresh the state of all WAITING tasks. This will, for example, update Catching Timer Events whose waiting time has passed. + + :param will_refresh_task: Callback that will be called prior to refreshing a task + :param did_refresh_task: Callback that will be called after refreshing a task """ assert not self.read_only for my_task in self.get_tasks(TaskState.WAITING): + if will_refresh_task is not None: + will_refresh_task(my_task) my_task.task_spec._update(my_task) + if did_refresh_task is not None: + did_refresh_task(my_task) def get_tasks_from_spec_name(self, name, workflow=None): return [t for t in self.get_tasks(workflow=workflow) if t.task_spec.name == name] diff --git a/SpiffWorkflow/camunda/parser/CamundaParser.py b/SpiffWorkflow/camunda/parser/CamundaParser.py index b9d0dc268..e91be639a 100644 --- a/SpiffWorkflow/camunda/parser/CamundaParser.py +++ b/SpiffWorkflow/camunda/parser/CamundaParser.py @@ -6,7 +6,9 @@ from SpiffWorkflow.dmn.parser.BpmnDmnParser import BpmnDmnParser from SpiffWorkflow.dmn.specs.BusinessRuleTask import BusinessRuleTask from SpiffWorkflow.camunda.parser.task_spec import BusinessRuleTaskParser -from SpiffWorkflow.bpmn.specs.events import EndEvent, IntermediateThrowEvent, StartEvent, IntermediateCatchEvent, BoundaryEvent +from SpiffWorkflow.bpmn.specs.events.StartEvent import StartEvent +from SpiffWorkflow.bpmn.specs.events.EndEvent import EndEvent +from SpiffWorkflow.bpmn.specs.events.IntermediateEvent import IntermediateThrowEvent, IntermediateCatchEvent, BoundaryEvent from .event_parsers import CamundaStartEventParser, CamundaEndEventParser, \ CamundaIntermediateCatchEventParser, CamundaIntermediateThrowEventParser, CamundaBoundaryEventParser diff --git a/SpiffWorkflow/camunda/serializer/__init__.py b/SpiffWorkflow/camunda/serializer/__init__.py index 62e56488a..e69de29bb 100644 --- a/SpiffWorkflow/camunda/serializer/__init__.py +++ b/SpiffWorkflow/camunda/serializer/__init__.py @@ -1,2 +0,0 @@ -from .task_spec_converters import UserTaskConverter, StartEventConverter, EndEventConverter, \ - BoundaryEventConverter, IntermediateCatchEventConverter, IntermediateThrowEventConverter diff --git a/SpiffWorkflow/camunda/serializer/task_spec_converters.py b/SpiffWorkflow/camunda/serializer/task_spec_converters.py index bb247e33a..3f997a0e3 100644 --- a/SpiffWorkflow/camunda/serializer/task_spec_converters.py +++ b/SpiffWorkflow/camunda/serializer/task_spec_converters.py @@ -1,6 +1,8 @@ from functools import partial -from SpiffWorkflow.bpmn.specs.events import EndEvent, IntermediateThrowEvent, StartEvent, IntermediateCatchEvent, BoundaryEvent +from SpiffWorkflow.bpmn.specs.events.StartEvent import StartEvent +from SpiffWorkflow.bpmn.specs.events.EndEvent import EndEvent +from SpiffWorkflow.bpmn.specs.events.IntermediateEvent import IntermediateThrowEvent, IntermediateCatchEvent, BoundaryEvent from ..specs.events.event_definitions import MessageEventDefinition from ...bpmn.serializer.bpmn_converters import BpmnTaskSpecConverter diff --git a/SpiffWorkflow/dmn/serializer/__init__.py b/SpiffWorkflow/dmn/serializer/__init__.py index 9f493c9d7..e69de29bb 100644 --- a/SpiffWorkflow/dmn/serializer/__init__.py +++ b/SpiffWorkflow/dmn/serializer/__init__.py @@ -1 +0,0 @@ -from .task_spec_converters import BusinessRuleTaskConverter \ No newline at end of file diff --git a/SpiffWorkflow/dmn/specs/BusinessRuleTask.py b/SpiffWorkflow/dmn/specs/BusinessRuleTask.py index 4a9684f25..5825c0232 100644 --- a/SpiffWorkflow/dmn/specs/BusinessRuleTask.py +++ b/SpiffWorkflow/dmn/specs/BusinessRuleTask.py @@ -1,6 +1,6 @@ from SpiffWorkflow.bpmn.exceptions import WorkflowTaskExecException -from ...specs import Simple +from ...specs.Simple import Simple from ...bpmn.specs.BpmnSpecMixin import BpmnSpecMixin from ...util.deep_merge import DeepMerge diff --git a/SpiffWorkflow/serializer/base.py b/SpiffWorkflow/serializer/base.py index 28b2e60ab..bbf4cc251 100644 --- a/SpiffWorkflow/serializer/base.py +++ b/SpiffWorkflow/serializer/base.py @@ -16,6 +16,71 @@ from builtins import object # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301 USA +import re +from .. import operators +from .. import specs +from ..specs.AcquireMutex import AcquireMutex +from ..specs.Cancel import Cancel +from ..specs.CancelTask import CancelTask +from ..specs.Celery import Celery +from ..specs.Choose import Choose +from ..specs.ExclusiveChoice import ExclusiveChoice +from ..specs.Execute import Execute +from ..specs.Gate import Gate +from ..specs.Join import Join +from ..specs.Merge import Merge +from ..specs.MultiChoice import MultiChoice +from ..specs.MultiInstance import MultiInstance +from ..specs.ReleaseMutex import ReleaseMutex +from ..specs.Simple import Simple +from ..specs.StartTask import StartTask +from ..specs.SubWorkflow import SubWorkflow +from ..specs.ThreadStart import ThreadStart +from ..specs.ThreadMerge import ThreadMerge +from ..specs.ThreadSplit import ThreadSplit +from ..specs.Transform import Transform +from ..specs.Trigger import Trigger +from ..specs.WorkflowSpec import WorkflowSpec +from ..specs.LoopResetTask import LoopResetTask + +# Create a list of tag names out of the spec names. +def spec_map(): + return { + 'acquire-mutex': AcquireMutex, + 'cancel': Cancel, + 'cancel-task': CancelTask, + 'celery': Celery, + 'choose': Choose, + 'exclusive-choice': ExclusiveChoice, + 'execute': Execute, + 'gate': Gate, + 'join': Join, + 'merge': Merge, + 'multi-choice': MultiChoice, + 'multi-instance': MultiInstance, + 'release-mutex': ReleaseMutex, + 'simple': Simple, + 'start-task': StartTask, + 'sub-workflow': SubWorkflow, + 'thread-start': ThreadStart, + 'thread-merge': ThreadMerge, + 'thread-split': ThreadSplit, + 'transform': Transform, + 'trigger': Trigger, + 'workflow-spec': WorkflowSpec, + 'loop-reset-task': LoopResetTask, + 'task': Simple, + } + +def op_map(): + return { + 'equals': operators.Equal, + 'not-equals': operators.NotEqual, + 'less-than': operators.LessThan, + 'greater-than': operators.GreaterThan, + 'matches': operators.Match + } + class Serializer(object): diff --git a/SpiffWorkflow/serializer/dict.py b/SpiffWorkflow/serializer/dict.py index 5688b5877..8d1e3ad42 100644 --- a/SpiffWorkflow/serializer/dict.py +++ b/SpiffWorkflow/serializer/dict.py @@ -24,11 +24,30 @@ from ..util.impl import get_class from ..task import Task from ..operators import (Attrib, PathAttrib, Equal, NotEqual, Operator, GreaterThan, LessThan, Match) -from ..specs import (Cancel, AcquireMutex, CancelTask, Celery, Choose, - ExclusiveChoice, Execute, Gate, Join, MultiChoice, - MultiInstance, ReleaseMutex, Simple, WorkflowSpec, - TaskSpec, SubWorkflow, StartTask, ThreadMerge, - ThreadSplit, ThreadStart, Merge, Trigger, LoopResetTask) +from ..specs.base import TaskSpec +from ..specs.AcquireMutex import AcquireMutex +from ..specs.Cancel import Cancel +from ..specs.CancelTask import CancelTask +from ..specs.Celery import Celery +from ..specs.Choose import Choose +from ..specs.ExclusiveChoice import ExclusiveChoice +from ..specs.Execute import Execute +from ..specs.Gate import Gate +from ..specs.Join import Join +from ..specs.Merge import Merge +from ..specs.MultiChoice import MultiChoice +from ..specs.MultiInstance import MultiInstance +from ..specs.ReleaseMutex import ReleaseMutex +from ..specs.Simple import Simple +from ..specs.StartTask import StartTask +from ..specs.SubWorkflow import SubWorkflow +from ..specs.ThreadStart import ThreadStart +from ..specs.ThreadMerge import ThreadMerge +from ..specs.ThreadSplit import ThreadSplit +from ..specs.Transform import Transform +from ..specs.Trigger import Trigger +from ..specs.WorkflowSpec import WorkflowSpec +from ..specs.LoopResetTask import LoopResetTask from .base import Serializer from .exceptions import TaskNotSupportedError, MissingSpecError import warnings diff --git a/SpiffWorkflow/serializer/prettyxml.py b/SpiffWorkflow/serializer/prettyxml.py index 25bec80e4..9bd189c52 100644 --- a/SpiffWorkflow/serializer/prettyxml.py +++ b/SpiffWorkflow/serializer/prettyxml.py @@ -18,25 +18,15 @@ # 02110-1301 USA import re import xml.dom.minidom as minidom -from .. import operators, specs +from .. import operators +from ..specs.Simple import Simple +from ..specs.WorkflowSpec import WorkflowSpec from ..exceptions import StorageException -from .base import Serializer +from .base import Serializer, spec_map, op_map # Create a list of tag names out of the spec names. -_spec_map = dict() -for name in dir(specs): - if name.startswith('_'): - continue - module = specs.__dict__[name] - name = re.sub(r'(.)([A-Z])', r'\1-\2', name).lower() - _spec_map[name] = module -_spec_map['task'] = specs.Simple - -_op_map = {'equals': operators.Equal, - 'not-equals': operators.NotEqual, - 'less-than': operators.LessThan, - 'greater-than': operators.GreaterThan, - 'matches': operators.Match} +_spec_map = spec_map() +_op_map = op_map() _exc = StorageException @@ -299,9 +289,9 @@ class XmlSerializer(Serializer): _exc('%s without a name attribute' % node.nodeName) # Read all task specs and create a list of successors. - workflow_spec = specs.WorkflowSpec(name, filename) + workflow_spec = WorkflowSpec(name, filename) del workflow_spec.task_specs['Start'] - end = specs.Simple(workflow_spec, 'End'), [] + end = Simple(workflow_spec, 'End'), [] read_specs = dict(end=end) for child_node in node.childNodes: if child_node.nodeType != minidom.Node.ELEMENT_NODE: diff --git a/SpiffWorkflow/serializer/xml.py b/SpiffWorkflow/serializer/xml.py index f4b18b6cc..c0d0572d7 100644 --- a/SpiffWorkflow/serializer/xml.py +++ b/SpiffWorkflow/serializer/xml.py @@ -24,29 +24,35 @@ from .. import specs, operators from ..task import Task, TaskStateNames from ..operators import (Attrib, Assign, PathAttrib, Equal, NotEqual, GreaterThan, LessThan, Match) -from ..specs import (Cancel, AcquireMutex, CancelTask, Celery, Choose, - ExclusiveChoice, Execute, Gate, Join, MultiChoice, - MultiInstance, ReleaseMutex, Simple, WorkflowSpec, - SubWorkflow, StartTask, ThreadMerge, - ThreadSplit, ThreadStart, Merge, Trigger, LoopResetTask) -from .base import Serializer +from ..specs.AcquireMutex import AcquireMutex +from ..specs.Cancel import Cancel +from ..specs.CancelTask import CancelTask +from ..specs.Celery import Celery +from ..specs.Choose import Choose +from ..specs.ExclusiveChoice import ExclusiveChoice +from ..specs.Execute import Execute +from ..specs.Gate import Gate +from ..specs.Join import Join +from ..specs.Merge import Merge +from ..specs.MultiChoice import MultiChoice +from ..specs.MultiInstance import MultiInstance +from ..specs.ReleaseMutex import ReleaseMutex +from ..specs.Simple import Simple +from ..specs.StartTask import StartTask +from ..specs.SubWorkflow import SubWorkflow +from ..specs.ThreadStart import ThreadStart +from ..specs.ThreadMerge import ThreadMerge +from ..specs.ThreadSplit import ThreadSplit +from ..specs.Transform import Transform +from ..specs.Trigger import Trigger +from ..specs.WorkflowSpec import WorkflowSpec +from ..specs.LoopResetTask import LoopResetTask +from .base import Serializer, spec_map, op_map from .exceptions import TaskNotSupportedError # Create a list of tag names out of the spec names. -_spec_map = dict() -for name in dir(specs): - if name.startswith('_'): - continue - module = specs.__dict__[name] - name = re.sub(r'(.)([A-Z])', r'\1-\2', name).lower() - _spec_map[name] = module -_spec_map['task'] = specs.Simple - -_op_map = {'equals': operators.Equal, - 'not-equals': operators.NotEqual, - 'less-than': operators.LessThan, - 'greater-than': operators.GreaterThan, - 'matches': operators.Match} +_spec_map = spec_map() +_op_map = op_map() class XmlSerializer(Serializer): diff --git a/SpiffWorkflow/signavio/parser/__init__.py b/SpiffWorkflow/signavio/parser/__init__.py index 477cb987b..e69de29bb 100644 --- a/SpiffWorkflow/signavio/parser/__init__.py +++ b/SpiffWorkflow/signavio/parser/__init__.py @@ -1 +0,0 @@ -from .tasks import CallActivityParser \ No newline at end of file diff --git a/SpiffWorkflow/specs/SubWorkflow.py b/SpiffWorkflow/specs/SubWorkflow.py index 58d9f779d..197a69125 100644 --- a/SpiffWorkflow/specs/SubWorkflow.py +++ b/SpiffWorkflow/specs/SubWorkflow.py @@ -18,7 +18,7 @@ # 02110-1301 USA import os -from . import StartTask +from .StartTask import StartTask from .base import TaskSpec from ..task import TaskState from ..exceptions import WorkflowException @@ -87,7 +87,7 @@ class SubWorkflow(TaskSpec): def _create_subworkflow(self, my_task): from ..serializer.prettyxml import XmlSerializer - from ..specs import WorkflowSpec + from ..specs.WorkflowSpec import WorkflowSpec from ..workflow import Workflow file_name = valueof(my_task, self.file) serializer = XmlSerializer() diff --git a/SpiffWorkflow/specs/ThreadMerge.py b/SpiffWorkflow/specs/ThreadMerge.py index 56e3a4c33..ddbd0d712 100644 --- a/SpiffWorkflow/specs/ThreadMerge.py +++ b/SpiffWorkflow/specs/ThreadMerge.py @@ -19,7 +19,7 @@ from ..task import TaskState from ..exceptions import WorkflowException from ..operators import valueof -from ..specs import Join +from ..specs.Join import Join class ThreadMerge(Join): diff --git a/SpiffWorkflow/specs/WorkflowSpec.py b/SpiffWorkflow/specs/WorkflowSpec.py index 8ea12710b..7f084cb3f 100644 --- a/SpiffWorkflow/specs/WorkflowSpec.py +++ b/SpiffWorkflow/specs/WorkflowSpec.py @@ -17,7 +17,7 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301 USA -from ..specs import StartTask +from ..specs.StartTask import StartTask class WorkflowSpec(object): @@ -82,7 +82,7 @@ class WorkflowSpec(object): :returns: empty list if valid, a list of errors if not """ results = [] - from ..specs import Join + from ..specs.Join import Join def recursive_find_loop(task, history): current = history[:] diff --git a/SpiffWorkflow/specs/__init__.py b/SpiffWorkflow/specs/__init__.py index 1b10f8195..e69de29bb 100644 --- a/SpiffWorkflow/specs/__init__.py +++ b/SpiffWorkflow/specs/__init__.py @@ -1,31 +0,0 @@ -# -*- coding: utf-8 -*- -# flake8: noqa - -from .base import TaskSpec -from .AcquireMutex import AcquireMutex -from .Cancel import Cancel -from .CancelTask import CancelTask -from .Celery import Celery -from .Choose import Choose -from .ExclusiveChoice import ExclusiveChoice -from .Execute import Execute -from .Gate import Gate -from .Join import Join -from .Merge import Merge -from .MultiChoice import MultiChoice -from .MultiInstance import MultiInstance -from .ReleaseMutex import ReleaseMutex -from .Simple import Simple -from .StartTask import StartTask -from .SubWorkflow import SubWorkflow -from .ThreadStart import ThreadStart -from .ThreadMerge import ThreadMerge -from .ThreadSplit import ThreadSplit -from .Transform import Transform -from .Trigger import Trigger -from .WorkflowSpec import WorkflowSpec -from .LoopResetTask import LoopResetTask - -import inspect -__all__ = [name for name, obj in list(locals().items()) - if not (name.startswith('_') or inspect.ismodule(obj))] diff --git a/SpiffWorkflow/spiff/parser/__init__.py b/SpiffWorkflow/spiff/parser/__init__.py index 6b38b3623..e69de29bb 100644 --- a/SpiffWorkflow/spiff/parser/__init__.py +++ b/SpiffWorkflow/spiff/parser/__init__.py @@ -1 +0,0 @@ -from .process import SpiffBpmnParser, VALIDATOR \ No newline at end of file diff --git a/SpiffWorkflow/spiff/parser/process.py b/SpiffWorkflow/spiff/parser/process.py index 7e3dd1691..a8238b6bb 100644 --- a/SpiffWorkflow/spiff/parser/process.py +++ b/SpiffWorkflow/spiff/parser/process.py @@ -3,8 +3,15 @@ import os from SpiffWorkflow.dmn.parser.BpmnDmnParser import BpmnDmnParser from SpiffWorkflow.bpmn.parser.BpmnParser import BpmnValidator, full_tag -from SpiffWorkflow.bpmn.specs.events import StartEvent, EndEvent, IntermediateThrowEvent, BoundaryEvent, IntermediateCatchEvent -from SpiffWorkflow.spiff.specs import NoneTask, ManualTask, UserTask, ScriptTask, SubWorkflowTask, TransactionSubprocess, CallActivity, ServiceTask +from SpiffWorkflow.bpmn.specs.events.EndEvent import EndEvent +from SpiffWorkflow.bpmn.specs.events.StartEvent import StartEvent +from SpiffWorkflow.bpmn.specs.events.IntermediateEvent import IntermediateThrowEvent, BoundaryEvent, IntermediateCatchEvent +from SpiffWorkflow.spiff.specs.none_task import NoneTask +from SpiffWorkflow.spiff.specs.manual_task import ManualTask +from SpiffWorkflow.spiff.specs.user_task import UserTask +from SpiffWorkflow.spiff.specs.script_task import ScriptTask +from SpiffWorkflow.spiff.specs.subworkflow_task import SubWorkflowTask, TransactionSubprocess, CallActivity +from SpiffWorkflow.spiff.specs.service_task import ServiceTask from SpiffWorkflow.spiff.specs.events.event_types import SendTask, ReceiveTask from SpiffWorkflow.spiff.parser.task_spec import SpiffTaskParser, SubWorkflowParser, CallActivityParser, ServiceTaskParser, ScriptTaskParser from SpiffWorkflow.spiff.parser.event_parsers import (SpiffStartEventParser, SpiffEndEventParser, SpiffBoundaryEventParser, diff --git a/SpiffWorkflow/spiff/serializer/__init__.py b/SpiffWorkflow/spiff/serializer/__init__.py index 364c3ebfc..e69de29bb 100644 --- a/SpiffWorkflow/spiff/serializer/__init__.py +++ b/SpiffWorkflow/spiff/serializer/__init__.py @@ -1,4 +0,0 @@ -from .task_spec_converters import NoneTaskConverter, ManualTaskConverter, UserTaskConverter, ScriptTaskConverter -from .task_spec_converters import TransactionSubprocessConverter, CallActivityTaskConverter, SubWorkflowTaskConverter -from .task_spec_converters import StartEventConverter, EndEventConverter, IntermediateCatchEventConverter, IntermediateThrowEventConverter, \ - BoundaryEventConverter, SendTaskConverter, ReceiveTaskConverter, ServiceTaskConverter diff --git a/SpiffWorkflow/spiff/serializer/task_spec_converters.py b/SpiffWorkflow/spiff/serializer/task_spec_converters.py index 5b6769685..a1c0525c2 100644 --- a/SpiffWorkflow/spiff/serializer/task_spec_converters.py +++ b/SpiffWorkflow/spiff/serializer/task_spec_converters.py @@ -1,9 +1,16 @@ from functools import partial from SpiffWorkflow.bpmn.serializer.bpmn_converters import BpmnTaskSpecConverter -from SpiffWorkflow.bpmn.specs.events import EndEvent, StartEvent, IntermediateThrowEvent, IntermediateCatchEvent, BoundaryEvent -from SpiffWorkflow.spiff.specs import NoneTask, ManualTask, UserTask, ScriptTask, ServiceTask, SubWorkflowTask, TransactionSubprocess, CallActivity -from SpiffWorkflow.spiff.specs.events import SendTask, ReceiveTask +from SpiffWorkflow.bpmn.specs.events.StartEvent import StartEvent +from SpiffWorkflow.bpmn.specs.events.EndEvent import EndEvent +from SpiffWorkflow.bpmn.specs.events.IntermediateEvent import IntermediateThrowEvent, IntermediateCatchEvent, BoundaryEvent +from SpiffWorkflow.spiff.specs.none_task import NoneTask +from SpiffWorkflow.spiff.specs.manual_task import ManualTask +from SpiffWorkflow.spiff.specs.user_task import UserTask +from SpiffWorkflow.spiff.specs.script_task import ScriptTask +from SpiffWorkflow.spiff.specs.service_task import ServiceTask +from SpiffWorkflow.spiff.specs.subworkflow_task import SubWorkflowTask, TransactionSubprocess, CallActivity +from SpiffWorkflow.spiff.specs.events.event_types import SendTask, ReceiveTask from SpiffWorkflow.spiff.specs.events.event_definitions import MessageEventDefinition diff --git a/SpiffWorkflow/spiff/specs/__init__.py b/SpiffWorkflow/spiff/specs/__init__.py index 1e18b634a..e69de29bb 100644 --- a/SpiffWorkflow/spiff/specs/__init__.py +++ b/SpiffWorkflow/spiff/specs/__init__.py @@ -1,6 +0,0 @@ -from .manual_task import ManualTask -from .none_task import NoneTask -from .subworkflow_task import SubWorkflowTask, TransactionSubprocess, CallActivity -from .user_task import UserTask -from .script_task import ScriptTask -from .service_task import ServiceTask diff --git a/SpiffWorkflow/spiff/specs/events/__init__.py b/SpiffWorkflow/spiff/specs/events/__init__.py index 2fc0bc117..e69de29bb 100644 --- a/SpiffWorkflow/spiff/specs/events/__init__.py +++ b/SpiffWorkflow/spiff/specs/events/__init__.py @@ -1 +0,0 @@ -from .event_types import SendTask, ReceiveTask \ No newline at end of file diff --git a/SpiffWorkflow/workflow.py b/SpiffWorkflow/workflow.py index 376f2a019..906cfa5c0 100644 --- a/SpiffWorkflow/workflow.py +++ b/SpiffWorkflow/workflow.py @@ -19,7 +19,7 @@ import logging -from . import specs +from .specs.Simple import Simple from .specs.LoopResetTask import LoopResetTask from .task import Task, TaskState from .util.compat import mutex @@ -61,7 +61,7 @@ class Workflow(object): if 'Root' in workflow_spec.task_specs: root = workflow_spec.task_specs['Root'] else: - root = specs.Simple(workflow_spec, 'Root') + root = Simple(workflow_spec, 'Root') logger.info('Initialize', extra=self.log_info()) # Setting TaskState.COMPLETED prevents the root task from being executed. diff --git a/doc/non-bpmn/tutorial/start.py b/doc/non-bpmn/tutorial/start.py index e52b66c63..4090384cc 100644 --- a/doc/non-bpmn/tutorial/start.py +++ b/doc/non-bpmn/tutorial/start.py @@ -1,6 +1,6 @@ import json from SpiffWorkflow.workflow import Workflow -from SpiffWorkflow.specs import WorkflowSpec +from SpiffWorkflow.specs.WorkflowSpec import WorkflowSpec from SpiffWorkflow.serializer.json import JSONSerializer # Load from JSON diff --git a/tests/SpiffWorkflow/PatternTest.py b/tests/SpiffWorkflow/PatternTest.py index 8d11528fd..f0d013ce0 100644 --- a/tests/SpiffWorkflow/PatternTest.py +++ b/tests/SpiffWorkflow/PatternTest.py @@ -6,7 +6,7 @@ import unittest import os sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..')) -from SpiffWorkflow.specs import WorkflowSpec +from SpiffWorkflow.specs.WorkflowSpec import WorkflowSpec from SpiffWorkflow.task import Task from SpiffWorkflow.serializer.prettyxml import XmlSerializer from tests.SpiffWorkflow.util import run_workflow diff --git a/tests/SpiffWorkflow/PersistSmallWorkflowTest.py b/tests/SpiffWorkflow/PersistSmallWorkflowTest.py index c580c87d7..b554be189 100644 --- a/tests/SpiffWorkflow/PersistSmallWorkflowTest.py +++ b/tests/SpiffWorkflow/PersistSmallWorkflowTest.py @@ -6,7 +6,9 @@ import os.path sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..')) from SpiffWorkflow.workflow import Workflow -from SpiffWorkflow.specs import Join, MultiChoice, WorkflowSpec +from SpiffWorkflow.specs.Join import Join +from SpiffWorkflow.specs.MultiChoice import MultiChoice +from SpiffWorkflow.specs.WorkflowSpec import WorkflowSpec from SpiffWorkflow.operators import Attrib, Equal, PathAttrib from SpiffWorkflow.task import TaskState from SpiffWorkflow.specs.Simple import Simple diff --git a/tests/SpiffWorkflow/TaskTest.py b/tests/SpiffWorkflow/TaskTest.py index af4f28e33..e44f68e6f 100644 --- a/tests/SpiffWorkflow/TaskTest.py +++ b/tests/SpiffWorkflow/TaskTest.py @@ -7,7 +7,8 @@ import os.path sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..')) from SpiffWorkflow.task import Task, TaskState, updateDotDict -from SpiffWorkflow.specs import WorkflowSpec, Simple +from SpiffWorkflow.specs.WorkflowSpec import WorkflowSpec +from SpiffWorkflow.specs.Simple import Simple class MockWorkflow(object): diff --git a/tests/SpiffWorkflow/WorkflowTest.py b/tests/SpiffWorkflow/WorkflowTest.py index e47f069da..0d2b0b3d0 100644 --- a/tests/SpiffWorkflow/WorkflowTest.py +++ b/tests/SpiffWorkflow/WorkflowTest.py @@ -7,7 +7,9 @@ data_dir = os.path.join(os.path.dirname(__file__), 'data') sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..')) from SpiffWorkflow.workflow import Workflow -from SpiffWorkflow.specs import Cancel, Simple, WorkflowSpec +from SpiffWorkflow.specs.Cancel import Cancel +from SpiffWorkflow.specs.Simple import Simple +from SpiffWorkflow.specs.WorkflowSpec import WorkflowSpec from SpiffWorkflow.task import TaskState from SpiffWorkflow.serializer.prettyxml import XmlSerializer diff --git a/tests/SpiffWorkflow/bpmn/ApprovalsTest.py b/tests/SpiffWorkflow/bpmn/ApprovalsTest.py index 19f493806..7576a23fe 100644 --- a/tests/SpiffWorkflow/bpmn/ApprovalsTest.py +++ b/tests/SpiffWorkflow/bpmn/ApprovalsTest.py @@ -2,7 +2,7 @@ import unittest from SpiffWorkflow.bpmn.workflow import BpmnWorkflow -from SpiffWorkflow.bpmn.specs.events import MessageEventDefinition +from SpiffWorkflow.bpmn.specs.events.event_definitions import MessageEventDefinition from tests.SpiffWorkflow.bpmn.BpmnWorkflowTestCase import BpmnWorkflowTestCase __author__ = 'matth' diff --git a/tests/SpiffWorkflow/bpmn/BpmnLoaderForTests.py b/tests/SpiffWorkflow/bpmn/BpmnLoaderForTests.py index 7a407cc7f..54c18709f 100644 --- a/tests/SpiffWorkflow/bpmn/BpmnLoaderForTests.py +++ b/tests/SpiffWorkflow/bpmn/BpmnLoaderForTests.py @@ -10,7 +10,7 @@ from SpiffWorkflow.bpmn.serializer.bpmn_converters import BpmnTaskSpecConverter # Many of our tests relied on the Packager to set the calledElement attribute on # Call Activities. I've moved that code to a customized parser. -from SpiffWorkflow.signavio.parser import CallActivityParser +from SpiffWorkflow.signavio.parser.tasks import CallActivityParser from SpiffWorkflow.bpmn.specs.SubWorkflowTask import CallActivity __author__ = 'matth' diff --git a/tests/SpiffWorkflow/bpmn/BpmnWorkflowSerializerTest.py b/tests/SpiffWorkflow/bpmn/BpmnWorkflowSerializerTest.py index d0d1a9479..ac2ae463c 100644 --- a/tests/SpiffWorkflow/bpmn/BpmnWorkflowSerializerTest.py +++ b/tests/SpiffWorkflow/bpmn/BpmnWorkflowSerializerTest.py @@ -6,7 +6,7 @@ from uuid import uuid4 from SpiffWorkflow.task import TaskState from SpiffWorkflow.bpmn.PythonScriptEngine import PythonScriptEngine from SpiffWorkflow.bpmn.parser.BpmnParser import BpmnParser -from SpiffWorkflow.bpmn.serializer import BpmnWorkflowSerializer +from SpiffWorkflow.bpmn.serializer.workflow import BpmnWorkflowSerializer from SpiffWorkflow.bpmn.serializer.BpmnSerializer import BpmnSerializer from SpiffWorkflow.bpmn.workflow import BpmnWorkflow from tests.SpiffWorkflow.bpmn.BpmnLoaderForTests import TestUserTaskConverter diff --git a/tests/SpiffWorkflow/bpmn/BpmnWorkflowTestCase.py b/tests/SpiffWorkflow/bpmn/BpmnWorkflowTestCase.py index 5a341188b..e2864919e 100644 --- a/tests/SpiffWorkflow/bpmn/BpmnWorkflowTestCase.py +++ b/tests/SpiffWorkflow/bpmn/BpmnWorkflowTestCase.py @@ -7,7 +7,7 @@ from SpiffWorkflow.bpmn.parser.BpmnParser import BpmnValidator from SpiffWorkflow.task import TaskState -from SpiffWorkflow.bpmn.serializer import BpmnWorkflowSerializer +from SpiffWorkflow.bpmn.serializer.workflow import BpmnWorkflowSerializer from .BpmnLoaderForTests import TestUserTaskConverter, TestBpmnParser __author__ = 'matth' diff --git a/tests/SpiffWorkflow/bpmn/ProcessDependencyTest.py b/tests/SpiffWorkflow/bpmn/ProcessDependencyTest.py index b3a795196..86514a034 100644 --- a/tests/SpiffWorkflow/bpmn/ProcessDependencyTest.py +++ b/tests/SpiffWorkflow/bpmn/ProcessDependencyTest.py @@ -3,7 +3,7 @@ import os import unittest from SpiffWorkflow.camunda.parser.CamundaParser import CamundaParser -from SpiffWorkflow.spiff.parser import SpiffBpmnParser +from SpiffWorkflow.spiff.parser.process import SpiffBpmnParser from tests.SpiffWorkflow.bpmn.BpmnWorkflowTestCase import BpmnWorkflowTestCase diff --git a/tests/SpiffWorkflow/bpmn/events/MultipleEventsTest.py b/tests/SpiffWorkflow/bpmn/events/MultipleEventsTest.py index b1e2a24d5..86c552358 100644 --- a/tests/SpiffWorkflow/bpmn/events/MultipleEventsTest.py +++ b/tests/SpiffWorkflow/bpmn/events/MultipleEventsTest.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- import unittest -from SpiffWorkflow.bpmn.specs.events import CancelEventDefinition, SignalEventDefinition +from SpiffWorkflow.bpmn.specs.events.event_definitions import CancelEventDefinition, SignalEventDefinition from SpiffWorkflow.task import TaskState from SpiffWorkflow.bpmn.workflow import BpmnWorkflow from tests.SpiffWorkflow.bpmn.BpmnWorkflowTestCase import BpmnWorkflowTestCase diff --git a/tests/SpiffWorkflow/bpmn/events/TimerDurationBoundaryOnTaskTest.py b/tests/SpiffWorkflow/bpmn/events/TimerDurationBoundaryOnTaskTest.py index e87de251e..9bd1f322b 100644 --- a/tests/SpiffWorkflow/bpmn/events/TimerDurationBoundaryOnTaskTest.py +++ b/tests/SpiffWorkflow/bpmn/events/TimerDurationBoundaryOnTaskTest.py @@ -5,7 +5,7 @@ import datetime import time from datetime import timedelta -from SpiffWorkflow.bpmn.specs.events import EndEvent +from SpiffWorkflow.bpmn.specs.events.EndEvent import EndEvent from SpiffWorkflow.task import TaskState from SpiffWorkflow.bpmn.workflow import BpmnWorkflow from SpiffWorkflow.bpmn.PythonScriptEngine import PythonScriptEngine diff --git a/tests/SpiffWorkflow/camunda/BaseTestCase.py b/tests/SpiffWorkflow/camunda/BaseTestCase.py index 6ea39d0ac..b41a8aab7 100644 --- a/tests/SpiffWorkflow/camunda/BaseTestCase.py +++ b/tests/SpiffWorkflow/camunda/BaseTestCase.py @@ -1,12 +1,12 @@ # -*- coding: utf-8 -*- import os -from SpiffWorkflow.bpmn.serializer import BpmnWorkflowSerializer +from SpiffWorkflow.bpmn.serializer.workflow import BpmnWorkflowSerializer from SpiffWorkflow.camunda.parser.CamundaParser import CamundaParser -from SpiffWorkflow.camunda.serializer import UserTaskConverter, StartEventConverter, EndEventConverter, \ +from SpiffWorkflow.camunda.serializer.task_spec_converters import UserTaskConverter, StartEventConverter, EndEventConverter, \ IntermediateCatchEventConverter, IntermediateThrowEventConverter, BoundaryEventConverter -from SpiffWorkflow.dmn.serializer import BusinessRuleTaskConverter +from SpiffWorkflow.dmn.serializer.task_spec_converters import BusinessRuleTaskConverter from tests.SpiffWorkflow.bpmn.BpmnWorkflowTestCase import BpmnWorkflowTestCase diff --git a/tests/SpiffWorkflow/camunda/specs/UserTaskSpecTest.py b/tests/SpiffWorkflow/camunda/specs/UserTaskSpecTest.py index 2d3c16d7f..33f621912 100644 --- a/tests/SpiffWorkflow/camunda/specs/UserTaskSpecTest.py +++ b/tests/SpiffWorkflow/camunda/specs/UserTaskSpecTest.py @@ -3,7 +3,8 @@ import unittest from SpiffWorkflow.camunda.specs.UserTask import FormField, UserTask, Form, \ EnumFormField -from SpiffWorkflow.specs import WorkflowSpec, TaskSpec +from SpiffWorkflow.specs.base import TaskSpec +from SpiffWorkflow.specs.WorkflowSpec import WorkflowSpec class UserTaskSpecTest(unittest.TestCase): diff --git a/tests/SpiffWorkflow/data/spiff/workflow1.py b/tests/SpiffWorkflow/data/spiff/workflow1.py index fba204bd6..bc963fea1 100644 --- a/tests/SpiffWorkflow/data/spiff/workflow1.py +++ b/tests/SpiffWorkflow/data/spiff/workflow1.py @@ -1,6 +1,11 @@ # -*- coding: utf-8 -*- -from SpiffWorkflow.specs import ExclusiveChoice, Join, MultiChoice, MultiInstance, Simple, WorkflowSpec +from SpiffWorkflow.specs.ExclusiveChoice import ExclusiveChoice +from SpiffWorkflow.specs.Join import Join +from SpiffWorkflow.specs.MultiChoice import MultiChoice +from SpiffWorkflow.specs.MultiInstance import MultiInstance +from SpiffWorkflow.specs.Simple import Simple +from SpiffWorkflow.specs.WorkflowSpec import WorkflowSpec from SpiffWorkflow.operators import Attrib, Equal, NotEqual diff --git a/tests/SpiffWorkflow/serializer/baseTest.py b/tests/SpiffWorkflow/serializer/baseTest.py index 9bb79b137..7ac41f3c7 100644 --- a/tests/SpiffWorkflow/serializer/baseTest.py +++ b/tests/SpiffWorkflow/serializer/baseTest.py @@ -11,7 +11,7 @@ sys.path.insert(0, os.path.join(dirname, '..')) from PatternTest import run_workflow, PatternTest from SpiffWorkflow.serializer.base import Serializer -from SpiffWorkflow.specs import WorkflowSpec +from SpiffWorkflow.specs.WorkflowSpec import WorkflowSpec from SpiffWorkflow.workflow import Workflow from SpiffWorkflow.serializer.exceptions import TaskNotSupportedError diff --git a/tests/SpiffWorkflow/specs/CeleryTest.py b/tests/SpiffWorkflow/specs/CeleryTest.py index 9190dd33f..ac8116881 100644 --- a/tests/SpiffWorkflow/specs/CeleryTest.py +++ b/tests/SpiffWorkflow/specs/CeleryTest.py @@ -6,7 +6,8 @@ import unittest import pickle sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..')) from .TaskSpecTest import TaskSpecTest -from SpiffWorkflow.specs import Celery, WorkflowSpec +from SpiffWorkflow.specs.Celery import Celery +from SpiffWorkflow.specs.WorkflowSpec import WorkflowSpec from SpiffWorkflow.operators import Attrib from SpiffWorkflow.serializer.dict import DictionarySerializer from base64 import b64encode diff --git a/tests/SpiffWorkflow/specs/ExecuteTest.py b/tests/SpiffWorkflow/specs/ExecuteTest.py index bd3b06fd5..fc16db931 100644 --- a/tests/SpiffWorkflow/specs/ExecuteTest.py +++ b/tests/SpiffWorkflow/specs/ExecuteTest.py @@ -10,7 +10,7 @@ sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..')) from tests.SpiffWorkflow.util import run_workflow from .TaskSpecTest import TaskSpecTest from SpiffWorkflow.task import TaskState -from SpiffWorkflow.specs import Execute +from SpiffWorkflow.specs.Execute import Execute class ExecuteTest(TaskSpecTest): diff --git a/tests/SpiffWorkflow/specs/JoinTest.py b/tests/SpiffWorkflow/specs/JoinTest.py index 3eeb92866..7224701f5 100644 --- a/tests/SpiffWorkflow/specs/JoinTest.py +++ b/tests/SpiffWorkflow/specs/JoinTest.py @@ -8,7 +8,7 @@ import unittest sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..')) from .TaskSpecTest import TaskSpecTest -from SpiffWorkflow.specs import Join +from SpiffWorkflow.specs.Join import Join class JoinTest(TaskSpecTest): diff --git a/tests/SpiffWorkflow/specs/MergeTest.py b/tests/SpiffWorkflow/specs/MergeTest.py index 68f028d90..6fc692a66 100644 --- a/tests/SpiffWorkflow/specs/MergeTest.py +++ b/tests/SpiffWorkflow/specs/MergeTest.py @@ -8,7 +8,9 @@ import unittest sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..')) from .JoinTest import JoinTest -from SpiffWorkflow.specs import Merge, WorkflowSpec, Simple +from SpiffWorkflow.specs.Merge import Merge +from SpiffWorkflow.specs.WorkflowSpec import WorkflowSpec +from SpiffWorkflow.specs.Simple import Simple from SpiffWorkflow.workflow import Workflow diff --git a/tests/SpiffWorkflow/specs/SubWorkflowTest.py b/tests/SpiffWorkflow/specs/SubWorkflowTest.py index aed09fc27..5baacf99e 100644 --- a/tests/SpiffWorkflow/specs/SubWorkflowTest.py +++ b/tests/SpiffWorkflow/specs/SubWorkflowTest.py @@ -6,7 +6,7 @@ import os sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..')) -from SpiffWorkflow.specs import WorkflowSpec +from SpiffWorkflow.specs.WorkflowSpec import WorkflowSpec from SpiffWorkflow.specs.SubWorkflow import SubWorkflow from SpiffWorkflow.serializer.prettyxml import XmlSerializer from SpiffWorkflow.task import TaskState diff --git a/tests/SpiffWorkflow/specs/TaskSpecTest.py b/tests/SpiffWorkflow/specs/TaskSpecTest.py index 2b213b4af..2509d6184 100644 --- a/tests/SpiffWorkflow/specs/TaskSpecTest.py +++ b/tests/SpiffWorkflow/specs/TaskSpecTest.py @@ -5,9 +5,11 @@ import unittest import os sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..')) -from SpiffWorkflow.specs import WorkflowSpec, Simple, Join +from SpiffWorkflow.specs.Join import Join +from SpiffWorkflow.specs.Simple import Simple +from SpiffWorkflow.specs.WorkflowSpec import WorkflowSpec from SpiffWorkflow.exceptions import WorkflowException -from SpiffWorkflow.specs import TaskSpec +from SpiffWorkflow.specs.base import TaskSpec from SpiffWorkflow.serializer.dict import DictionarySerializer diff --git a/tests/SpiffWorkflow/specs/TransformTest.py b/tests/SpiffWorkflow/specs/TransformTest.py index ca2aaf1c3..228a038ec 100644 --- a/tests/SpiffWorkflow/specs/TransformTest.py +++ b/tests/SpiffWorkflow/specs/TransformTest.py @@ -9,7 +9,8 @@ sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..')) from tests.SpiffWorkflow.util import run_workflow from .TaskSpecTest import TaskSpecTest -from SpiffWorkflow.specs import Transform, Simple +from SpiffWorkflow.specs.Transform import Transform +from SpiffWorkflow.specs.Simple import Simple class TransformTest(TaskSpecTest): diff --git a/tests/SpiffWorkflow/specs/WorkflowSpecTest.py b/tests/SpiffWorkflow/specs/WorkflowSpecTest.py index 8b0289b8d..9b4c0d322 100644 --- a/tests/SpiffWorkflow/specs/WorkflowSpecTest.py +++ b/tests/SpiffWorkflow/specs/WorkflowSpecTest.py @@ -15,7 +15,8 @@ try: except ImportError as e: from tests.SpiffWorkflow.util import track_workflow from SpiffWorkflow.workflow import Workflow -from SpiffWorkflow.specs import Join, WorkflowSpec +from SpiffWorkflow.specs.Join import Join +from SpiffWorkflow.specs.WorkflowSpec import WorkflowSpec from SpiffWorkflow.serializer.prettyxml import XmlSerializer serializer = XmlSerializer() diff --git a/tests/SpiffWorkflow/spiff/BaseTestCase.py b/tests/SpiffWorkflow/spiff/BaseTestCase.py index 9e882fcb9..b085d1f76 100644 --- a/tests/SpiffWorkflow/spiff/BaseTestCase.py +++ b/tests/SpiffWorkflow/spiff/BaseTestCase.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- import os -from SpiffWorkflow.spiff.parser import SpiffBpmnParser, VALIDATOR -from SpiffWorkflow.spiff.serializer import NoneTaskConverter, \ +from SpiffWorkflow.spiff.parser.process import SpiffBpmnParser, VALIDATOR +from SpiffWorkflow.spiff.serializer.task_spec_converters import NoneTaskConverter, \ ManualTaskConverter, UserTaskConverter, ScriptTaskConverter, \ SubWorkflowTaskConverter, TransactionSubprocessConverter, \ CallActivityTaskConverter, \ @@ -11,7 +11,7 @@ from SpiffWorkflow.spiff.serializer import NoneTaskConverter, \ IntermediateCatchEventConverter, IntermediateThrowEventConverter, \ ServiceTaskConverter from SpiffWorkflow.dmn.serializer.task_spec_converters import BusinessRuleTaskConverter -from SpiffWorkflow.bpmn.serializer import BpmnWorkflowSerializer +from SpiffWorkflow.bpmn.serializer.workflow import BpmnWorkflowSerializer from tests.SpiffWorkflow.bpmn.BpmnWorkflowTestCase import BpmnWorkflowTestCase From a0b923c9ad98d07d3cf46dca689a01b13d41aa02 Mon Sep 17 00:00:00 2001 From: burnettk Date: Fri, 4 Nov 2022 09:33:44 -0400 Subject: [PATCH 11/12] Squashed 'spiffworkflow-backend/' changes from dba09086ba..5c6601237e 5c6601237e upgrade spiff and add commented out assertion 150cb68824 Change steps when viewing a process instance model (#18) beac7f40c4 prevent backfill from exploding when a primary file name on another model does not exist 3e6b61911e work around parser.get_process_dependencies returning a set containing the element None 65c343337d Point back to spiff main (#19) 7eafd5c994 Track spiff step details more granularly (#17) 85829dd56d Clear the remaining __init__.py imports in SpiffWorkflow (#14) c3468ca548 From the logs, allow viewing a diagram in a previous state (#15) git-subtree-dir: spiffworkflow-backend git-subtree-split: 5c6601237ebdccf864b23dac74bf3e1ca77ead1e --- .../{bdd1d64689db_.py => b1647eff45c9_.py} | 20 ++- poetry.lock | 40 +++-- src/spiffworkflow_backend/api.yml | 6 + .../load_database_models.py | 3 + .../models/process_instance.py | 3 + .../models/spiff_logging.py | 1 + .../models/spiff_step_details.py | 23 +++ .../routes/process_api_blueprint.py | 17 ++- .../scripts/get_current_user.py | 4 +- .../scripts/get_process_info.py | 2 +- .../services/logging_service.py | 8 + .../services/process_instance_processor.py | 138 ++++++++++++++---- .../services/spec_file_service.py | 9 +- .../integration/test_process_api.py | 2 + .../unit/test_spiff_logging.py | 1 + 15 files changed, 219 insertions(+), 58 deletions(-) rename migrations/versions/{bdd1d64689db_.py => b1647eff45c9_.py} (95%) create mode 100644 src/spiffworkflow_backend/models/spiff_step_details.py diff --git a/migrations/versions/bdd1d64689db_.py b/migrations/versions/b1647eff45c9_.py similarity index 95% rename from migrations/versions/bdd1d64689db_.py rename to migrations/versions/b1647eff45c9_.py index 555661497..d6ff25e3b 100644 --- a/migrations/versions/bdd1d64689db_.py +++ b/migrations/versions/b1647eff45c9_.py @@ -1,8 +1,8 @@ """empty message -Revision ID: bdd1d64689db +Revision ID: b1647eff45c9 Revises: -Create Date: 2022-11-02 11:31:50.606843 +Create Date: 2022-11-02 14:25:09.992800 """ from alembic import op @@ -10,7 +10,7 @@ import sqlalchemy as sa # revision identifiers, used by Alembic. -revision = 'bdd1d64689db' +revision = 'b1647eff45c9' down_revision = None branch_labels = None depends_on = None @@ -106,6 +106,7 @@ def upgrade(): sa.Column('status', sa.String(length=50), nullable=True), sa.Column('bpmn_version_control_type', sa.String(length=50), nullable=True), sa.Column('bpmn_version_control_identifier', sa.String(length=255), nullable=True), + sa.Column('spiff_step', sa.Integer(), nullable=True), sa.ForeignKeyConstraint(['process_initiator_id'], ['user.id'], ), sa.PrimaryKeyConstraint('id') ) @@ -229,10 +230,22 @@ def upgrade(): sa.Column('timestamp', sa.DECIMAL(precision=17, scale=6), nullable=False), sa.Column('message', sa.String(length=255), nullable=True), sa.Column('current_user_id', sa.Integer(), nullable=True), + sa.Column('spiff_step', sa.Integer(), nullable=False), sa.ForeignKeyConstraint(['current_user_id'], ['user.id'], ), sa.ForeignKeyConstraint(['process_instance_id'], ['process_instance.id'], ), sa.PrimaryKeyConstraint('id') ) + op.create_table('spiff_step_details', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('process_instance_id', sa.Integer(), nullable=False), + sa.Column('spiff_step', sa.Integer(), nullable=False), + sa.Column('task_json', sa.JSON(), nullable=False), + sa.Column('timestamp', sa.DECIMAL(precision=17, scale=6), nullable=False), + sa.Column('completed_by_user_id', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['completed_by_user_id'], ['user.id'], ), + sa.ForeignKeyConstraint(['process_instance_id'], ['process_instance.id'], ), + sa.PrimaryKeyConstraint('id') + ) op.create_table('active_task_user', sa.Column('id', sa.Integer(), nullable=False), sa.Column('active_task_id', sa.Integer(), nullable=False), @@ -266,6 +279,7 @@ def downgrade(): op.drop_index(op.f('ix_active_task_user_user_id'), table_name='active_task_user') op.drop_index(op.f('ix_active_task_user_active_task_id'), table_name='active_task_user') op.drop_table('active_task_user') + op.drop_table('spiff_step_details') op.drop_table('spiff_logging') op.drop_table('permission_assignment') op.drop_table('message_instance') diff --git a/poetry.lock b/poetry.lock index c474c696d..8b1e9cb75 100644 --- a/poetry.lock +++ b/poetry.lock @@ -95,7 +95,7 @@ python-versions = ">=3.5" dev = ["cloudpickle", "coverage[toml] (>=5.0.2)", "furo", "hypothesis", "mypy (>=0.900,!=0.940)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "sphinx", "sphinx-notfound-page", "zope.interface"] docs = ["furo", "sphinx", "sphinx-notfound-page", "zope.interface"] tests = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "zope.interface"] -tests-no-zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins"] +tests_no_zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins"] [[package]] name = "Babel" @@ -268,7 +268,7 @@ optional = false python-versions = ">=3.6.0" [package.extras] -unicode-backport = ["unicodedata2"] +unicode_backport = ["unicodedata2"] [[package]] name = "classify-imports" @@ -1512,7 +1512,7 @@ urllib3 = ">=1.21.1,<1.27" [package.extras] socks = ["PySocks (>=1.5.6,!=1.5.7)"] -use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] +use_chardet_on_py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "requests-toolbelt" @@ -1625,7 +1625,7 @@ falcon = ["falcon (>=1.4)"] fastapi = ["fastapi (>=0.79.0)"] flask = ["blinker (>=1.1)", "flask (>=0.11)"] httpx = ["httpx (>=0.16.0)"] -pure-eval = ["asttokens", "executing", "pure-eval"] +pure_eval = ["asttokens", "executing", "pure-eval"] pyspark = ["pyspark (>=2.4.4)"] quart = ["blinker (>=1.1)", "quart (>=0.16.1)"] rq = ["rq (>=0.6)"] @@ -1873,7 +1873,7 @@ pytz = "*" type = "git" url = "https://github.com/sartography/SpiffWorkflow" reference = "main" -resolved_reference = "a6392d19061f623394f5705fb78af23673d3940d" +resolved_reference = "8d820dce1f439bb76bc07e39629832d998d6f634" [[package]] name = "SQLAlchemy" @@ -1891,19 +1891,19 @@ aiomysql = ["aiomysql", "greenlet (!=0.4.17)"] aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing_extensions (!=3.10.0.1)"] asyncio = ["greenlet (!=0.4.17)"] asyncmy = ["asyncmy (>=0.2.3,!=0.2.4)", "greenlet (!=0.4.17)"] -mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2)"] +mariadb_connector = ["mariadb (>=1.0.1,!=1.1.2)"] mssql = ["pyodbc"] -mssql-pymssql = ["pymssql"] -mssql-pyodbc = ["pyodbc"] +mssql_pymssql = ["pymssql"] +mssql_pyodbc = ["pyodbc"] mypy = ["mypy (>=0.910)", "sqlalchemy2-stubs"] mysql = ["mysqlclient (>=1.4.0)", "mysqlclient (>=1.4.0,<2)"] -mysql-connector = ["mysql-connector-python"] +mysql_connector = ["mysql-connector-python"] oracle = ["cx_oracle (>=7)", "cx_oracle (>=7,<8)"] postgresql = ["psycopg2 (>=2.7)"] -postgresql-asyncpg = ["asyncpg", "greenlet (!=0.4.17)"] -postgresql-pg8000 = ["pg8000 (>=1.16.6,!=1.29.0)"] -postgresql-psycopg2binary = ["psycopg2-binary"] -postgresql-psycopg2cffi = ["psycopg2cffi"] +postgresql_asyncpg = ["asyncpg", "greenlet (!=0.4.17)"] +postgresql_pg8000 = ["pg8000 (>=1.16.6,!=1.29.0)"] +postgresql_psycopg2binary = ["psycopg2-binary"] +postgresql_psycopg2cffi = ["psycopg2cffi"] pymysql = ["pymysql", "pymysql (<1)"] sqlcipher = ["sqlcipher3_binary"] @@ -2946,10 +2946,7 @@ orjson = [ {file = "orjson-3.8.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b68a42a31f8429728183c21fb440c21de1b62e5378d0d73f280e2d894ef8942e"}, {file = "orjson-3.8.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ff13410ddbdda5d4197a4a4c09969cb78c722a67550f0a63c02c07aadc624833"}, {file = "orjson-3.8.0-cp310-none-win_amd64.whl", hash = "sha256:2d81e6e56bbea44be0222fb53f7b255b4e7426290516771592738ca01dbd053b"}, - {file = "orjson-3.8.0-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:200eae21c33f1f8b02a11f5d88d76950cd6fd986d88f1afe497a8ae2627c49aa"}, - {file = "orjson-3.8.0-cp311-cp311-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:9529990f3eab54b976d327360aa1ff244a4b12cb5e4c5b3712fcdd96e8fe56d4"}, {file = "orjson-3.8.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:e2defd9527651ad39ec20ae03c812adf47ef7662bdd6bc07dabb10888d70dc62"}, - {file = "orjson-3.8.0-cp311-none-win_amd64.whl", hash = "sha256:b21c7af0ff6228ca7105f54f0800636eb49201133e15ddb80ac20c1ce973ef07"}, {file = "orjson-3.8.0-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:9e6ac22cec72d5b39035b566e4b86c74b84866f12b5b0b6541506a080fb67d6d"}, {file = "orjson-3.8.0-cp37-cp37m-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:e2f4a5542f50e3d336a18cb224fc757245ca66b1fd0b70b5dd4471b8ff5f2b0e"}, {file = "orjson-3.8.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1418feeb8b698b9224b1f024555895169d481604d5d884498c1838d7412794c"}, @@ -3062,7 +3059,18 @@ py = [ {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, ] pyasn1 = [ + {file = "pyasn1-0.4.8-py2.4.egg", hash = "sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3"}, + {file = "pyasn1-0.4.8-py2.5.egg", hash = "sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf"}, + {file = "pyasn1-0.4.8-py2.6.egg", hash = "sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00"}, + {file = "pyasn1-0.4.8-py2.7.egg", hash = "sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8"}, {file = "pyasn1-0.4.8-py2.py3-none-any.whl", hash = "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d"}, + {file = "pyasn1-0.4.8-py3.1.egg", hash = "sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86"}, + {file = "pyasn1-0.4.8-py3.2.egg", hash = "sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7"}, + {file = "pyasn1-0.4.8-py3.3.egg", hash = "sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576"}, + {file = "pyasn1-0.4.8-py3.4.egg", hash = "sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12"}, + {file = "pyasn1-0.4.8-py3.5.egg", hash = "sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2"}, + {file = "pyasn1-0.4.8-py3.6.egg", hash = "sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359"}, + {file = "pyasn1-0.4.8-py3.7.egg", hash = "sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776"}, {file = "pyasn1-0.4.8.tar.gz", hash = "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba"}, ] pycodestyle = [ diff --git a/src/spiffworkflow_backend/api.yml b/src/spiffworkflow_backend/api.yml index 614d4f26c..0f0a49c24 100755 --- a/src/spiffworkflow_backend/api.yml +++ b/src/spiffworkflow_backend/api.yml @@ -1000,6 +1000,12 @@ paths: description: If true, this wil return all tasks associated with the process instance and not just user tasks. schema: type: boolean + - name: spiff_step + in: query + required: false + description: If set will return the tasks as they were during a specific step of execution. + schema: + type: integer get: tags: - Process Instances diff --git a/src/spiffworkflow_backend/load_database_models.py b/src/spiffworkflow_backend/load_database_models.py index 7283b19b1..14dcac0dc 100644 --- a/src/spiffworkflow_backend/load_database_models.py +++ b/src/spiffworkflow_backend/load_database_models.py @@ -46,6 +46,9 @@ from spiffworkflow_backend.models.process_instance_report import ( from spiffworkflow_backend.models.refresh_token import RefreshTokenModel # noqa: F401 from spiffworkflow_backend.models.secret_model import SecretModel # noqa: F401 from spiffworkflow_backend.models.spiff_logging import SpiffLoggingModel # noqa: F401 +from spiffworkflow_backend.models.spiff_step_details import ( + SpiffStepDetailsModel, +) # noqa: F401 from spiffworkflow_backend.models.user import UserModel # noqa: F401 from spiffworkflow_backend.models.group import GroupModel # noqa: F401 diff --git a/src/spiffworkflow_backend/models/process_instance.py b/src/spiffworkflow_backend/models/process_instance.py index 1c2098e91..50c3c9f76 100644 --- a/src/spiffworkflow_backend/models/process_instance.py +++ b/src/spiffworkflow_backend/models/process_instance.py @@ -81,6 +81,7 @@ class ProcessInstanceModel(SpiffworkflowBaseDBModel): spiff_logs = relationship("SpiffLoggingModel", cascade="delete") # type: ignore message_instances = relationship("MessageInstanceModel", cascade="delete") # type: ignore message_correlations = relationship("MessageCorrelationModel", cascade="delete") # type: ignore + spiff_step_details = relationship("SpiffStepDetailsModel", cascade="delete") # type: ignore bpmn_json: str | None = deferred(db.Column(db.JSON)) # type: ignore start_in_seconds: int | None = db.Column(db.Integer) @@ -92,6 +93,7 @@ class ProcessInstanceModel(SpiffworkflowBaseDBModel): bpmn_xml_file_contents: bytes | None = None bpmn_version_control_type: str = db.Column(db.String(50)) bpmn_version_control_identifier: str = db.Column(db.String(255)) + spiff_step: int = db.Column(db.Integer) @property def serialized(self) -> dict[str, Any]: @@ -110,6 +112,7 @@ class ProcessInstanceModel(SpiffworkflowBaseDBModel): "end_in_seconds": self.end_in_seconds, "process_initiator_id": self.process_initiator_id, "bpmn_xml_file_contents": local_bpmn_xml_file_contents, + "spiff_step": self.spiff_step, } @property diff --git a/src/spiffworkflow_backend/models/spiff_logging.py b/src/spiffworkflow_backend/models/spiff_logging.py index a655ec513..58f13cd4e 100644 --- a/src/spiffworkflow_backend/models/spiff_logging.py +++ b/src/spiffworkflow_backend/models/spiff_logging.py @@ -25,3 +25,4 @@ class SpiffLoggingModel(SpiffworkflowBaseDBModel): timestamp: float = db.Column(db.DECIMAL(17, 6), nullable=False) message: Optional[str] = db.Column(db.String(255), nullable=True) current_user_id: int = db.Column(ForeignKey(UserModel.id), nullable=True) + spiff_step: int = db.Column(db.Integer, nullable=False) diff --git a/src/spiffworkflow_backend/models/spiff_step_details.py b/src/spiffworkflow_backend/models/spiff_step_details.py new file mode 100644 index 000000000..1706c2e91 --- /dev/null +++ b/src/spiffworkflow_backend/models/spiff_step_details.py @@ -0,0 +1,23 @@ +"""Spiff_step_details.""" +from dataclasses import dataclass + +from flask_bpmn.models.db import db +from flask_bpmn.models.db import SpiffworkflowBaseDBModel +from sqlalchemy import ForeignKey +from sqlalchemy.orm import deferred + +from spiffworkflow_backend.models.process_instance import ProcessInstanceModel +from spiffworkflow_backend.models.user import UserModel + + +@dataclass +class SpiffStepDetailsModel(SpiffworkflowBaseDBModel): + """SpiffStepDetailsModel.""" + + __tablename__ = "spiff_step_details" + id: int = db.Column(db.Integer, primary_key=True) + process_instance_id: int = db.Column(ForeignKey(ProcessInstanceModel.id), nullable=False) # type: ignore + spiff_step: int = db.Column(db.Integer, nullable=False) + task_json: str | None = deferred(db.Column(db.JSON, nullable=False)) # type: ignore + timestamp: float = db.Column(db.DECIMAL(17, 6), nullable=False) + completed_by_user_id: int = db.Column(ForeignKey(UserModel.id), nullable=True) diff --git a/src/spiffworkflow_backend/routes/process_api_blueprint.py b/src/spiffworkflow_backend/routes/process_api_blueprint.py index 0523ad255..41cd9d996 100644 --- a/src/spiffworkflow_backend/routes/process_api_blueprint.py +++ b/src/spiffworkflow_backend/routes/process_api_blueprint.py @@ -56,6 +56,7 @@ from spiffworkflow_backend.models.process_model import ProcessModelInfoSchema from spiffworkflow_backend.models.secret_model import SecretModel from spiffworkflow_backend.models.secret_model import SecretModelSchema from spiffworkflow_backend.models.spiff_logging import SpiffLoggingModel +from spiffworkflow_backend.models.spiff_step_details import SpiffStepDetailsModel from spiffworkflow_backend.models.user import UserModel from spiffworkflow_backend.routes.user import verify_token from spiffworkflow_backend.services.authorization_service import AuthorizationService @@ -954,10 +955,23 @@ def task_list_my_tasks(page: int = 1, per_page: int = 100) -> flask.wrappers.Res def process_instance_task_list( - process_instance_id: int, all_tasks: bool = False + process_instance_id: int, all_tasks: bool = False, spiff_step: int = 0 ) -> flask.wrappers.Response: """Process_instance_task_list.""" process_instance = find_process_instance_by_id_or_raise(process_instance_id) + + if spiff_step > 0: + step_detail = ( + db.session.query(SpiffStepDetailsModel) + .filter( + SpiffStepDetailsModel.process_instance_id == process_instance.id, + SpiffStepDetailsModel.spiff_step == spiff_step, + ) + .first() + ) + if step_detail is not None: + process_instance.bpmn_json = json.dumps(step_detail.task_json) + processor = ProcessInstanceProcessor(process_instance) spiff_tasks = None @@ -1233,6 +1247,7 @@ def script_unit_test_run( """Script_unit_test_run.""" # FIXME: We should probably clear this somewhere else but this works current_app.config["THREAD_LOCAL_DATA"].process_instance_id = None + current_app.config["THREAD_LOCAL_DATA"].spiff_step = None python_script = _get_required_parameter_or_raise("python_script", body) input_json = _get_required_parameter_or_raise("input_json", body) diff --git a/src/spiffworkflow_backend/scripts/get_current_user.py b/src/spiffworkflow_backend/scripts/get_current_user.py index b8c314c0e..a1a1b47e9 100644 --- a/src/spiffworkflow_backend/scripts/get_current_user.py +++ b/src/spiffworkflow_backend/scripts/get_current_user.py @@ -9,8 +9,8 @@ from spiffworkflow_backend.models.script_attributes_context import ( from spiffworkflow_backend.scripts.script import Script -class GetUser(Script): - """GetUser.""" +class GetCurrentUser(Script): + """GetCurrentUser.""" def get_description(self) -> str: """Get_description.""" diff --git a/src/spiffworkflow_backend/scripts/get_process_info.py b/src/spiffworkflow_backend/scripts/get_process_info.py index b8ad3d687..45c70d6ba 100644 --- a/src/spiffworkflow_backend/scripts/get_process_info.py +++ b/src/spiffworkflow_backend/scripts/get_process_info.py @@ -8,7 +8,7 @@ from spiffworkflow_backend.scripts.script import Script class GetProcessInfo(Script): - """GetUser.""" + """GetProcessInfo.""" def get_description(self) -> str: """Get_description.""" diff --git a/src/spiffworkflow_backend/services/logging_service.py b/src/spiffworkflow_backend/services/logging_service.py index ce30e8b92..13f66e00d 100644 --- a/src/spiffworkflow_backend/services/logging_service.py +++ b/src/spiffworkflow_backend/services/logging_service.py @@ -108,6 +108,8 @@ class SpiffFilter(logging.Filter): if hasattr(tld, "process_instance_id"): process_instance_id = tld.process_instance_id setattr(record, "process_instance_id", process_instance_id) # noqa: B010 + if hasattr(tld, "spiff_step"): + setattr(record, "spiff_step", tld.spiff_step) # noqa: 8010 if hasattr(g, "user") and g.user: setattr(record, "current_user_id", g.user.id) # noqa: B010 return True @@ -204,6 +206,11 @@ class DBHandler(logging.Handler): timestamp = record.created message = record.msg if hasattr(record, "msg") else None current_user_id = record.current_user_id if hasattr(record, "current_user_id") else None # type: ignore + spiff_step = ( + record.spiff_step # type: ignore + if hasattr(record, "spiff_step") and record.spiff_step is not None # type: ignore + else 1 + ) spiff_log = SpiffLoggingModel( process_instance_id=record.process_instance_id, # type: ignore bpmn_process_identifier=bpmn_process_identifier, @@ -214,6 +221,7 @@ class DBHandler(logging.Handler): message=message, timestamp=timestamp, current_user_id=current_user_id, + spiff_step=spiff_step, ) db.session.add(spiff_log) db.session.commit() diff --git a/src/spiffworkflow_backend/services/process_instance_processor.py b/src/spiffworkflow_backend/services/process_instance_processor.py index fecde1b90..35320f652 100644 --- a/src/spiffworkflow_backend/services/process_instance_processor.py +++ b/src/spiffworkflow_backend/services/process_instance_processor.py @@ -29,31 +29,39 @@ from SpiffWorkflow.bpmn.exceptions import WorkflowTaskExecException # type: ign from SpiffWorkflow.bpmn.parser.ValidationException import ValidationException # type: ignore from SpiffWorkflow.bpmn.PythonScriptEngine import Box # type: ignore from SpiffWorkflow.bpmn.PythonScriptEngine import PythonScriptEngine -from SpiffWorkflow.bpmn.serializer import BpmnWorkflowSerializer # type: ignore +from SpiffWorkflow.bpmn.serializer.workflow import BpmnWorkflowSerializer # type: ignore from SpiffWorkflow.bpmn.specs.BpmnProcessSpec import BpmnProcessSpec # type: ignore -from SpiffWorkflow.bpmn.specs.events import CancelEventDefinition # type: ignore -from SpiffWorkflow.bpmn.specs.events import EndEvent +from SpiffWorkflow.bpmn.specs.events.EndEvent import EndEvent # type: ignore +from SpiffWorkflow.bpmn.specs.events.event_definitions import CancelEventDefinition # type: ignore from SpiffWorkflow.bpmn.workflow import BpmnWorkflow # type: ignore from SpiffWorkflow.dmn.parser.BpmnDmnParser import BpmnDmnParser # type: ignore -from SpiffWorkflow.dmn.serializer import BusinessRuleTaskConverter # type: ignore +from SpiffWorkflow.dmn.serializer.task_spec_converters import BusinessRuleTaskConverter # type: ignore from SpiffWorkflow.exceptions import WorkflowException # type: ignore from SpiffWorkflow.serializer.exceptions import MissingSpecError # type: ignore from SpiffWorkflow.spiff.parser.process import SpiffBpmnParser # type: ignore -from SpiffWorkflow.spiff.serializer import BoundaryEventConverter # type: ignore -from SpiffWorkflow.spiff.serializer import CallActivityTaskConverter -from SpiffWorkflow.spiff.serializer import EndEventConverter -from SpiffWorkflow.spiff.serializer import IntermediateCatchEventConverter -from SpiffWorkflow.spiff.serializer import IntermediateThrowEventConverter -from SpiffWorkflow.spiff.serializer import ManualTaskConverter -from SpiffWorkflow.spiff.serializer import NoneTaskConverter -from SpiffWorkflow.spiff.serializer import ReceiveTaskConverter -from SpiffWorkflow.spiff.serializer import ScriptTaskConverter -from SpiffWorkflow.spiff.serializer import SendTaskConverter -from SpiffWorkflow.spiff.serializer import ServiceTaskConverter -from SpiffWorkflow.spiff.serializer import StartEventConverter -from SpiffWorkflow.spiff.serializer import SubWorkflowTaskConverter -from SpiffWorkflow.spiff.serializer import TransactionSubprocessConverter -from SpiffWorkflow.spiff.serializer import UserTaskConverter +from SpiffWorkflow.spiff.serializer.task_spec_converters import BoundaryEventConverter # type: ignore +from SpiffWorkflow.spiff.serializer.task_spec_converters import ( + CallActivityTaskConverter, +) +from SpiffWorkflow.spiff.serializer.task_spec_converters import EndEventConverter +from SpiffWorkflow.spiff.serializer.task_spec_converters import ( + IntermediateCatchEventConverter, +) +from SpiffWorkflow.spiff.serializer.task_spec_converters import ( + IntermediateThrowEventConverter, +) +from SpiffWorkflow.spiff.serializer.task_spec_converters import ManualTaskConverter +from SpiffWorkflow.spiff.serializer.task_spec_converters import NoneTaskConverter +from SpiffWorkflow.spiff.serializer.task_spec_converters import ReceiveTaskConverter +from SpiffWorkflow.spiff.serializer.task_spec_converters import ScriptTaskConverter +from SpiffWorkflow.spiff.serializer.task_spec_converters import SendTaskConverter +from SpiffWorkflow.spiff.serializer.task_spec_converters import ServiceTaskConverter +from SpiffWorkflow.spiff.serializer.task_spec_converters import StartEventConverter +from SpiffWorkflow.spiff.serializer.task_spec_converters import SubWorkflowTaskConverter +from SpiffWorkflow.spiff.serializer.task_spec_converters import ( + TransactionSubprocessConverter, +) +from SpiffWorkflow.spiff.serializer.task_spec_converters import UserTaskConverter from SpiffWorkflow.task import Task as SpiffTask # type: ignore from SpiffWorkflow.task import TaskState from SpiffWorkflow.util.deep_merge import DeepMerge # type: ignore @@ -79,12 +87,16 @@ from spiffworkflow_backend.models.process_model import ProcessModelInfo from spiffworkflow_backend.models.script_attributes_context import ( ScriptAttributesContext, ) +from spiffworkflow_backend.models.spiff_step_details import SpiffStepDetailsModel from spiffworkflow_backend.models.user import UserModel from spiffworkflow_backend.models.user import UserModelSchema from spiffworkflow_backend.scripts.script import Script from spiffworkflow_backend.services.file_system_service import FileSystemService from spiffworkflow_backend.services.process_model_service import ProcessModelService from spiffworkflow_backend.services.service_task_service import ServiceTaskDelegate +from spiffworkflow_backend.services.spec_file_service import ( + ProcessModelFileNotFoundError, +) from spiffworkflow_backend.services.spec_file_service import SpecFileService from spiffworkflow_backend.services.user_service import UserService @@ -276,9 +288,9 @@ class ProcessInstanceProcessor: self, process_instance_model: ProcessInstanceModel, validate_only: bool = False ) -> None: """Create a Workflow Processor based on the serialized information available in the process_instance model.""" - current_app.config[ - "THREAD_LOCAL_DATA" - ].process_instance_id = process_instance_model.id + tld = current_app.config["THREAD_LOCAL_DATA"] + tld.process_instance_id = process_instance_model.id + tld.spiff_step = process_instance_model.spiff_step # we want this to be the fully qualified path to the process model including all group subcomponents current_app.config["THREAD_LOCAL_DATA"].process_model_identifier = ( @@ -411,10 +423,8 @@ class ProcessInstanceProcessor: bpmn_process_spec, subprocesses ) - def add_user_info_to_process_instance( - self, bpmn_process_instance: BpmnWorkflow - ) -> None: - """Add_user_info_to_process_instance.""" + def current_user(self) -> Any: + """Current_user.""" current_user = None if UserService.has_user(): current_user = UserService.current_user() @@ -425,6 +435,14 @@ class ProcessInstanceProcessor: elif self.process_instance_model.process_initiator_id: current_user = self.process_instance_model.process_initiator + return current_user + + def add_user_info_to_process_instance( + self, bpmn_process_instance: BpmnWorkflow + ) -> None: + """Add_user_info_to_process_instance.""" + current_user = self.current_user() + if current_user: current_user_data = UserModelSchema().dump(current_user) tasks = bpmn_process_instance.get_tasks(TaskState.READY) @@ -542,9 +560,31 @@ class ProcessInstanceProcessor: "lane_assignment_id": lane_assignment_id, } + def save_spiff_step_details(self) -> None: + """SaveSpiffStepDetails.""" + bpmn_json = self.serialize() + wf_json = json.loads(bpmn_json) + task_json = "{}" + if "tasks" in wf_json: + task_json = json.dumps(wf_json["tasks"]) + + # TODO want to just save the tasks, something wasn't immediately working + # so after the flow works with the full wf_json revisit this + task_json = wf_json + details_model = SpiffStepDetailsModel( + process_instance_id=self.process_instance_model.id, + spiff_step=self.process_instance_model.spiff_step or 1, + task_json=task_json, + timestamp=round(time.time()), + completed_by_user_id=self.current_user().id, + ) + db.session.add(details_model) + db.session.commit() + def save(self) -> None: """Saves the current state of this processor to the database.""" self.process_instance_model.bpmn_json = self.serialize() + complete_states = [TaskState.CANCELLED, TaskState.COMPLETED] user_tasks = list(self.get_all_user_tasks()) self.process_instance_model.status = self.get_status().value @@ -632,10 +672,14 @@ class ProcessInstanceProcessor: process_models = ProcessModelService().get_process_models() for process_model in process_models: if process_model.primary_file_name: - etree_element = SpecFileService.get_etree_element_from_file_name( - process_model, process_model.primary_file_name - ) - bpmn_process_identifiers = [] + try: + etree_element = SpecFileService.get_etree_element_from_file_name( + process_model, process_model.primary_file_name + ) + bpmn_process_identifiers = [] + except ProcessModelFileNotFoundError: + # if primary_file_name doesn't actually exist on disk, then just go on to the next process_model + continue try: bpmn_process_identifiers = ( @@ -663,6 +707,11 @@ class ProcessInstanceProcessor: bpmn_process_identifier: str, ) -> str: """Bpmn_file_full_path_from_bpmn_process_identifier.""" + if bpmn_process_identifier is None: + raise ValueError( + "bpmn_file_full_path_from_bpmn_process_identifier: bpmn_process_identifier is unexpectedly None" + ) + bpmn_process_id_lookup = BpmnProcessIdLookup.query.filter_by( bpmn_process_identifier=bpmn_process_identifier ).first() @@ -695,6 +744,10 @@ class ProcessInstanceProcessor: if processed_identifiers is None: processed_identifiers = set() processor_dependencies = parser.get_process_dependencies() + + # since get_process_dependencies() returns a set with None sometimes, we need to remove it + processor_dependencies = processor_dependencies - {None} + processor_dependencies_new = processor_dependencies - processed_identifiers bpmn_process_identifiers_in_parser = parser.get_process_ids() @@ -930,11 +983,29 @@ class ProcessInstanceProcessor: db.session.commit() + def increment_spiff_step(self) -> None: + """Spiff_step++.""" + spiff_step = self.process_instance_model.spiff_step or 0 + spiff_step += 1 + self.process_instance_model.spiff_step = spiff_step + current_app.config["THREAD_LOCAL_DATA"].spiff_step = spiff_step + db.session.add(self.process_instance_model) + db.session.commit() + def do_engine_steps(self, exit_at: None = None, save: bool = False) -> None: """Do_engine_steps.""" try: - self.bpmn_process_instance.refresh_waiting_tasks() - self.bpmn_process_instance.do_engine_steps(exit_at=exit_at) + self.bpmn_process_instance.refresh_waiting_tasks( + will_refresh_task=lambda t: self.increment_spiff_step(), + did_refresh_task=lambda t: self.save_spiff_step_details(), + ) + + self.bpmn_process_instance.do_engine_steps( + exit_at=exit_at, + will_complete_task=lambda t: self.increment_spiff_step(), + did_complete_task=lambda t: self.save_spiff_step_details(), + ) + self.process_bpmn_messages() self.queue_waiting_receive_messages() @@ -956,6 +1027,7 @@ class ProcessInstanceProcessor: # A little hackly, but make the bpmn_process_instance catch a cancel event. bpmn_process_instance.signal("cancel") # generate a cancel signal. bpmn_process_instance.catch(CancelEventDefinition()) + # Due to this being static, can't save granular step details in this case bpmn_process_instance.do_engine_steps() except WorkflowTaskExecException as we: raise ApiError.from_workflow_exception("task_error", str(we), we) from we @@ -1054,7 +1126,9 @@ class ProcessInstanceProcessor: def complete_task(self, task: SpiffTask) -> None: """Complete_task.""" + self.increment_spiff_step() self.bpmn_process_instance.complete_task_from_id(task.id) + self.save_spiff_step_details() def get_data(self) -> dict[str, Any]: """Get_data.""" diff --git a/src/spiffworkflow_backend/services/spec_file_service.py b/src/spiffworkflow_backend/services/spec_file_service.py index 4e1e30e2f..eb2a322f9 100644 --- a/src/spiffworkflow_backend/services/spec_file_service.py +++ b/src/spiffworkflow_backend/services/spec_file_service.py @@ -27,6 +27,10 @@ from spiffworkflow_backend.services.file_system_service import FileSystemService from spiffworkflow_backend.services.process_model_service import ProcessModelService +class ProcessModelFileNotFoundError(Exception): + """ProcessModelFileNotFoundError.""" + + class SpecFileService(FileSystemService): """SpecFileService.""" @@ -90,9 +94,8 @@ class SpecFileService(FileSystemService): """Get_data.""" file_path = SpecFileService.file_path(process_model_info, file_name) if not os.path.exists(file_path): - raise ApiError( - "unknown_file", - f"No file found with name {file_name} in {process_model_info.display_name}", + raise ProcessModelFileNotFoundError( + f"No file found with name {file_name} in {process_model_info.display_name}" ) with open(file_path, "rb") as f_handle: spec_file_data = f_handle.read() diff --git a/tests/spiffworkflow_backend/integration/test_process_api.py b/tests/spiffworkflow_backend/integration/test_process_api.py index 9a923b97b..7ac6b923e 100644 --- a/tests/spiffworkflow_backend/integration/test_process_api.py +++ b/tests/spiffworkflow_backend/integration/test_process_api.py @@ -1119,6 +1119,8 @@ class TestProcessApi(BaseTest): ) assert response.json is not None + # assert response.json['next_task'] is not None + active_tasks = ( db.session.query(ActiveTaskModel) .filter(ActiveTaskModel.process_instance_id == process_instance_id) diff --git a/tests/spiffworkflow_backend/unit/test_spiff_logging.py b/tests/spiffworkflow_backend/unit/test_spiff_logging.py index c4a5984f1..d8680b719 100644 --- a/tests/spiffworkflow_backend/unit/test_spiff_logging.py +++ b/tests/spiffworkflow_backend/unit/test_spiff_logging.py @@ -36,6 +36,7 @@ class TestSpiffLogging(BaseTest): bpmn_task_identifier=bpmn_task_identifier, message=message, timestamp=timestamp, + spiff_step=1, ) assert spiff_log.timestamp == timestamp From fbebc727257a57ad5505e19d0aaecdfd4a9166c8 Mon Sep 17 00:00:00 2001 From: burnettk Date: Fri, 4 Nov 2022 09:33:46 -0400 Subject: [PATCH 12/12] Squashed 'spiffworkflow-frontend/' changes from ca2bc557f1..1df0c1a9b2 1df0c1a9b2 Change steps when viewing a process instance model (#18) b471cbaa77 Prettier 01fc31aa27 From the logs, allow viewing a diagram in a previous state (#15) git-subtree-dir: spiffworkflow-frontend git-subtree-split: 1df0c1a9b2af5e22343da13f78e585096f877c65 --- src/routes/AdminRoutes.tsx | 4 ++ src/routes/ProcessInstanceLogList.tsx | 11 +++- src/routes/ProcessInstanceShow.tsx | 80 +++++++++++++++++++++++++-- 3 files changed, 88 insertions(+), 7 deletions(-) diff --git a/src/routes/AdminRoutes.tsx b/src/routes/AdminRoutes.tsx index c3e39e16e..776a5f341 100644 --- a/src/routes/AdminRoutes.tsx +++ b/src/routes/AdminRoutes.tsx @@ -76,6 +76,10 @@ export default function AdminRoutes() { path="process-models/:process_group_id/:process_model_id/process-instances/:process_instance_id" element={} /> + } + /> } diff --git a/src/routes/ProcessInstanceLogList.tsx b/src/routes/ProcessInstanceLogList.tsx index f2d297f02..83e56ac54 100644 --- a/src/routes/ProcessInstanceLogList.tsx +++ b/src/routes/ProcessInstanceLogList.tsx @@ -1,6 +1,6 @@ import { useEffect, useState } from 'react'; import { Table } from 'react-bootstrap'; -import { useParams, useSearchParams } from 'react-router-dom'; +import { useParams, useSearchParams, Link } from 'react-router-dom'; import PaginationForTable from '../components/PaginationForTable'; import ProcessBreadcrumb from '../components/ProcessBreadcrumb'; import { @@ -39,7 +39,14 @@ export default function ProcessInstanceLogList() { {rowToUse.bpmn_task_name} {rowToUse.bpmn_task_type} {rowToUse.username} - {convertSecondsToFormattedDate(rowToUse.timestamp)} + + + {convertSecondsToFormattedDate(rowToUse.timestamp)} + + ); }); diff --git a/src/routes/ProcessInstanceShow.tsx b/src/routes/ProcessInstanceShow.tsx index f5336df8f..642c7d657 100644 --- a/src/routes/ProcessInstanceShow.tsx +++ b/src/routes/ProcessInstanceShow.tsx @@ -32,10 +32,16 @@ export default function ProcessInstanceShow() { path: `/process-models/${params.process_group_id}/${params.process_model_id}/process-instances/${params.process_instance_id}`, successCallback: setProcessInstance, }); - HttpService.makeCallToBackend({ - path: `/process-instance/${params.process_instance_id}/tasks?all_tasks=true`, - successCallback: setTasks, - }); + if (typeof params.spiff_step === 'undefined') + HttpService.makeCallToBackend({ + path: `/process-instance/${params.process_instance_id}/tasks?all_tasks=true`, + successCallback: setTasks, + }); + else + HttpService.makeCallToBackend({ + path: `/process-instance/${params.process_instance_id}/tasks?all_tasks=true&spiff_step=${params.spiff_step}`, + successCallback: setTasks, + }); }, [params]); const deleteProcessInstance = () => { @@ -90,6 +96,62 @@ export default function ProcessInstanceShow() { return taskIds; }; + const currentSpiffStep = (processInstanceToUse: any) => { + if (typeof params.spiff_step === 'undefined') { + return processInstanceToUse.spiff_step; + } + + return Number(params.spiff_step); + }; + + const showingFirstSpiffStep = (processInstanceToUse: any) => { + return currentSpiffStep(processInstanceToUse) === 1; + }; + + const showingLastSpiffStep = (processInstanceToUse: any) => { + return ( + currentSpiffStep(processInstanceToUse) === processInstanceToUse.spiff_step + ); + }; + + const spiffStepLink = ( + processInstanceToUse: any, + label: string, + distance: number + ) => { + return ( +
  • + + {label} + +
  • + ); + }; + + const previousStepLink = (processInstanceToUse: any) => { + if (showingFirstSpiffStep(processInstanceToUse)) { + return null; + } + + return spiffStepLink(processInstanceToUse, 'Previous Step', -1); + }; + + const nextStepLink = (processInstanceToUse: any) => { + if (showingLastSpiffStep(processInstanceToUse)) { + return null; + } + + return spiffStepLink(processInstanceToUse, 'Next Step', 1); + }; + const getInfoTag = (processInstanceToUse: any) => { const currentEndDate = convertSecondsToFormattedDate( processInstanceToUse.end_in_seconds @@ -129,6 +191,12 @@ export default function ProcessInstanceShow() { Messages +
  • + Step {currentSpiffStep(processInstanceToUse)} of{' '} + {processInstanceToUse.spiff_step} +
  • + {previousStepLink(processInstanceToUse)} + {nextStepLink(processInstanceToUse)} ); }; @@ -228,7 +296,9 @@ export default function ProcessInstanceShow() { }; const canEditTaskData = (task: any) => { - return task.state === 'READY'; + return ( + task.state === 'READY' && showingLastSpiffStep(processInstance as any) + ); }; const cancelEditingTaskData = () => {