Skip to content

Commit ba2a163

Browse files
authored
mgmt flow functions (#726)
* mgmt flow functions * readme * PR ficx * coverage fix * add async * fix pr docstring for async run
1 parent f5f08e1 commit ba2a163

File tree

5 files changed

+425
-3
lines changed

5 files changed

+425
-3
lines changed

README.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1096,6 +1096,62 @@ exported_theme = descope_client.mgmt.flow.export_theme()
10961096
imported_theme = descope_client.mgmt.flow.import_flow(
10971097
theme={}
10981098
)
1099+
1100+
# Run a flow with the given flow id and options.
1101+
# You can use the FlowRunOptions class or pass a dict directly.
1102+
from descope import FlowRunOptions
1103+
1104+
# Using FlowRunOptions class
1105+
result = descope_client.mgmt.flow.run_flow(
1106+
flow_id="my-flow-id",
1107+
options=FlowRunOptions(
1108+
input={"key": "value"},
1109+
preview=True,
1110+
tenant="tenant-id",
1111+
),
1112+
)
1113+
1114+
# Or using a dict
1115+
result = descope_client.mgmt.flow.run_flow(
1116+
flow_id="my-flow-id",
1117+
options={
1118+
"input": {"key": "value"},
1119+
"preview": True,
1120+
"tenant": "tenant-id",
1121+
},
1122+
)
1123+
1124+
# Run a flow asynchronously for long-running flows.
1125+
# This returns immediately with an execution ID that can be used to check the result later.
1126+
from descope import FlowRunOptions
1127+
1128+
# Start an async flow run
1129+
async_result = descope_client.mgmt.flow.run_flow_async(
1130+
flow_id="my-flow-id",
1131+
options=FlowRunOptions(
1132+
flow_input={"key": "value"},
1133+
preview=True,
1134+
tenant="tenant-id",
1135+
),
1136+
)
1137+
execution_id = async_result["executionId"]
1138+
1139+
# Or using a dict
1140+
async_result = descope_client.mgmt.flow.run_flow_async(
1141+
flow_id="my-flow-id",
1142+
options={
1143+
"input": {"key": "value"},
1144+
"preview": True,
1145+
"tenant": "tenant-id",
1146+
},
1147+
)
1148+
execution_id = async_result["executionId"]
1149+
1150+
# Check the result of an async flow execution
1151+
# Poll this endpoint until the flow completes
1152+
result = descope_client.mgmt.flow.get_flow_async_result(
1153+
execution_id=execution_id,
1154+
)
10991155
```
11001156

11011157
### Query SSO Groups

descope/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
DescoperRBAC,
2727
DescoperRole,
2828
DescoperTagRole,
29+
FlowRunOptions,
2930
MgmtKeyProjectRole,
3031
MgmtKeyReBac,
3132
MgmtKeyStatus,

descope/management/common.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,9 @@ class MgmtV1:
209209
flow_delete_path = "/v1/mgmt/flow/delete"
210210
flow_import_path = "/v1/mgmt/flow/import"
211211
flow_export_path = "/v1/mgmt/flow/export"
212+
flow_run_path = "/v1/mgmt/flow/run"
213+
flow_async_run_path = "/v1/mgmt/flow/async/run"
214+
flow_async_result_path = "/v1/mgmt/flow/async/result"
212215

213216
# theme
214217
theme_import_path = "/v1/mgmt/theme/import"
@@ -283,6 +286,42 @@ def __init__(
283286
self.refresh_duration = refresh_duration
284287

285288

289+
class FlowRunOptions:
290+
"""
291+
Options for running a flow.
292+
"""
293+
294+
def __init__(
295+
self,
296+
flow_input: Optional[Dict[str, Any]] = None,
297+
preview: Optional[bool] = None,
298+
tenant: Optional[str] = None,
299+
):
300+
self.flow_input = flow_input
301+
self.preview = preview
302+
self.tenant = tenant
303+
304+
def to_dict(self) -> Dict[str, Any]:
305+
result: Dict[str, Any] = {}
306+
if self.flow_input is not None:
307+
result["input"] = self.flow_input
308+
if self.preview is not None:
309+
result["preview"] = self.preview
310+
if self.tenant is not None:
311+
result["tenant"] = self.tenant
312+
return result
313+
314+
@staticmethod
315+
def from_dict(options: Optional[dict]) -> Optional["FlowRunOptions"]:
316+
if options is None:
317+
return None
318+
return FlowRunOptions(
319+
flow_input=options.get("input"),
320+
preview=options.get("preview"),
321+
tenant=options.get("tenant"),
322+
)
323+
324+
286325
class MgmtLoginOptions:
287326
def __init__(
288327
self,

descope/management/flow.py

Lines changed: 96 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
from typing import List
1+
from typing import List, Optional, Union
22

33
from descope._http_base import HTTPBase
4-
from descope.management.common import MgmtV1
4+
from descope.management.common import FlowRunOptions, MgmtV1
55

66

77
class Flow(HTTPBase):
@@ -146,3 +146,97 @@ def import_theme(
146146
},
147147
)
148148
return response.json()
149+
150+
def run_flow(
151+
self,
152+
flow_id: str,
153+
options: Optional[Union[FlowRunOptions, dict]] = None,
154+
) -> dict:
155+
"""
156+
Run a flow with the given flow id and options.
157+
158+
Args:
159+
flow_id (str): the flow id to run.
160+
options (Optional[Union[FlowRunOptions, dict]]): optional flow run options containing:
161+
- input: optional input data to pass to the flow.
162+
- preview: optional flag to run the flow in preview mode.
163+
- tenant: optional tenant ID to run the flow for.
164+
165+
Return value (dict):
166+
Return dict with the flow execution result.
167+
168+
Raise:
169+
AuthException: raised if run operation fails
170+
"""
171+
body: dict = {"flowId": flow_id}
172+
173+
if options is not None:
174+
if isinstance(options, dict):
175+
options = FlowRunOptions.from_dict(options)
176+
if options is not None:
177+
body.update(options.to_dict())
178+
179+
response = self._http.post(
180+
MgmtV1.flow_run_path,
181+
body=body,
182+
)
183+
return response.json()
184+
185+
def run_flow_async(
186+
self,
187+
flow_id: str,
188+
options: Optional[Union[FlowRunOptions, dict]] = None,
189+
) -> dict:
190+
"""
191+
Run a flow asynchronously with the given flow id and options.
192+
193+
Args:
194+
flow_id (str): the flow id to run.
195+
options (Optional[Union[FlowRunOptions, dict]]): optional flow run options containing:
196+
- input: optional input data to pass to the flow.
197+
- preview: optional flag to run the flow in preview mode.
198+
- tenant: optional tenant ID to run the flow for.
199+
200+
Return value (dict):
201+
Return dict with the async flow execution result.
202+
use the get_flow_async_result() method with this result's executionId
203+
to get the actual flow's result.
204+
205+
Raise:
206+
AuthException: raised if run operation fails
207+
"""
208+
body: dict = {"flowId": flow_id}
209+
210+
if options is not None:
211+
if isinstance(options, dict):
212+
options = FlowRunOptions.from_dict(options)
213+
if options is not None:
214+
body.update(options.to_dict())
215+
216+
response = self._http.post(
217+
MgmtV1.flow_async_run_path,
218+
body=body,
219+
)
220+
return response.json()
221+
222+
def get_flow_async_result(
223+
self,
224+
execution_id: str,
225+
) -> dict:
226+
"""
227+
Get the result of an async flow execution.
228+
229+
Args:
230+
execution_id (str): the execution id returned from run_flow_async.
231+
232+
Return value (dict):
233+
Return dict with the async flow execution result.
234+
235+
Raise:
236+
AuthException: raised if the operation fails
237+
"""
238+
response = self._http.post(
239+
MgmtV1.flow_async_result_path,
240+
body={"executionId": execution_id},
241+
)
242+
return response.json()

0 commit comments

Comments
 (0)