qctrl-workflow-client 3.0.0__tar.gz → 3.1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {qctrl_workflow_client-3.0.0 → qctrl_workflow_client-3.1.1}/PKG-INFO +2 -2
- {qctrl_workflow_client-3.0.0 → qctrl_workflow_client-3.1.1}/pyproject.toml +4 -4
- {qctrl_workflow_client-3.0.0 → qctrl_workflow_client-3.1.1}/qctrlworkflowclient/__init__.py +1 -1
- {qctrl_workflow_client-3.0.0 → qctrl_workflow_client-3.1.1}/qctrlworkflowclient/functions.py +70 -0
- {qctrl_workflow_client-3.0.0 → qctrl_workflow_client-3.1.1}/qctrlworkflowclient/router/api.py +24 -8
- {qctrl_workflow_client-3.0.0 → qctrl_workflow_client-3.1.1}/LICENSE +0 -0
- {qctrl_workflow_client-3.0.0 → qctrl_workflow_client-3.1.1}/README.md +0 -0
- {qctrl_workflow_client-3.0.0 → qctrl_workflow_client-3.1.1}/qctrlworkflowclient/defaults.py +0 -0
- {qctrl_workflow_client-3.0.0 → qctrl_workflow_client-3.1.1}/qctrlworkflowclient/globals.py +0 -0
- {qctrl_workflow_client-3.0.0 → qctrl_workflow_client-3.1.1}/qctrlworkflowclient/products.py +0 -0
- {qctrl_workflow_client-3.0.0 → qctrl_workflow_client-3.1.1}/qctrlworkflowclient/router/__init__.py +0 -0
- {qctrl_workflow_client-3.0.0 → qctrl_workflow_client-3.1.1}/qctrlworkflowclient/router/base.py +0 -0
- {qctrl_workflow_client-3.0.0 → qctrl_workflow_client-3.1.1}/qctrlworkflowclient/router/local.py +0 -0
- {qctrl_workflow_client-3.0.0 → qctrl_workflow_client-3.1.1}/qctrlworkflowclient/settings.py +0 -0
- {qctrl_workflow_client-3.0.0 → qctrl_workflow_client-3.1.1}/qctrlworkflowclient/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: qctrl-workflow-client
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.1.1
|
|
4
4
|
Summary: Q-CTRL Client
|
|
5
5
|
Home-page: https://q-ctrl.com
|
|
6
6
|
License: https://q-ctrl.com/terms
|
|
@@ -33,7 +33,7 @@ Requires-Dist: importlib-metadata (>=6.8.0,<7.0.0)
|
|
|
33
33
|
Requires-Dist: packaging (>=23.1.0,<24.0.0)
|
|
34
34
|
Requires-Dist: qctrl-client (>=9.1.0,<10.0.0)
|
|
35
35
|
Requires-Dist: qctrl-commons (>=22.0.0,<23.0.0)
|
|
36
|
-
Requires-Dist: requests (>=2.
|
|
36
|
+
Requires-Dist: requests (>=2.32.0,<3.0.0)
|
|
37
37
|
Requires-Dist: tenacity (>=8.1.0,<9.0.0)
|
|
38
38
|
Requires-Dist: tomli (>=2.0.1,<3.0.0)
|
|
39
39
|
Project-URL: Documentation, https://docs.q-ctrl.com
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "qctrl-workflow-client"
|
|
3
|
-
version = "3.
|
|
3
|
+
version = "3.1.1"
|
|
4
4
|
description = "Q-CTRL Client"
|
|
5
5
|
license = "https://q-ctrl.com/terms"
|
|
6
6
|
authors = ["Q-CTRL <support@q-ctrl.com>"]
|
|
@@ -79,16 +79,16 @@ tomli = "^2.0.1"
|
|
|
79
79
|
importlib-metadata = "^6.8.0"
|
|
80
80
|
gql = "^3.4.0"
|
|
81
81
|
tenacity = "^8.1.0"
|
|
82
|
-
requests = "^2.
|
|
82
|
+
requests = "^2.32.0"
|
|
83
83
|
packaging = "^23.1.0"
|
|
84
84
|
qctrl-commons = { version = "^22.0.0", source = "PyPI" }
|
|
85
85
|
qctrl-client = { version = "^9.1.0", source = "PyPI" }
|
|
86
86
|
|
|
87
87
|
[tool.poetry.group.dev.dependencies]
|
|
88
|
-
black = "^
|
|
88
|
+
black = "^24.3.0"
|
|
89
89
|
isort = "^5.12.0"
|
|
90
90
|
pre-commit = "^3.3.3"
|
|
91
|
-
pylint = "^2.
|
|
91
|
+
pylint = "^3.2.2"
|
|
92
92
|
pytest = "^7.2.2"
|
|
93
93
|
pytest-cov = "^4.0.0"
|
|
94
94
|
pytest-mock = "^3.10.0"
|
{qctrl_workflow_client-3.0.0 → qctrl_workflow_client-3.1.1}/qctrlworkflowclient/functions.py
RENAMED
|
@@ -20,6 +20,10 @@ from typing import (
|
|
|
20
20
|
)
|
|
21
21
|
from warnings import warn
|
|
22
22
|
|
|
23
|
+
from qctrlcommons.exceptions import QctrlArgumentsValueError
|
|
24
|
+
|
|
25
|
+
from qctrlworkflowclient.router.api import ApiRouter
|
|
26
|
+
|
|
23
27
|
|
|
24
28
|
def core_workflow(
|
|
25
29
|
get_config: Callable, workflow: str, formatter: Optional[Callable] = None
|
|
@@ -61,6 +65,72 @@ def core_workflow(
|
|
|
61
65
|
# the function
|
|
62
66
|
config = get_config()
|
|
63
67
|
router = config.get_router()
|
|
68
|
+
|
|
69
|
+
if isinstance(router, ApiRouter):
|
|
70
|
+
router.set_async_state(kwargs.pop("is_async", False))
|
|
71
|
+
|
|
72
|
+
data = func(*args, **kwargs)
|
|
73
|
+
result = router(workflow, data)
|
|
74
|
+
|
|
75
|
+
if formatter:
|
|
76
|
+
result = formatter(result)
|
|
77
|
+
|
|
78
|
+
return result
|
|
79
|
+
|
|
80
|
+
return customized_decorator
|
|
81
|
+
|
|
82
|
+
return decorator
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def async_core_workflow(
|
|
86
|
+
get_config: Callable, workflow: str, formatter: Optional[Callable] = None
|
|
87
|
+
):
|
|
88
|
+
"""
|
|
89
|
+
Decorator for a function which will execute asynchronously workflow.
|
|
90
|
+
The decorated function should return the data to be used
|
|
91
|
+
during async workflow execution. When being used in a client
|
|
92
|
+
package, it is recommended to use a partial to provide
|
|
93
|
+
a default value for `get_config` e.g.
|
|
94
|
+
|
|
95
|
+
async_fire_opal_workflow = partial(
|
|
96
|
+
async_core_workflow,
|
|
97
|
+
get_fire_opal_config
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
@async_fire_opal_workflow("execute")
|
|
101
|
+
def execute(...):
|
|
102
|
+
|
|
103
|
+
Parameters
|
|
104
|
+
----------
|
|
105
|
+
get_config : Callable
|
|
106
|
+
Returns a `CoreClientSettings` instance. The configured
|
|
107
|
+
router will be used to execute the workflow.
|
|
108
|
+
workflow : str
|
|
109
|
+
The registered name of the workflow to be executed.
|
|
110
|
+
formatter : Callable, optional
|
|
111
|
+
Optional callable which can be used to format the workflow
|
|
112
|
+
result. The callable should accept exactly one argument
|
|
113
|
+
which is the raw result fo the workflow. If used, the
|
|
114
|
+
decorated function will return the result of this callable.
|
|
115
|
+
"""
|
|
116
|
+
|
|
117
|
+
def decorator(func: Callable):
|
|
118
|
+
@wraps(func)
|
|
119
|
+
def customized_decorator(*args, **kwargs):
|
|
120
|
+
# router is instantiated before function is called
|
|
121
|
+
# so any alteration to settings is visible within
|
|
122
|
+
# the function
|
|
123
|
+
config = get_config()
|
|
124
|
+
router = config.get_router()
|
|
125
|
+
|
|
126
|
+
# Set the async state to True
|
|
127
|
+
router.set_async_state(True)
|
|
128
|
+
if "is_async" in kwargs:
|
|
129
|
+
raise QctrlArgumentsValueError(
|
|
130
|
+
description="The asynchronous state of this function cannot be altered.",
|
|
131
|
+
arguments={"is_async": kwargs.get("is_async")},
|
|
132
|
+
)
|
|
133
|
+
|
|
64
134
|
data = func(*args, **kwargs)
|
|
65
135
|
result = router(workflow, data)
|
|
66
136
|
|
{qctrl_workflow_client-3.0.0 → qctrl_workflow_client-3.1.1}/qctrlworkflowclient/router/api.py
RENAMED
|
@@ -199,6 +199,13 @@ class ApiRouter(BaseRouter):
|
|
|
199
199
|
self._settings = settings
|
|
200
200
|
self._validate()
|
|
201
201
|
self._parallel_task_collector = None
|
|
202
|
+
self._async = False
|
|
203
|
+
|
|
204
|
+
def set_async_state(self, is_async: bool):
|
|
205
|
+
"""
|
|
206
|
+
Toggle asynchronous state of workflow execution.
|
|
207
|
+
"""
|
|
208
|
+
self._async = is_async
|
|
202
209
|
|
|
203
210
|
def _validate(self):
|
|
204
211
|
"""
|
|
@@ -384,6 +391,9 @@ class ApiRouter(BaseRouter):
|
|
|
384
391
|
errors=action_data["errors"],
|
|
385
392
|
)
|
|
386
393
|
|
|
394
|
+
if self._async:
|
|
395
|
+
return {"async_result": action}
|
|
396
|
+
|
|
387
397
|
if self._parallel_task_collector is not None:
|
|
388
398
|
async_result = {"async_result": action}
|
|
389
399
|
self._parallel_task_collector.add(async_result)
|
|
@@ -428,16 +438,11 @@ class ApiRouter(BaseRouter):
|
|
|
428
438
|
message = warning_data["message"]
|
|
429
439
|
warn(Warning(message))
|
|
430
440
|
|
|
431
|
-
|
|
432
|
-
wait=_POLL_WAIT_CHAIN,
|
|
433
|
-
retry=retry_if_result(lambda action: not action.is_finished()),
|
|
434
|
-
)
|
|
435
|
-
def _poll_for_completion(self, action: Action) -> Action:
|
|
441
|
+
def update_action_status(self, action: Action) -> Action:
|
|
436
442
|
"""
|
|
437
|
-
|
|
438
|
-
|
|
443
|
+
Update the action status. When finished, an updated
|
|
444
|
+
`Action` object is returned.
|
|
439
445
|
"""
|
|
440
|
-
|
|
441
446
|
_query = gql.gql(
|
|
442
447
|
"""
|
|
443
448
|
query($modelId: String!) {
|
|
@@ -467,6 +472,17 @@ class ApiRouter(BaseRouter):
|
|
|
467
472
|
|
|
468
473
|
return action
|
|
469
474
|
|
|
475
|
+
@retry(
|
|
476
|
+
wait=_POLL_WAIT_CHAIN,
|
|
477
|
+
retry=retry_if_result(lambda action: not action.is_finished()),
|
|
478
|
+
)
|
|
479
|
+
def _poll_for_completion(self, action: Action) -> Action:
|
|
480
|
+
"""
|
|
481
|
+
Poll the API waiting for the action to be finished.
|
|
482
|
+
When finished, an updated `Action` object is returned.
|
|
483
|
+
"""
|
|
484
|
+
return self.update_action_status(action)
|
|
485
|
+
|
|
470
486
|
def get_result(self, action: Action) -> DecodedResult:
|
|
471
487
|
"""
|
|
472
488
|
Return the result of the action.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{qctrl_workflow_client-3.0.0 → qctrl_workflow_client-3.1.1}/qctrlworkflowclient/router/__init__.py
RENAMED
|
File without changes
|
{qctrl_workflow_client-3.0.0 → qctrl_workflow_client-3.1.1}/qctrlworkflowclient/router/base.py
RENAMED
|
File without changes
|
{qctrl_workflow_client-3.0.0 → qctrl_workflow_client-3.1.1}/qctrlworkflowclient/router/local.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|