dara-core 1.16.21__py3-none-any.whl → 1.16.22__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 CHANGED
@@ -34,6 +34,7 @@ __version__ = version('dara-core')
34
34
 
35
35
  __all__ = [
36
36
  'action',
37
+ 'ActionCtx',
37
38
  'ConfigurationBuilder',
38
39
  'DerivedVariable',
39
40
  'DerivedDataVariable',
@@ -20,6 +20,7 @@ from __future__ import annotations
20
20
  from pydantic import BaseModel
21
21
 
22
22
  from dara.core.interactivity.actions import (
23
+ ActionCtx,
23
24
  DownloadContent,
24
25
  DownloadContentImpl,
25
26
  DownloadVariable,
@@ -45,6 +46,7 @@ from dara.core.interactivity.url_variable import UrlVariable
45
46
 
46
47
  __all__ = [
47
48
  'action',
49
+ 'ActionCtx',
48
50
  'AnyVariable',
49
51
  'AnyDataVariable',
50
52
  'DataVariable',
@@ -52,6 +52,7 @@ from dara.core.base_definitions import (
52
52
  AnnotatedAction,
53
53
  )
54
54
  from dara.core.base_definitions import DaraBaseModel as BaseModel
55
+ from dara.core.base_definitions import TaskProgressUpdate
55
56
  from dara.core.interactivity.data_variable import DataVariable
56
57
  from dara.core.internal.download import generate_download_code
57
58
  from dara.core.internal.registry_lookup import RegistryLookup
@@ -1192,6 +1193,70 @@ class ActionCtx:
1192
1193
  """
1193
1194
  return await DownloadVariable(variable=variable, file_name=file_name, type=type).execute(self)
1194
1195
 
1196
+ async def run_task(
1197
+ self,
1198
+ func: Callable,
1199
+ args: Union[List[Any], None] = None,
1200
+ kwargs: Union[Dict[str, Any], None] = None,
1201
+ on_progress: Optional[Callable[[TaskProgressUpdate], Union[None, Awaitable[None]]]] = None,
1202
+ ):
1203
+ """
1204
+ Run a calculation as a task in a separate process. Recommended for CPU intensive tasks.
1205
+ Returns the result of the task function.
1206
+
1207
+ Note that the function must be defined in a separate module as configured in `task_module` field of the
1208
+ configuration builder. This is because Dara spawns separate worker processes only designed to run
1209
+ functions from that designated module.
1210
+
1211
+ ```python
1212
+ from dara.core import ConfigurationBuilder, TaskProgressUpdate, action, ActionCtx, Variable
1213
+ from dara.components import Text, Stack, Button
1214
+ from .my_module import my_task_function
1215
+
1216
+ config = ConfigurationBuilder()
1217
+ config.task_module = 'my_module'
1218
+
1219
+ status = Variable('Not started')
1220
+
1221
+ @action
1222
+ async def my_task(ctx: ActionCtx):
1223
+ async def on_progress(update: TaskProgressUpdate):
1224
+ await ctx.update(status, f'Progress: {update.progress}% - {update.message}')
1225
+
1226
+ try:
1227
+ result = await ctx.run_task(my_task_function, args=[1, 10], on_progress=on_progress)
1228
+ await ctx.update(status, f'Result: {result}')
1229
+ except Exception as e:
1230
+ await ctx.update(status, f'Error: {e}')
1231
+
1232
+ def task_page():
1233
+ return Stack(Text('Status display:'), Text(text=status), Button('Run', onclick=my_task()))
1234
+
1235
+ config.add_page(name='task', content=task_page())
1236
+ ```
1237
+
1238
+ :param func: the function to run as a task
1239
+ :param args: the arguments to pass to the function
1240
+ :param kwargs: the keyword arguments to pass to the function
1241
+ :param on_progress: a callback to receive progress updates
1242
+ """
1243
+ from dara.core.internal.registries import utils_registry
1244
+ from dara.core.internal.tasks import Task, TaskManager
1245
+
1246
+ task_mgr: TaskManager = utils_registry.get('TaskManager')
1247
+
1248
+ task = Task(func=func, args=args, kwargs=kwargs, on_progress=on_progress)
1249
+ pending_task = await task_mgr.run_task(task)
1250
+
1251
+ # Run until completion
1252
+ await pending_task.event.wait()
1253
+
1254
+ # Raise exception if there was one
1255
+ if pending_task.error:
1256
+ raise pending_task.error
1257
+
1258
+ return pending_task.result
1259
+
1195
1260
  async def execute_action(self, action: ActionImpl):
1196
1261
  """
1197
1262
  Execute a given action.
@@ -90,7 +90,7 @@ class DerivedVariable(NonDataVariable, Generic[VariableType]):
90
90
 
91
91
  def __init__(
92
92
  self,
93
- func: Callable[..., VariableType],
93
+ func: Callable[..., VariableType] | Callable[..., Awaitable[VariableType]],
94
94
  variables: List[AnyVariable],
95
95
  cache: Optional[CacheArgType] = Cache.Type.GLOBAL,
96
96
  run_as_task: bool = False,
@@ -17,7 +17,7 @@ limitations under the License.
17
17
 
18
18
  import inspect
19
19
  import math
20
- from typing import Any, Callable, Dict, List, Optional, Union
20
+ from typing import Any, Awaitable, Callable, Dict, List, Optional, Union, overload
21
21
 
22
22
  from anyio import (
23
23
  CancelScope,
@@ -70,6 +70,7 @@ class Task(BaseTask):
70
70
  notify_channels: Optional[List[str]] = None,
71
71
  cache_key: Optional[str] = None,
72
72
  task_id: Optional[str] = None,
73
+ on_progress: Optional[Callable[[TaskProgressUpdate], Union[None, Awaitable[None]]]] = None,
73
74
  ):
74
75
  """
75
76
  :param func: The function to execute within the process
@@ -87,6 +88,7 @@ class Task(BaseTask):
87
88
  self.notify_channels = notify_channels if notify_channels is not None else []
88
89
  self.cache_key = cache_key
89
90
  self.reg_entry = reg_entry
91
+ self.on_progress = on_progress
90
92
 
91
93
  super().__init__(task_id)
92
94
 
@@ -359,6 +361,14 @@ class TaskManager:
359
361
  self.ws_manager = ws_manager
360
362
  self.store = store
361
363
 
364
+ @overload
365
+ async def run_task(self, task: PendingTask, ws_channel: Optional[str] = None) -> Any:
366
+ ...
367
+
368
+ @overload
369
+ async def run_task(self, task: BaseTask, ws_channel: Optional[str] = None) -> PendingTask:
370
+ ...
371
+
362
372
  async def run_task(self, task: BaseTask, ws_channel: Optional[str] = None):
363
373
  """
364
374
  Run a task and store it in the tasks dict
@@ -504,6 +514,8 @@ class TaskManager:
504
514
  'message': message.message,
505
515
  }
506
516
  )
517
+ if isinstance(task, Task) and task.on_progress:
518
+ await run_user_handler(task.on_progress, args=(message,))
507
519
  elif isinstance(message, TaskResult):
508
520
  # Resolve the pending task related to the result
509
521
  if message.task_id in self.tasks:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dara-core
3
- Version: 1.16.21
3
+ Version: 1.16.22
4
4
  Summary: Dara Framework Core
5
5
  Home-page: https://dara.causalens.com/
6
6
  License: Apache-2.0
@@ -20,10 +20,10 @@ Requires-Dist: async-asgi-testclient (>=1.4.11,<2.0.0)
20
20
  Requires-Dist: certifi (>=2024.7.4)
21
21
  Requires-Dist: click (==8.1.3)
22
22
  Requires-Dist: colorama (>=0.4.6,<0.5.0)
23
- Requires-Dist: create-dara-app (==1.16.21)
23
+ Requires-Dist: create-dara-app (==1.16.22)
24
24
  Requires-Dist: croniter (>=1.0.15,<3.0.0)
25
25
  Requires-Dist: cryptography (>=42.0.4)
26
- Requires-Dist: dara-components (==1.16.21) ; extra == "all"
26
+ Requires-Dist: dara-components (==1.16.22) ; extra == "all"
27
27
  Requires-Dist: exceptiongroup (>=1.1.3,<2.0.0)
28
28
  Requires-Dist: fastapi (>=0.115.0,<0.116.0)
29
29
  Requires-Dist: fastapi_vite_dara (==0.4.0)
@@ -54,7 +54,7 @@ Description-Content-Type: text/markdown
54
54
 
55
55
  # Dara Application Framework
56
56
 
57
- <img src="https://github.com/causalens/dara/blob/v1.16.21/img/dara_light.svg?raw=true">
57
+ <img src="https://github.com/causalens/dara/blob/v1.16.22/img/dara_light.svg?raw=true">
58
58
 
59
59
  ![Master tests](https://github.com/causalens/dara/actions/workflows/tests.yml/badge.svg?branch=master)
60
60
  [![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0)
@@ -99,7 +99,7 @@ source .venv/bin/activate
99
99
  dara start
100
100
  ```
101
101
 
102
- ![Dara App](https://github.com/causalens/dara/blob/v1.16.21/img/components_gallery.png?raw=true)
102
+ ![Dara App](https://github.com/causalens/dara/blob/v1.16.22/img/components_gallery.png?raw=true)
103
103
 
104
104
  Note: `pip` installation uses [PEP 660](https://peps.python.org/pep-0660/) `pyproject.toml`-based editable installs which require `pip >= 21.3` and `setuptools >= 64.0.0`. You can upgrade both with:
105
105
 
@@ -116,9 +116,9 @@ Explore some of our favorite apps - a great way of getting started and getting t
116
116
 
117
117
  | Dara App | Description |
118
118
  | -------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
119
- | ![Large Language Model](https://github.com/causalens/dara/blob/v1.16.21/img/llm.png?raw=true) | Demonstrates how to use incorporate a LLM chat box into your decision app to understand model insights |
120
- | ![Plot Interactivity](https://github.com/causalens/dara/blob/v1.16.21/img/plot_interactivity.png?raw=true) | Demonstrates how to enable the user to interact with plots, trigger actions based on clicks, mouse movements and other interactions with `Bokeh` or `Plotly` plots |
121
- | ![Graph Editor](https://github.com/causalens/dara/blob/v1.16.21/img/graph_viewer.png?raw=true) | Demonstrates how to use the `CausalGraphViewer` component to display your graphs or networks, customising the displayed information through colors and tooltips, and updating the page based on user interaction. |
119
+ | ![Large Language Model](https://github.com/causalens/dara/blob/v1.16.22/img/llm.png?raw=true) | Demonstrates how to use incorporate a LLM chat box into your decision app to understand model insights |
120
+ | ![Plot Interactivity](https://github.com/causalens/dara/blob/v1.16.22/img/plot_interactivity.png?raw=true) | Demonstrates how to enable the user to interact with plots, trigger actions based on clicks, mouse movements and other interactions with `Bokeh` or `Plotly` plots |
121
+ | ![Graph Editor](https://github.com/causalens/dara/blob/v1.16.22/img/graph_viewer.png?raw=true) | Demonstrates how to use the `CausalGraphViewer` component to display your graphs or networks, customising the displayed information through colors and tooltips, and updating the page based on user interaction. |
122
122
 
123
123
  Check out our [App Gallery](https://dara.causalens.com/gallery) for more inspiration!
124
124
 
@@ -145,9 +145,9 @@ And the supporting UI packages and tools.
145
145
  - `ui-utils` - miscellaneous utility functions
146
146
  - `ui-widgets` - widget components
147
147
 
148
- More information on the repository structure can be found in the [CONTRIBUTING.md](https://github.com/causalens/dara/blob/v1.16.21/CONTRIBUTING.md) file.
148
+ More information on the repository structure can be found in the [CONTRIBUTING.md](https://github.com/causalens/dara/blob/v1.16.22/CONTRIBUTING.md) file.
149
149
 
150
150
  ## License
151
151
 
152
- Dara is open-source and licensed under the [Apache 2.0 License](https://github.com/causalens/dara/blob/v1.16.21/LICENSE).
152
+ Dara is open-source and licensed under the [Apache 2.0 License](https://github.com/causalens/dara/blob/v1.16.22/LICENSE).
153
153
 
@@ -1,4 +1,4 @@
1
- dara/core/__init__.py,sha256=eF6Fmf5TkWYIPiZ3CR6kMGinIcFXoA8LQN5m4EpZzHY,2094
1
+ dara/core/__init__.py,sha256=Hib2omvNFpEk72wyYMWQrbf18-uKyn4GW8LlcAtBMoI,2111
2
2
  dara/core/actions.py,sha256=gARcrrtzYuBAVJUCtuHwpFc6PPVPb7x3ITIISCLw0GA,965
3
3
  dara/core/auth/__init__.py,sha256=H0bJoXff5wIRZmHvvQ3y9p5SXA9lM8OuLCGceYGqfb0,851
4
4
  dara/core/auth/base.py,sha256=qxmiIzx-n2g4ZWicgxsYtHjiB14AemOWM_GNxcr98mE,3294
@@ -14,14 +14,14 @@ dara/core/data_utils.py,sha256=5GGz4vk6srLO8HMySiAEk_xZCvmf0SeTTgVi-N4qaKY,12636
14
14
  dara/core/defaults.py,sha256=UkjWwIbo8GLyn8RZRoD3cJe174-3wHZYzvMB0hQCnMg,4150
15
15
  dara/core/definitions.py,sha256=QouD2P2XInW6bqrhPtrfIyDi8i99Au2PTBdWBtgBVrE,16713
16
16
  dara/core/http.py,sha256=LR1Kr5Hca-Z6klNl-M8R8Q1eOfFh3hLrjVS3kVrRsKA,4658
17
- dara/core/interactivity/__init__.py,sha256=3e5G5Nww33irzs1LinUmfs6wYpmSLPp9e4BHplw3gIk,2294
18
- dara/core/interactivity/actions.py,sha256=paujB21J5MYbYZlIP2dIbUStqKbm9PsfCcpcYmOqCSI,45605
17
+ dara/core/interactivity/__init__.py,sha256=zZp4wO6nHZ_-IzDtlv8D5mjlutn4bckqIiSCaPoCYZw,2326
18
+ dara/core/interactivity/actions.py,sha256=yMw8S11wj4J2HVmDsmedh9D0IZFL9hxw6WGNj7X2f6M,48198
19
19
  dara/core/interactivity/any_data_variable.py,sha256=1dLLxLuDErRsgaFPSTXxZHvpVucKKty90twQE6N-_NI,5286
20
20
  dara/core/interactivity/any_variable.py,sha256=LOGhbDdYffujlRxF4LR9ZuWdai03R-EXuGsTEJAwfo0,13544
21
21
  dara/core/interactivity/condition.py,sha256=q_RDDt-DtZEUQL054Mc7zHyJIJIGACljJ2gOFygCHQc,1309
22
22
  dara/core/interactivity/data_variable.py,sha256=pvPOx6SMxHWDxoo5Ea5xqLwrBTrWN68x8lnBiblYSGg,11760
23
23
  dara/core/interactivity/derived_data_variable.py,sha256=u2HOts5rtmzK3D1K383YfYYQnb4pHZF3rTu1lfwMpPA,15323
24
- dara/core/interactivity/derived_variable.py,sha256=7ActxJISTI-EdYUaoqioi8SPznpfCPlqDYlFJO43a38,21886
24
+ dara/core/interactivity/derived_variable.py,sha256=x_vdt8hvgubDEISX6GfpR5CS7n2Vxq3oZIkVd8Daiw0,21927
25
25
  dara/core/interactivity/filtering.py,sha256=BZsWsQvXPhn6WUoAFpAtgN6hXlGDudPbi4h97Qao2ic,9197
26
26
  dara/core/interactivity/loop_variable.py,sha256=EqZX3bMCwKmI2Yu4pQ7TJG9hf3PY2AlAIBLxEzHFbTw,2998
27
27
  dara/core/interactivity/non_data_variable.py,sha256=IMH5cNce2O6RUbu4HB_VLT-BBnDnGHr3lp09XU_lWa4,2378
@@ -59,7 +59,7 @@ dara/core/internal/routing.py,sha256=D2HFfwPKKpDuvvIwXInDWKoq2-zweMVmt4MiVBzorO0
59
59
  dara/core/internal/scheduler.py,sha256=tKpyN_yhtEepfqfkNTfFep055dl-Lq1_Itte6FTkH9o,12978
60
60
  dara/core/internal/settings.py,sha256=ViEni6lVXvbP6Ofb0VoTaWXkI0XajmD-LBpqz1LzwpA,3923
61
61
  dara/core/internal/store.py,sha256=kLRDuYEFwqpJMS0CmL5jGmETs645Xcug4jlelJqk5w4,7706
62
- dara/core/internal/tasks.py,sha256=oCfmOMm3pVH0-dvZzJv4nspCRWc_u-J3J7lmNI_ys5E,24763
62
+ dara/core/internal/tasks.py,sha256=5NdUWGwy11Dd0riPBxiUP9IMb6Is7bfSnD40WLVRFik,25328
63
63
  dara/core/internal/utils.py,sha256=b1YYkn8qHl6-GY6cCm2MS1NXRS9j_rElYCKMZOxJgrY,8232
64
64
  dara/core/internal/websocket.py,sha256=qeW7KOeJ_FPkpAJNZaVwxIN_DqDv7XK7uyjTxJ8HIno,22043
65
65
  dara/core/jinja/index.html,sha256=1gkCFiihXOUH7vp7tT5gH8mKeJB4KqNg394xO3a0usI,1208
@@ -106,8 +106,8 @@ dara/core/visual/themes/__init__.py,sha256=aM4mgoIYo2neBSw5FRzswsht7PUKjLthiHLmF
106
106
  dara/core/visual/themes/dark.py,sha256=UQGDooOc8ric73eHs9E0ltYP4UCrwqQ3QxqN_fb4PwY,1942
107
107
  dara/core/visual/themes/definitions.py,sha256=nS_gQvOzCt5hTmj74d0_siq_9QWuj6wNuir4VCHy0Dk,2779
108
108
  dara/core/visual/themes/light.py,sha256=-Tviq8oEwGbdFULoDOqPuHO0UpAZGsBy8qFi0kAGolQ,1944
109
- dara_core-1.16.21.dist-info/LICENSE,sha256=r9u1w2RvpLMV6YjuXHIKXRBKzia3fx_roPwboGcLqCc,10944
110
- dara_core-1.16.21.dist-info/METADATA,sha256=GU0DRGfGG3DPDKHF_xCnlOgibNnCB7zccD42ys_Cvlo,7507
111
- dara_core-1.16.21.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
112
- dara_core-1.16.21.dist-info/entry_points.txt,sha256=H__D5sNIGuPIhVam0DChNL-To5k8Y7nY7TAFz9Mz6cc,139
113
- dara_core-1.16.21.dist-info/RECORD,,
109
+ dara_core-1.16.22.dist-info/LICENSE,sha256=r9u1w2RvpLMV6YjuXHIKXRBKzia3fx_roPwboGcLqCc,10944
110
+ dara_core-1.16.22.dist-info/METADATA,sha256=OaGKDjB2t-bVSdBdPCJCOz3MbS5V_Cqsb9zazY8dh-I,7507
111
+ dara_core-1.16.22.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
112
+ dara_core-1.16.22.dist-info/entry_points.txt,sha256=H__D5sNIGuPIhVam0DChNL-To5k8Y7nY7TAFz9Mz6cc,139
113
+ dara_core-1.16.22.dist-info/RECORD,,