dara-core 1.20.3__py3-none-any.whl → 1.21.1__py3-none-any.whl
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.
- dara/core/__init__.py +8 -42
- dara/core/configuration.py +33 -4
- dara/core/defaults.py +7 -0
- dara/core/definitions.py +22 -35
- dara/core/interactivity/actions.py +29 -28
- dara/core/interactivity/plain_variable.py +6 -2
- dara/core/interactivity/switch_variable.py +2 -2
- dara/core/internal/execute_action.py +75 -6
- dara/core/internal/routing.py +526 -354
- dara/core/internal/tasks.py +1 -1
- dara/core/jinja/index.html +97 -1
- dara/core/jinja/index_autojs.html +116 -10
- dara/core/js_tooling/js_utils.py +35 -14
- dara/core/main.py +137 -89
- dara/core/persistence.py +6 -2
- dara/core/router/__init__.py +5 -0
- dara/core/router/compat.py +77 -0
- dara/core/router/components.py +143 -0
- dara/core/router/dependency_graph.py +62 -0
- dara/core/router/router.py +887 -0
- dara/core/umd/{dara.core.umd.js → dara.core.umd.cjs} +62588 -46966
- dara/core/umd/style.css +52 -9
- dara/core/visual/components/__init__.py +16 -11
- dara/core/visual/components/menu.py +4 -0
- dara/core/visual/components/menu_link.py +1 -0
- dara/core/visual/components/powered_by_causalens.py +9 -0
- dara/core/visual/components/sidebar_frame.py +1 -0
- dara/core/visual/dynamic_component.py +1 -1
- {dara_core-1.20.3.dist-info → dara_core-1.21.1.dist-info}/METADATA +10 -10
- {dara_core-1.20.3.dist-info → dara_core-1.21.1.dist-info}/RECORD +33 -26
- {dara_core-1.20.3.dist-info → dara_core-1.21.1.dist-info}/LICENSE +0 -0
- {dara_core-1.20.3.dist-info → dara_core-1.21.1.dist-info}/WHEEL +0 -0
- {dara_core-1.20.3.dist-info → dara_core-1.21.1.dist-info}/entry_points.txt +0 -0
|
@@ -20,7 +20,8 @@ from __future__ import annotations
|
|
|
20
20
|
import asyncio
|
|
21
21
|
from collections.abc import Mapping
|
|
22
22
|
from contextvars import ContextVar
|
|
23
|
-
from
|
|
23
|
+
from functools import partial
|
|
24
|
+
from typing import Any, Callable, Literal, Optional, Union
|
|
24
25
|
|
|
25
26
|
import anyio
|
|
26
27
|
|
|
@@ -42,13 +43,16 @@ from dara.core.logging import dev_logger
|
|
|
42
43
|
CURRENT_ACTION_ID = ContextVar('current_action_id', default='')
|
|
43
44
|
|
|
44
45
|
|
|
45
|
-
async def _execute_action(
|
|
46
|
+
async def _execute_action(
|
|
47
|
+
handler: Callable, ctx: ActionCtx, values: Mapping[str, Any], _on_error: Literal['raise', 'notify'] = 'notify'
|
|
48
|
+
):
|
|
46
49
|
"""
|
|
47
50
|
Execute the action handler within the given action context, handling any exceptions that occur.
|
|
48
51
|
|
|
49
52
|
:param handler: the action handler to execute
|
|
50
53
|
:param ctx: the action context to use
|
|
51
54
|
:param values: the resolved values to pass to the handler
|
|
55
|
+
:param _on_error: whether to raise or notify on errors
|
|
52
56
|
"""
|
|
53
57
|
bound_arg = None
|
|
54
58
|
kwarg_names = list(values.keys())
|
|
@@ -71,13 +75,18 @@ async def _execute_action(handler: Callable, ctx: ActionCtx, values: Mapping[str
|
|
|
71
75
|
try:
|
|
72
76
|
return await run_user_handler(handler, args=args, kwargs=parsed_values)
|
|
73
77
|
except Exception as e:
|
|
74
|
-
|
|
75
|
-
|
|
78
|
+
if _on_error == 'raise':
|
|
79
|
+
raise
|
|
80
|
+
elif _on_error == 'notify':
|
|
81
|
+
dev_logger.error('Error executing action', e)
|
|
82
|
+
await ctx.notify('An error occurred while executing the action', 'Error', 'ERROR')
|
|
76
83
|
finally:
|
|
77
84
|
await ctx._end_execution()
|
|
78
85
|
|
|
79
86
|
|
|
80
|
-
async def _stream_action(
|
|
87
|
+
async def _stream_action(
|
|
88
|
+
handler: Callable, ctx: ActionCtx, _on_error: Literal['raise', 'notify'] = 'notify', **values: Mapping[str, Any]
|
|
89
|
+
):
|
|
81
90
|
"""
|
|
82
91
|
Run the action handler and stream the results to the frontend.
|
|
83
92
|
Executes two tasks in parallel:
|
|
@@ -91,13 +100,73 @@ async def _stream_action(handler: Callable, ctx: ActionCtx, **values: Mapping[st
|
|
|
91
100
|
try:
|
|
92
101
|
async with anyio.create_task_group() as tg:
|
|
93
102
|
# Execute the handler and a stream consumer in parallel
|
|
94
|
-
tg.start_soon(_execute_action, handler, ctx, values)
|
|
103
|
+
tg.start_soon(partial(_execute_action, _on_error=_on_error), handler, ctx, values)
|
|
95
104
|
tg.start_soon(ctx._handle_results)
|
|
96
105
|
finally:
|
|
97
106
|
# None is treated as a sentinel value to stop waiting for new actions to come in on the client
|
|
98
107
|
await ctx._on_action(None)
|
|
99
108
|
|
|
100
109
|
|
|
110
|
+
async def execute_action_sync(
|
|
111
|
+
action_def: ActionResolverDef,
|
|
112
|
+
inp: Any,
|
|
113
|
+
values: Mapping[str, Any],
|
|
114
|
+
static_kwargs: Mapping[str, Any],
|
|
115
|
+
store: CacheStore,
|
|
116
|
+
task_mgr: TaskManager,
|
|
117
|
+
):
|
|
118
|
+
"""
|
|
119
|
+
Execute an action until completion.
|
|
120
|
+
Used for executing `on_load` route actions.
|
|
121
|
+
|
|
122
|
+
:param action_def: resolver definition
|
|
123
|
+
:param inp: input to the action
|
|
124
|
+
:param values: values from the frontend
|
|
125
|
+
:param static_kwargs: mapping of var names to current values for static arguments
|
|
126
|
+
:param store: store instance
|
|
127
|
+
:param task_mgr: task manager instance - task are not supported here but passed for compat
|
|
128
|
+
"""
|
|
129
|
+
action = action_def.resolver
|
|
130
|
+
assert action is not None, 'Action resolver must be defined'
|
|
131
|
+
|
|
132
|
+
results = []
|
|
133
|
+
|
|
134
|
+
# Construct a context which handles action messages by accumulating them in an array
|
|
135
|
+
async def handle_action(act_impl: Optional[ActionImpl]):
|
|
136
|
+
if act_impl is not None:
|
|
137
|
+
results.append(act_impl)
|
|
138
|
+
|
|
139
|
+
ctx = ActionCtx(inp, handle_action)
|
|
140
|
+
ACTION_CONTEXT.set(ctx)
|
|
141
|
+
|
|
142
|
+
resolved_kwargs = {}
|
|
143
|
+
|
|
144
|
+
if values is not None:
|
|
145
|
+
annotations = action.__annotations__
|
|
146
|
+
|
|
147
|
+
async def _resolve_kwarg(val: Any, key: str):
|
|
148
|
+
typ = annotations.get(key)
|
|
149
|
+
val = await resolve_dependency(val, store, task_mgr)
|
|
150
|
+
resolved_kwargs[key] = deserialize(val, typ)
|
|
151
|
+
|
|
152
|
+
async with anyio.create_task_group() as tg:
|
|
153
|
+
for key, value in values.items():
|
|
154
|
+
tg.start_soon(_resolve_kwarg, value, key)
|
|
155
|
+
|
|
156
|
+
# Merge resolved dynamic kwargs with static kwargs received
|
|
157
|
+
resolved_kwargs = {**resolved_kwargs, **static_kwargs}
|
|
158
|
+
|
|
159
|
+
# Disallow tasks here
|
|
160
|
+
has_tasks = any(isinstance(extra, BaseTask) for extra in resolved_kwargs.values())
|
|
161
|
+
if has_tasks:
|
|
162
|
+
raise ValueError('This action does not support tasks')
|
|
163
|
+
|
|
164
|
+
# Run until completion, raising on errors
|
|
165
|
+
await _stream_action(action, ctx, _on_error='raise', **resolved_kwargs)
|
|
166
|
+
|
|
167
|
+
return results
|
|
168
|
+
|
|
169
|
+
|
|
101
170
|
async def execute_action(
|
|
102
171
|
action_def: ActionResolverDef,
|
|
103
172
|
inp: Any,
|