dara-core 1.16.21__py3-none-any.whl → 1.16.23__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',
dara/core/definitions.py CHANGED
@@ -70,6 +70,11 @@ DEFAULT_ERROR_TITLE = 'Unexpected error occurred'
70
70
  DEFAULT_ERROR_DESCRIPTION = 'Try again or contact the application owner'
71
71
 
72
72
 
73
+ def _kebab_to_camel(string: str):
74
+ chunks = string.split('-')
75
+ return chunks[0] + ''.join([chunk[0].upper() + chunk[1:].lower() for chunk in chunks[1:]])
76
+
77
+
73
78
  class ErrorHandlingConfig(BaseModel):
74
79
  title: str = DEFAULT_ERROR_TITLE
75
80
  """Title to display in the error boundary"""
@@ -77,8 +82,27 @@ class ErrorHandlingConfig(BaseModel):
77
82
  description: str = DEFAULT_ERROR_DESCRIPTION
78
83
  """Description to display in the error boundary"""
79
84
 
80
- raw_css: Optional[Union[CSSProperties, dict, str]] = None
81
- """Raw styling to apply to the displayed error boundary"""
85
+ raw_css: Optional[Any] = None
86
+ """
87
+ Raw styling to apply to the displayed error boundary.
88
+ Accepts a CSSProperties, dict, str, or NonDataVariable.
89
+ """
90
+
91
+ @field_validator('raw_css', mode='before')
92
+ @classmethod
93
+ def validate_raw_css(cls, value):
94
+ from dara.core.interactivity.non_data_variable import NonDataVariable
95
+
96
+ if isinstance(value, str):
97
+ return str
98
+ if isinstance(value, dict):
99
+ return {_kebab_to_camel(k): v for k, v in value.items()}
100
+ if isinstance(value, NonDataVariable):
101
+ return value
102
+ if isinstance(value, CSSProperties):
103
+ return value
104
+
105
+ raise ValueError(f'raw_css must be a CSSProperties, dict, str, or NonDataVariable, got {type(value)}')
82
106
 
83
107
  def model_dump(self, *args, **kwargs):
84
108
  result = super().model_dump(*args, **kwargs)
@@ -120,14 +144,15 @@ class ComponentInstance(BaseModel):
120
144
  required_routes: ClassVar[List[ApiRoute]] = []
121
145
  """List of routes the component depends on. Will be implicitly added to the app if this component is used"""
122
146
 
123
- raw_css: Optional[Union[CSSProperties, dict, str]] = None
147
+ raw_css: Optional[Any] = None
124
148
  """
125
149
  Raw styling to apply to the component.
126
- Can be an dict/CSSProperties instance representing the `styles` tag, or a string injected directly into the CSS of the wrapping component.
150
+ Can be an dict/CSSProperties instance representing the `styles` tag, a string injected directly into the CSS of the wrapping component,
151
+ or a NonDataVariable resoling to either of the above.
127
152
 
128
153
  ```python
129
154
 
130
- from dara.core import CSSProperties
155
+ from dara.core import CSSProperties, Variable
131
156
 
132
157
  # `style` - use the class for autocompletion/typesense
133
158
  Stack(..., raw_css=CSSProperties(maxWidth='100px'))
@@ -140,6 +165,9 @@ class ComponentInstance(BaseModel):
140
165
  max-width: 100px;
141
166
  \"\"\")
142
167
 
168
+ css_var = Variable('color: red;')
169
+ Stack(..., raw_css=css_var)
170
+
143
171
  ```
144
172
  """
145
173
 
@@ -173,17 +201,23 @@ class ComponentInstance(BaseModel):
173
201
 
174
202
  @field_validator('raw_css', mode='before')
175
203
  @classmethod
176
- def parse_css(cls, css: Optional[Union[CSSProperties, dict, str]]):
204
+ def parse_css(cls, css: Optional[Any]):
205
+ from dara.core.interactivity.non_data_variable import NonDataVariable
206
+
177
207
  # If it's a plain dict, change kebab case to camel case
178
208
  if isinstance(css, dict):
209
+ return {_kebab_to_camel(k): v for k, v in css.items()}
210
+
211
+ if isinstance(css, NonDataVariable):
212
+ return css
179
213
 
180
- def kebab_to_camel(string: str):
181
- chunks = string.split('-')
182
- return chunks[0] + ''.join([chunk[0].upper() + chunk[1:].lower() for chunk in chunks[1:]])
214
+ if isinstance(css, CSSProperties):
215
+ return css
183
216
 
184
- return {kebab_to_camel(k): v for k, v in css.items()}
217
+ if isinstance(css, str):
218
+ return css
185
219
 
186
- return css
220
+ raise ValueError(f'raw_css must be a CSSProperties, dict, str, or NonDataVariable, got {type(css)}')
187
221
 
188
222
  @classmethod
189
223
  def isinstance(cls, obj: Any) -> bool:
@@ -399,7 +433,6 @@ class BaseFallback(StyledComponentInstance):
399
433
 
400
434
  ComponentInstance.model_rebuild()
401
435
 
402
-
403
436
  ComponentInstanceType = Union[ComponentInstance, Callable[..., ComponentInstance]]
404
437
 
405
438
 
@@ -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:
@@ -17386,6 +17386,62 @@ var __privateWrapper = (obj, member, setter, getter) => ({
17386
17386
  var _baseIteratee = baseIteratee$3;
17387
17387
  var e$2 = "object" == typeof navigator ? navigator.platform : "";
17388
17388
  /Mac|iPod|iPhone|iPad/.test(e$2);
17389
+ function useIMEEnter({ onKeyDown: userKeyDown, onKeyUp: userKeyUp, onCompositionStart: userCompStart, onCompositionEnd: userCompEnd }) {
17390
+ const isComposingRef = React.useRef(false);
17391
+ const justEndedRef = React.useRef(false);
17392
+ const handleCompositionStart = React.useCallback((e2) => {
17393
+ isComposingRef.current = true;
17394
+ userCompStart === null || userCompStart === void 0 ? void 0 : userCompStart(e2);
17395
+ }, [userCompStart]);
17396
+ const handleCompositionEnd = React.useCallback((e2) => {
17397
+ isComposingRef.current = false;
17398
+ justEndedRef.current = true;
17399
+ userCompEnd === null || userCompEnd === void 0 ? void 0 : userCompEnd(e2);
17400
+ }, [userCompEnd]);
17401
+ const handleKeyDownCapture = React.useCallback((e2) => {
17402
+ if (isComposingRef.current) {
17403
+ e2.preventDefault();
17404
+ e2.stopPropagation();
17405
+ return;
17406
+ }
17407
+ if (justEndedRef.current) {
17408
+ if (e2.which === 229) {
17409
+ e2.preventDefault();
17410
+ e2.stopPropagation();
17411
+ return;
17412
+ }
17413
+ justEndedRef.current = false;
17414
+ }
17415
+ }, []);
17416
+ const handleKeyDown = React.useCallback((e2) => {
17417
+ if (isComposingRef.current) {
17418
+ return;
17419
+ }
17420
+ userKeyDown === null || userKeyDown === void 0 ? void 0 : userKeyDown(e2);
17421
+ }, [userKeyDown]);
17422
+ const handleKeyUpCapture = React.useCallback((e2) => {
17423
+ if (isComposingRef.current || justEndedRef.current) {
17424
+ justEndedRef.current = false;
17425
+ e2.preventDefault();
17426
+ e2.stopPropagation();
17427
+ }
17428
+ }, []);
17429
+ const handleKeyUp = React.useCallback((e2) => {
17430
+ if (isComposingRef.current || justEndedRef.current) {
17431
+ justEndedRef.current = false;
17432
+ return;
17433
+ }
17434
+ userKeyUp === null || userKeyUp === void 0 ? void 0 : userKeyUp(e2);
17435
+ }, [userKeyUp]);
17436
+ return {
17437
+ onCompositionStart: handleCompositionStart,
17438
+ onCompositionEnd: handleCompositionEnd,
17439
+ onKeyDownCapture: handleKeyDownCapture,
17440
+ onKeyDown: handleKeyDown,
17441
+ onKeyUpCapture: handleKeyUpCapture,
17442
+ onKeyUp: handleKeyUp
17443
+ };
17444
+ }
17389
17445
  globalThis && globalThis.__awaiter || function(thisArg, _arguments, P, generator) {
17390
17446
  function adopt(value) {
17391
17447
  return value instanceof P ? value : new P(function(resolve) {
@@ -26380,7 +26436,14 @@ var __privateWrapper = (obj, member, setter, getter) => ({
26380
26436
  onComplete();
26381
26437
  }
26382
26438
  };
26383
- return jsxRuntime.exports.jsxs(InputWrapper$3, { className, style, children: [jsxRuntime.exports.jsx(PrimaryInput, Object.assign({}, rest, { defaultValue: initialValue, isErrored: !!errorMsg, onChange: handleChange, onKeyDown: handleKeyDown, ref, type, min: minValue, max: maxValue })), errorMsg && jsxRuntime.exports.jsx(ErrorMessage$1, { children: errorMsg })] });
26439
+ const handlers = useIMEEnter({
26440
+ onKeyDown: handleKeyDown,
26441
+ onKeyUp: rest.onKeyUp,
26442
+ onCompositionStart: rest.onCompositionStart,
26443
+ onCompositionEnd: rest.onCompositionEnd
26444
+ });
26445
+ const spreadProps = Object.assign(Object.assign({}, rest), handlers);
26446
+ return jsxRuntime.exports.jsxs(InputWrapper$3, { className, style, children: [jsxRuntime.exports.jsx(PrimaryInput, Object.assign({}, spreadProps, { defaultValue: initialValue, isErrored: !!errorMsg, onChange: handleChange, ref, type, min: minValue, max: maxValue })), errorMsg && jsxRuntime.exports.jsx(ErrorMessage$1, { children: errorMsg })] });
26384
26447
  });
26385
26448
  Input$1.displayName = "Input";
26386
26449
  const Wrapper$7 = styled__default.default.div`
@@ -51842,244 +51905,6 @@ Inferred class string: "${iconClasses}."`
51842
51905
  return /* @__PURE__ */ React__default.default.createElement(Icon, { ...props, className: `${String((_a = props.className) != null ? _a : "")} ${iconClasses}` });
51843
51906
  };
51844
51907
  }
51845
- function flexStyles(props, displayCtx2, useDisplayContext) {
51846
- let flexBasis = props.basis;
51847
- let flexShrink = props.shrink;
51848
- let flexGrow = props.grow;
51849
- if (useDisplayContext) {
51850
- if (props.width && displayCtx2.direction === "horizontal") {
51851
- flexBasis != null ? flexBasis : flexBasis = props.width;
51852
- flexShrink != null ? flexShrink : flexShrink = "0";
51853
- flexGrow != null ? flexGrow : flexGrow = "0";
51854
- }
51855
- if (props.height && displayCtx2.direction === "vertical") {
51856
- flexBasis != null ? flexBasis : flexBasis = props.height;
51857
- flexShrink != null ? flexShrink : flexShrink = "0";
51858
- flexGrow != null ? flexGrow : flexGrow = "0";
51859
- }
51860
- }
51861
- if (props.hug || props.hug !== false && displayCtx2.hug) {
51862
- flexBasis != null ? flexBasis : flexBasis = "content";
51863
- flexShrink != null ? flexShrink : flexShrink = "1";
51864
- flexGrow != null ? flexGrow : flexGrow = "0";
51865
- }
51866
- return { flexBasis, flexGrow, flexShrink };
51867
- }
51868
- function parseRawCss(rawCss) {
51869
- const isRawObject = typeof rawCss === "object" && rawCss !== null && rawCss !== void 0;
51870
- const componentCss = !isRawObject && typeof rawCss === "string" ? rawCss : "";
51871
- const styles2 = isRawObject ? rawCss : {};
51872
- return [styles2, componentCss];
51873
- }
51874
- function useComponentStyles(props, useDisplayContext = true) {
51875
- const [rawStyles, rawCss] = parseRawCss(props.raw_css);
51876
- const displayCtx$1 = React.useContext(displayCtx);
51877
- const flexProps = flexStyles(props, displayCtx$1, useDisplayContext);
51878
- const styles2 = React.useMemo(() => {
51879
- var _a;
51880
- const stylesObj = {
51881
- backgroundColor: props.background,
51882
- border: props.border,
51883
- borderRadius: props.border_radius,
51884
- color: props.color,
51885
- fontFamily: props.font,
51886
- fontSize: props.font_size,
51887
- fontStyle: props.italic ? "italic" : "normal",
51888
- fontWeight: props.bold ? "bold" : "normal",
51889
- gap: props.gap,
51890
- height: props.height,
51891
- margin: props.margin,
51892
- maxHeight: props.max_height,
51893
- maxWidth: props.max_width,
51894
- minHeight: props.min_height,
51895
- minWidth: props.min_width,
51896
- overflow: props.overflow,
51897
- padding: props.padding,
51898
- position: props.position,
51899
- textDecoration: props.underline ? "underline" : "none",
51900
- width: props.width,
51901
- ...flexProps,
51902
- ...rawStyles,
51903
- ...(_a = props.style) != null ? _a : {}
51904
- };
51905
- return Object.fromEntries(Object.entries(stylesObj).filter(([, v2]) => v2 !== null && v2 !== void 0));
51906
- }, [useDeepCompare(props)]);
51907
- return [styles2, rawCss];
51908
- }
51909
- function useUrlSync(options) {
51910
- const urlSerializer = React.useCallback((val) => {
51911
- if (val === void 0 || val === null) {
51912
- return "";
51913
- }
51914
- if (["string", "number", "boolean"].includes(typeof val)) {
51915
- return String(val);
51916
- }
51917
- return JSON.stringify(val);
51918
- }, []);
51919
- const urlDeserializer = React.useCallback((val) => {
51920
- if (val === "") {
51921
- return void 0;
51922
- }
51923
- try {
51924
- return JSON.parse(val);
51925
- } catch {
51926
- return val;
51927
- }
51928
- }, []);
51929
- const listenChangeURL = React.useCallback((handler) => {
51930
- const unregister = options.history.listen(() => {
51931
- handler();
51932
- });
51933
- return () => unregister();
51934
- }, []);
51935
- const memoryOptions = {
51936
- getURL: () => {
51937
- return window.location.origin + options.history.location.pathname + options.history.location.search;
51938
- },
51939
- pushURL: (url) => {
51940
- options.history.push(url.replace(window.location.origin, ""));
51941
- },
51942
- replaceURL: (url) => {
51943
- options.history.replace(url.replace(window.location.origin, ""));
51944
- }
51945
- };
51946
- return {
51947
- browserInterface: {
51948
- listenChangeURL,
51949
- ...options.memory_TEST ? memoryOptions : {}
51950
- },
51951
- deserialize: urlDeserializer,
51952
- location: { part: "queryParams" },
51953
- serialize: urlSerializer
51954
- };
51955
- }
51956
- const Wrapper$2 = styled__default.default.div`
51957
- display: flex;
51958
- align-items: center;
51959
- justify-content: center;
51960
-
51961
- width: 100%;
51962
- height: 100%;
51963
- `;
51964
- const FlashingDots = styled__default.default.div`
51965
- position: relative;
51966
-
51967
- width: 10px;
51968
- height: 10px;
51969
-
51970
- color: ${(props) => props.theme.colors.grey4};
51971
-
51972
- background-color: ${(props) => props.theme.colors.grey4};
51973
- border-radius: 5px;
51974
-
51975
- animation: dot-flashing 1s infinite linear alternate;
51976
- animation-delay: 0.5s;
51977
-
51978
- &::before,
51979
- &::after {
51980
- content: '';
51981
- position: absolute;
51982
- top: 0;
51983
- display: inline-block;
51984
- }
51985
-
51986
- &::before {
51987
- left: -15px;
51988
-
51989
- width: 10px;
51990
- height: 10px;
51991
-
51992
- color: ${(props) => props.theme.colors.grey4};
51993
-
51994
- background-color: ${(props) => props.theme.colors.grey4};
51995
- border-radius: 5px;
51996
-
51997
- animation: dot-flashing 1s infinite alternate;
51998
- animation-delay: 0s;
51999
- }
52000
-
52001
- &::after {
52002
- left: 15px;
52003
-
52004
- width: 10px;
52005
- height: 10px;
52006
-
52007
- color: ${(props) => props.theme.colors.grey4};
52008
-
52009
- background-color: ${(props) => props.theme.colors.grey4};
52010
- border-radius: 5px;
52011
-
52012
- animation: dot-flashing 1s infinite alternate;
52013
- animation-delay: 1s;
52014
- }
52015
-
52016
- @keyframes dot-flashing {
52017
- 0% {
52018
- background-color: ${(props) => props.theme.colors.grey4};
52019
- }
52020
-
52021
- 50%,
52022
- 100% {
52023
- background-color: ${(props) => props.theme.colors.grey3};
52024
- }
52025
- }
52026
- `;
52027
- function Dots(props) {
52028
- return /* @__PURE__ */ React__default.default.createElement(Wrapper$2, { className: props.className, style: props.style }, /* @__PURE__ */ React__default.default.createElement(FlashingDots, { "data-testid": "LOADING" }));
52029
- }
52030
- const StyledDots$1 = injectCss(Dots);
52031
- function DefaultFallback(props) {
52032
- const [style, css2] = useComponentStyles(props);
52033
- return /* @__PURE__ */ React__default.default.createElement(StyledDots$1, { $rawCss: css2, style });
52034
- }
52035
- const Center = styled__default.default.div`
52036
- overflow: hidden;
52037
- display: flex;
52038
- flex-direction: column;
52039
- align-items: center;
52040
- justify-content: center;
52041
-
52042
- width: 100%;
52043
- height: 100%;
52044
-
52045
- background: ${(props) => props.colored ? props.theme.colors.blue1 : ""};
52046
- `;
52047
- const CenteredDivWithGap = styled__default.default(Center)`
52048
- gap: 0.6rem;
52049
- margin: 10px;
52050
- text-align: center;
52051
- `;
52052
- const errorMessages = {
52053
- "403": {
52054
- description: "You are not authorised to access this application. Please contact the application owner to enable access.",
52055
- styling: "error",
52056
- title: "We were not able to authenticate you"
52057
- },
52058
- default: {
52059
- description: "Your login session may have expired. Try again.",
52060
- styling: "primary",
52061
- title: "We were not able to authenticate you"
52062
- }
52063
- };
52064
- function ErrorPage() {
52065
- const { search } = useLocation();
52066
- const query = React.useMemo(() => new URLSearchParams(search), [search]);
52067
- const code = query.get("code");
52068
- const errorConfig = code && errorMessages[code] || errorMessages.default;
52069
- return /* @__PURE__ */ React__default.default.createElement(CenteredDivWithGap, null, /* @__PURE__ */ React__default.default.createElement("h1", null, errorConfig.title), /* @__PURE__ */ React__default.default.createElement("p", null, errorConfig.description), /* @__PURE__ */ React__default.default.createElement(Button$1, { href: "/login", styling: errorConfig.styling }, "Retry"));
52070
- }
52071
- function onTokenChange(cb) {
52072
- return store.subscribe(getTokenKey(), cb);
52073
- }
52074
- function getSessionToken() {
52075
- return store.getValueSync(getTokenKey());
52076
- }
52077
- function setSessionToken(token) {
52078
- store.setValue(getTokenKey(), token);
52079
- }
52080
- function useSessionToken() {
52081
- return React__namespace.useSyncExternalStore(onTokenChange, getSessionToken);
52082
- }
52083
51908
  class EventBus {
52084
51909
  constructor(parentBus) {
52085
51910
  __privateAdd(this, _events$, new Subject());
@@ -52112,19 +51937,6 @@ Inferred class string: "${iconClasses}."`
52112
51937
  }, [bus, onEvent]);
52113
51938
  return /* @__PURE__ */ React__namespace.createElement(EventBusContext.Provider, { value: bus }, children);
52114
51939
  }
52115
- function useActionRegistry() {
52116
- const { actionRegistry: actions } = React.useContext(registriesCtx);
52117
- const get2 = React.useCallback(
52118
- (impl) => {
52119
- if (actions && actions[impl.name]) {
52120
- return actions[impl.name];
52121
- }
52122
- throw new Error(`Attempted to load an action (${impl.name}) that is not in the registry`);
52123
- },
52124
- [actions]
52125
- );
52126
- return React.useMemo(() => ({ get: get2 }), [get2]);
52127
- }
52128
51940
  const _StateSynchronizer = class {
52129
51941
  constructor() {
52130
51942
  __privateAdd(this, _observers, /* @__PURE__ */ new Map());
@@ -54182,6 +53994,18 @@ Inferred class string: "${iconClasses}."`
54182
53994
  escapePathComponent,
54183
53995
  unescapePathComponent
54184
53996
  });
53997
+ function onTokenChange(cb) {
53998
+ return store.subscribe(getTokenKey(), cb);
53999
+ }
54000
+ function getSessionToken() {
54001
+ return store.getValueSync(getTokenKey());
54002
+ }
54003
+ function setSessionToken(token) {
54004
+ store.setValue(getTokenKey(), token);
54005
+ }
54006
+ function useSessionToken() {
54007
+ return React__namespace.useSyncExternalStore(onTokenChange, getSessionToken);
54008
+ }
54185
54009
  const STORE_EXTRAS_MAP = /* @__PURE__ */ new Map();
54186
54010
  const STORE_VARIABLE_MAP = /* @__PURE__ */ new Map();
54187
54011
  const STORE_SEQUENCE_MAP = /* @__PURE__ */ new Map();
@@ -54495,6 +54319,246 @@ Inferred class string: "${iconClasses}."`
54495
54319
  const deferred = useDeferLoadable(loadable);
54496
54320
  return [deferred, setLoadable];
54497
54321
  }
54322
+ function flexStyles(props, displayCtx2, useDisplayContext) {
54323
+ let flexBasis = props.basis;
54324
+ let flexShrink = props.shrink;
54325
+ let flexGrow = props.grow;
54326
+ if (useDisplayContext) {
54327
+ if (props.width && displayCtx2.direction === "horizontal") {
54328
+ flexBasis != null ? flexBasis : flexBasis = props.width;
54329
+ flexShrink != null ? flexShrink : flexShrink = "0";
54330
+ flexGrow != null ? flexGrow : flexGrow = "0";
54331
+ }
54332
+ if (props.height && displayCtx2.direction === "vertical") {
54333
+ flexBasis != null ? flexBasis : flexBasis = props.height;
54334
+ flexShrink != null ? flexShrink : flexShrink = "0";
54335
+ flexGrow != null ? flexGrow : flexGrow = "0";
54336
+ }
54337
+ }
54338
+ if (props.hug || props.hug !== false && displayCtx2.hug) {
54339
+ flexBasis != null ? flexBasis : flexBasis = "content";
54340
+ flexShrink != null ? flexShrink : flexShrink = "1";
54341
+ flexGrow != null ? flexGrow : flexGrow = "0";
54342
+ }
54343
+ return { flexBasis, flexGrow, flexShrink };
54344
+ }
54345
+ function parseRawCss(rawCss) {
54346
+ const isRawObject = typeof rawCss === "object" && rawCss !== null && rawCss !== void 0;
54347
+ const componentCss = !isRawObject && typeof rawCss === "string" ? rawCss : "";
54348
+ const styles2 = isRawObject ? rawCss : {};
54349
+ return [styles2, componentCss];
54350
+ }
54351
+ function useComponentStyles(props, useDisplayContext = true) {
54352
+ const [rawCssValue] = useVariable(props.raw_css);
54353
+ const [rawStyles, rawCss] = parseRawCss(rawCssValue);
54354
+ const displayCtx$1 = React.useContext(displayCtx);
54355
+ const flexProps = flexStyles(props, displayCtx$1, useDisplayContext);
54356
+ const styles2 = React.useMemo(() => {
54357
+ var _a;
54358
+ const stylesObj = {
54359
+ backgroundColor: props.background,
54360
+ border: props.border,
54361
+ borderRadius: props.border_radius,
54362
+ color: props.color,
54363
+ fontFamily: props.font,
54364
+ fontSize: props.font_size,
54365
+ fontStyle: props.italic ? "italic" : "normal",
54366
+ fontWeight: props.bold ? "bold" : "normal",
54367
+ gap: props.gap,
54368
+ height: props.height,
54369
+ margin: props.margin,
54370
+ maxHeight: props.max_height,
54371
+ maxWidth: props.max_width,
54372
+ minHeight: props.min_height,
54373
+ minWidth: props.min_width,
54374
+ overflow: props.overflow,
54375
+ padding: props.padding,
54376
+ position: props.position,
54377
+ textDecoration: props.underline ? "underline" : "none",
54378
+ width: props.width,
54379
+ ...flexProps,
54380
+ ...rawStyles,
54381
+ ...(_a = props.style) != null ? _a : {}
54382
+ };
54383
+ return Object.fromEntries(Object.entries(stylesObj).filter(([, v2]) => v2 !== null && v2 !== void 0));
54384
+ }, [useDeepCompare(props)]);
54385
+ return [styles2, rawCss];
54386
+ }
54387
+ function useUrlSync(options) {
54388
+ const urlSerializer = React.useCallback((val) => {
54389
+ if (val === void 0 || val === null) {
54390
+ return "";
54391
+ }
54392
+ if (["string", "number", "boolean"].includes(typeof val)) {
54393
+ return String(val);
54394
+ }
54395
+ return JSON.stringify(val);
54396
+ }, []);
54397
+ const urlDeserializer = React.useCallback((val) => {
54398
+ if (val === "") {
54399
+ return void 0;
54400
+ }
54401
+ try {
54402
+ return JSON.parse(val);
54403
+ } catch {
54404
+ return val;
54405
+ }
54406
+ }, []);
54407
+ const listenChangeURL = React.useCallback((handler) => {
54408
+ const unregister = options.history.listen(() => {
54409
+ handler();
54410
+ });
54411
+ return () => unregister();
54412
+ }, []);
54413
+ const memoryOptions = {
54414
+ getURL: () => {
54415
+ return window.location.origin + options.history.location.pathname + options.history.location.search;
54416
+ },
54417
+ pushURL: (url) => {
54418
+ options.history.push(url.replace(window.location.origin, ""));
54419
+ },
54420
+ replaceURL: (url) => {
54421
+ options.history.replace(url.replace(window.location.origin, ""));
54422
+ }
54423
+ };
54424
+ return {
54425
+ browserInterface: {
54426
+ listenChangeURL,
54427
+ ...options.memory_TEST ? memoryOptions : {}
54428
+ },
54429
+ deserialize: urlDeserializer,
54430
+ location: { part: "queryParams" },
54431
+ serialize: urlSerializer
54432
+ };
54433
+ }
54434
+ const Wrapper$2 = styled__default.default.div`
54435
+ display: flex;
54436
+ align-items: center;
54437
+ justify-content: center;
54438
+
54439
+ width: 100%;
54440
+ height: 100%;
54441
+ `;
54442
+ const FlashingDots = styled__default.default.div`
54443
+ position: relative;
54444
+
54445
+ width: 10px;
54446
+ height: 10px;
54447
+
54448
+ color: ${(props) => props.theme.colors.grey4};
54449
+
54450
+ background-color: ${(props) => props.theme.colors.grey4};
54451
+ border-radius: 5px;
54452
+
54453
+ animation: dot-flashing 1s infinite linear alternate;
54454
+ animation-delay: 0.5s;
54455
+
54456
+ &::before,
54457
+ &::after {
54458
+ content: '';
54459
+ position: absolute;
54460
+ top: 0;
54461
+ display: inline-block;
54462
+ }
54463
+
54464
+ &::before {
54465
+ left: -15px;
54466
+
54467
+ width: 10px;
54468
+ height: 10px;
54469
+
54470
+ color: ${(props) => props.theme.colors.grey4};
54471
+
54472
+ background-color: ${(props) => props.theme.colors.grey4};
54473
+ border-radius: 5px;
54474
+
54475
+ animation: dot-flashing 1s infinite alternate;
54476
+ animation-delay: 0s;
54477
+ }
54478
+
54479
+ &::after {
54480
+ left: 15px;
54481
+
54482
+ width: 10px;
54483
+ height: 10px;
54484
+
54485
+ color: ${(props) => props.theme.colors.grey4};
54486
+
54487
+ background-color: ${(props) => props.theme.colors.grey4};
54488
+ border-radius: 5px;
54489
+
54490
+ animation: dot-flashing 1s infinite alternate;
54491
+ animation-delay: 1s;
54492
+ }
54493
+
54494
+ @keyframes dot-flashing {
54495
+ 0% {
54496
+ background-color: ${(props) => props.theme.colors.grey4};
54497
+ }
54498
+
54499
+ 50%,
54500
+ 100% {
54501
+ background-color: ${(props) => props.theme.colors.grey3};
54502
+ }
54503
+ }
54504
+ `;
54505
+ function Dots(props) {
54506
+ return /* @__PURE__ */ React__default.default.createElement(Wrapper$2, { className: props.className, style: props.style }, /* @__PURE__ */ React__default.default.createElement(FlashingDots, { "data-testid": "LOADING" }));
54507
+ }
54508
+ const StyledDots$1 = injectCss(Dots);
54509
+ function DefaultFallback(props) {
54510
+ const [style, css2] = useComponentStyles(props);
54511
+ return /* @__PURE__ */ React__default.default.createElement(StyledDots$1, { $rawCss: css2, style });
54512
+ }
54513
+ const Center = styled__default.default.div`
54514
+ overflow: hidden;
54515
+ display: flex;
54516
+ flex-direction: column;
54517
+ align-items: center;
54518
+ justify-content: center;
54519
+
54520
+ width: 100%;
54521
+ height: 100%;
54522
+
54523
+ background: ${(props) => props.colored ? props.theme.colors.blue1 : ""};
54524
+ `;
54525
+ const CenteredDivWithGap = styled__default.default(Center)`
54526
+ gap: 0.6rem;
54527
+ margin: 10px;
54528
+ text-align: center;
54529
+ `;
54530
+ const errorMessages = {
54531
+ "403": {
54532
+ description: "You are not authorised to access this application. Please contact the application owner to enable access.",
54533
+ styling: "error",
54534
+ title: "We were not able to authenticate you"
54535
+ },
54536
+ default: {
54537
+ description: "Your login session may have expired. Try again.",
54538
+ styling: "primary",
54539
+ title: "We were not able to authenticate you"
54540
+ }
54541
+ };
54542
+ function ErrorPage() {
54543
+ const { search } = useLocation();
54544
+ const query = React.useMemo(() => new URLSearchParams(search), [search]);
54545
+ const code = query.get("code");
54546
+ const errorConfig = code && errorMessages[code] || errorMessages.default;
54547
+ return /* @__PURE__ */ React__default.default.createElement(CenteredDivWithGap, null, /* @__PURE__ */ React__default.default.createElement("h1", null, errorConfig.title), /* @__PURE__ */ React__default.default.createElement("p", null, errorConfig.description), /* @__PURE__ */ React__default.default.createElement(Button$1, { href: "/login", styling: errorConfig.styling }, "Retry"));
54548
+ }
54549
+ function useActionRegistry() {
54550
+ const { actionRegistry: actions } = React.useContext(registriesCtx);
54551
+ const get2 = React.useCallback(
54552
+ (impl) => {
54553
+ if (actions && actions[impl.name]) {
54554
+ return actions[impl.name];
54555
+ }
54556
+ throw new Error(`Attempted to load an action (${impl.name}) that is not in the registry`);
54557
+ },
54558
+ [actions]
54559
+ );
54560
+ return React.useMemo(() => ({ get: get2 }), [get2]);
54561
+ }
54498
54562
  async function invokeAction(input, executionId, annotatedAction, actionCtx) {
54499
54563
  const resolvedKwargs = Object.keys(annotatedAction.dynamic_kwargs).reduce(
54500
54564
  (acc, k2) => {
@@ -55811,7 +55875,8 @@ Inferred class string: "${iconClasses}."`
55811
55875
  `;
55812
55876
  function ErrorDisplay$1(props) {
55813
55877
  var _a, _b, _c, _d, _e2;
55814
- const [styles2, css2] = parseRawCss((_a = props.config) == null ? void 0 : _a.raw_css);
55878
+ const [cssValue] = useVariable((_a = props.config) == null ? void 0 : _a.raw_css);
55879
+ const [styles2, css2] = parseRawCss(cssValue);
55815
55880
  const defaultMessage = props.error instanceof UserError ? props.error.message : "Try again or contact the application owner.";
55816
55881
  return /* @__PURE__ */ React__default.default.createElement(ErrorDisplayWrapper, { $rawCss: css2, style: styles2 }, /* @__PURE__ */ React__default.default.createElement(ContentWrapper, null, /* @__PURE__ */ React__default.default.createElement(ErrorContent, null, /* @__PURE__ */ React__default.default.createElement(ErrorTitle$1, null, /* @__PURE__ */ React__default.default.createElement(IconWrapper, null, /* @__PURE__ */ React__default.default.createElement(ErrorIcon, { "aria-hidden": true, className: "fa-solid fa-circle-xmark fa-lg" })), (_c = (_b = props == null ? void 0 : props.config) == null ? void 0 : _b.title) != null ? _c : "Error"), /* @__PURE__ */ React__default.default.createElement(ErrorText, null, (_e2 = (_d = props == null ? void 0 : props.config) == null ? void 0 : _d.description) != null ? _e2 : defaultMessage))), props.resetErrorBoundary && /* @__PURE__ */ React__default.default.createElement(RetryButton, { onClick: () => props.resetErrorBoundary(props.error), type: "button" }, /* @__PURE__ */ React__default.default.createElement("i", { "aria-hidden": true, className: "fa-solid fa-rotate fa-xl" })));
55817
55882
  }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dara-core
3
- Version: 1.16.21
3
+ Version: 1.16.23
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.23)
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.23) ; 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.23/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.23/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.23/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.23/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.23/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.23/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.23/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
@@ -12,16 +12,16 @@ dara/core/configuration.py,sha256=bWD9oL_lqCEq88I2Zr39cPt_8jZIwq5vUAyLFrsmVYQ,22
12
12
  dara/core/css.py,sha256=KWCJTPpx4tTezP9VJO3k-RSVhWwomJr-4USoLz9vNAs,1771
13
13
  dara/core/data_utils.py,sha256=5GGz4vk6srLO8HMySiAEk_xZCvmf0SeTTgVi-N4qaKY,12636
14
14
  dara/core/defaults.py,sha256=UkjWwIbo8GLyn8RZRoD3cJe174-3wHZYzvMB0hQCnMg,4150
15
- dara/core/definitions.py,sha256=QouD2P2XInW6bqrhPtrfIyDi8i99Au2PTBdWBtgBVrE,16713
15
+ dara/core/definitions.py,sha256=KmJdLWwurLBRZonPz94N9947cG1jMrs-wzqtof6ubK0,17762
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
@@ -82,7 +82,7 @@ dara/core/metrics/cache.py,sha256=bGXwjO_rSc-FkS3PnPi1mvIZf1x-hvmG113dAUk1g-Y,26
82
82
  dara/core/metrics/runtime.py,sha256=YP-6Dz0GeI9_Yr7bUk_-OqShyFySGH_AKpDO126l6es,1833
83
83
  dara/core/metrics/utils.py,sha256=aKaa_hskV3M3h4xOGZYvegDLq_OWOEUlslkQKrrPQiI,2281
84
84
  dara/core/persistence.py,sha256=-lnksbGfHwabeRjbJkceoFd0kHfCu4gK2fud8dkeDTg,18538
85
- dara/core/umd/dara.core.umd.js,sha256=ph5XlnK-CaIB7b2iq7NMD3IGaXT7zz0ukn4QLdNjN_8,4723511
85
+ dara/core/umd/dara.core.umd.js,sha256=dHJvK0B3dARTocGdCvCuOVZAx4qHwwviYwX4EaxrwT4,4725934
86
86
  dara/core/umd/style.css,sha256=YQtQ4veiSktnyONl0CU1iU1kKfcQhreH4iASi1MP7Ak,4095007
87
87
  dara/core/visual/__init__.py,sha256=QN0wbG9HPQ_vXh8BO8DnBXeYLIENVTNtRmYzZf1lx7c,577
88
88
  dara/core/visual/components/__init__.py,sha256=eg6M2YcH1o-I2H3IqLaD32ExfZcXhKuH5KTM52Ow6RM,2359
@@ -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.23.dist-info/LICENSE,sha256=r9u1w2RvpLMV6YjuXHIKXRBKzia3fx_roPwboGcLqCc,10944
110
+ dara_core-1.16.23.dist-info/METADATA,sha256=nkpL_PljY5X2YcGsCF4jMTmvKJ8iIcfD2tbrjlsD6Rk,7507
111
+ dara_core-1.16.23.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
112
+ dara_core-1.16.23.dist-info/entry_points.txt,sha256=H__D5sNIGuPIhVam0DChNL-To5k8Y7nY7TAFz9Mz6cc,139
113
+ dara_core-1.16.23.dist-info/RECORD,,