run_pyl had various recommendations that I find a bit of a pain in the butt, but that I did anyway.

This commit is contained in:
Dan 2023-01-25 16:43:28 -05:00
parent b59cca0212
commit eedc994e3e
11 changed files with 79 additions and 57 deletions

View File

@ -10,15 +10,15 @@ from typing import Union
import flask.wrappers
import jinja2
from SpiffWorkflow.exceptions import WorkflowTaskException
from flask import current_app
from flask import g
from flask import jsonify
from flask import make_response
from flask.wrappers import Response
from jinja2 import TemplateSyntaxError
from SpiffWorkflow.exceptions import WorkflowTaskException # type: ignore
from SpiffWorkflow.task import Task as SpiffTask # type: ignore
from SpiffWorkflow.task import TaskState
from jinja2 import TemplateSyntaxError
from sqlalchemy import and_
from sqlalchemy import asc
from sqlalchemy import desc
@ -293,9 +293,11 @@ def task_show(process_instance_id: int, task_id: str) -> flask.wrappers.Response
task.properties["instructionsForEndUser"] = _render_jinja_template(
task.properties["instructionsForEndUser"], spiff_task
)
except WorkflowTaskException as wfe:
except WorkflowTaskException as wfe:
wfe.add_note("Failed to render instructions for end user.")
raise ApiError.from_workflow_exception("instructions_error", str(wfe), exp=wfe)
raise ApiError.from_workflow_exception(
"instructions_error", str(wfe), exp=wfe
) from wfe
return make_response(jsonify(task), 200)
@ -518,10 +520,13 @@ def _prepare_form_data(
return _render_jinja_template(file_contents, spiff_task)
except WorkflowTaskException as wfe:
wfe.add_note(f"Error in Json Form File '{form_file}'")
api_error = ApiError.from_workflow_exception("instructions_error", str(wfe), exp=wfe)
api_error = ApiError.from_workflow_exception(
"instructions_error", str(wfe), exp=wfe
)
api_error.file_name = form_file
raise api_error
def _render_jinja_template(unprocessed_template: str, spiff_task: SpiffTask) -> str:
"""Render_jinja_template."""
jinja_environment = jinja2.Environment(
@ -531,11 +536,17 @@ def _render_jinja_template(unprocessed_template: str, spiff_task: SpiffTask) ->
template = jinja_environment.from_string(unprocessed_template)
return template.render(**spiff_task.data)
except jinja2.exceptions.TemplateError as template_error:
wfe = WorkflowTaskException(str(template_error), task=spiff_task, exception=template_error)
wfe = WorkflowTaskException(
str(template_error), task=spiff_task, exception=template_error
)
if isinstance(template_error, TemplateSyntaxError):
wfe.line_number = template_error.lineno
wfe.error_line = template_error.source.split('\n')[template_error.lineno - 1]
wfe.add_note("Jinja2 template errors can happen when trying to displaying task data")
wfe.error_line = template_error.source.split("\n")[
template_error.lineno - 1
]
wfe.add_note(
"Jinja2 template errors can happen when trying to displaying task data"
)
raise wfe from template_error
@ -582,14 +593,19 @@ def _update_form_schema_with_task_data_as_needed(
if task_data_var not in task.data:
wte = WorkflowTaskException(
f"Error building form. Attempting to create a selection list"
f" with options from variable '{task_data_var}' but it doesn't"
f" exist in the Task Data.", task=task)
(
"Error building form. Attempting to create a"
" selection list with options from variable"
f" '{task_data_var}' but it doesn't exist in"
" the Task Data."
),
task=task,
)
raise (
ApiError.from_workflow_exception(
error_code="missing_task_data_var",
message=str(wte),
exp=wte
exp=wte,
)
)

View File

@ -873,7 +873,10 @@ class ProcessInstanceProcessor:
f"Event of type {event_definition.event_type} sent to process instance"
f" {self.process_instance_model.id}"
)
self.bpmn_process_instance.catch(event_definition)
try:
self.bpmn_process_instance.catch(event_definition)
except Exception as e:
print(e)
self.do_engine_steps(save=True)
def add_step(self, step: Union[dict, None] = None) -> None:

View File

@ -1,25 +1,30 @@
"""Test_various_bpmn_constructs."""
from typing import Any
from flask.app import Flask
from flask.testing import FlaskClient
from tests.spiffworkflow_backend.helpers.base_test import BaseTest
from tests.spiffworkflow_backend.helpers.test_data import load_test_spec
from spiffworkflow_backend import db
from spiffworkflow_backend.models.human_task import HumanTaskModel
from tests.spiffworkflow_backend.helpers.base_test import BaseTest
from spiffworkflow_backend.models.user import UserModel
from tests.spiffworkflow_backend.helpers.test_data import load_test_spec
class TestForGoodErrors(BaseTest):
"""Assure when certain errors happen when rendering a jinaj2 error that it makes
some sense."""
"""Assure when certain errors happen when rendering a jinaj2 error that it makes some sense."""
def get_next_user_task(self, process_instance_id: int,
client: FlaskClient,
with_super_admin_user: UserModel,
):
def get_next_user_task(
self,
process_instance_id: int,
client: FlaskClient,
with_super_admin_user: UserModel,
) -> Any:
"""Returns the next available user task for a given process instance, if possible."""
human_tasks = (
db.session.query(HumanTaskModel)
.filter(HumanTaskModel.process_instance_id == process_instance_id)
.all()
.filter(HumanTaskModel.process_instance_id == process_instance_id)
.all()
)
assert len(human_tasks) > 0, "No human tasks found for process."
human_task = human_tasks[0]
@ -30,12 +35,13 @@ class TestForGoodErrors(BaseTest):
return response
def test_invalid_form(
self,
app: Flask,
client: FlaskClient,
with_db_and_bpmn_file_cleanup: None,
with_super_admin_user: UserModel,
self,
app: Flask,
client: FlaskClient,
with_db_and_bpmn_file_cleanup: None,
with_super_admin_user: UserModel,
) -> None:
"""React json form schema with bad jinja syntax provides good error."""
process_model = load_test_spec(
process_model_id="group/simple_form_with_error",
process_model_source_directory="simple_form_with_error",
@ -53,13 +59,15 @@ class TestForGoodErrors(BaseTest):
headers=self.logged_in_headers(with_super_admin_user),
)
assert response.status_code == 200
response = self.get_next_user_task(process_instance_id, client, with_super_admin_user)
response = self.get_next_user_task(
process_instance_id, client, with_super_admin_user
)
assert response.json is not None
assert response.json['error_type'] == 'TemplateSyntaxError'
assert response.json['line_number'] == 3
assert response.json['file_name'] == 'simple_form.json'
assert response.json["error_type"] == "TemplateSyntaxError"
assert response.json["line_number"] == 3
assert response.json["file_name"] == "simple_form.json"
def test_jinja2_error_message_for_end_user_instructions (
def test_jinja2_error_message_for_end_user_instructions(
self,
app: Flask,
client: FlaskClient,
@ -80,14 +88,16 @@ class TestForGoodErrors(BaseTest):
f"/v1.0/process-instances/{self.modify_process_identifier_for_path_param(process_model.id)}/{process_instance.id}/run",
headers=self.logged_in_headers(with_super_admin_user),
)
response = self.get_next_user_task(process_instance.id, client, with_super_admin_user)
response = self.get_next_user_task(
process_instance.id, client, with_super_admin_user
)
assert response.status_code == 400
assert response.json is not None
assert response.json['error_type'] == 'TemplateSyntaxError'
assert response.json['line_number'] == 3
assert response.json['error_line'] == '{{ x +=- 1}}'
assert response.json['file_name'] == 'instructions_error.bpmn'
assert 'instructions for end user' in response.json['message']
assert 'Jinja2' in response.json['message']
assert 'unexpected \'=\'' in response.json['message']
assert response.json["error_type"] == "TemplateSyntaxError"
assert response.json["line_number"] == 3
assert response.json["error_line"] == "{{ x +=- 1}}"
assert response.json["file_name"] == "instructions_error.bpmn"
assert "instructions for end user" in response.json["message"]
assert "Jinja2" in response.json["message"]
assert "unexpected '='" in response.json["message"]

View File

@ -2806,7 +2806,7 @@ class TestProcessApi(BaseTest):
)
data = {
"dateTime": "timedelta(hours=1)",
"dateTime": "PT1H",
"external": True,
"internal": True,
"label": "Event_0e4owa3",

View File

@ -59,11 +59,7 @@ export default function ErrorDisplay() {
}
errorTag = (
<Notification
title={title}
onClose={() => (removeError())}
type="error"
>
<Notification title={title} onClose={() => removeError()} type="error">
{message}
<br />
{sentryLinkTag}

View File

@ -115,11 +115,11 @@ export default function ProcessInstanceRun({
};
const processInstanceCreateAndRun = () => {
setErrorObject(null);
removeError();
HttpService.makeCallToBackend({
path: processInstanceCreatePath,
successCallback: processModelRun,
failureCallback: setErrorObject,
failureCallback: addError,
httpMethod: 'POST',
});
};

View File

@ -1,4 +1,4 @@
import React, { createContext, useState, useCallback } from 'react';
import React, { createContext, useState } from 'react';
import { ErrorForDisplay } from '../interfaces';
type ErrorContextType = {
@ -28,7 +28,7 @@ export default function APIErrorProvider({ children }) {
addError: (newError: ErrorForDisplay | null) => addError(newError),
removeError: () => removeError(),
}),
[error, addError, removeError]
[error]
);
return (

View File

@ -8,7 +8,6 @@ import {
DEFAULT_PER_PAGE,
DEFAULT_PAGE,
} from './components/PaginationForTable';
import { ErrorForDisplay } from './interfaces';
// https://www.30secondsofcode.org/js/s/slugify
export const slugifyString = (str: any) => {

View File

@ -26,7 +26,7 @@ export default function Configuration() {
const { ability } = usePermissionFetcher(permissionRequestData);
useEffect(() => {
console.log("Configuration remove error")
console.log('Configuration remove error');
removeError();
let newSelectedTabIndex = 0;
if (location.pathname.match(/^\/admin\/configuration\/authentications\b/)) {

View File

@ -3,7 +3,6 @@ import { Route, Routes, useLocation, useNavigate } from 'react-router-dom';
// @ts-ignore
import { Tabs, TabList, Tab } from '@carbon/react';
import TaskShow from './TaskShow';
import useAPIError from '../hooks/UseApiError';
import MyTasks from './MyTasks';
import GroupedTasks from './GroupedTasks';
import CompletedInstances from './CompletedInstances';
@ -11,7 +10,6 @@ import CreateNewInstance from './CreateNewInstance';
export default function HomePageRoutes() {
const location = useLocation();
const { removeError } = useAPIError();
const [selectedTabIndex, setSelectedTabIndex] = useState<number>(0);
const navigate = useNavigate();

View File

@ -717,7 +717,7 @@ export default function ProcessInstanceShow({ variant }: OwnProps) {
setSelectingEvent(false);
initializeTaskDataToDisplay(taskToDisplay);
setEventPayload('{}');
console.log("cancel updating task")
console.log('cancel updating task');
removeError();
};
@ -737,7 +737,7 @@ export default function ProcessInstanceShow({ variant }: OwnProps) {
if (!taskToDisplay) {
return;
}
console.log("saveTaskData")
console.log('saveTaskData');
removeError();
// taskToUse is copy of taskToDisplay, with taskDataToDisplay in data attribute