Merge branch 'main' into cullerton

# Conflicts:
#	tests/spiffworkflow_backend/integration/test_process_api.py
This commit is contained in:
mike cullerton 2022-06-27 11:06:17 -04:00
commit 77227c545a
29 changed files with 334 additions and 297 deletions

View File

@ -39,7 +39,7 @@ Spiffworkflow Backend
Features
--------
* TODO
* Backend API portion of the spiffworkflow engine webapp
Requirements

View File

@ -10,7 +10,7 @@ set -o errtrace -o errexit -o nounset -o pipefail
# run migrations
export FLASK_APP=/app/src/spiffworkflow_backend
if [ "${DOWNGRADE_DB:-}" = "true" ]; then
if [[ "${DOWNGRADE_DB:-}" == "true" ]]; then
echo 'Downgrading database...'
poetry run flask db downgrade
fi
@ -32,4 +32,4 @@ if [[ "${APPLICATION_ROOT:-}" != "/" ]]; then
fi
# THIS MUST BE THE LAST COMMAND!
exec poetry run gunicorn ${additional_args} --bind "0.0.0.0:$SPIFFWORKFLOW_BACKEND_PORT" --workers=3 --timeout 90 --log-level debug wsgi:app
exec poetry run gunicorn ${additional_args} --bind "0.0.0.0:$port" --workers=3 --timeout 90 --log-level debug wsgi:app

View File

@ -17,5 +17,6 @@ if [[ -z "${BPMN_SPEC_ABSOLUTE_DIR:-}" ]]; then
fi
export FLASK_SESSION_SECRET_KEY=super_secret_key
export APPLICATION_ROOT="/"
FLASK_APP=src/spiffworkflow_backend poetry run flask run -p 7000
./bin/boot_server_in_docker

View File

@ -1,8 +1,8 @@
"""empty message
Revision ID: 26094f78f273
Revision ID: ae997451b037
Revises:
Create Date: 2022-06-22 16:42:29.228683
Create Date: 2022-06-24 13:47:56.423142
"""
from alembic import op
@ -10,7 +10,7 @@ import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '26094f78f273'
revision = 'ae997451b037'
down_revision = None
branch_labels = None
depends_on = None

235
poetry.lock generated
View File

@ -88,7 +88,7 @@ tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>
[[package]]
name = "babel"
version = "2.10.2"
version = "2.10.3"
description = "Internationalization utilities"
category = "main"
optional = false
@ -336,7 +336,7 @@ PyYAML = ">=3.11"
[[package]]
name = "colorama"
version = "0.4.4"
version = "0.4.5"
description = "Cross-platform colored terminal text."
category = "main"
optional = false
@ -495,7 +495,7 @@ pycodestyle = "*"
[[package]]
name = "flake8-bugbear"
version = "22.4.25"
version = "22.6.22"
description = "A plugin for flake8 finding likely bugs and design problems in your program. Contains warnings that don't belong in pyflakes and pycodestyle."
category = "dev"
optional = false
@ -619,7 +619,7 @@ werkzeug = "*"
type = "git"
url = "https://github.com/sartography/flask-bpmn"
reference = "main"
resolved_reference = "899fd5335259a1cc33ecdb36f775cd91499d4b62"
resolved_reference = "3dbe2117afb378eaff71872080b45453a61a129d"
[[package]]
name = "flask-cors"
@ -707,21 +707,9 @@ python-versions = ">= 2.7, != 3.0.*, != 3.1.*, != 3.2.*, != 3.3.*"
Flask = ">=0.10"
SQLAlchemy = ">=0.8.0"
[[package]]
name = "flask-sqlalchemy-stubs"
version = "0.2"
description = "flask_sqlalchemy stubs"
category = "dev"
optional = false
python-versions = "*"
[package.dependencies]
mypy = ">=0.720"
typing-extensions = ">=3.7.4"
[[package]]
name = "furo"
version = "2022.6.4.1"
version = "2022.6.21"
description = "A clean customisable Sphinx documentation theme."
category = "dev"
optional = false
@ -915,7 +903,7 @@ python-versions = ">=3.6"
[[package]]
name = "libcst"
version = "0.4.4"
version = "0.4.5"
description = "A concrete syntax tree with AST-like properties for Python 3.5, 3.6, 3.7, 3.8, 3.9, and 3.10 programs."
category = "dev"
optional = false
@ -1124,7 +1112,7 @@ python-versions = ">=2.6"
[[package]]
name = "pep8-naming"
version = "0.12.1"
version = "0.13.0"
description = "Check PEP-8 naming conventions, plugin for flake8"
category = "dev"
optional = false
@ -1132,7 +1120,6 @@ python-versions = "*"
[package.dependencies]
flake8 = ">=3.9.1"
flake8-polyfill = ">=1.0.2,<2"
[[package]]
name = "platformdirs"
@ -1199,7 +1186,7 @@ wcwidth = "*"
[[package]]
name = "protobuf"
version = "4.21.1"
version = "4.21.2"
description = ""
category = "main"
optional = false
@ -1302,11 +1289,11 @@ python-versions = ">=3.7"
[[package]]
name = "pytest"
version = "6.2.5"
version = "7.1.2"
description = "pytest: simple powerful testing with Python"
category = "main"
optional = false
python-versions = ">=3.6"
python-versions = ">=3.7"
[package.dependencies]
atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""}
@ -1316,10 +1303,10 @@ iniconfig = "*"
packaging = "*"
pluggy = ">=0.12,<2.0"
py = ">=1.8.2"
toml = "*"
tomli = ">=1.0.0"
[package.extras]
testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"]
testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"]
[[package]]
name = "pytest-flask"
@ -1357,7 +1344,7 @@ tests = ["pytest-postgresql (>=2.4.0,<4.0.0)", "psycopg2-binary", "pytest (>=6.0
[[package]]
name = "pytest-mock"
version = "3.7.0"
version = "3.8.1"
description = "Thin-wrapper around the mock package for easier use with pytest"
category = "main"
optional = false
@ -1645,7 +1632,7 @@ docs = ["furo", "myst-parser", "sphinx-copybutton", "sphinx-inline-tabs", "ipyth
[[package]]
name = "sphinx-click"
version = "4.1.0"
version = "4.2.0"
description = "Sphinx extension that automatically documents click applications"
category = "dev"
optional = false
@ -1747,11 +1734,11 @@ pytz = "*"
type = "git"
url = "https://github.com/sartography/SpiffWorkflow"
reference = "main"
resolved_reference = "535f0c6d97f844dfdbb026a2a9ea3ffb5133a424"
resolved_reference = "26fa5865aa636dd70006a07c7e6233d93464684b"
[[package]]
name = "sqlalchemy"
version = "1.4.37"
version = "1.4.39"
description = "Database Abstraction Library"
category = "main"
optional = false
@ -1827,7 +1814,7 @@ python-versions = ">=3.6.1"
name = "toml"
version = "0.10.2"
description = "Python Library for Tom's Obvious, Minimal Language"
category = "main"
category = "dev"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
@ -1835,7 +1822,7 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
name = "tomli"
version = "2.0.1"
description = "A lil' TOML parser"
category = "dev"
category = "main"
optional = false
python-versions = ">=3.7"
@ -2034,7 +2021,7 @@ testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-
[metadata]
lock-version = "1.1"
python-versions = "^3.9"
content-hash = "5aae09a360d44ea3e42a0152ba755e3cb7d464a8fbf8d2fb8bdaf6ece66cbb57"
content-hash = "b62cf79b84095d7587533e0ac88c8be8a035e97dac57e521273f246bca78cf78"
[metadata.files]
alabaster = [
@ -2070,8 +2057,8 @@ attrs = [
{file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"},
]
babel = [
{file = "Babel-2.10.2-py3-none-any.whl", hash = "sha256:81a3beca4d0cd40a9cfb9e2adb2cf39261c2f959b92e7a74750befe5d79afd7b"},
{file = "Babel-2.10.2.tar.gz", hash = "sha256:7aed055f0c04c9e7f51a2f75261e41e1c804efa724cb65b60a970dd4448d469d"},
{file = "Babel-2.10.3-py3-none-any.whl", hash = "sha256:ff56f4892c1c4bf0d814575ea23471c230d544203c7748e8c68f0089478d48eb"},
{file = "Babel-2.10.3.tar.gz", hash = "sha256:7614553711ee97490f732126dc077f8d0ae084ebc6a96e23db1482afabdb2c51"},
]
bandit = [
{file = "bandit-1.7.2-py3-none-any.whl", hash = "sha256:e20402cadfd126d85b68ed4c8862959663c8c372dbbb1fca8f8e2c9f55a067ec"},
@ -2215,8 +2202,8 @@ clickclick = [
{file = "clickclick-20.10.2.tar.gz", hash = "sha256:4efb13e62353e34c5eef7ed6582c4920b418d7dedc86d819e22ee089ba01802c"},
]
colorama = [
{file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
{file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"},
{file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"},
{file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"},
]
configparser = [
{file = "configparser-5.2.0-py3-none-any.whl", hash = "sha256:e8b39238fb6f0153a069aa253d349467c3c4737934f253ef6abac5fe0eca1e5d"},
@ -2301,8 +2288,8 @@ flake8-bandit = [
{file = "flake8_bandit-2.1.2.tar.gz", hash = "sha256:687fc8da2e4a239b206af2e54a90093572a60d0954f3054e23690739b0b0de3b"},
]
flake8-bugbear = [
{file = "flake8-bugbear-22.4.25.tar.gz", hash = "sha256:f7c080563fca75ee6b205d06b181ecba22b802babb96b0b084cc7743d6908a55"},
{file = "flake8_bugbear-22.4.25-py3-none-any.whl", hash = "sha256:ec374101cddf65bd7a96d393847d74e58d3b98669dbf9768344c39b6290e8bd6"},
{file = "flake8-bugbear-22.6.22.tar.gz", hash = "sha256:ac3317eba27d79dc19dcdeb7356ca1f656f0cde11d899c4551badf770f05cbef"},
{file = "flake8_bugbear-22.6.22-py3-none-any.whl", hash = "sha256:ad2b33dbe33a6d4ca1f0037e1d156d0a89107ee63c0600e3b4f7b60e37998ac2"},
]
flake8-docstrings = [
{file = "flake8-docstrings-1.6.0.tar.gz", hash = "sha256:9fe7c6a306064af8e62a055c2f61e9eb1da55f84bb39caef2b84ce53708ac34b"},
@ -2351,13 +2338,9 @@ flask-sqlalchemy = [
{file = "Flask-SQLAlchemy-2.5.1.tar.gz", hash = "sha256:2bda44b43e7cacb15d4e05ff3cc1f8bc97936cc464623424102bfc2c35e95912"},
{file = "Flask_SQLAlchemy-2.5.1-py2.py3-none-any.whl", hash = "sha256:f12c3d4cc5cc7fdcc148b9527ea05671718c3ea45d50c7e732cceb33f574b390"},
]
flask-sqlalchemy-stubs = [
{file = "flask_sqlalchemy-stubs-0.2.tar.gz", hash = "sha256:e4656bf4ddfcc4092a79dc75456978fd6761302f62f56526221ca867bd65c4b4"},
{file = "flask_sqlalchemy_stubs-0.2-py3-none-any.whl", hash = "sha256:7d8e21571b4ee92b15b9ad0dad0d1f488543272a85d76a58580df0ba6685142f"},
]
furo = [
{file = "furo-2022.6.4.1-py3-none-any.whl", hash = "sha256:79f2d3a61e3d971c0acd59f53d3202e7336789cd893f7bdc3cc7bc37d6ef252c"},
{file = "furo-2022.6.4.1.tar.gz", hash = "sha256:c927848edf3292030d0719ebdab9e16d56f1b91c68562b9be316aa5b843775ab"},
{file = "furo-2022.6.21-py3-none-any.whl", hash = "sha256:061b68e323345e27fcba024cf33a1e77f3dfd8d9987410be822749a706e2add6"},
{file = "furo-2022.6.21.tar.gz", hash = "sha256:9aa983b7488a4601d13113884bfb7254502c8729942e073a0acb87a5512af223"},
]
gitdb = [
{file = "gitdb-4.0.9-py3-none-any.whl", hash = "sha256:8033ad4e853066ba6ca92050b9df2f89301b8fc8bf7e9324d412a63f8bf1a8fd"},
@ -2508,30 +2491,30 @@ lazy-object-proxy = [
{file = "lazy_object_proxy-1.7.1-pp37.pp38-none-any.whl", hash = "sha256:d66906d5785da8e0be7360912e99c9188b70f52c422f9fc18223347235691a84"},
]
libcst = [
{file = "libcst-0.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6d15f7260abe8cc1becf9b43c734cc4e478ba9dbb26611b3c7720f3da4a25320"},
{file = "libcst-0.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:41cd5cc5fc66b49e5ec5893d4fec65621b5bbbdc38d9ab2166708de4584eb97a"},
{file = "libcst-0.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca12c433c656ae8ce25ae054b754c0efa27d53f97692b11a0e46f0f33cade917"},
{file = "libcst-0.4.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32f1fe6ca6a280e414975d9416e5af1361a6c1fe0f64c663b4aec19c26e80fde"},
{file = "libcst-0.4.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:815103ea4c872de482cbf5ad86f6e7b14973add586eedf221986e57a919be866"},
{file = "libcst-0.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:0a7502575cd8b8aaba215c865c18b49fc4ad4ce0550dadb4091e4b20146a0995"},
{file = "libcst-0.4.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:fc47440a45b5d359fd68db95845fa2a99d7b27e30f68ea96c7bb971d9e5e4193"},
{file = "libcst-0.4.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76fbacca5724afa6235936fad81b61ecd46cd952573ba7b05a3128b84b8c60f1"},
{file = "libcst-0.4.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0348e7cee1a46b5172a9cd7cb127ec2d8e7c0cfd80f3269ccc9f91c46d7b9542"},
{file = "libcst-0.4.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bd6807c93e5836b1948765d3d717abea8f7a6483a4461ae1824c1dce1ce5fcd7"},
{file = "libcst-0.4.4-cp37-cp37m-win_amd64.whl", hash = "sha256:762df9c4e0918a7a9a54a8b92337239b5459d97832a77789eaa05cd48898daef"},
{file = "libcst-0.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d3f5d0cf993e7bc6a705d6f06c661f11dcf56a701634ef1c903823c1bd2864c1"},
{file = "libcst-0.4.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:501f331c6ef0897e23aa2771f3e21f40317985fb5134fc08be67c33e38f29786"},
{file = "libcst-0.4.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14843f619dac08e84255f0bbf82c2b33e3339e0fb4d302dc359a9b9fa3c7a10b"},
{file = "libcst-0.4.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:642231fcf88886460e07048ccfaa59064e601b49d55b1384081cfda9544e642c"},
{file = "libcst-0.4.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0bb6146400d5c7be327a6a393462258aa0b71aa112fe8f32613467573c02622c"},
{file = "libcst-0.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:1e1565873cbf13eb883f9264407c1d7b9b4202ae3cfc1fcb95d0fd3755269915"},
{file = "libcst-0.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7b39eb51c627dd0dfdb88257baa34084b58c656966c1f16a94b85918551d05fd"},
{file = "libcst-0.4.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0c78f911763d47759d221ec0a527a7fa42dc3117c6218b1a0c655a1d43135553"},
{file = "libcst-0.4.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76cacc13466010454a3af9f81cd44e85565faf82241cb9a97a3bc6c559fca612"},
{file = "libcst-0.4.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc5e6d74171a05e0e4aa939802cdea719ac105c534009e5922795e736d9c7d4a"},
{file = "libcst-0.4.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:33e61c37d17a680692b11b92045e5cb5edc091b16426d18db2331b6c31991538"},
{file = "libcst-0.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:01b42d2748bdc28b9477ae4a39ca8b1689c1dfce8e6a1054086d5c51a61be150"},
{file = "libcst-0.4.4.tar.gz", hash = "sha256:0326fd7915bade33e5794a07c46fa1822cb1eabc3af4c2d821127102bdefbe04"},
{file = "libcst-0.4.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5e123209fb81c958cace1b9a1750cf443515265bec231d52f84ed93347463a16"},
{file = "libcst-0.4.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b1e178a57a294afba329f02d0a7af4f06792a65d7e7bf36157519311c1d9a849"},
{file = "libcst-0.4.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1685b99ceaff8296e5f2395d4f8dbea26baaba730f49d73f608dfcd77e5d86ef"},
{file = "libcst-0.4.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e73a119c3b9d0f225d3f6416805fd87245fe5441028c2adfefb949c7728b6bbe"},
{file = "libcst-0.4.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4e66d7349d02b947199621c159327b9a19767280308556c1ab54613a64e3eee2"},
{file = "libcst-0.4.5-cp310-cp310-win_amd64.whl", hash = "sha256:9bff5b970d52eaf723d2232ebb2db2cfeb9bf3d68978316ee698f49ba869b310"},
{file = "libcst-0.4.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:00f72f86915a32e68ffffce4d45ef89af54f34113fdb3b000e262dc28dd1d8c2"},
{file = "libcst-0.4.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a17d7512b996af17ce649363963332405d4566b0d54a404e019918caf78c1dee"},
{file = "libcst-0.4.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb3248b6eb50df73a712b517a643d0d20b2afd8ebb405d76d0ab1af2fbb2a2a6"},
{file = "libcst-0.4.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a28ec30e3bcd8ce15311dd68a707f608e4c4bde282ea2657ecb13c24b2bf206f"},
{file = "libcst-0.4.5-cp37-cp37m-win_amd64.whl", hash = "sha256:ac24e390532687ceca3d5d1ff5cca36abe3947d4da235de47f2803c65f78eda1"},
{file = "libcst-0.4.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3116776ea9e56a48da98ae4c94c2c5c8be4c45c7247855d9461eedae0cffae4f"},
{file = "libcst-0.4.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0d3c50eeee2d6003e7ca0098f519e8f531e0c973bfbbe274d241ed3f617e905b"},
{file = "libcst-0.4.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b9e2108235cd5ad67c9a344267fba6c29ecb3bbeff01d3de4701f31f18fbeb3"},
{file = "libcst-0.4.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9d8948ab7dc2dfd1c5b078f29ba3987d4107075ad4aa011db42bc805154ec9f"},
{file = "libcst-0.4.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fc41cf393be128d8c2023c1871f9bafb39ddd9875ff53aef9cb9dda03ca0ab5d"},
{file = "libcst-0.4.5-cp38-cp38-win_amd64.whl", hash = "sha256:5012ccfed435c6cd00f506e5705cc7d325b585562a23b84a78395094ad342ddc"},
{file = "libcst-0.4.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bdac3fcd49329659dceef8ddeb88a0f565235f7a2e0d953c27bc91316574f49d"},
{file = "libcst-0.4.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:298756f36604dee1bbc10f39ee6ef592047c0a4faca4c7b3a863ff48934af9fa"},
{file = "libcst-0.4.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46e40161d44c2fe043722d07584a2b0b85672570b2fca673a9d8760e3678f276"},
{file = "libcst-0.4.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7dddb5f8894aa5637fa0cc3b4a0f7b069d209d1bd91437719f3bd62a358998a"},
{file = "libcst-0.4.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:72b52e74c9c3950e43424e706e01991a83671fa7b140191875dc1fb810ef41c1"},
{file = "libcst-0.4.5-cp39-cp39-win_amd64.whl", hash = "sha256:05d2bdb8d2bed5e3c55066804084e0e26a982aed2b357d3503a214aa66e21348"},
{file = "libcst-0.4.5.tar.gz", hash = "sha256:a17442b62a22bef6ce0734ff33801378575ab8a9f9a33dbafe236270cdbcdb3c"},
]
livereload = [
{file = "livereload-2.6.3.tar.gz", hash = "sha256:776f2f865e59fde56490a56bcc6773b6917366bce0c267c60ee8aaf1a0959869"},
@ -2733,8 +2716,8 @@ pbr = [
{file = "pbr-5.9.0.tar.gz", hash = "sha256:e8dca2f4b43560edef58813969f52a56cef023146cbb8931626db80e6c1c4308"},
]
pep8-naming = [
{file = "pep8-naming-0.12.1.tar.gz", hash = "sha256:bb2455947757d162aa4cad55dba4ce029005cd1692f2899a21d51d8630ca7841"},
{file = "pep8_naming-0.12.1-py2.py3-none-any.whl", hash = "sha256:4a8daeaeb33cfcde779309fc0c9c0a68a3bbe2ad8a8308b763c5068f86eb9f37"},
{file = "pep8-naming-0.13.0.tar.gz", hash = "sha256:9f38e6dcf867a1fb7ad47f5ff72c0ddae544a6cf64eb9f7600b7b3c0bb5980b5"},
{file = "pep8_naming-0.13.0-py3-none-any.whl", hash = "sha256:069ea20e97f073b3e6d4f789af2a57816f281ca64b86210c7d471117a4b6bfd0"},
]
platformdirs = [
{file = "platformdirs-2.5.2-py3-none-any.whl", hash = "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788"},
@ -2757,20 +2740,20 @@ prompt-toolkit = [
{file = "prompt_toolkit-3.0.29.tar.gz", hash = "sha256:bd640f60e8cecd74f0dc249713d433ace2ddc62b65ee07f96d358e0b152b6ea7"},
]
protobuf = [
{file = "protobuf-4.21.1-cp310-abi3-win32.whl", hash = "sha256:52c1e44e25f2949be7ffa7c66acbfea940b0945dd416920231f7cb30ea5ac6db"},
{file = "protobuf-4.21.1-cp310-abi3-win_amd64.whl", hash = "sha256:72d357cc4d834cc85bd957e8b8e1f4b64c2eac9ca1a942efeb8eb2e723fca852"},
{file = "protobuf-4.21.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:3767c64593a49c7ac0accd08ed39ce42744405f0989d468f0097a17496fdbe84"},
{file = "protobuf-4.21.1-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:0d4719e724472e296062ba8e82a36d64693fcfdb550d9dff98af70ca79eafe3d"},
{file = "protobuf-4.21.1-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:a4c0c6f2f95a559e59a0258d3e4b186f340cbdc5adec5ce1bc06d01972527c88"},
{file = "protobuf-4.21.1-cp37-cp37m-win32.whl", hash = "sha256:32fff501b6df3050936d1839b80ea5899bf34db24792d223d7640611f67de15a"},
{file = "protobuf-4.21.1-cp37-cp37m-win_amd64.whl", hash = "sha256:b3d7d4b4945fe3c001403b6c24442901a5e58c0a3059290f5a63523ed4435f82"},
{file = "protobuf-4.21.1-cp38-cp38-win32.whl", hash = "sha256:34400fd76f85bdae9a2e9c1444ea4699c0280962423eff4418765deceebd81b5"},
{file = "protobuf-4.21.1-cp38-cp38-win_amd64.whl", hash = "sha256:c8829092c5aeb61619161269b2f8a2e36fd7cb26abbd9282d3bc453f02769146"},
{file = "protobuf-4.21.1-cp39-cp39-win32.whl", hash = "sha256:2b35602cb65d53c168c104469e714bf68670335044c38eee3c899d6a8af03ffc"},
{file = "protobuf-4.21.1-cp39-cp39-win_amd64.whl", hash = "sha256:3f2ed842e8ca43b790cb4a101bcf577226e0ded98a6a6ba2d5e12095a08dc4da"},
{file = "protobuf-4.21.1-py2.py3-none-any.whl", hash = "sha256:b309fda192850ac4184ca1777aab9655564bc8d10a9cc98f10e1c8bf11295c22"},
{file = "protobuf-4.21.1-py3-none-any.whl", hash = "sha256:79cd8d0a269b714f6b32641f86928c718e8d234466919b3f552bfb069dbb159b"},
{file = "protobuf-4.21.1.tar.gz", hash = "sha256:5d9b5c8270461706973c3871c6fbdd236b51dfe9dab652f1fb6a36aa88287e47"},
{file = "protobuf-4.21.2-cp310-abi3-win32.whl", hash = "sha256:d622dc75e289e8b3031dd8b4e87df508f11a6b3d86a49fb50256af7ce030d35b"},
{file = "protobuf-4.21.2-cp310-abi3-win_amd64.whl", hash = "sha256:4758b9c22ad0486639a68cea58d38571f233019a73212d78476ec648f68a49a3"},
{file = "protobuf-4.21.2-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:e3d3df3292ab4bae85213b9ebef566b5aedb45f97425a92fac5b2e431d31e71c"},
{file = "protobuf-4.21.2-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:29eaf8e9db33bc3bae14576ad61370aa2b64ea5d6e6cd705042692e5e0404b10"},
{file = "protobuf-4.21.2-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:ef0768a609a02b2b412fa0f59f1242f1597e9bb15188d043f3fde09115ca6c69"},
{file = "protobuf-4.21.2-cp37-cp37m-win32.whl", hash = "sha256:5f8c7488e74024fa12b46aab4258f707d7d6e94c8d322d7c45cc13770f66ab59"},
{file = "protobuf-4.21.2-cp37-cp37m-win_amd64.whl", hash = "sha256:57a593e40257ab4f164fe6e171651b1386c98f8ec5f5a8643642889c50d4f3c4"},
{file = "protobuf-4.21.2-cp38-cp38-win32.whl", hash = "sha256:b82ac05b0651a4d2b9d56f5aeef3d711f5858eb4b71c13d77553739e5930a74a"},
{file = "protobuf-4.21.2-cp38-cp38-win_amd64.whl", hash = "sha256:f2f43ae8dff452aee3026b59ea0a09245ab2529a55a0984992e76bcf848610e1"},
{file = "protobuf-4.21.2-cp39-cp39-win32.whl", hash = "sha256:7b2dcca25d88ec77358eed3d031c8260b5bf3023fff03a31c9584591c5910833"},
{file = "protobuf-4.21.2-cp39-cp39-win_amd64.whl", hash = "sha256:095fda15fe04a79c9f0edab09b424be46dd057b15986d235b84c8cea91659df7"},
{file = "protobuf-4.21.2-py2.py3-none-any.whl", hash = "sha256:9b42afb67e19010cdda057e439574ccd944902ea14b0d52ba0bfba2aad50858d"},
{file = "protobuf-4.21.2-py3-none-any.whl", hash = "sha256:853708afc3a7eed4df28a8d4bd4812f829f8d736c104dd8d584ccff27969e311"},
{file = "protobuf-4.21.2.tar.gz", hash = "sha256:863f65e137d9de4a76cac39ae731a19bea1c30997f512ecf0dc9348112313401"},
]
psycopg2 = [
{file = "psycopg2-2.9.3-cp310-cp310-win32.whl", hash = "sha256:083707a696e5e1c330af2508d8fab36f9700b26621ccbcb538abe22e15485362"},
@ -2841,8 +2824,8 @@ pyrsistent = [
{file = "pyrsistent-0.18.1.tar.gz", hash = "sha256:d4d61f8b993a7255ba714df3aca52700f8125289f84f704cf80916517c46eb96"},
]
pytest = [
{file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"},
{file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"},
{file = "pytest-7.1.2-py3-none-any.whl", hash = "sha256:13d0e3ccfc2b6e26be000cb6568c832ba67ba32e719443bfe725814d3c42433c"},
{file = "pytest-7.1.2.tar.gz", hash = "sha256:a06a0425453864a270bc45e71f783330a7428defb4230fb5e6a731fde06ecd45"},
]
pytest-flask = [
{file = "pytest-flask-1.2.0.tar.gz", hash = "sha256:46fde652f77777bf02dc91205aec4ce20cdf2acbbbd66a918ab91f5c14693d3d"},
@ -2853,8 +2836,8 @@ pytest-flask-sqlalchemy = [
{file = "pytest_flask_sqlalchemy-1.1.0-py3-none-any.whl", hash = "sha256:b9f272d5c4092fcbe4a6284e402a37cad84f5b9be3c0bbe1a11927f24c99ff83"},
]
pytest-mock = [
{file = "pytest-mock-3.7.0.tar.gz", hash = "sha256:5112bd92cc9f186ee96e1a92efc84969ea494939c3aead39c50f421c4cc69534"},
{file = "pytest_mock-3.7.0-py3-none-any.whl", hash = "sha256:6cff27cec936bf81dc5ee87f07132b807bcda51106b5ec4b90a04331cba76231"},
{file = "pytest-mock-3.8.1.tar.gz", hash = "sha256:2c6d756d5d3bf98e2e80797a959ca7f81f479e7d1f5f571611b0fdd6d1745240"},
{file = "pytest_mock-3.8.1-py3-none-any.whl", hash = "sha256:d989f11ca4a84479e288b0cd1e6769d6ad0d3d7743dcc75e460d1416a5f2135a"},
]
python-dateutil = [
{file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"},
@ -3066,8 +3049,8 @@ sphinx-basic-ng = [
{file = "sphinx_basic_ng-0.0.1a11.tar.gz", hash = "sha256:bf9a8fda0379c7d2ab51c9543f2b18e014b77fb295b49d64f3c1a910c863b34f"},
]
sphinx-click = [
{file = "sphinx-click-4.1.0.tar.gz", hash = "sha256:fedebd39991243ec5cfa1c9e483db7ea2621b3df2012315c89c6f1f3722f192b"},
{file = "sphinx_click-4.1.0-py3-none-any.whl", hash = "sha256:60d6507bf623e20e9cbab732d19fc4890cc36a394c82ba8e2320f9f9fdc4571e"},
{file = "sphinx-click-4.2.0.tar.gz", hash = "sha256:8429705474ebb009de5603c35b6a7bfe8501dbdb12d847cbb01f18277d4b7d9a"},
{file = "sphinx_click-4.2.0-py3-none-any.whl", hash = "sha256:3ba8c97a40deaf09245c540accc4ac5c1d2942eaed0fa598403cdbf04a9cf95f"},
]
sphinxcontrib-applehelp = [
{file = "sphinxcontrib-applehelp-1.0.2.tar.gz", hash = "sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58"},
@ -3095,42 +3078,42 @@ sphinxcontrib-serializinghtml = [
]
SpiffWorkflow = []
sqlalchemy = [
{file = "SQLAlchemy-1.4.37-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:d9050b0c4a7f5538650c74aaba5c80cd64450e41c206f43ea6d194ae6d060ff9"},
{file = "SQLAlchemy-1.4.37-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:b4c92823889cf9846b972ee6db30c0e3a92c0ddfc76c6060a6cda467aa5fb694"},
{file = "SQLAlchemy-1.4.37-cp27-cp27m-win32.whl", hash = "sha256:b55932fd0e81b43f4aff397c8ad0b3c038f540af37930423ab8f47a20b117e4c"},
{file = "SQLAlchemy-1.4.37-cp27-cp27m-win_amd64.whl", hash = "sha256:4a17c1a1152ca4c29d992714aa9df3054da3af1598e02134f2e7314a32ef69d8"},
{file = "SQLAlchemy-1.4.37-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:ffe487570f47536b96eff5ef2b84034a8ba4e19aab5ab7647e677d94a119ea55"},
{file = "SQLAlchemy-1.4.37-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:78363f400fbda80f866e8e91d37d36fe6313ff847ded08674e272873c1377ea5"},
{file = "SQLAlchemy-1.4.37-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ee34c85cbda7779d66abac392c306ec78c13f5c73a1f01b8b767916d4895d23"},
{file = "SQLAlchemy-1.4.37-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8b38e088659b30c2ca0af63e5d139fad1779a7925d75075a08717a21c406c0f6"},
{file = "SQLAlchemy-1.4.37-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6629c79967a6c92e33fad811599adf9bc5cee6e504a1027bbf9cc1b6fb2d276d"},
{file = "SQLAlchemy-1.4.37-cp310-cp310-win32.whl", hash = "sha256:2aac2a685feb9882d09f457f4e5586c885d578af4e97a2b759e91e8c457cbce5"},
{file = "SQLAlchemy-1.4.37-cp310-cp310-win_amd64.whl", hash = "sha256:7a44683cf97744a405103ef8fdd31199e9d7fc41b4a67e9044523b29541662b0"},
{file = "SQLAlchemy-1.4.37-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:cffc67cdd07f0e109a1fc83e333972ae423ea5ad414585b63275b66b870ea62b"},
{file = "SQLAlchemy-1.4.37-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:17417327b87a0f703c9a20180f75e953315207d048159aff51822052f3e33e69"},
{file = "SQLAlchemy-1.4.37-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:aaa0e90e527066409c2ea5676282cf4afb4a40bb9dce0f56c8ec2768bff22a6e"},
{file = "SQLAlchemy-1.4.37-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c1d9fb3931e27d59166bb5c4dcc911400fee51082cfba66ceb19ac954ade068"},
{file = "SQLAlchemy-1.4.37-cp36-cp36m-win32.whl", hash = "sha256:0e7fd52e48e933771f177c2a1a484b06ea03774fc7741651ebdf19985a34037c"},
{file = "SQLAlchemy-1.4.37-cp36-cp36m-win_amd64.whl", hash = "sha256:eec39a17bab3f69c44c9df4e0ed87c7306f2d2bf1eca3070af644927ec4199fa"},
{file = "SQLAlchemy-1.4.37-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:caca6acf3f90893d7712ae2c6616ecfeac3581b4cc677c928a330ce6fbad4319"},
{file = "SQLAlchemy-1.4.37-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50c8eaf44c3fed5ba6758d375de25f163e46137c39fda3a72b9ee1d1bb327dfc"},
{file = "SQLAlchemy-1.4.37-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:139c50b9384e6d32a74fc4dcd0e9717f343ed38f95dbacf832c782c68e3862f3"},
{file = "SQLAlchemy-1.4.37-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4c3b009c9220ae6e33f17b45f43fb46b9a1d281d76118405af13e26376f2e11"},
{file = "SQLAlchemy-1.4.37-cp37-cp37m-win32.whl", hash = "sha256:9785d6f962d2c925aeb06a7539ac9d16608877da6aeaaf341984b3693ae80a02"},
{file = "SQLAlchemy-1.4.37-cp37-cp37m-win_amd64.whl", hash = "sha256:3197441772dc3b1c6419f13304402f2418a18d7fe78000aa5a026e7100836739"},
{file = "SQLAlchemy-1.4.37-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:3862a069a24f354145e01a76c7c720c263d62405fe5bed038c46a7ce900f5dd6"},
{file = "SQLAlchemy-1.4.37-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e8706919829d455a9fa687c6bbd1b048e36fec3919a59f2d366247c2bfdbd9c"},
{file = "SQLAlchemy-1.4.37-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:06ec11a5e6a4b6428167d3ce33b5bd455c020c867dabe3e6951fa98836e0741d"},
{file = "SQLAlchemy-1.4.37-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d58f2d9d1a4b1459e8956a0153a4119da80f54ee5a9ea623cd568e99459a3ef1"},
{file = "SQLAlchemy-1.4.37-cp38-cp38-win32.whl", hash = "sha256:d6927c9e3965b194acf75c8e0fb270b4d54512db171f65faae15ef418721996e"},
{file = "SQLAlchemy-1.4.37-cp38-cp38-win_amd64.whl", hash = "sha256:a91d0668cada27352432f15b92ac3d43e34d8f30973fa8b86f5e9fddee928f3b"},
{file = "SQLAlchemy-1.4.37-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:f9940528bf9c4df9e3c3872d23078b6b2da6431c19565637c09f1b88a427a684"},
{file = "SQLAlchemy-1.4.37-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29a742c29fea12259f1d2a9ee2eb7fe4694a85d904a4ac66d15e01177b17ad7f"},
{file = "SQLAlchemy-1.4.37-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7e579d6e281cc937bdb59917017ab98e618502067e04efb1d24ac168925e1d2a"},
{file = "SQLAlchemy-1.4.37-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a940c551cfbd2e1e646ceea2777944425f5c3edff914bc808fe734d9e66f8d71"},
{file = "SQLAlchemy-1.4.37-cp39-cp39-win32.whl", hash = "sha256:5e4e517ce72fad35cce364a01aff165f524449e9c959f1837dc71088afa2824c"},
{file = "SQLAlchemy-1.4.37-cp39-cp39-win_amd64.whl", hash = "sha256:c37885f83b59e248bebe2b35beabfbea398cb40960cdc6d3a76eac863d4e1938"},
{file = "SQLAlchemy-1.4.37.tar.gz", hash = "sha256:3688f92c62db6c5df268e2264891078f17ecb91e3141b400f2e28d0f75796dea"},
{file = "SQLAlchemy-1.4.39-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:4770eb3ba69ec5fa41c681a75e53e0e342ac24c1f9220d883458b5596888e43a"},
{file = "SQLAlchemy-1.4.39-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:752ef2e8dbaa3c5d419f322e3632f00ba6b1c3230f65bc97c2ff5c5c6c08f441"},
{file = "SQLAlchemy-1.4.39-cp27-cp27m-win32.whl", hash = "sha256:b30e70f1594ee3c8902978fd71900d7312453922827c4ce0012fa6a8278d6df4"},
{file = "SQLAlchemy-1.4.39-cp27-cp27m-win_amd64.whl", hash = "sha256:864d4f89f054819cb95e93100b7d251e4d114d1c60bc7576db07b046432af280"},
{file = "SQLAlchemy-1.4.39-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:8f901be74f00a13bf375241a778455ee864c2c21c79154aad196b7a994e1144f"},
{file = "SQLAlchemy-1.4.39-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:1745987ada1890b0e7978abdb22c133eca2e89ab98dc17939042240063e1ef21"},
{file = "SQLAlchemy-1.4.39-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ede13a472caa85a13abe5095e71676af985d7690eaa8461aeac5c74f6600b6c0"},
{file = "SQLAlchemy-1.4.39-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7f13644b15665f7322f9e0635129e0ef2098409484df67fcd225d954c5861559"},
{file = "SQLAlchemy-1.4.39-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26146c59576dfe9c546c9f45397a7c7c4a90c25679492ff610a7500afc7d03a6"},
{file = "SQLAlchemy-1.4.39-cp310-cp310-win32.whl", hash = "sha256:91d2b89bb0c302f89e753bea008936acfa4e18c156fb264fe41eb6bbb2bbcdeb"},
{file = "SQLAlchemy-1.4.39-cp310-cp310-win_amd64.whl", hash = "sha256:50e7569637e2e02253295527ff34666706dbb2bc5f6c61a5a7f44b9610c9bb09"},
{file = "SQLAlchemy-1.4.39-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:107df519eb33d7f8e0d0d052128af2f25066c1a0f6b648fd1a9612ab66800b86"},
{file = "SQLAlchemy-1.4.39-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f24d4d6ec301688c59b0c4bb1c1c94c5d0bff4ecad33bb8f5d9efdfb8d8bc925"},
{file = "SQLAlchemy-1.4.39-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7b2785dd2a0c044a36836857ac27310dc7a99166253551ee8f5408930958cc60"},
{file = "SQLAlchemy-1.4.39-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e6e2c8581c6620136b9530137954a8376efffd57fe19802182c7561b0ab48b48"},
{file = "SQLAlchemy-1.4.39-cp36-cp36m-win32.whl", hash = "sha256:fbc076f79d830ae4c9d49926180a1140b49fa675d0f0d555b44c9a15b29f4c80"},
{file = "SQLAlchemy-1.4.39-cp36-cp36m-win_amd64.whl", hash = "sha256:0ec54460475f0c42512895c99c63d90dd2d9cbd0c13491a184182e85074b04c5"},
{file = "SQLAlchemy-1.4.39-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:6f95706da857e6e79b54c33c1214f5467aab10600aa508ddd1239d5df271986e"},
{file = "SQLAlchemy-1.4.39-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:621f050e72cc7dfd9ad4594ff0abeaad954d6e4a2891545e8f1a53dcdfbef445"},
{file = "SQLAlchemy-1.4.39-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:05a05771617bfa723ba4cef58d5b25ac028b0d68f28f403edebed5b8243b3a87"},
{file = "SQLAlchemy-1.4.39-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20bf65bcce65c538e68d5df27402b39341fabeecf01de7e0e72b9d9836c13c52"},
{file = "SQLAlchemy-1.4.39-cp37-cp37m-win32.whl", hash = "sha256:f2a42acc01568b9701665e85562bbff78ec3e21981c7d51d56717c22e5d3d58b"},
{file = "SQLAlchemy-1.4.39-cp37-cp37m-win_amd64.whl", hash = "sha256:6d81de54e45f1d756785405c9d06cd17918c2eecc2d4262dc2d276ca612c2f61"},
{file = "SQLAlchemy-1.4.39-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:5c2d19bfb33262bf987ef0062345efd0f54c4189c2d95159c72995457bf4a359"},
{file = "SQLAlchemy-1.4.39-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14ea8ff2d33c48f8e6c3c472111d893b9e356284d1482102da9678195e5a8eac"},
{file = "SQLAlchemy-1.4.39-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ec3985c883d6d217cf2013028afc6e3c82b8907192ba6195d6e49885bfc4b19d"},
{file = "SQLAlchemy-1.4.39-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1962dfee37b7fb17d3d4889bf84c4ea08b1c36707194c578f61e6e06d12ab90f"},
{file = "SQLAlchemy-1.4.39-cp38-cp38-win32.whl", hash = "sha256:047ef5ccd8860f6147b8ac6c45a4bc573d4e030267b45d9a1c47b55962ff0e6f"},
{file = "SQLAlchemy-1.4.39-cp38-cp38-win_amd64.whl", hash = "sha256:b71be98ef6e180217d1797185c75507060a57ab9cd835653e0112db16a710f0d"},
{file = "SQLAlchemy-1.4.39-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:365b75938049ae31cf2176efd3d598213ddb9eb883fbc82086efa019a5f649df"},
{file = "SQLAlchemy-1.4.39-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7a7667d928ba6ee361a3176e1bef6847c1062b37726b33505cc84136f657e0d"},
{file = "SQLAlchemy-1.4.39-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c6d00cb9da8d0cbfaba18cad046e94b06de6d4d0ffd9d4095a3ad1838af22528"},
{file = "SQLAlchemy-1.4.39-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0538b66f959771c56ff996d828081908a6a52a47c5548faed4a3d0a027a5368"},
{file = "SQLAlchemy-1.4.39-cp39-cp39-win32.whl", hash = "sha256:d1f665e50592caf4cad3caed3ed86f93227bffe0680218ccbb293bd5a6734ca8"},
{file = "SQLAlchemy-1.4.39-cp39-cp39-win_amd64.whl", hash = "sha256:8b773c9974c272aae0fa7e95b576d98d17ee65f69d8644f9b6ffc90ee96b4d19"},
{file = "SQLAlchemy-1.4.39.tar.gz", hash = "sha256:8194896038753b46b08a0b0ae89a5d80c897fb601dd51e243ed5720f1f155d27"},
]
sqlalchemy-stubs = [
{file = "sqlalchemy-stubs-0.4.tar.gz", hash = "sha256:c665d6dd4482ef642f01027fa06c3d5e91befabb219dc71fc2a09e7d7695f7ae"},

View File

@ -48,7 +48,7 @@ types-pytz = "^2022.1.0"
[tool.poetry.dev-dependencies]
pytest = "^6.2.5"
pytest = "^7.1.2"
coverage = {extras = ["toml"], version = "^6.1"}
safety = "^1.10.3"
mypy = ">=0.961"
@ -67,8 +67,8 @@ bandit = "1.7.2"
flake8-bugbear = "^22.4.25"
flake8-docstrings = "^1.6.0"
flake8-rst-docstrings = "^0.2.3"
flask-sqlalchemy-stubs = "^0.2"
pep8-naming = "^0.12.1"
# flask-sqlalchemy-stubs = "^0.2"
pep8-naming = "^0.13.0"
darglint = "^1.8.1"
reorder-python-imports = "^3.1.0"
pre-commit-hooks = "^4.0.1"

View File

@ -0,0 +1,17 @@
"""Fixture_data."""
from typing import Any
from flask_bpmn.models.db import db
from spiffworkflow_backend.models.user import UserModel
def find_or_create_user(username: str = "test_user1") -> Any:
"""Find_or_create_user."""
user = UserModel.query.filter_by(username=username).first()
if user is None:
user = UserModel(username=username)
db.session.add(user)
db.session.commit()
return user

View File

@ -8,15 +8,15 @@ class DataStoreModel(SpiffworkflowBaseDBModel):
"""DataStoreModel."""
__tablename__ = "data_store"
id = db.Column(db.Integer, primary_key=True) # type: ignore
updated_at_in_seconds = db.Column(db.Integer) # type: ignore
key = db.Column(db.String(50), nullable=False) # type: ignore
process_instance_id = db.Column(db.Integer) # type: ignore
task_spec = db.Column(db.String(50)) # type: ignore
spec_id = db.Column(db.String(50)) # type: ignore
user_id = db.Column(db.String(50), nullable=True) # type: ignore
file_id = db.Column(db.Integer, db.ForeignKey("file.id"), nullable=True) # type: ignore
value = db.Column(db.String(50)) # type: ignore
id = db.Column(db.Integer, primary_key=True)
updated_at_in_seconds = db.Column(db.Integer)
key = db.Column(db.String(50), nullable=False)
process_instance_id = db.Column(db.Integer)
task_spec = db.Column(db.String(50))
spec_id = db.Column(db.String(50))
user_id = db.Column(db.String(50), nullable=True)
file_id = db.Column(db.Integer, db.ForeignKey("file.id"), nullable=True)
value = db.Column(db.String(50))
class DataStoreSchema(SQLAlchemyAutoSchema): # type: ignore

View File

@ -19,25 +19,25 @@ class FileModel(SpiffworkflowBaseDBModel):
"""FileModel."""
__tablename__ = "file"
id = db.Column(db.Integer, primary_key=True) # type: ignore
name = db.Column(db.String(50), nullable=False) # type: ignore
type = db.Column(db.String(50), nullable=False) # type: ignore
content_type = db.Column(db.String(50), nullable=False) # type: ignore
process_instance_id = db.Column( # type: ignore
db.Integer, db.ForeignKey("process_instance.id"), nullable=True # type: ignore
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50), nullable=False)
type = db.Column(db.String(50), nullable=False)
content_type = db.Column(db.String(50), nullable=False)
process_instance_id = db.Column(
db.Integer, db.ForeignKey("process_instance.id"), nullable=True
)
task_spec = db.Column(db.String(50), nullable=True) # type: ignore
irb_doc_code = db.Column( # type: ignore
db.String(50), nullable=False # type: ignore
task_spec = db.Column(db.String(50), nullable=True)
irb_doc_code = db.Column(
db.String(50), nullable=False
) # Code reference to the documents.xlsx reference file.
data_stores = relationship(DataStoreModel, cascade="all,delete", backref="file")
md5_hash = db.Column(db.String(50), unique=False, nullable=False) # type: ignore
md5_hash = db.Column(db.String(50), unique=False, nullable=False)
data = deferred(db.Column(db.LargeBinary)) # type: ignore
size = db.Column(db.Integer, default=0) # type: ignore
updated_at_in_seconds = db.Column(db.Integer) # type: ignore
created_at_in_seconds = db.Column(db.Integer) # type: ignore
user_uid = db.Column(db.String(50), db.ForeignKey("user.uid"), nullable=True) # type: ignore
archived = db.Column(db.Boolean, default=False) # type: ignore
size = db.Column(db.Integer, default=0)
updated_at_in_seconds = db.Column(db.Integer)
created_at_in_seconds = db.Column(db.Integer)
user_uid = db.Column(db.String(50), db.ForeignKey("user.uid"), nullable=True)
archived = db.Column(db.Boolean, default=False)
class FileType(SpiffEnum):
@ -105,7 +105,7 @@ class File:
irb_doc_code: Optional[str] = None
data_store: Optional[dict] = field(default_factory=dict)
user_uid: Optional[str] = None
file_contents: Optional[str] = None
file_contents: Optional[bytes] = None
process_model_id: Optional[str] = None
process_group_id: Optional[str] = None
archived: bool = False

View File

@ -19,7 +19,7 @@ class GroupModel(FlaskBpmnGroupModel):
__tablename__ = "group"
__table_args__ = {"extend_existing": True}
new_name_two = db.Column(db.String(255)) # type: ignore
new_name_two = db.Column(db.String(255))
user_group_assignments = relationship("UserGroupAssignmentModel", cascade="delete")
users = relationship( # type: ignore
"UserModel",

View File

@ -29,10 +29,10 @@ class PermissionAssignmentModel(SpiffworkflowBaseDBModel):
"""PermissionAssignmentModel."""
__tablename__ = "permission_assignment"
id = db.Column(db.Integer, primary_key=True) # type: ignore
principal_id = db.Column(ForeignKey(PrincipalModel.id), nullable=False) # type: ignore
permission_target_id = db.Column( # type: ignore
id = db.Column(db.Integer, primary_key=True)
principal_id = db.Column(ForeignKey(PrincipalModel.id), nullable=False)
permission_target_id = db.Column(
ForeignKey(PermissionTargetModel.id), nullable=False
)
grant_type = db.Column(Enum(GrantDeny)) # type: ignore
permission = db.Column(Enum(Permission)) # type: ignore
grant_type = db.Column(Enum(GrantDeny))
permission = db.Column(Enum(Permission))

View File

@ -19,7 +19,7 @@ class PermissionTargetModel(SpiffworkflowBaseDBModel):
),
)
id = db.Column(db.Integer, primary_key=True) # type: ignore
id = db.Column(db.Integer, primary_key=True)
# process_group_id = db.Column(ForeignKey(ProcessGroupModel.id), nullable=True) # type: ignore
# process_model_identifier = db.Column(ForeignKey(ProcessModel.id), nullable=True) # type: ignore
# process_instance_id = db.Column(ForeignKey(ProcessInstanceModel.id), nullable=True) # type: ignore

View File

@ -14,6 +14,6 @@ class PrincipalModel(SpiffworkflowBaseDBModel):
__tablename__ = "principal"
__table_args__ = (CheckConstraint("NOT(user_id IS NULL AND group_id IS NULL)"),)
id = db.Column(db.Integer, primary_key=True) # type: ignore
user_id = db.Column(ForeignKey(UserModel.id), nullable=True) # type: ignore
group_id = db.Column(ForeignKey(GroupModel.id), nullable=True) # type: ignore
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(ForeignKey(UserModel.id), nullable=True)
group_id = db.Column(ForeignKey(GroupModel.id), nullable=True)

View File

@ -80,18 +80,18 @@ class ProcessInstanceModel(SpiffworkflowBaseDBModel):
"""ProcessInstanceModel."""
__tablename__ = "process_instance"
id: int = db.Column(db.Integer, primary_key=True) # type: ignore
process_model_identifier: str = db.Column(db.String(50), nullable=False, index=True) # type: ignore
process_group_identifier: str = db.Column(db.String(50), nullable=False, index=True) # type: ignore
process_initiator_id: int = db.Column(ForeignKey(UserModel.id), nullable=False) # type: ignore
id: int = db.Column(db.Integer, primary_key=True)
process_model_identifier: str = db.Column(db.String(50), nullable=False, index=True)
process_group_identifier: str = db.Column(db.String(50), nullable=False, index=True)
process_initiator_id: int = db.Column(ForeignKey(UserModel.id), nullable=False)
process_initiator = relationship("UserModel")
bpmn_json: str | None = deferred(db.Column(db.JSON)) # type: ignore
start_in_seconds: int | None = db.Column(db.Integer) # type: ignore
end_in_seconds: int | None = db.Column(db.Integer) # type: ignore
updated_at_in_seconds: int = db.Column(db.Integer) # type: ignore
created_at_in_seconds: int = db.Column(db.Integer) # type: ignore
status: str = db.Column(db.String()) # type: ignore
start_in_seconds: int | None = db.Column(db.Integer)
end_in_seconds: int | None = db.Column(db.Integer)
updated_at_in_seconds: int = db.Column(db.Integer)
created_at_in_seconds: int = db.Column(db.Integer)
status: str = db.Column(db.String(50))
@property
def serialized(self) -> dict[str, int | str | None]:
@ -131,7 +131,7 @@ class ProcessInstanceModelSchema(Schema):
status = marshmallow.fields.Method("get_status", dump_only=True)
def get_status(self, obj):
def get_status(self, obj: ProcessInstanceModel) -> str:
"""Get_status."""
return obj.status
@ -231,7 +231,7 @@ class ProcessInstanceMetadata:
description: str | None = None
spec_version: str | None = None
state: str | None = None
status: ProcessInstanceStatus | None = None
status: str | None = None
total_tasks: int | None = None
completed_tasks: int | None = None
is_review: bool | None = None

View File

@ -14,14 +14,14 @@ class ProcessInstanceReportModel(SpiffworkflowBaseDBModel):
"""ProcessInstanceReportModel."""
__tablename__ = "process_instance_report"
id = db.Column(db.Integer, primary_key=True) # type: ignore
process_model_identifier = db.Column(db.String(50), nullable=False, index=True) # type: ignore
process_group_identifier = db.Column(db.String(50), nullable=False, index=True) # type: ignore
id = db.Column(db.Integer, primary_key=True)
process_model_identifier = db.Column(db.String(50), nullable=False, index=True)
process_group_identifier = db.Column(db.String(50), nullable=False, index=True)
report_json = deferred(db.Column(db.JSON)) # type: ignore
created_by_id = db.Column(ForeignKey(UserModel.id), nullable=False) # type: ignore
created_by_id = db.Column(ForeignKey(UserModel.id), nullable=False)
created_by = relationship("UserModel")
created_at_in_seconds = db.Column(db.Integer) # type: ignore
updated_at_in_seconds = db.Column(db.Integer) # type: ignore
created_at_in_seconds = db.Column(db.Integer)
updated_at_in_seconds = db.Column(db.Integer)
@property
def serialized(self) -> dict[str, Union[str, int]]:

View File

@ -40,7 +40,7 @@ class ProcessModelInfo:
display_order: int | None = 0
is_review: bool = False
files: list[File] | None = field(default_factory=list[File])
fault_or_suspend_on_exception: NotificationType = NotificationType.fault.value
fault_or_suspend_on_exception: str = NotificationType.fault.value
exception_notification_addresses: list[str] = field(default_factory=list)
def __post_init__(self) -> None:

View File

@ -33,29 +33,29 @@ class TaskEventModel(SpiffworkflowBaseDBModel):
"""TaskEventModel."""
__tablename__ = "task_event"
id = db.Column(db.Integer, primary_key=True) # type: ignore
user_uid = db.Column( # type: ignore
db.String(50), nullable=False # type: ignore
id = db.Column(db.Integer, primary_key=True)
user_uid = db.Column(
db.String(50), nullable=False
) # In some cases the unique user id may not exist in the db yet.
process_instance_id = db.Column( # type: ignore
db.Integer, db.ForeignKey("process_instance.id"), nullable=False # type: ignore
process_instance_id = db.Column(
db.Integer, db.ForeignKey("process_instance.id"), nullable=False
)
spec_version = db.Column(db.String(50)) # type: ignore
action = db.Column(db.String(50)) # type: ignore
task_id = db.Column(db.String(50)) # type: ignore
task_name = db.Column(db.String(50)) # type: ignore
task_title = db.Column(db.String(50)) # type: ignore
task_type = db.Column(db.String(50)) # type: ignore
task_state = db.Column(db.String(50)) # type: ignore
task_lane = db.Column(db.String(50)) # type: ignore
form_data = db.Column( # type: ignore
db.JSON # type: ignore
spec_version = db.Column(db.String(50))
action = db.Column(db.String(50))
task_id = db.Column(db.String(50))
task_name = db.Column(db.String(50))
task_title = db.Column(db.String(50))
task_type = db.Column(db.String(50))
task_state = db.Column(db.String(50))
task_lane = db.Column(db.String(50))
form_data = db.Column(
db.JSON
) # And form data submitted when the task was completed.
mi_type = db.Column(db.String(50)) # type: ignore
mi_count = db.Column(db.Integer) # type: ignore
mi_index = db.Column(db.Integer) # type: ignore
process_name = db.Column(db.String(50)) # type: ignore
date = db.Column(db.DateTime(timezone=True), default=func.now()) # type: ignore
mi_type = db.Column(db.String(50))
mi_count = db.Column(db.Integer)
mi_index = db.Column(db.Integer)
process_name = db.Column(db.String(50))
date = db.Column(db.DateTime(timezone=True), default=func.now())
class TaskEventModelSchema(SQLAlchemyAutoSchema):

View File

@ -18,11 +18,11 @@ class UserModel(SpiffworkflowBaseDBModel):
"""UserModel."""
__tablename__ = "user"
id = db.Column(db.Integer, primary_key=True) # type: ignore
username = db.Column(db.String(50), nullable=False, unique=True) # type: ignore
uid = db.Column(db.String(50), unique=True) # type: ignore
name = db.Column(db.String(50)) # type: ignore
email = db.Column(db.String(50)) # type: ignore
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(50), nullable=False, unique=True)
uid = db.Column(db.String(50), unique=True)
name = db.Column(db.String(50))
email = db.Column(db.String(50))
user_group_assignments = relationship(UserGroupAssignmentModel, cascade="delete")
groups = relationship( # type: ignore
GroupModel,
@ -101,6 +101,6 @@ class AdminSessionModel(SpiffworkflowBaseDBModel):
"""AdminSessionModel."""
__tablename__ = "admin_session"
id = db.Column(db.Integer, primary_key=True) # type: ignore
token = db.Column(db.String(50), unique=True) # type: ignore
admin_impersonate_uid = db.Column(db.String(50)) # type: ignore
id = db.Column(db.Integer, primary_key=True)
token = db.Column(db.String(50), unique=True)
admin_impersonate_uid = db.Column(db.String(50))

View File

@ -10,10 +10,10 @@ class UserGroupAssignmentModel(SpiffworkflowBaseDBModel):
__tablename__ = "user_group_assignment"
__table_args__ = (
db.UniqueConstraint("user_id", "group_id", name="user_group_assignment_unique"), # type: ignore
db.UniqueConstraint("user_id", "group_id", name="user_group_assignment_unique"),
)
id = db.Column(db.Integer, primary_key=True) # type: ignore
user_id = db.Column(ForeignKey("user.id"), nullable=False) # type: ignore
group_id = db.Column(ForeignKey("group.id"), nullable=False) # type: ignore
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(ForeignKey("user.id"), nullable=False)
group_id = db.Column(ForeignKey("group.id"), nullable=False)
group = relationship("GroupModel", overlaps="groups,user_group_assignments,users") # type: ignore
user = relationship("UserModel", overlaps="groups,user_group_assignments,users") # type: ignore

View File

@ -2,7 +2,6 @@
import json
from typing import Any
from typing import Dict
from typing import List
from typing import Optional
from typing import Union
@ -13,7 +12,6 @@ from flask import g
from flask import Response
from flask_bpmn.api.api_error import ApiError
from flask_bpmn.models.db import db
from werkzeug.datastructures import FileStorage
from spiffworkflow_backend.exceptions.process_entity_not_found_error import (
ProcessEntityNotFoundError,
@ -117,10 +115,24 @@ def process_model_add(
) -> flask.wrappers.Response:
"""Add_process_model."""
process_model_info = ProcessModelInfoSchema().load(body)
if process_model_info is None:
raise ApiError(
code="process_model_could_not_be_created",
message=f"Process Model could not be created from given body: {body}",
status_code=400,
)
process_model_service = ProcessModelService()
process_group = process_model_service.get_process_group(
process_model_info.process_group_id
)
if process_group is None:
raise ApiError(
code="process_model_could_not_be_created",
message=f"Process Model could not be created from given body because Process Group could not be found: {body}",
status_code=400,
)
process_model_info.process_group = process_group
workflows = process_model_service.cleanup_workflow_spec_display_order(process_group)
size = len(workflows)
@ -143,16 +155,14 @@ def process_model_delete(
def process_model_update(
process_group_id: str, process_model_id: str, body: Dict[str, Union[str, bool, int]]
) -> Dict[str, Union[str, bool, int]]:
) -> Any:
"""Process_model_update."""
process_model = ProcessModelInfoSchema().load(body)
ProcessModelService().update_spec(process_model)
return ProcessModelInfoSchema().dump(process_model)
def process_model_show(
process_group_id: str, process_model_id: str
) -> Dict[str, Union[str, List[Dict[str, Optional[Union[str, int, bool]]]], bool, int]]:
def process_model_show(process_group_id: str, process_model_id: str) -> Any:
"""Process_model_show."""
process_model = get_process_model(process_model_id, process_group_id)
files = sorted(SpecFileService.get_files(process_model))
@ -185,9 +195,7 @@ def process_model_list(
return Response(json.dumps(response_json), status=200, mimetype="application/json")
def get_file(
process_group_id: str, process_model_id: str, file_name: str
) -> Dict[str, Optional[Union[str, int, bool]]]:
def get_file(process_group_id: str, process_model_id: str, file_name: str) -> Any:
"""Get_file."""
process_model = get_process_model(process_model_id, process_group_id)
files = SpecFileService.get_files(process_model, file_name)
@ -231,6 +239,13 @@ def add_file(process_group_id: str, process_model_id: str) -> flask.wrappers.Res
process_model_service = ProcessModelService()
process_model = get_process_model(process_model_id, process_group_id)
request_file = get_file_from_request()
if not request_file.filename:
raise ApiError(
code="could_not_get_filename",
message="Could not get filename from request",
status_code=400,
)
file = SpecFileService.add_file(
process_model, request_file.filename, request_file.stream.read()
)
@ -263,8 +278,8 @@ def process_instance_create(
def process_instance_run(
process_group_id: str,
process_model_id: str,
process_instance_id: str,
do_engine_steps: bool = None,
process_instance_id: int,
do_engine_steps: bool = False,
) -> flask.wrappers.Response:
"""Process_instance_run."""
process_instance = ProcessInstanceService().get_process_instance(
@ -314,6 +329,20 @@ def process_instance_list(
results = ProcessInstanceModel.query.filter_by(
process_model_identifier=process_model.id
)
# this can never happen. obviously the class has the columns it defines. this is just to appease mypy.
if (
ProcessInstanceModel.start_in_seconds is None
or ProcessInstanceModel.end_in_seconds is None
):
raise (
ApiError(
code="unexpected_condition",
message="Something went very wrong",
status_code=500,
)
)
if start_from is not None:
results = results.filter(ProcessInstanceModel.start_in_seconds >= start_from)
if start_till is not None:
@ -326,7 +355,7 @@ def process_instance_list(
results = results.filter(ProcessInstanceModel.status == process_status)
process_instances = results.order_by(
ProcessInstanceModel.start_in_seconds.desc(), ProcessInstanceModel.id.desc()
ProcessInstanceModel.start_in_seconds.desc(), ProcessInstanceModel.id.desc() # type: ignore
).paginate(page, per_page, False)
serialized_results = []
@ -346,7 +375,9 @@ def process_instance_list(
return Response(json.dumps(response_json), status=200, mimetype="application/json")
def process_instance_delete(process_group_id, process_model_id, process_instance_id):
def process_instance_delete(
_process_group_id: str, _process_model_id: str, process_instance_id: int
) -> flask.wrappers.Response:
"""Create_process_instance."""
process_instance = ProcessInstanceModel.query.filter_by(
id=process_instance_id
@ -374,7 +405,7 @@ def process_instance_report(
process_instances = (
ProcessInstanceModel.query.filter_by(process_model_identifier=process_model.id)
.order_by(
ProcessInstanceModel.start_in_seconds.desc(), ProcessInstanceModel.id.desc()
ProcessInstanceModel.start_in_seconds.desc(), ProcessInstanceModel.id.desc() # type: ignore
)
.paginate(page, per_page, False)
)
@ -399,7 +430,7 @@ def process_instance_report(
return Response(json.dumps(response_json), status=200, mimetype="application/json")
def get_file_from_request() -> FileStorage:
def get_file_from_request() -> Any:
"""Get_file_from_request."""
request_file = connexion.request.files.get("file")
if not request_file:

View File

@ -3,8 +3,8 @@ import json
import time
from flask_bpmn.models.db import db
from tests.spiffworkflow_backend.helpers.test_data import find_or_create_user
from spiffworkflow_backend.helpers.fixture_data import find_or_create_user
from spiffworkflow_backend.models.process_instance import ProcessInstanceModel
from spiffworkflow_backend.models.process_instance import ProcessInstanceStatus
@ -17,16 +17,23 @@ def load_fixtures() -> list[ProcessInstanceModel]:
statuses = ProcessInstanceStatus.list()
current_time = round(time.time())
# as of 2022-06-24
# not_started - 1 hour ago
# user_input_required - 2 hours ago
# waiting - 3 hourse ago
# complete - 4 hours ago
# faulted - 5 hours ago
# suspended - 6 hours ago
process_instances = []
for i in range(5):
for i in range(len(statuses)):
process_instance = ProcessInstanceModel(
status=ProcessInstanceStatus[statuses[i]],
status=statuses[i],
process_initiator=user,
process_model_identifier=test_process_model_id,
process_group_identifier=test_process_group_id,
updated_at_in_seconds=round(time.time()),
start_in_seconds=(3600 * i) + current_time,
end_in_seconds=(3600 * i + 20) + current_time,
start_in_seconds=current_time - (3600 * i),
end_in_seconds=current_time - (3600 * i - 20),
bpmn_json=json.dumps({"i": i}),
)
db.session.add(process_instance)

View File

@ -18,7 +18,7 @@ class ErrorHandlingService:
"""ErrorHandlingService."""
@staticmethod
def set_instance_status(instance_id: str, status: str) -> None:
def set_instance_status(instance_id: int, status: str) -> None:
"""Set_instance_status."""
instance = (
db.session.query(ProcessInstanceModel)
@ -28,7 +28,6 @@ class ErrorHandlingService:
if instance:
instance.status = status
db.session.commit()
return instance
def handle_error(
self, _processor: ProcessInstanceProcessor, _error: Union[ApiError, Exception]

View File

@ -254,7 +254,7 @@ class ProcessInstanceProcessor:
% (process_instance_model.id, e.__class__.__name__, str(e))
)
process_instance_model.bpmn_json = None
process_instance_model.status = ProcessInstanceStatus.not_started
process_instance_model.status = ProcessInstanceStatus.not_started.value
# clear out any task assignments
db.session.query(TaskEventModel).filter(

View File

@ -126,7 +126,7 @@ class ProcessInstanceService:
else:
return {}
def get_process_instance(self, process_instance_id):
def get_process_instance(self, process_instance_id: int) -> Any:
"""Get_process_instance."""
result = (
db.session.query(ProcessInstanceModel)

View File

@ -179,15 +179,17 @@ class ProcessModelService(FileSystemService):
return []
return process_group.process_models
def get_process_group(self, process_group_id: str) -> Optional[ProcessGroup]:
def get_process_group(self, process_group_id: str) -> ProcessGroup:
"""Look for a given process_group, and return it."""
if not os.path.exists(FileSystemService.root_path()):
return None # Nothing to scan yet. There are no files.
with os.scandir(FileSystemService.root_path()) as directory_items:
for item in directory_items:
if item.is_dir() and item.name == process_group_id:
return self.__scan_process_group(item)
return None
if os.path.exists(FileSystemService.root_path()):
with os.scandir(FileSystemService.root_path()) as directory_items:
for item in directory_items:
if item.is_dir() and item.name == process_group_id:
return self.__scan_process_group(item)
raise ProcessEntityNotFoundError(
"process_group_not_found", f"Process Group Id: {process_group_id}"
)
def add_process_group(self, process_group: ProcessGroup) -> ProcessGroup:
"""Add_process_group."""

View File

@ -1,9 +1,7 @@
"""User."""
from typing import Any
from typing import Dict
from typing import Optional
from flask_bpmn.models.db import db
from tests.spiffworkflow_backend.helpers.example_data import ExampleDataLoader
from spiffworkflow_backend.exceptions.process_entity_not_found_error import (
@ -15,23 +13,16 @@ from spiffworkflow_backend.models.user import UserModel
from spiffworkflow_backend.services.process_model_service import ProcessModelService
def find_or_create_user(username: str = "test_user1") -> Any:
"""Find_or_create_user."""
user = UserModel.query.filter_by(username=username).first()
if user is None:
user = UserModel(username=username)
db.session.add(user)
db.session.commit()
return user
def assure_process_group_exists(process_group_id: Optional[str] = None) -> ProcessGroup:
"""Assure_process_group_exists."""
process_group = None
workflow_spec_service = ProcessModelService()
if process_group_id is not None:
process_group = workflow_spec_service.get_process_group(process_group_id)
try:
process_group = workflow_spec_service.get_process_group(process_group_id)
except ProcessEntityNotFoundError:
process_group = None
if process_group is None:
process_group_id_to_create = "test_process_group"
if process_group_id is not None:

View File

@ -2,16 +2,15 @@
import io
import json
import time
from typing import Any
from typing import Dict
from typing import Optional
from typing import Union
import pytest
from flask.app import Flask
from flask.testing import FlaskClient
from flask_bpmn.models.db import db
from flask_mail import Mail
from tests.spiffworkflow_backend.helpers.test_data import find_or_create_user
from tests.spiffworkflow_backend.helpers.test_data import load_test_spec
from tests.spiffworkflow_backend.helpers.test_data import logged_in_headers
from werkzeug.test import TestResponse
@ -19,6 +18,7 @@ from werkzeug.test import TestResponse
from spiffworkflow_backend.exceptions.process_entity_not_found_error import (
ProcessEntityNotFoundError,
)
from spiffworkflow_backend.helpers.fixture_data import find_or_create_user
from spiffworkflow_backend.models.process_group import ProcessGroup
from spiffworkflow_backend.models.process_group import ProcessGroupSchema
from spiffworkflow_backend.models.process_instance import ProcessInstanceModel
@ -235,6 +235,7 @@ def test_process_group_add(
# Check what is returned
result = ProcessGroupSchema().loads(response.get_data(as_text=True))
assert result is not None
assert result.display_name == "Another Test Category"
assert result.id == "test"
@ -263,8 +264,8 @@ def test_process_group_delete(
f"/v1.0/process-groups/{process_group_id}", headers=logged_in_headers(user)
)
deleted = ProcessModelService().get_process_group(process_group_id)
assert deleted is None
with pytest.raises(ProcessEntityNotFoundError):
ProcessModelService().get_process_group(process_group_id)
def test_process_group_update(
@ -548,9 +549,9 @@ def test_get_process_model_when_not_found(
"""Test_get_process_model_when_not_found."""
user = find_or_create_user()
process_model_dir_name = "THIS_NO_EXISTS"
group = create_process_group(client, user, "my_group")
group_id = create_process_group(client, user, "my_group")
response = client.get(
f"/v1.0/process-models/{group.json['id']}/{process_model_dir_name}",
f"/v1.0/process-models/{group_id}/{process_model_dir_name}",
headers=logged_in_headers(user),
)
assert response.status_code == 400
@ -577,7 +578,7 @@ def test_process_instance_create(
def test_process_instance_run(
app: Flask, client: FlaskClient, with_bpmn_file_cleanup: None
):
) -> None:
"""Test_process_instance_run."""
process_group_id = "runs_without_input"
process_model_id = "sample"
@ -586,12 +587,14 @@ def test_process_instance_run(
response = create_process_instance(
client, process_group_id, process_model_id, headers
)
assert response.json is not None
process_instance_id = response.json["id"]
response = client.post(
f"/v1.0/process-models/{process_group_id}/{process_model_id}/process-instances/{process_instance_id}/run",
headers=logged_in_headers(user),
)
assert response.json is not None
assert type(response.json["updated_at_in_seconds"]) is int
assert response.json["updated_at_in_seconds"] > 0
assert response.json["status"] == "complete"
@ -929,7 +932,7 @@ def test_process_model_file_create(
assert result["process_group_id"] == process_group_id
assert result["process_model_id"] == process_model_id
assert result["name"] == file_name
assert bytes(result["file_contents"], "utf-8") == file_data
assert bytes(str(result["file_contents"]), "utf-8") == file_data
def create_process_instance(
@ -950,14 +953,14 @@ def create_process_instance(
def create_process_model(
client: FlaskClient,
process_group_id=None,
process_model_id: str = None,
process_model_display_name: str = None,
process_model_description: str = None,
fault_or_suspend_on_exception: NotificationType = None,
exception_notification_addresses: list = None,
process_group_id: Optional[str] = None,
process_model_id: Optional[str] = None,
process_model_display_name: Optional[str] = None,
process_model_description: Optional[str] = None,
fault_or_suspend_on_exception: Optional[str] = None,
exception_notification_addresses: Optional[list] = None,
primary_process_id: str = None,
primary_file_name: str = None
primary_file_name: str = None,
) -> TestResponse:
"""Create_process_model."""
process_model_service = ProcessModelService()
@ -978,7 +981,7 @@ def create_process_model(
if process_model_description is None:
process_model_description = "Om nom nom delicious cookies"
if fault_or_suspend_on_exception is None:
fault_or_suspend_on_exception = NotificationType.suspend
fault_or_suspend_on_exception = NotificationType.suspend.value
if exception_notification_addresses is None:
exception_notification_addresses = []
if primary_process_id is None:
@ -1013,19 +1016,19 @@ def create_process_model(
def create_spec_file(
client: FlaskClient,
process_group_id: str = None,
process_model_id: str = None,
file_name: str = None,
file_data: bytes = None,
) -> Dict[str, Optional[Union[str, bool, int]]]:
process_group_id: str = "",
process_model_id: str = "",
file_name: str = "",
file_data: bytes = b"",
) -> Any:
"""Test_create_spec_file."""
if process_group_id is None:
if process_group_id == "":
process_group_id = "random_fact"
if process_model_id is None:
if process_model_id == "":
process_model_id = "random_fact"
if file_name is None:
if file_name == "":
file_name = "random_fact.svg"
if file_data is None:
if file_data == b"":
file_data = b"abcdef"
spec = load_test_spec(process_model_id, process_group_id=process_group_id)
data = {"file": (io.BytesIO(file_data), file_name)}
@ -1053,7 +1056,9 @@ def create_spec_file(
return file
def create_process_group(client, user, process_group_id, display_name=""):
def create_process_group(
client: FlaskClient, user: Any, process_group_id: str, display_name: str = ""
) -> str:
"""Create_process_group."""
process_group = ProcessGroup(
id=process_group_id, display_name=display_name, display_order=0, admin=False
@ -1065,8 +1070,9 @@ def create_process_group(client, user, process_group_id, display_name=""):
data=json.dumps(ProcessGroupSchema().dump(process_group)),
)
assert response.status_code == 201
assert response.json is not None
assert response.json["id"] == process_group_id
return response
return process_group_id
# def test_get_process_model(self):

View File

@ -11,6 +11,6 @@ def test_start_dates_are_one_hour_apart(app: Flask) -> None:
assert len(process_instances) > 2
assert process_instances[0].start_in_seconds is not None
assert process_instances[1].start_in_seconds is not None
assert (process_instances[0].start_in_seconds + 3600) == (
assert (process_instances[0].start_in_seconds - 3600) == (
process_instances[1].start_in_seconds
)

View File

@ -1,8 +1,8 @@
"""Test Permissions."""
from flask.app import Flask
from flask_bpmn.models.db import db
from tests.spiffworkflow_backend.helpers.test_data import find_or_create_user
from spiffworkflow_backend.helpers.fixture_data import find_or_create_user
from spiffworkflow_backend.models.principal import PrincipalModel
# from tests.spiffworkflow_backend.helpers.test_data import find_or_create_process_group