updated typeguard and fixed issues w/ burnettk
This commit is contained in:
parent
eacc50080c
commit
0811922c2e
|
@ -23,7 +23,7 @@ from spiffworkflow_backend.services.process_model_service import ProcessModelSer
|
|||
# We need to call this before importing spiffworkflow_backend
|
||||
# otherwise typeguard cannot work. hence the noqa: E402
|
||||
if os.environ.get("RUN_TYPEGUARD") == "true":
|
||||
from typeguard.importhook import install_import_hook
|
||||
from typeguard import install_import_hook
|
||||
|
||||
install_import_hook(packages="spiffworkflow_backend")
|
||||
|
||||
|
|
|
@ -3502,19 +3502,23 @@ files = [
|
|||
|
||||
[[package]]
|
||||
name = "typeguard"
|
||||
version = "2.13.3"
|
||||
version = "3.0.2"
|
||||
description = "Run-time type checker for Python"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.5.3"
|
||||
python-versions = ">=3.7.4"
|
||||
files = [
|
||||
{file = "typeguard-2.13.3-py3-none-any.whl", hash = "sha256:5e3e3be01e887e7eafae5af63d1f36c849aaa94e3a0112097312aabfa16284f1"},
|
||||
{file = "typeguard-2.13.3.tar.gz", hash = "sha256:00edaa8da3a133674796cf5ea87d9f4b4c367d77476e185e80251cc13dfbb8c4"},
|
||||
{file = "typeguard-3.0.2-py3-none-any.whl", hash = "sha256:bbe993854385284ab42fd5bd3bee6f6556577ce8b50696d6cb956d704f286c8e"},
|
||||
{file = "typeguard-3.0.2.tar.gz", hash = "sha256:fee5297fdb28f8e9efcb8142b5ee219e02375509cd77ea9d270b5af826358d5a"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
importlib-metadata = {version = ">=3.6", markers = "python_version < \"3.10\""}
|
||||
typing-extensions = {version = ">=4.4.0", markers = "python_version < \"3.11\""}
|
||||
|
||||
[package.extras]
|
||||
doc = ["sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"]
|
||||
test = ["mypy", "pytest", "typing-extensions"]
|
||||
doc = ["packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"]
|
||||
test = ["mypy (>=0.991)", "pytest (>=7)"]
|
||||
|
||||
[[package]]
|
||||
name = "types-click"
|
||||
|
@ -3934,4 +3938,4 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more
|
|||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = ">=3.9,<3.12"
|
||||
content-hash = "994c36ab39238500b4fd05bc1ccdd2d729dd5f66749ab77b1028371147bdf753"
|
||||
content-hash = "53f3340f73de770b4fbebff3fcd396cdf1bc2c082b929ade350f31a9df6c3860"
|
||||
|
|
|
@ -93,7 +93,7 @@ pytest = "^7.1.2"
|
|||
coverage = {extras = ["toml"], version = "^6.1"}
|
||||
safety = "^2.3.1"
|
||||
mypy = ">=0.961"
|
||||
typeguard = "^2"
|
||||
typeguard = "^3"
|
||||
xdoctest = {extras = ["colors"], version = "^1.0.1"}
|
||||
sphinx = "^5.0.2"
|
||||
sphinx-autobuild = ">=2021.3.14"
|
||||
|
|
|
@ -5,13 +5,11 @@ import sys
|
|||
import typing
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
from typing import cast
|
||||
|
||||
if sys.version_info < (3, 11):
|
||||
from typing_extensions import TypedDict, NotRequired
|
||||
else:
|
||||
from typing import TypedDict, NotRequired
|
||||
from typing import Optional
|
||||
|
||||
from sqlalchemy import ForeignKey
|
||||
from sqlalchemy.orm import relationship
|
||||
|
@ -19,11 +17,7 @@ from sqlalchemy.orm import relationship
|
|||
from spiffworkflow_backend.models.db import db
|
||||
from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel
|
||||
from spiffworkflow_backend.models.json_data import JsonDataModel # noqa: F401
|
||||
from spiffworkflow_backend.models.process_instance import ProcessInstanceModel
|
||||
from spiffworkflow_backend.models.user import UserModel
|
||||
from spiffworkflow_backend.services.process_instance_processor import (
|
||||
ProcessInstanceProcessor,
|
||||
)
|
||||
|
||||
|
||||
class FilterValue(TypedDict):
|
||||
|
@ -149,78 +143,3 @@ class ProcessInstanceReportModel(SpiffworkflowBaseDBModel):
|
|||
if isinstance(value, str) or isinstance(value, int):
|
||||
field_value = str(field_value).replace("{{" + key + "}}", str(value))
|
||||
return field_value
|
||||
|
||||
# modeled after https://github.com/suyash248/sqlalchemy-json-querybuilder
|
||||
# just supports "equals" operator for now.
|
||||
# perhaps we will use the database instead of filtering in memory in the future and then we might use this lib directly.
|
||||
def passes_filter(self, process_instance_dict: dict, substitution_variables: dict) -> bool:
|
||||
"""Passes_filter."""
|
||||
if "filter_by" in self.report_metadata:
|
||||
for filter_by in self.report_metadata["filter_by"]:
|
||||
field_name = filter_by["field_name"]
|
||||
operator = filter_by["operator"]
|
||||
field_value = self.with_substitutions(filter_by["field_value"], substitution_variables)
|
||||
if operator == "equals":
|
||||
if str(process_instance_dict.get(field_name)) != str(field_value):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def order_things(self, process_instance_dicts: list) -> list:
|
||||
"""Order_things."""
|
||||
order_by = self.report_metadata["order_by"]
|
||||
|
||||
def order_by_function_for_lambda(
|
||||
process_instance_dict: dict,
|
||||
) -> list[Reversor | str | None]:
|
||||
"""Order_by_function_for_lambda."""
|
||||
comparison_values: list[Reversor | str | None] = []
|
||||
for order_by_item in order_by:
|
||||
if order_by_item.startswith("-"):
|
||||
# remove leading - from order_by_item
|
||||
order_by_item = order_by_item[1:]
|
||||
sort_value = process_instance_dict.get(order_by_item)
|
||||
comparison_values.append(Reversor(sort_value))
|
||||
else:
|
||||
sort_value = cast(Optional[str], process_instance_dict.get(order_by_item))
|
||||
comparison_values.append(sort_value)
|
||||
return comparison_values
|
||||
|
||||
return sorted(process_instance_dicts, key=order_by_function_for_lambda)
|
||||
|
||||
def generate_report(
|
||||
self,
|
||||
process_instances: list[ProcessInstanceModel],
|
||||
substitution_variables: dict | None,
|
||||
) -> ProcessInstanceReportResult:
|
||||
"""Generate_report."""
|
||||
if substitution_variables is None:
|
||||
substitution_variables = {}
|
||||
|
||||
def to_serialized(process_instance: ProcessInstanceModel) -> dict:
|
||||
"""To_serialized."""
|
||||
processor = ProcessInstanceProcessor(process_instance)
|
||||
process_instance.data = processor.get_current_data()
|
||||
return process_instance.serialized_flat
|
||||
|
||||
process_instance_dicts = map(to_serialized, process_instances)
|
||||
results = []
|
||||
for process_instance_dict in process_instance_dicts:
|
||||
if self.passes_filter(process_instance_dict, substitution_variables):
|
||||
results.append(process_instance_dict)
|
||||
|
||||
if "order_by" in self.report_metadata:
|
||||
results = self.order_things(results)
|
||||
|
||||
if "columns" in self.report_metadata:
|
||||
column_keys_to_keep = [c["accessor"] for c in self.report_metadata["columns"]]
|
||||
|
||||
pruned_results = []
|
||||
for result in results:
|
||||
dict_you_want = {
|
||||
your_key: result[your_key] for your_key in column_keys_to_keep if result.get(your_key)
|
||||
}
|
||||
pruned_results.append(dict_you_want)
|
||||
results = pruned_results
|
||||
|
||||
return ProcessInstanceReportResult(report_metadata=self.report_metadata, results=results)
|
||||
|
|
|
@ -692,7 +692,7 @@ def _find_process_instance_for_me_or_raise(
|
|||
process_instance_id: int,
|
||||
) -> ProcessInstanceModel:
|
||||
"""_find_process_instance_for_me_or_raise."""
|
||||
process_instance: ProcessInstanceModel = (
|
||||
process_instance: Optional[ProcessInstanceModel] = (
|
||||
ProcessInstanceModel.query.filter_by(id=process_instance_id)
|
||||
.outerjoin(HumanTaskModel)
|
||||
.outerjoin(
|
||||
|
|
|
@ -438,7 +438,7 @@ def process_model_create_with_natural_language(
|
|||
|
||||
def _get_file_from_request() -> FileStorage:
|
||||
"""Get_file_from_request."""
|
||||
request_file: FileStorage = connexion.request.files.get("file")
|
||||
request_file: Optional[FileStorage] = connexion.request.files.get("file")
|
||||
if not request_file:
|
||||
raise ApiError(
|
||||
error_code="no_file_given",
|
||||
|
|
|
@ -53,98 +53,105 @@ class ProcessInstanceReportService:
|
|||
}
|
||||
system_report_completed_instances_initiated_by_me: ReportMetadata = {
|
||||
"columns": [
|
||||
{"Header": "id", "accessor": "id"},
|
||||
{"Header": "id", "accessor": "id", "filterable": False},
|
||||
{
|
||||
"Header": "process_model_display_name",
|
||||
"accessor": "process_model_display_name",
|
||||
"filterable": False,
|
||||
},
|
||||
{"Header": "start_in_seconds", "accessor": "start_in_seconds"},
|
||||
{"Header": "end_in_seconds", "accessor": "end_in_seconds"},
|
||||
{"Header": "status", "accessor": "status"},
|
||||
{"Header": "start_in_seconds", "accessor": "start_in_seconds", "filterable": False},
|
||||
{"Header": "end_in_seconds", "accessor": "end_in_seconds", "filterable": False},
|
||||
{"Header": "status", "accessor": "status", "filterable": False},
|
||||
],
|
||||
"filter_by": [
|
||||
{"field_name": "initiated_by_me", "field_value": True},
|
||||
{"field_name": "process_status", "field_value": terminal_status_values},
|
||||
{"field_name": "initiated_by_me", "field_value": True, "operator": "equals"},
|
||||
{"field_name": "process_status", "field_value": terminal_status_values, "operator": "equals"},
|
||||
],
|
||||
"order_by": ["-start_in_seconds", "-id"],
|
||||
}
|
||||
system_report_completed_instances_with_tasks_completed_by_me: ReportMetadata = {
|
||||
"columns": cls.builtin_column_options(),
|
||||
"filter_by": [
|
||||
{"field_name": "with_tasks_completed_by_me", "field_value": True},
|
||||
{"field_name": "process_status", "field_value": terminal_status_values},
|
||||
{"field_name": "with_tasks_completed_by_me", "field_value": True, "operator": "equals"},
|
||||
{"field_name": "process_status", "field_value": terminal_status_values, "operator": "equals"},
|
||||
],
|
||||
"order_by": ["-start_in_seconds", "-id"],
|
||||
}
|
||||
system_report_completed_instances: ReportMetadata = {
|
||||
"columns": cls.builtin_column_options(),
|
||||
"filter_by": [
|
||||
{"field_name": "process_status", "field_value": terminal_status_values},
|
||||
{"field_name": "process_status", "field_value": terminal_status_values, "operator": "equals"},
|
||||
],
|
||||
"order_by": ["-start_in_seconds", "-id"],
|
||||
}
|
||||
system_report_in_progress_instances_initiated_by_me: ReportMetadata = {
|
||||
"columns": [
|
||||
{"Header": "id", "accessor": "id"},
|
||||
{"Header": "id", "accessor": "id", "filterable": False},
|
||||
{
|
||||
"Header": "process_model_display_name",
|
||||
"accessor": "process_model_display_name",
|
||||
"filterable": False,
|
||||
},
|
||||
{"Header": "Task", "accessor": "task_title"},
|
||||
{"Header": "Waiting For", "accessor": "waiting_for"},
|
||||
{"Header": "Started", "accessor": "start_in_seconds"},
|
||||
{"Header": "Last Updated", "accessor": "task_updated_at_in_seconds"},
|
||||
{"Header": "status", "accessor": "status"},
|
||||
{"Header": "Task", "accessor": "task_title", "filterable": False},
|
||||
{"Header": "Waiting For", "accessor": "waiting_for", "filterable": False},
|
||||
{"Header": "Started", "accessor": "start_in_seconds", "filterable": False},
|
||||
{"Header": "Last Updated", "accessor": "task_updated_at_in_seconds", "filterable": False},
|
||||
{"Header": "status", "accessor": "status", "filterable": False},
|
||||
],
|
||||
"filter_by": [
|
||||
{"field_name": "initiated_by_me", "field_value": True},
|
||||
{"field_name": "process_status", "field_value": non_terminal_status_values},
|
||||
{"field_name": "initiated_by_me", "field_value": True, "operator": "equals"},
|
||||
{"field_name": "process_status", "field_value": non_terminal_status_values, "operator": "equals"},
|
||||
{
|
||||
"field_name": "with_oldest_open_task",
|
||||
"field_value": True,
|
||||
"operator": "equals",
|
||||
},
|
||||
],
|
||||
"order_by": ["-start_in_seconds", "-id"],
|
||||
}
|
||||
system_report_in_progress_instances_with_tasks_for_me: ReportMetadata = {
|
||||
"columns": [
|
||||
{"Header": "id", "accessor": "id"},
|
||||
{"Header": "id", "accessor": "id", "filterable": False},
|
||||
{
|
||||
"Header": "process_model_display_name",
|
||||
"accessor": "process_model_display_name",
|
||||
"filterable": False,
|
||||
},
|
||||
{"Header": "Task", "accessor": "task_title"},
|
||||
{"Header": "Started By", "accessor": "process_initiator_username"},
|
||||
{"Header": "Started", "accessor": "start_in_seconds"},
|
||||
{"Header": "Last Updated", "accessor": "task_updated_at_in_seconds"},
|
||||
{"Header": "Task", "accessor": "task_title", "filterable": False},
|
||||
{"Header": "Started By", "accessor": "process_initiator_username", "filterable": False},
|
||||
{"Header": "Started", "accessor": "start_in_seconds", "filterable": False},
|
||||
{"Header": "Last Updated", "accessor": "task_updated_at_in_seconds", "filterable": False},
|
||||
],
|
||||
"filter_by": [
|
||||
{"field_name": "with_tasks_i_can_complete", "field_value": True},
|
||||
{"field_name": "process_status", "field_value": active_status_values},
|
||||
{"field_name": "with_tasks_i_can_complete", "field_value": True, "operator": "equals"},
|
||||
{"field_name": "process_status", "field_value": active_status_values, "operator": "equals"},
|
||||
{
|
||||
"field_name": "with_oldest_open_task",
|
||||
"field_value": True,
|
||||
"operator": "equals",
|
||||
},
|
||||
],
|
||||
"order_by": ["-start_in_seconds", "-id"],
|
||||
}
|
||||
system_report_in_progress_instances_with_tasks: ReportMetadata = {
|
||||
"columns": [
|
||||
{"Header": "id", "accessor": "id"},
|
||||
{"Header": "id", "accessor": "id", "filterable": False},
|
||||
{
|
||||
"Header": "process_model_display_name",
|
||||
"accessor": "process_model_display_name",
|
||||
"filterable": False,
|
||||
},
|
||||
{"Header": "Task", "accessor": "task_title"},
|
||||
{"Header": "Started By", "accessor": "process_initiator_username"},
|
||||
{"Header": "Started", "accessor": "start_in_seconds"},
|
||||
{"Header": "Last Updated", "accessor": "task_updated_at_in_seconds"},
|
||||
{"Header": "Task", "accessor": "task_title", "filterable": False},
|
||||
{"Header": "Started By", "accessor": "process_initiator_username", "filterable": False},
|
||||
{"Header": "Started", "accessor": "start_in_seconds", "filterable": False},
|
||||
{"Header": "Last Updated", "accessor": "task_updated_at_in_seconds", "filterable": False},
|
||||
],
|
||||
"filter_by": [
|
||||
{"field_name": "process_status", "field_value": active_status_values},
|
||||
{"field_name": "process_status", "field_value": active_status_values, "operator": "equals"},
|
||||
{
|
||||
"field_name": "with_oldest_open_task",
|
||||
"field_value": True,
|
||||
"operator": "equals",
|
||||
},
|
||||
],
|
||||
"order_by": ["-start_in_seconds", "-id"],
|
||||
|
@ -165,7 +172,8 @@ class ProcessInstanceReportService:
|
|||
}
|
||||
if metadata_key not in temp_system_metadata_map:
|
||||
return None
|
||||
return temp_system_metadata_map[metadata_key]
|
||||
return_value: ReportMetadata = temp_system_metadata_map[metadata_key]
|
||||
return return_value
|
||||
|
||||
@classmethod
|
||||
def compile_report(cls, report_metadata: ReportMetadata, user: UserModel) -> None:
|
||||
|
@ -173,7 +181,9 @@ class ProcessInstanceReportService:
|
|||
old_filters = copy.deepcopy(report_metadata["filter_by"])
|
||||
for filter in old_filters:
|
||||
if filter["field_name"] == "initiated_by_me":
|
||||
compiled_filters.append({"field_name": "process_initiator_username", "field_value": user.username})
|
||||
compiled_filters.append(
|
||||
{"field_name": "process_initiator_username", "field_value": user.username, "operator": "equals"}
|
||||
)
|
||||
else:
|
||||
compiled_filters.append(filter)
|
||||
|
||||
|
|
|
@ -792,7 +792,6 @@ class TestProcessApi(BaseTest):
|
|||
content_type="multipart/form-data",
|
||||
headers=self.logged_in_headers(with_super_admin_user),
|
||||
)
|
||||
|
||||
assert response.status_code == 400
|
||||
assert response.json is not None
|
||||
assert response.json["error_code"] == "no_file_given"
|
||||
|
@ -1853,7 +1852,13 @@ class TestProcessApi(BaseTest):
|
|||
|
||||
# Without filtering we should get all 5 instances
|
||||
report_metadata_body: ReportMetadata = {
|
||||
"filter_by": [{"field_name": "process_model_identifier", "field_value": process_model_identifier}],
|
||||
"filter_by": [
|
||||
{
|
||||
"field_name": "process_model_identifier",
|
||||
"field_value": process_model_identifier,
|
||||
"operator": "equals",
|
||||
}
|
||||
],
|
||||
"columns": [],
|
||||
"order_by": [],
|
||||
}
|
||||
|
@ -1868,8 +1873,16 @@ class TestProcessApi(BaseTest):
|
|||
for i in range(5):
|
||||
report_metadata_body = {
|
||||
"filter_by": [
|
||||
{"field_name": "process_model_identifier", "field_value": process_model_identifier},
|
||||
{"field_name": "process_status", "field_value": ProcessInstanceStatus[statuses[i]].value},
|
||||
{
|
||||
"field_name": "process_model_identifier",
|
||||
"field_value": process_model_identifier,
|
||||
"operator": "equals",
|
||||
},
|
||||
{
|
||||
"field_name": "process_status",
|
||||
"field_value": ProcessInstanceStatus[statuses[i]].value,
|
||||
"operator": "equals",
|
||||
},
|
||||
],
|
||||
"columns": [],
|
||||
"order_by": [],
|
||||
|
@ -1883,8 +1896,12 @@ class TestProcessApi(BaseTest):
|
|||
|
||||
report_metadata_body = {
|
||||
"filter_by": [
|
||||
{"field_name": "process_model_identifier", "field_value": process_model_identifier},
|
||||
{"field_name": "process_status", "field_value": "not_started,complete"},
|
||||
{
|
||||
"field_name": "process_model_identifier",
|
||||
"field_value": process_model_identifier,
|
||||
"operator": "equals",
|
||||
},
|
||||
{"field_name": "process_status", "field_value": "not_started,complete", "operator": "equals"},
|
||||
],
|
||||
"columns": [],
|
||||
"order_by": [],
|
||||
|
@ -1900,7 +1917,7 @@ class TestProcessApi(BaseTest):
|
|||
# filter by start/end seconds
|
||||
# start > 1000 - this should eliminate the first
|
||||
report_metadata_body = {
|
||||
"filter_by": [{"field_name": "start_from", "field_value": 1001}],
|
||||
"filter_by": [{"field_name": "start_from", "field_value": 1001, "operator": "equals"}],
|
||||
"columns": [],
|
||||
"order_by": [],
|
||||
}
|
||||
|
@ -1920,8 +1937,8 @@ class TestProcessApi(BaseTest):
|
|||
# start > 2000, end < 5000 - this should eliminate the first 2 and the last
|
||||
report_metadata_body = {
|
||||
"filter_by": [
|
||||
{"field_name": "start_from", "field_value": 2001},
|
||||
{"field_name": "end_to", "field_value": 5999},
|
||||
{"field_name": "start_from", "field_value": 2001, "operator": "equals"},
|
||||
{"field_name": "end_to", "field_value": 5999, "operator": "equals"},
|
||||
],
|
||||
"columns": [],
|
||||
"order_by": [],
|
||||
|
@ -1937,8 +1954,8 @@ class TestProcessApi(BaseTest):
|
|||
# start > 1000, start < 4000 - this should eliminate the first and the last 2
|
||||
report_metadata_body = {
|
||||
"filter_by": [
|
||||
{"field_name": "start_from", "field_value": 1001},
|
||||
{"field_name": "start_to", "field_value": 3999},
|
||||
{"field_name": "start_from", "field_value": 1001, "operator": "equals"},
|
||||
{"field_name": "start_to", "field_value": 3999, "operator": "equals"},
|
||||
],
|
||||
"columns": [],
|
||||
"order_by": [],
|
||||
|
@ -1954,8 +1971,8 @@ class TestProcessApi(BaseTest):
|
|||
# end > 2000, end < 6000 - this should eliminate the first and the last
|
||||
report_metadata_body = {
|
||||
"filter_by": [
|
||||
{"field_name": "end_from", "field_value": 2001},
|
||||
{"field_name": "end_to", "field_value": 5999},
|
||||
{"field_name": "end_from", "field_value": 2001, "operator": "equals"},
|
||||
{"field_name": "end_to", "field_value": 5999, "operator": "equals"},
|
||||
],
|
||||
"columns": [],
|
||||
"order_by": [],
|
||||
|
|
Loading…
Reference in New Issue