dara-core 1.16.23__py3-none-any.whl → 1.17.0__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/base_definitions.py +9 -0
- dara/core/interactivity/__init__.py +2 -0
- dara/core/interactivity/actions.py +1 -9
- dara/core/interactivity/condition.py +8 -0
- dara/core/interactivity/plain_variable.py +0 -14
- dara/core/interactivity/switch_variable.py +416 -0
- dara/core/internal/dependency_resolution.py +138 -1
- dara/core/main.py +3 -0
- dara/core/umd/dara.core.umd.js +124 -2
- {dara_core-1.16.23.dist-info → dara_core-1.17.0.dist-info}/METADATA +10 -10
- {dara_core-1.16.23.dist-info → dara_core-1.17.0.dist-info}/RECORD +14 -13
- {dara_core-1.16.23.dist-info → dara_core-1.17.0.dist-info}/LICENSE +0 -0
- {dara_core-1.16.23.dist-info → dara_core-1.17.0.dist-info}/WHEEL +0 -0
- {dara_core-1.16.23.dist-info → dara_core-1.17.0.dist-info}/entry_points.txt +0 -0
dara/core/base_definitions.py
CHANGED
|
@@ -428,6 +428,15 @@ class PendingTask(BaseTask):
|
|
|
428
428
|
"""
|
|
429
429
|
self.subscribers -= 1
|
|
430
430
|
|
|
431
|
+
async def value(self):
|
|
432
|
+
"""
|
|
433
|
+
Wait for the task to complete and return the result
|
|
434
|
+
"""
|
|
435
|
+
await self.event.wait()
|
|
436
|
+
if self.error:
|
|
437
|
+
raise self.error
|
|
438
|
+
return self.result
|
|
439
|
+
|
|
431
440
|
|
|
432
441
|
class PendingValue:
|
|
433
442
|
"""
|
|
@@ -42,6 +42,7 @@ from dara.core.interactivity.derived_data_variable import DerivedDataVariable
|
|
|
42
42
|
from dara.core.interactivity.derived_variable import DerivedVariable
|
|
43
43
|
from dara.core.interactivity.non_data_variable import NonDataVariable
|
|
44
44
|
from dara.core.interactivity.plain_variable import Variable
|
|
45
|
+
from dara.core.interactivity.switch_variable import SwitchVariable
|
|
45
46
|
from dara.core.interactivity.url_variable import UrlVariable
|
|
46
47
|
|
|
47
48
|
__all__ = [
|
|
@@ -52,6 +53,7 @@ __all__ = [
|
|
|
52
53
|
'DataVariable',
|
|
53
54
|
'NonDataVariable',
|
|
54
55
|
'Variable',
|
|
56
|
+
'SwitchVariable',
|
|
55
57
|
'DerivedVariable',
|
|
56
58
|
'DerivedDataVariable',
|
|
57
59
|
'UrlVariable',
|
|
@@ -1247,15 +1247,7 @@ class ActionCtx:
|
|
|
1247
1247
|
|
|
1248
1248
|
task = Task(func=func, args=args, kwargs=kwargs, on_progress=on_progress)
|
|
1249
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
|
|
1250
|
+
return await pending_task.value()
|
|
1259
1251
|
|
|
1260
1252
|
async def execute_action(self, action: ActionImpl):
|
|
1261
1253
|
"""
|
|
@@ -20,6 +20,8 @@ from __future__ import annotations
|
|
|
20
20
|
from enum import Enum
|
|
21
21
|
from typing import TYPE_CHECKING, ClassVar, Union
|
|
22
22
|
|
|
23
|
+
from pydantic import SerializerFunctionWrapHandler, model_serializer
|
|
24
|
+
|
|
23
25
|
from dara.core.base_definitions import DaraBaseModel as BaseModel
|
|
24
26
|
|
|
25
27
|
# Type-only imports
|
|
@@ -46,3 +48,9 @@ class Condition(BaseModel):
|
|
|
46
48
|
variable: AnyVariable
|
|
47
49
|
|
|
48
50
|
Operator: ClassVar[OperatorType] = Operator
|
|
51
|
+
|
|
52
|
+
@model_serializer(mode='wrap')
|
|
53
|
+
def ser_model(self, nxt: SerializerFunctionWrapHandler) -> dict:
|
|
54
|
+
parent_dict = nxt(self)
|
|
55
|
+
|
|
56
|
+
return {**parent_dict, '__typename': 'Condition'}
|
|
@@ -37,20 +37,6 @@ from dara.core.internal.utils import call_async
|
|
|
37
37
|
from dara.core.logging import dev_logger
|
|
38
38
|
from dara.core.persistence import PersistenceStore
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
def _is_subclass_safe(value: type, base: type) -> bool:
|
|
42
|
-
"""
|
|
43
|
-
Check if a class is a subclass of another class. Returns False if the value is not a class.
|
|
44
|
-
|
|
45
|
-
:param value: the class to check
|
|
46
|
-
:param base: the class to check against
|
|
47
|
-
"""
|
|
48
|
-
try:
|
|
49
|
-
return issubclass(value, base)
|
|
50
|
-
except TypeError:
|
|
51
|
-
return False
|
|
52
|
-
|
|
53
|
-
|
|
54
40
|
VARIABLE_INIT_OVERRIDE = ContextVar[Optional[Callable[[dict], dict]]]('VARIABLE_INIT_OVERRIDE', default=None)
|
|
55
41
|
|
|
56
42
|
VariableType = TypeVar('VariableType')
|
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Copyright 2023 Impulse Innovations Limited
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
you may not use this file except in compliance with the License.
|
|
7
|
+
You may obtain a copy of the License at
|
|
8
|
+
|
|
9
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
|
|
11
|
+
Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
See the License for the specific language governing permissions and
|
|
15
|
+
limitations under the License.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
from typing import Any, Dict, Optional, Union
|
|
21
|
+
|
|
22
|
+
from pydantic import SerializerFunctionWrapHandler, field_validator, model_serializer
|
|
23
|
+
|
|
24
|
+
from dara.core.interactivity.condition import Condition
|
|
25
|
+
from dara.core.interactivity.non_data_variable import NonDataVariable
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class SwitchVariable(NonDataVariable):
|
|
29
|
+
"""
|
|
30
|
+
A SwitchVariable represents a conditional value that switches between
|
|
31
|
+
different values based on a condition or variable value.
|
|
32
|
+
|
|
33
|
+
SwitchVariable provides a clean way to create conditional logic in your
|
|
34
|
+
application by mapping input values or conditions to output values. It
|
|
35
|
+
supports boolean conditions, value mappings, and default fallbacks.
|
|
36
|
+
|
|
37
|
+
There are three main patterns for creating SwitchVariables:
|
|
38
|
+
|
|
39
|
+
1. **Boolean Conditions**: Switch between two values based on a true/false condition
|
|
40
|
+
2. **Value Mapping**: Map specific input values to corresponding output values
|
|
41
|
+
3. **Mixed Usage**: Combine conditions and mappings with default fallbacks
|
|
42
|
+
|
|
43
|
+
Examples:
|
|
44
|
+
Basic boolean switching:
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
from dara.core import ConfigurationBuilder, Variable, SwitchVariable
|
|
48
|
+
from dara.components import Stack, Text, Button, Card
|
|
49
|
+
|
|
50
|
+
config = ConfigurationBuilder()
|
|
51
|
+
is_admin = Variable(default=False)
|
|
52
|
+
|
|
53
|
+
# Show different UI based on admin status
|
|
54
|
+
ui_mode = SwitchVariable.when(
|
|
55
|
+
condition=is_admin,
|
|
56
|
+
true_value='Admin Panel',
|
|
57
|
+
false_value='User Panel'
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
# Complete component usage
|
|
61
|
+
page_content = Card(
|
|
62
|
+
Stack(
|
|
63
|
+
Text('Current Mode:'),
|
|
64
|
+
Text(text=ui_mode),
|
|
65
|
+
Button('Toggle Admin', onclick=is_admin.toggle())
|
|
66
|
+
),
|
|
67
|
+
title='Admin Panel Demo'
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
config.add_page('Admin Demo', content=page_content)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Value mapping with defaults:
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
from dara.core import ConfigurationBuilder, Variable, SwitchVariable
|
|
77
|
+
from dara.components import Stack, Text, Select, Item, Card
|
|
78
|
+
|
|
79
|
+
config = ConfigurationBuilder()
|
|
80
|
+
user_role = Variable(default='guest')
|
|
81
|
+
|
|
82
|
+
# Map user roles to permission levels
|
|
83
|
+
permissions = SwitchVariable.match(
|
|
84
|
+
value=user_role,
|
|
85
|
+
mapping={
|
|
86
|
+
'admin': 'Full Access',
|
|
87
|
+
'editor': 'Write Access',
|
|
88
|
+
'viewer': 'Read Access'
|
|
89
|
+
},
|
|
90
|
+
default='No Access' # for unknown roles
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
# Complete component usage
|
|
94
|
+
page_content = Card(
|
|
95
|
+
Stack(
|
|
96
|
+
Text('Select Role:'),
|
|
97
|
+
Select(
|
|
98
|
+
value=user_role,
|
|
99
|
+
items=[
|
|
100
|
+
Item(label='Guest', value='guest'),
|
|
101
|
+
Item(label='Viewer', value='viewer'),
|
|
102
|
+
Item(label='Editor', value='editor'),
|
|
103
|
+
Item(label='Admin', value='admin')
|
|
104
|
+
]
|
|
105
|
+
),
|
|
106
|
+
Text('Permissions:'),
|
|
107
|
+
Text(text=permissions)
|
|
108
|
+
),
|
|
109
|
+
title='Role Permissions'
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
config.add_page('Permissions Demo', content=page_content)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Complex conditions:
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
from dara.core import Variable, SwitchVariable
|
|
119
|
+
from dara.components import Stack, Text, Input, Card
|
|
120
|
+
|
|
121
|
+
score = Variable(default=85)
|
|
122
|
+
|
|
123
|
+
# Grade based on score ranges
|
|
124
|
+
grade = SwitchVariable.when(
|
|
125
|
+
condition=score >= 90,
|
|
126
|
+
true_value='A Grade',
|
|
127
|
+
false_value='B Grade'
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
# Complete component usage
|
|
131
|
+
grade_component = Card(
|
|
132
|
+
Stack(
|
|
133
|
+
Text('Enter Score:'),
|
|
134
|
+
Input(value=score, type='number'),
|
|
135
|
+
Text('Grade (>=90 = A, <90 = B):'),
|
|
136
|
+
Text(text=grade)
|
|
137
|
+
),
|
|
138
|
+
title='Grade Calculator'
|
|
139
|
+
)
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Switching on computed conditions:
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
from dara.core import Variable, SwitchVariable
|
|
146
|
+
from dara.components import Stack, Text, Input, Card
|
|
147
|
+
|
|
148
|
+
temperature = Variable(default=20)
|
|
149
|
+
|
|
150
|
+
# Weather advice based on temperature
|
|
151
|
+
advice = SwitchVariable.when(
|
|
152
|
+
condition=temperature > 25,
|
|
153
|
+
true_value='Wear light clothes - it\'s warm!',
|
|
154
|
+
false_value='Wear warm clothes - it\'s cool!'
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
# Complete component usage
|
|
158
|
+
weather_app = Card(
|
|
159
|
+
Stack(
|
|
160
|
+
Text('Temperature (°C):'),
|
|
161
|
+
Input(value=temperature, type='number'),
|
|
162
|
+
Text('Advice:'),
|
|
163
|
+
Text(text=advice)
|
|
164
|
+
),
|
|
165
|
+
title='Weather Advisor'
|
|
166
|
+
)
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Using with other variables:
|
|
170
|
+
|
|
171
|
+
```python
|
|
172
|
+
from dara.core import Variable, SwitchVariable
|
|
173
|
+
from dara.components import Stack, Text, Select, Item, Card
|
|
174
|
+
|
|
175
|
+
user_preference = Variable(default='auto')
|
|
176
|
+
mapping_variable = Variable({
|
|
177
|
+
'auto': 'System Theme',
|
|
178
|
+
'light': 'Light Theme',
|
|
179
|
+
'dark': 'Dark Theme'
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
# Theme selection with user preference override
|
|
183
|
+
active_theme = SwitchVariable.match(
|
|
184
|
+
value=user_preference,
|
|
185
|
+
mapping=mapping_variable,
|
|
186
|
+
default='Default Theme'
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
# Complete component usage
|
|
190
|
+
theme_selector = Card(
|
|
191
|
+
Stack(
|
|
192
|
+
Text('Theme Preference:'),
|
|
193
|
+
Select(
|
|
194
|
+
value=user_preference,
|
|
195
|
+
items=[
|
|
196
|
+
Item(label='Auto', value='auto'),
|
|
197
|
+
Item(label='Light', value='light'),
|
|
198
|
+
Item(label='Dark', value='dark')
|
|
199
|
+
]
|
|
200
|
+
),
|
|
201
|
+
Text('Active Theme:'),
|
|
202
|
+
Text(text=active_theme)
|
|
203
|
+
),
|
|
204
|
+
title='Theme Selector'
|
|
205
|
+
)
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Note:
|
|
209
|
+
- Value can be a condition, raw value, or variable
|
|
210
|
+
- Value map can be a variable or a dict
|
|
211
|
+
- Default can be a variable or a raw value
|
|
212
|
+
- The switch evaluation happens reactively when underlying variables change
|
|
213
|
+
- Default values are only used in mapping scenarios when the switch value
|
|
214
|
+
doesn't match any key in the mapping
|
|
215
|
+
|
|
216
|
+
Key Serialization:
|
|
217
|
+
When using mappings with SwitchVariable, be aware that JavaScript object keys
|
|
218
|
+
are always strings. The system automatically converts lookup keys to strings:
|
|
219
|
+
- Python: {True: 'admin', False: 'user'}
|
|
220
|
+
- JavaScript: {"true": "admin", "false": "user"}
|
|
221
|
+
- Boolean values are converted to lowercase strings ("true"/"false")
|
|
222
|
+
- Other values use standard string conversion to match JavaScript's String() behavior
|
|
223
|
+
"""
|
|
224
|
+
|
|
225
|
+
value: Optional[Union[Condition, NonDataVariable, Any]] = None
|
|
226
|
+
# must be typed as any, otherwise pydantic is trying to instantiate the variables incorrectly
|
|
227
|
+
value_map: Optional[Any] = None
|
|
228
|
+
default: Optional[Any] = None
|
|
229
|
+
|
|
230
|
+
def __init__(
|
|
231
|
+
self,
|
|
232
|
+
value: Union[Condition, NonDataVariable, Any],
|
|
233
|
+
value_map: Dict[Any, Any] | NonDataVariable,
|
|
234
|
+
default: Optional[Any] = None,
|
|
235
|
+
uid: Optional[str] = None,
|
|
236
|
+
):
|
|
237
|
+
"""
|
|
238
|
+
Create a SwitchVariable with a mapping of values.
|
|
239
|
+
|
|
240
|
+
:param value: Variable, condition, or value to switch on
|
|
241
|
+
:param value_map: Dict mapping switch values to return values
|
|
242
|
+
:param default: Default value when switch value not in mapping
|
|
243
|
+
:param uid: Unique identifier for this variable
|
|
244
|
+
"""
|
|
245
|
+
super().__init__(
|
|
246
|
+
uid=uid,
|
|
247
|
+
value=value,
|
|
248
|
+
value_map=value_map,
|
|
249
|
+
default=default,
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
@field_validator('value_map')
|
|
253
|
+
@classmethod
|
|
254
|
+
def validate_value_map(cls, v):
|
|
255
|
+
"""
|
|
256
|
+
Validate that value_map is either a dict or a NonDataVariable.
|
|
257
|
+
|
|
258
|
+
:param v: The value to validate
|
|
259
|
+
:return: The validated value
|
|
260
|
+
:raises ValueError: If value_map is not a dict or NonDataVariable
|
|
261
|
+
"""
|
|
262
|
+
if v is None:
|
|
263
|
+
return v
|
|
264
|
+
if isinstance(v, dict):
|
|
265
|
+
return v
|
|
266
|
+
if isinstance(v, NonDataVariable):
|
|
267
|
+
return v
|
|
268
|
+
raise ValueError(f'value_map must be a dict or NonDataVariable, got {type(v)}')
|
|
269
|
+
|
|
270
|
+
@classmethod
|
|
271
|
+
def when(
|
|
272
|
+
cls,
|
|
273
|
+
condition: Union[Condition, NonDataVariable, Any],
|
|
274
|
+
true_value: Union[Any, NonDataVariable],
|
|
275
|
+
false_value: Union[Any, NonDataVariable],
|
|
276
|
+
uid: Optional[str] = None,
|
|
277
|
+
) -> 'SwitchVariable':
|
|
278
|
+
"""
|
|
279
|
+
Create a SwitchVariable for boolean conditions.
|
|
280
|
+
|
|
281
|
+
This is the most common pattern for simple if/else logic. The condition
|
|
282
|
+
is evaluated and returns true_value if truthy, false_value otherwise.
|
|
283
|
+
|
|
284
|
+
:param condition: Condition to evaluate (Variable, Condition object, or any value)
|
|
285
|
+
:param true_value: Value to return when condition evaluates to True
|
|
286
|
+
:param false_value: Value to return when condition evaluates to False
|
|
287
|
+
:param uid: Unique identifier for this variable
|
|
288
|
+
:return: SwitchVariable configured for boolean switching
|
|
289
|
+
|
|
290
|
+
Example with variable condition:
|
|
291
|
+
```python
|
|
292
|
+
from dara.core import Variable, SwitchVariable
|
|
293
|
+
from dara.components import Stack, Text, Button
|
|
294
|
+
|
|
295
|
+
is_loading = Variable(default=True)
|
|
296
|
+
|
|
297
|
+
# Show spinner while loading, content when done
|
|
298
|
+
display = SwitchVariable.when(
|
|
299
|
+
condition=is_loading,
|
|
300
|
+
true_value='Loading...',
|
|
301
|
+
false_value='Content loaded!'
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
# Use in a complete component
|
|
305
|
+
page_content = Stack(
|
|
306
|
+
Text(text=display),
|
|
307
|
+
Button(
|
|
308
|
+
text='Toggle Loading',
|
|
309
|
+
onclick=is_loading.toggle()
|
|
310
|
+
)
|
|
311
|
+
)
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
Example with a condition object:
|
|
315
|
+
|
|
316
|
+
```python
|
|
317
|
+
from dara.core import Variable, SwitchVariable
|
|
318
|
+
from dara.components import Stack, Text, Input, Card
|
|
319
|
+
|
|
320
|
+
# Temperature-based clothing advice
|
|
321
|
+
temperature = Variable(default=20)
|
|
322
|
+
advice = SwitchVariable.when(
|
|
323
|
+
condition=temperature > 25,
|
|
324
|
+
true_value='Wear light clothes - it\'s warm!',
|
|
325
|
+
false_value='Wear warm clothes - it\'s cool!'
|
|
326
|
+
)
|
|
327
|
+
|
|
328
|
+
# Complete weather advice component
|
|
329
|
+
weather_component = Card(
|
|
330
|
+
Stack(
|
|
331
|
+
Text('Enter temperature (°C):'),
|
|
332
|
+
Input(value=temperature, type='number'),
|
|
333
|
+
Text('Advice:'),
|
|
334
|
+
Text(text=advice)
|
|
335
|
+
),
|
|
336
|
+
title='Weather Advice'
|
|
337
|
+
)
|
|
338
|
+
```
|
|
339
|
+
"""
|
|
340
|
+
return cls(
|
|
341
|
+
value=condition,
|
|
342
|
+
value_map={True: true_value, False: false_value},
|
|
343
|
+
uid=uid,
|
|
344
|
+
)
|
|
345
|
+
|
|
346
|
+
@classmethod
|
|
347
|
+
def match(
|
|
348
|
+
cls,
|
|
349
|
+
value: Union[NonDataVariable, Any],
|
|
350
|
+
mapping: Union[Dict[Any, Any], NonDataVariable],
|
|
351
|
+
default: Optional[Union[Any, NonDataVariable]] = None,
|
|
352
|
+
uid: Optional[str] = None,
|
|
353
|
+
) -> 'SwitchVariable':
|
|
354
|
+
"""
|
|
355
|
+
Create a SwitchVariable with a custom mapping.
|
|
356
|
+
|
|
357
|
+
This pattern is useful when you have multiple specific values to map to
|
|
358
|
+
different outputs, similar to a switch statement in other languages.
|
|
359
|
+
|
|
360
|
+
:param value: Variable or value to switch on
|
|
361
|
+
:param mapping: Dict mapping switch values to return values
|
|
362
|
+
:param default: Default value when switch value not found in mapping
|
|
363
|
+
:param uid: Unique identifier for this variable
|
|
364
|
+
:return: SwitchVariable configured with the provided mapping
|
|
365
|
+
|
|
366
|
+
Example:
|
|
367
|
+
```python
|
|
368
|
+
from dara.core import Variable, SwitchVariable
|
|
369
|
+
from dara.components import Stack, Text, Select, Item
|
|
370
|
+
|
|
371
|
+
status = Variable(default='pending')
|
|
372
|
+
|
|
373
|
+
# Map status codes to user-friendly messages
|
|
374
|
+
message = SwitchVariable.match(
|
|
375
|
+
value=status,
|
|
376
|
+
mapping={
|
|
377
|
+
'pending': 'Please wait...',
|
|
378
|
+
'success': 'Operation completed!',
|
|
379
|
+
'error': 'Something went wrong',
|
|
380
|
+
'cancelled': 'Operation was cancelled'
|
|
381
|
+
},
|
|
382
|
+
default='Unknown status'
|
|
383
|
+
)
|
|
384
|
+
|
|
385
|
+
# Use in a complete component
|
|
386
|
+
page_content = Stack(
|
|
387
|
+
Select(
|
|
388
|
+
value=status,
|
|
389
|
+
items=[
|
|
390
|
+
Item(label='Pending', value='pending'),
|
|
391
|
+
Item(label='Success', value='success'),
|
|
392
|
+
Item(label='Error', value='error'),
|
|
393
|
+
Item(label='Cancelled', value='cancelled')
|
|
394
|
+
]
|
|
395
|
+
),
|
|
396
|
+
Text(text=message)
|
|
397
|
+
)
|
|
398
|
+
```
|
|
399
|
+
"""
|
|
400
|
+
return cls(
|
|
401
|
+
value=value,
|
|
402
|
+
value_map=mapping,
|
|
403
|
+
default=default,
|
|
404
|
+
uid=uid,
|
|
405
|
+
)
|
|
406
|
+
|
|
407
|
+
@model_serializer(mode='wrap')
|
|
408
|
+
def ser_model(self, nxt: SerializerFunctionWrapHandler) -> dict:
|
|
409
|
+
"""
|
|
410
|
+
Serialize the SwitchVariable model with additional metadata.
|
|
411
|
+
|
|
412
|
+
:param nxt: The next serializer function in the chain
|
|
413
|
+
:return: Serialized dictionary with __typename and uid fields
|
|
414
|
+
"""
|
|
415
|
+
parent_dict = nxt(self)
|
|
416
|
+
return {**parent_dict, '__typename': 'SwitchVariable', 'uid': str(parent_dict['uid'])}
|
|
@@ -19,12 +19,14 @@ from typing import Any, List, Literal, Optional, Union
|
|
|
19
19
|
|
|
20
20
|
from typing_extensions import TypedDict, TypeGuard
|
|
21
21
|
|
|
22
|
+
from dara.core.base_definitions import BaseTask, PendingTask
|
|
22
23
|
from dara.core.interactivity import DataVariable, DerivedDataVariable, DerivedVariable
|
|
23
24
|
from dara.core.interactivity.filtering import FilterQuery
|
|
24
25
|
from dara.core.internal.cache_store import CacheStore
|
|
25
26
|
from dara.core.internal.pandas_utils import remove_index
|
|
26
27
|
from dara.core.internal.registry_lookup import RegistryLookup
|
|
27
28
|
from dara.core.internal.tasks import TaskManager
|
|
29
|
+
from dara.core.logging import dev_logger
|
|
28
30
|
|
|
29
31
|
|
|
30
32
|
class ResolvedDerivedVariable(TypedDict):
|
|
@@ -50,6 +52,14 @@ class ResolvedDataVariable(TypedDict):
|
|
|
50
52
|
uid: str
|
|
51
53
|
|
|
52
54
|
|
|
55
|
+
class ResolvedSwitchVariable(TypedDict):
|
|
56
|
+
type: Literal['switch']
|
|
57
|
+
uid: str
|
|
58
|
+
value: Any
|
|
59
|
+
value_map: Any
|
|
60
|
+
default: Any
|
|
61
|
+
|
|
62
|
+
|
|
53
63
|
def is_resolved_derived_variable(obj: Any) -> TypeGuard[ResolvedDerivedVariable]:
|
|
54
64
|
return isinstance(obj, dict) and 'uid' in obj and obj.get('type') == 'derived'
|
|
55
65
|
|
|
@@ -62,8 +72,14 @@ def is_resolved_data_variable(obj: Any) -> TypeGuard[ResolvedDataVariable]:
|
|
|
62
72
|
return isinstance(obj, dict) and 'uid' in obj and obj.get('type') == 'data'
|
|
63
73
|
|
|
64
74
|
|
|
75
|
+
def is_resolved_switch_variable(obj: Any) -> TypeGuard[ResolvedSwitchVariable]:
|
|
76
|
+
return isinstance(obj, dict) and 'uid' in obj and obj.get('type') == 'switch'
|
|
77
|
+
|
|
78
|
+
|
|
65
79
|
async def resolve_dependency(
|
|
66
|
-
entry: Union[
|
|
80
|
+
entry: Union[
|
|
81
|
+
ResolvedDerivedDataVariable, ResolvedDataVariable, ResolvedDerivedVariable, ResolvedSwitchVariable, Any
|
|
82
|
+
],
|
|
67
83
|
store: CacheStore,
|
|
68
84
|
task_mgr: TaskManager,
|
|
69
85
|
):
|
|
@@ -84,6 +100,9 @@ async def resolve_dependency(
|
|
|
84
100
|
if is_resolved_data_variable(entry):
|
|
85
101
|
return await _resolve_data_var(entry, store)
|
|
86
102
|
|
|
103
|
+
if is_resolved_switch_variable(entry):
|
|
104
|
+
return await _resolve_switch_var(entry, store, task_mgr)
|
|
105
|
+
|
|
87
106
|
return entry
|
|
88
107
|
|
|
89
108
|
|
|
@@ -149,3 +168,121 @@ async def _resolve_data_var(data_variable_entry: ResolvedDataVariable, store: Ca
|
|
|
149
168
|
var = await registry_mgr.get(data_variable_registry, str(data_variable_entry.get('uid')))
|
|
150
169
|
result = await DataVariable.get_value(var, store, data_variable_entry.get('filters', None))
|
|
151
170
|
return remove_index(result)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def _normalize_lookup_key(value: Any) -> str:
|
|
174
|
+
"""
|
|
175
|
+
Normalize a value to a string key that matches JavaScript object key serialization.
|
|
176
|
+
This ensures consistent lookup between Python backend and JavaScript frontend.
|
|
177
|
+
|
|
178
|
+
JavaScript's String() conversion rules:
|
|
179
|
+
- String(true) -> "true", String(false) -> "false"
|
|
180
|
+
- String(null) -> "null", String(undefined) -> "undefined"
|
|
181
|
+
- Numbers and other types are converted to their string representation
|
|
182
|
+
|
|
183
|
+
:param value: The value to normalize as a lookup key
|
|
184
|
+
:return: String representation suitable for object key lookup
|
|
185
|
+
"""
|
|
186
|
+
if isinstance(value, bool):
|
|
187
|
+
# JavaScript String(true) -> "true", String(false) -> "false"
|
|
188
|
+
return str(value).lower()
|
|
189
|
+
elif value is None:
|
|
190
|
+
# JavaScript String(null) -> "null"
|
|
191
|
+
return 'null'
|
|
192
|
+
else:
|
|
193
|
+
# For numbers, strings, and other types, use standard string conversion
|
|
194
|
+
return str(value)
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def _evaluate_condition(condition: dict) -> bool:
|
|
198
|
+
"""
|
|
199
|
+
Evaluate a condition object and return the boolean result.
|
|
200
|
+
|
|
201
|
+
:param condition: condition dict with 'variable', 'operator', and 'other' keys
|
|
202
|
+
:return: boolean result of the condition evaluation
|
|
203
|
+
"""
|
|
204
|
+
variable_value = condition['variable']
|
|
205
|
+
operator = condition['operator']
|
|
206
|
+
other_value = condition['other']
|
|
207
|
+
|
|
208
|
+
if operator == 'equal':
|
|
209
|
+
return variable_value == other_value
|
|
210
|
+
elif operator == 'truthy':
|
|
211
|
+
return bool(variable_value)
|
|
212
|
+
elif operator == 'not_equal':
|
|
213
|
+
return variable_value != other_value
|
|
214
|
+
else:
|
|
215
|
+
# strictly numeric comparisons, ensure they're numbers just in case
|
|
216
|
+
val_a = float(variable_value)
|
|
217
|
+
val_b = float(other_value)
|
|
218
|
+
|
|
219
|
+
if operator == 'greater_than':
|
|
220
|
+
return val_a > val_b
|
|
221
|
+
elif operator == 'greater_equal':
|
|
222
|
+
return val_a >= val_b
|
|
223
|
+
elif operator == 'less_than':
|
|
224
|
+
return val_a < val_b
|
|
225
|
+
elif operator == 'less_equal':
|
|
226
|
+
return val_a <= val_b
|
|
227
|
+
else:
|
|
228
|
+
raise ValueError(f'Unknown condition operator: {operator}')
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
async def _resolve_switch_var(switch_variable_entry: ResolvedSwitchVariable, store: CacheStore, task_mgr: TaskManager):
|
|
232
|
+
"""
|
|
233
|
+
Resolve a switch variable by evaluating its constituent parts and returning the appropriate value.
|
|
234
|
+
|
|
235
|
+
:param switch_variable_entry: switch variable entry
|
|
236
|
+
:param store: store instance to use for caching
|
|
237
|
+
:param task_mgr: task manager instance
|
|
238
|
+
"""
|
|
239
|
+
|
|
240
|
+
async def _resolve_maybe_task(value: Any) -> Any:
|
|
241
|
+
if isinstance(value, BaseTask):
|
|
242
|
+
task_result = await task_mgr.run_task(value)
|
|
243
|
+
if isinstance(task_result, PendingTask):
|
|
244
|
+
return await task_result.value()
|
|
245
|
+
return task_result
|
|
246
|
+
return value
|
|
247
|
+
|
|
248
|
+
# resolve the constituent parts
|
|
249
|
+
resolved_value = await resolve_dependency(switch_variable_entry.get('value'), store, task_mgr)
|
|
250
|
+
resolved_value = await _resolve_maybe_task(resolved_value)
|
|
251
|
+
|
|
252
|
+
resolved_value_map = await resolve_dependency(switch_variable_entry.get('value_map'), store, task_mgr)
|
|
253
|
+
resolved_value_map = await _resolve_maybe_task(resolved_value_map)
|
|
254
|
+
|
|
255
|
+
resolved_default = await resolve_dependency(switch_variable_entry.get('default'), store, task_mgr)
|
|
256
|
+
resolved_default = await _resolve_maybe_task(resolved_default)
|
|
257
|
+
|
|
258
|
+
# The frontend should have already evaluated conditions and sent the resolved value
|
|
259
|
+
# For switch variables, we just need to look up the value in the mapping
|
|
260
|
+
if isinstance(resolved_value_map, dict):
|
|
261
|
+
# value could be a condition object
|
|
262
|
+
if isinstance(resolved_value, dict) and resolved_value.get('__typename') == 'Condition':
|
|
263
|
+
# Evaluate the condition and use the boolean result as the lookup key
|
|
264
|
+
try:
|
|
265
|
+
# First, resolve any nested dependencies in the condition's 'other' field
|
|
266
|
+
condition_copy = resolved_value.copy()
|
|
267
|
+
condition_copy['other'] = await resolve_dependency(condition_copy.get('other'), store, task_mgr)
|
|
268
|
+
condition_copy['other'] = await _resolve_maybe_task(condition_copy['other'])
|
|
269
|
+
|
|
270
|
+
# Also resolve the variable field in case it's a dependency
|
|
271
|
+
condition_copy['variable'] = await resolve_dependency(condition_copy.get('variable'), store, task_mgr)
|
|
272
|
+
condition_copy['variable'] = await _resolve_maybe_task(condition_copy['variable'])
|
|
273
|
+
|
|
274
|
+
# Evaluate the condition
|
|
275
|
+
resolved_value = _evaluate_condition(condition_copy)
|
|
276
|
+
except Exception as e:
|
|
277
|
+
# If condition evaluation fails, log and use default
|
|
278
|
+
dev_logger.error('Error evaluating condition', error=e)
|
|
279
|
+
return resolved_default
|
|
280
|
+
|
|
281
|
+
# Normalize the lookup key to match JavaScript object key serialization
|
|
282
|
+
resolved_value = _normalize_lookup_key(resolved_value)
|
|
283
|
+
|
|
284
|
+
# Try to get the value from the mapping, fall back to default
|
|
285
|
+
return resolved_value_map.get(resolved_value, resolved_default)
|
|
286
|
+
|
|
287
|
+
# If value_map is not a dict (shouldn't happen in normal cases), return default
|
|
288
|
+
return resolved_default
|
dara/core/main.py
CHANGED
|
@@ -314,6 +314,9 @@ def _start_application(config: Configuration):
|
|
|
314
314
|
template_registry.register(name, renderer(config))
|
|
315
315
|
|
|
316
316
|
except Exception as e:
|
|
317
|
+
import traceback
|
|
318
|
+
|
|
319
|
+
traceback.print_exc()
|
|
317
320
|
dev_logger.error(
|
|
318
321
|
'Something went wrong when building application template, there is most likely an issue in the application logic',
|
|
319
322
|
e,
|
dara/core/umd/dara.core.umd.js
CHANGED
|
@@ -50158,6 +50158,9 @@ You must set sticky: 'left' | 'right' for the '${bugWithUnderColumnsSticky.Heade
|
|
|
50158
50158
|
function isLoopVariable(variable) {
|
|
50159
50159
|
return variable && typeof variable == "object" && variable.hasOwnProperty("uid") && variable.hasOwnProperty("__typename") && variable.__typename === "LoopVariable";
|
|
50160
50160
|
}
|
|
50161
|
+
function isSwitchVariable(variable) {
|
|
50162
|
+
return isVariable(variable) && variable.__typename === "SwitchVariable";
|
|
50163
|
+
}
|
|
50161
50164
|
function isResolvedDerivedVariable(value) {
|
|
50162
50165
|
return value && typeof value === "object" && "values" in value && "type" in value && value.type === "derived" && "uid" in value;
|
|
50163
50166
|
}
|
|
@@ -50167,6 +50170,9 @@ You must set sticky: 'left' | 'right' for the '${bugWithUnderColumnsSticky.Heade
|
|
|
50167
50170
|
function isResolvedDerivedDataVariable(value) {
|
|
50168
50171
|
return value && typeof value === "object" && "filters" in value && "values" in value && "type" in value && value.type === "derived-data" && "uid" in value;
|
|
50169
50172
|
}
|
|
50173
|
+
function isResolvedSwitchVariable(value) {
|
|
50174
|
+
return value && typeof value === "object" && "type" in value && value.type === "switch" && "uid" in value && "value_map" in value;
|
|
50175
|
+
}
|
|
50170
50176
|
function isActionImpl(action) {
|
|
50171
50177
|
return action && typeof action === "object" && action.__typename === "ActionImpl";
|
|
50172
50178
|
}
|
|
@@ -50174,6 +50180,9 @@ You must set sticky: 'left' | 'right' for the '${bugWithUnderColumnsSticky.Heade
|
|
|
50174
50180
|
return action && "uid" in action && "definition_uid" in action && "dynamic_kwargs" in action;
|
|
50175
50181
|
}
|
|
50176
50182
|
const isPyComponent = (value) => isObject_1(value) && "props" in value && isObject_1(value.props) && "func_name" in value.props && "dynamic_kwargs" in value.props;
|
|
50183
|
+
function isCondition(value) {
|
|
50184
|
+
return value && typeof value === "object" && value.__typename === "Condition";
|
|
50185
|
+
}
|
|
50177
50186
|
function commonjsRequire(path) {
|
|
50178
50187
|
throw new Error('Could not dynamically require "' + path + '". Please configure the dynamicRequireTargets or/and ignoreDynamicRequires option of @rollup/plugin-commonjs appropriately for this require call to work.');
|
|
50179
50188
|
}
|
|
@@ -51103,11 +51112,16 @@ You must set sticky: 'left' | 'right' for the '${bugWithUnderColumnsSticky.Heade
|
|
|
51103
51112
|
...lookup,
|
|
51104
51113
|
...nestedLookup
|
|
51105
51114
|
};
|
|
51106
|
-
} else {
|
|
51115
|
+
} else if (isResolvedSwitchVariable(val)) {
|
|
51107
51116
|
const varDef = def.variables[key];
|
|
51108
51117
|
const identifier = getIdentifier(varDef);
|
|
51109
51118
|
lookup[identifier] = val;
|
|
51110
51119
|
normalizedValues.push({ __ref: identifier });
|
|
51120
|
+
} else {
|
|
51121
|
+
const varDef = def.variables[key];
|
|
51122
|
+
const identifier = getIdentifier(varDef);
|
|
51123
|
+
lookup[identifier] = val === void 0 ? null : val;
|
|
51124
|
+
normalizedValues.push({ __ref: identifier });
|
|
51111
51125
|
}
|
|
51112
51126
|
}
|
|
51113
51127
|
return {
|
|
@@ -52935,6 +52949,14 @@ Inferred class string: "${iconClasses}."`
|
|
|
52935
52949
|
values: formatDerivedVariableRequest(nestedValues)
|
|
52936
52950
|
};
|
|
52937
52951
|
}
|
|
52952
|
+
if (isResolvedSwitchVariable(val)) {
|
|
52953
|
+
return {
|
|
52954
|
+
...val,
|
|
52955
|
+
value: formatDerivedVariableRequest([val.value])[0],
|
|
52956
|
+
value_map: formatDerivedVariableRequest([val.value_map])[0],
|
|
52957
|
+
default: formatDerivedVariableRequest([val.default])[0]
|
|
52958
|
+
};
|
|
52959
|
+
}
|
|
52938
52960
|
return val;
|
|
52939
52961
|
});
|
|
52940
52962
|
}
|
|
@@ -53007,9 +53029,23 @@ Inferred class string: "${iconClasses}."`
|
|
|
53007
53029
|
values: resolvedValues
|
|
53008
53030
|
};
|
|
53009
53031
|
}
|
|
53032
|
+
if (isResolvedSwitchVariable(value)) {
|
|
53033
|
+
return {
|
|
53034
|
+
...value,
|
|
53035
|
+
value: resolveValue(value.value, getter),
|
|
53036
|
+
value_map: resolveValue(value.value_map, getter),
|
|
53037
|
+
default: resolveValue(value.default, getter)
|
|
53038
|
+
};
|
|
53039
|
+
}
|
|
53010
53040
|
if (isResolvedDataVariable(value)) {
|
|
53011
53041
|
return value;
|
|
53012
53042
|
}
|
|
53043
|
+
if (isCondition(value)) {
|
|
53044
|
+
return {
|
|
53045
|
+
...value,
|
|
53046
|
+
variable: resolveValue(value.variable, getter)
|
|
53047
|
+
};
|
|
53048
|
+
}
|
|
53013
53049
|
if (Recoil_index_2(value)) {
|
|
53014
53050
|
return getter(value);
|
|
53015
53051
|
}
|
|
@@ -53020,7 +53056,13 @@ Inferred class string: "${iconClasses}."`
|
|
|
53020
53056
|
if (deps && !deps.includes(idx)) {
|
|
53021
53057
|
return [];
|
|
53022
53058
|
}
|
|
53023
|
-
|
|
53059
|
+
if (isResolvedDerivedVariable(val) || isResolvedDerivedDataVariable(val)) {
|
|
53060
|
+
return getDeps(val.values, val.deps).flat();
|
|
53061
|
+
}
|
|
53062
|
+
if (isResolvedSwitchVariable(val)) {
|
|
53063
|
+
return getDeps([val.value, val.value_map, val.default], [0, 1, 2]).flat();
|
|
53064
|
+
}
|
|
53065
|
+
return val;
|
|
53024
53066
|
});
|
|
53025
53067
|
}
|
|
53026
53068
|
function useTriggerIndex(variable) {
|
|
@@ -53365,6 +53407,24 @@ Inferred class string: "${iconClasses}."`
|
|
|
53365
53407
|
if (isUrlVariable(variable)) {
|
|
53366
53408
|
return resolver(getOrRegisterUrlVariable(variable));
|
|
53367
53409
|
}
|
|
53410
|
+
if (isSwitchVariable(variable)) {
|
|
53411
|
+
let resolvedValue = isVariable(variable.value) ? resolveVariable(variable.value, client, taskContext, extras, resolver) : variable.value;
|
|
53412
|
+
if (isCondition(resolvedValue)) {
|
|
53413
|
+
resolvedValue = {
|
|
53414
|
+
...resolvedValue,
|
|
53415
|
+
variable: resolveVariable(resolvedValue.variable, client, taskContext, extras, resolver)
|
|
53416
|
+
};
|
|
53417
|
+
}
|
|
53418
|
+
const resolvedValueMap = isVariable(variable.value_map) ? resolveVariable(variable.value_map, client, taskContext, extras, resolver) : variable.value_map;
|
|
53419
|
+
const resolvedDefault = isVariable(variable.default) ? resolveVariable(variable.default, client, taskContext, extras, resolver) : variable.default;
|
|
53420
|
+
return {
|
|
53421
|
+
type: "switch",
|
|
53422
|
+
uid: variable.uid,
|
|
53423
|
+
value: resolvedValue,
|
|
53424
|
+
value_map: resolvedValueMap,
|
|
53425
|
+
default: resolvedDefault
|
|
53426
|
+
};
|
|
53427
|
+
}
|
|
53368
53428
|
return resolver(getOrRegisterPlainVariable(variable, client, taskContext, extras));
|
|
53369
53429
|
}
|
|
53370
53430
|
/*!
|
|
@@ -54257,6 +54317,46 @@ Inferred class string: "${iconClasses}."`
|
|
|
54257
54317
|
function StoreProviders({ children }) {
|
|
54258
54318
|
return /* @__PURE__ */ React__namespace.createElement(BackendStoreSync, null, /* @__PURE__ */ React__namespace.createElement(BrowserStoreSync, null, children));
|
|
54259
54319
|
}
|
|
54320
|
+
function isConditionTrue(operator, value, other) {
|
|
54321
|
+
if (operator === ConditionOperator.EQUAL) {
|
|
54322
|
+
return value === other;
|
|
54323
|
+
}
|
|
54324
|
+
if (operator === ConditionOperator.NOT_EQUAL) {
|
|
54325
|
+
return value !== other;
|
|
54326
|
+
}
|
|
54327
|
+
if (operator === ConditionOperator.GREATER_EQUAL) {
|
|
54328
|
+
return value >= other;
|
|
54329
|
+
}
|
|
54330
|
+
if (operator === ConditionOperator.GREATER_THAN) {
|
|
54331
|
+
return value > other;
|
|
54332
|
+
}
|
|
54333
|
+
if (operator === ConditionOperator.LESS_EQUAL) {
|
|
54334
|
+
return value <= other;
|
|
54335
|
+
}
|
|
54336
|
+
if (operator === ConditionOperator.LESS_THAN) {
|
|
54337
|
+
return value < other;
|
|
54338
|
+
}
|
|
54339
|
+
if (operator === ConditionOperator.TRUTHY) {
|
|
54340
|
+
return !!value;
|
|
54341
|
+
}
|
|
54342
|
+
throw new Error(`Unexpected operator ${String(operator)} passed to conditional (If) component`);
|
|
54343
|
+
}
|
|
54344
|
+
function useConditionOrVariable(arg) {
|
|
54345
|
+
if (isCondition(arg)) {
|
|
54346
|
+
const value = useVariable(arg.variable)[0];
|
|
54347
|
+
const other = useVariable(arg.other)[0];
|
|
54348
|
+
return isConditionTrue(arg.operator, value, other);
|
|
54349
|
+
}
|
|
54350
|
+
return useVariable(arg)[0];
|
|
54351
|
+
}
|
|
54352
|
+
function useSwitchVariable(variable) {
|
|
54353
|
+
var _a;
|
|
54354
|
+
const value = useConditionOrVariable(variable.value);
|
|
54355
|
+
const [valueMap] = useVariable(variable.value_map);
|
|
54356
|
+
const [defaultValue] = useVariable(variable.default);
|
|
54357
|
+
const lookupKey = String(value);
|
|
54358
|
+
return (_a = valueMap[lookupKey]) != null ? _a : defaultValue;
|
|
54359
|
+
}
|
|
54260
54360
|
function warnUpdateOnDerivedState() {
|
|
54261
54361
|
console.warn("You tried to call update on variable with derived state, this is a noop and will be ignored.");
|
|
54262
54362
|
}
|
|
@@ -54302,6 +54402,9 @@ Inferred class string: "${iconClasses}."`
|
|
|
54302
54402
|
}, [urlValue]);
|
|
54303
54403
|
return [urlValue, setUrlValue];
|
|
54304
54404
|
}
|
|
54405
|
+
if (isSwitchVariable(variable)) {
|
|
54406
|
+
return [useSwitchVariable(variable), warnUpdateOnDerivedState];
|
|
54407
|
+
}
|
|
54305
54408
|
const recoilState = getOrRegisterPlainVariable(variable, wsClient, taskContext, extras);
|
|
54306
54409
|
if (!isDerivedVariable(variable.default)) {
|
|
54307
54410
|
const [value, setValue] = Recoil_index_22(recoilState);
|
|
@@ -54907,6 +55010,9 @@ Inferred class string: "${iconClasses}."`
|
|
|
54907
55010
|
ctx.extras,
|
|
54908
55011
|
(v2) => ctx.snapshot.getLoadable(v2).getValue()
|
|
54909
55012
|
);
|
|
55013
|
+
if (isResolvedSwitchVariable(resolved)) {
|
|
55014
|
+
throw new UserError("Switch variables are not supported in this context");
|
|
55015
|
+
}
|
|
54910
55016
|
if (!shouldFetchVariable || !isDerivedVariable(variable) && !isDataVariable(variable) && !isDerivedDataVariable(variable)) {
|
|
54911
55017
|
return resolved;
|
|
54912
55018
|
}
|
|
@@ -55257,6 +55363,14 @@ Inferred class string: "${iconClasses}."`
|
|
|
55257
55363
|
values: cleanedValues
|
|
55258
55364
|
};
|
|
55259
55365
|
}
|
|
55366
|
+
if (isResolvedSwitchVariable(value)) {
|
|
55367
|
+
return {
|
|
55368
|
+
...value,
|
|
55369
|
+
value: cleanValue(value.value, force),
|
|
55370
|
+
value_map: cleanValue(value.value_map, force),
|
|
55371
|
+
default: cleanValue(value.default, force)
|
|
55372
|
+
};
|
|
55373
|
+
}
|
|
55260
55374
|
return value;
|
|
55261
55375
|
}
|
|
55262
55376
|
function cleanKwargs(kwargs, force) {
|
|
@@ -56790,6 +56904,8 @@ Inferred class string: "${iconClasses}."`
|
|
|
56790
56904
|
ctx.eventBus.publish("URL_VARIABLE_LOADED", { variable, value: variable.default });
|
|
56791
56905
|
} else if (isDataVariable(variable))
|
|
56792
56906
|
;
|
|
56907
|
+
else if (isSwitchVariable(variable))
|
|
56908
|
+
;
|
|
56793
56909
|
else {
|
|
56794
56910
|
const plainAtom = getOrRegisterPlainVariable(variable, ctx.wsClient, ctx.taskCtx, ctx.extras);
|
|
56795
56911
|
ctx.reset(plainAtom);
|
|
@@ -82580,6 +82696,8 @@ Inferred class string: "${iconClasses}."`
|
|
|
82580
82696
|
exports.injectCss = injectCss;
|
|
82581
82697
|
exports.isActionImpl = isActionImpl;
|
|
82582
82698
|
exports.isAnnotatedAction = isAnnotatedAction;
|
|
82699
|
+
exports.isCondition = isCondition;
|
|
82700
|
+
exports.isConditionTrue = isConditionTrue;
|
|
82583
82701
|
exports.isDataVariable = isDataVariable;
|
|
82584
82702
|
exports.isDerivedDataVariable = isDerivedDataVariable;
|
|
82585
82703
|
exports.isDerivedVariable = isDerivedVariable;
|
|
@@ -82592,6 +82710,8 @@ Inferred class string: "${iconClasses}."`
|
|
|
82592
82710
|
exports.isResolvedDataVariable = isResolvedDataVariable;
|
|
82593
82711
|
exports.isResolvedDerivedDataVariable = isResolvedDerivedDataVariable;
|
|
82594
82712
|
exports.isResolvedDerivedVariable = isResolvedDerivedVariable;
|
|
82713
|
+
exports.isResolvedSwitchVariable = isResolvedSwitchVariable;
|
|
82714
|
+
exports.isSwitchVariable = isSwitchVariable;
|
|
82595
82715
|
exports.isTaskResponse = isTaskResponse$1;
|
|
82596
82716
|
exports.isUrlVariable = isUrlVariable;
|
|
82597
82717
|
exports.isVariable = isVariable;
|
|
@@ -82620,6 +82740,7 @@ Inferred class string: "${iconClasses}."`
|
|
|
82620
82740
|
exports.useComponentRegistry = useComponentRegistry;
|
|
82621
82741
|
exports.useComponentStyles = useComponentStyles;
|
|
82622
82742
|
exports.useComponents = useComponents;
|
|
82743
|
+
exports.useConditionOrVariable = useConditionOrVariable;
|
|
82623
82744
|
exports.useConfig = useConfig;
|
|
82624
82745
|
exports.useDataVariable = useDataVariable;
|
|
82625
82746
|
exports.useDeferLoadable = useDeferLoadable;
|
|
@@ -82632,6 +82753,7 @@ Inferred class string: "${iconClasses}."`
|
|
|
82632
82753
|
exports.useRequestExtras = useRequestExtras;
|
|
82633
82754
|
exports.useSession = useSession;
|
|
82634
82755
|
exports.useSessionToken = useSessionToken;
|
|
82756
|
+
exports.useSwitchVariable = useSwitchVariable;
|
|
82635
82757
|
exports.useTaskContext = useTaskContext;
|
|
82636
82758
|
exports.useTemplate = useTemplate;
|
|
82637
82759
|
exports.useTriggerIndex = useTriggerIndex;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: dara-core
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.17.0
|
|
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.
|
|
23
|
+
Requires-Dist: create-dara-app (==1.17.0)
|
|
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.
|
|
26
|
+
Requires-Dist: dara-components (==1.17.0) ; 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.
|
|
57
|
+
<img src="https://github.com/causalens/dara/blob/v1.17.0/img/dara_light.svg?raw=true">
|
|
58
58
|
|
|
59
59
|

|
|
60
60
|
[](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
|
-

|
|
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
|
-
|  | Demonstrates how to use incorporate a LLM chat box into your decision app to understand model insights |
|
|
120
|
+
|  | 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
|
+
|  | 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.
|
|
148
|
+
More information on the repository structure can be found in the [CONTRIBUTING.md](https://github.com/causalens/dara/blob/v1.17.0/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.
|
|
152
|
+
Dara is open-source and licensed under the [Apache 2.0 License](https://github.com/causalens/dara/blob/v1.17.0/LICENSE).
|
|
153
153
|
|
|
@@ -6,7 +6,7 @@ dara/core/auth/basic.py,sha256=IMkoC1OeeRmnmjIqPHpybs8zSdbLlNKYLRvj08ajirg,4692
|
|
|
6
6
|
dara/core/auth/definitions.py,sha256=7SoUBlYQhccop4Rl0XlHjSBjBU41ZbCZHS7Y-fL9g84,3501
|
|
7
7
|
dara/core/auth/routes.py,sha256=1gOe1Z2Vv5MtpW5uvUYvyYWTJ_BDoLRllji1Plk4nss,7180
|
|
8
8
|
dara/core/auth/utils.py,sha256=sFQWbkclDi2842mhauTeLh5g5RsSrzS7AxlKSSnzhYM,7320
|
|
9
|
-
dara/core/base_definitions.py,sha256=
|
|
9
|
+
dara/core/base_definitions.py,sha256=wNYPDUFHHhjE4gH2fm1z2wba04Lrl3-7JDua01j-zCs,18062
|
|
10
10
|
dara/core/cli.py,sha256=hgzy8zrEB_JR2GF_nBBfs9d2I9LmjJt0OQJYOOCc284,8158
|
|
11
11
|
dara/core/configuration.py,sha256=bWD9oL_lqCEq88I2Zr39cPt_8jZIwq5vUAyLFrsmVYQ,22297
|
|
12
12
|
dara/core/css.py,sha256=KWCJTPpx4tTezP9VJO3k-RSVhWwomJr-4USoLz9vNAs,1771
|
|
@@ -14,18 +14,19 @@ 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=KmJdLWwurLBRZonPz94N9947cG1jMrs-wzqtof6ubK0,17762
|
|
16
16
|
dara/core/http.py,sha256=LR1Kr5Hca-Z6klNl-M8R8Q1eOfFh3hLrjVS3kVrRsKA,4658
|
|
17
|
-
dara/core/interactivity/__init__.py,sha256=
|
|
18
|
-
dara/core/interactivity/actions.py,sha256=
|
|
17
|
+
dara/core/interactivity/__init__.py,sha256=4gD69m5nRf6lefKdNx9K_fRJOqmsAwjALZqKiPtvutk,2415
|
|
18
|
+
dara/core/interactivity/actions.py,sha256=niNMt-IE_YXTtLpYrueTNCT60KelmNCGpUn7-WTVDQ4,48020
|
|
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
|
-
dara/core/interactivity/condition.py,sha256=
|
|
21
|
+
dara/core/interactivity/condition.py,sha256=69tdxgLqNbU-AlwHTWFdp-hvxGDugNnb_McDrz0mDtE,1575
|
|
22
22
|
dara/core/interactivity/data_variable.py,sha256=pvPOx6SMxHWDxoo5Ea5xqLwrBTrWN68x8lnBiblYSGg,11760
|
|
23
23
|
dara/core/interactivity/derived_data_variable.py,sha256=u2HOts5rtmzK3D1K383YfYYQnb4pHZF3rTu1lfwMpPA,15323
|
|
24
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
|
|
28
|
-
dara/core/interactivity/plain_variable.py,sha256=
|
|
28
|
+
dara/core/interactivity/plain_variable.py,sha256=ZIg9LhgfKEY1mfcWwysAXzeMRbVoFF61OYHt_od-9n0,9248
|
|
29
|
+
dara/core/interactivity/switch_variable.py,sha256=mC91kBoZON3JGBczv-YPvA5A6zY0mKqEr_7d3Sa_YMg,14194
|
|
29
30
|
dara/core/interactivity/url_variable.py,sha256=1ZPFHO3gq7ZuATHt4S9x5ijmk4GBVlUv5KJN6DkM49w,4357
|
|
30
31
|
dara/core/internal/__init__.py,sha256=QN0wbG9HPQ_vXh8BO8DnBXeYLIENVTNtRmYzZf1lx7c,577
|
|
31
32
|
dara/core/internal/cache_store/__init__.py,sha256=7JCmQwNIMzfyLZGnsk0BbT1EdDFO_PRZz86E9ATcC6c,139
|
|
@@ -36,7 +37,7 @@ dara/core/internal/cache_store/lru.py,sha256=V0KkpsU9oJ_vJ2j7iKFTxxihF1zCxVTvKBf
|
|
|
36
37
|
dara/core/internal/cache_store/ttl.py,sha256=7zcVYR9a2M5qOTWuhor-TgKBKERPn6qsZsDnoUyazfM,4755
|
|
37
38
|
dara/core/internal/cgroup.py,sha256=o1Qqn5LV3TOPK7lQ0xbQj01zYT1pv-X_edGx8VhFvEw,3218
|
|
38
39
|
dara/core/internal/custom_response.py,sha256=aSPonh8AdRjioTk1MaPwdaJHkO4R4aG_osGAGCIHbtg,1341
|
|
39
|
-
dara/core/internal/dependency_resolution.py,sha256=
|
|
40
|
+
dara/core/internal/dependency_resolution.py,sha256=YoDPvnEM5HXSJ1asrX8zrgceqj6EM1o5YVSWaFE8zUc,11161
|
|
40
41
|
dara/core/internal/devtools.py,sha256=YmJdYKEqfxrpXFYAM5sJ2wUtUhfvaCMbb9PuDcqFdt4,2441
|
|
41
42
|
dara/core/internal/download.py,sha256=2_fNIWDsV9f0BptTQRhBuIFXOO4th9pcYaIB7lsPcJU,3183
|
|
42
43
|
dara/core/internal/encoder_registry.py,sha256=tq2ka9RjStEFsxTdsWF6kSOU7rycggEq8YfDlzSyzKk,11277
|
|
@@ -76,13 +77,13 @@ dara/core/js_tooling/templates/dara.config.json,sha256=RZG_R_xJv_5rYIoz2QZulcG49
|
|
|
76
77
|
dara/core/js_tooling/templates/vite.config.template.ts,sha256=-_GgbqPAcg_rTL2JsWjqYqZa4w6p2fKa2nyqGnjqj18,888
|
|
77
78
|
dara/core/log_configs/logging.yaml,sha256=YJyD18psAmSVz6587dcEOyoulLuRFFu1g8yMXl1ylM0,706
|
|
78
79
|
dara/core/logging.py,sha256=HiEbksFvlsSunlJd7wZrYrhKzR0Y4il0982rIwg5wOo,13099
|
|
79
|
-
dara/core/main.py,sha256=
|
|
80
|
+
dara/core/main.py,sha256=LxWLueYonVMnstz8JnpiGACEvB8LXl75JGqfUCnmSEM,18382
|
|
80
81
|
dara/core/metrics/__init__.py,sha256=2UqpWHv-Ie58QLJIHJ9Szfjq8xifAuwy5FYGUIFwWtI,823
|
|
81
82
|
dara/core/metrics/cache.py,sha256=bGXwjO_rSc-FkS3PnPi1mvIZf1x-hvmG113dAUk1g-Y,2616
|
|
82
83
|
dara/core/metrics/runtime.py,sha256=YP-6Dz0GeI9_Yr7bUk_-OqShyFySGH_AKpDO126l6es,1833
|
|
83
84
|
dara/core/metrics/utils.py,sha256=aKaa_hskV3M3h4xOGZYvegDLq_OWOEUlslkQKrrPQiI,2281
|
|
84
85
|
dara/core/persistence.py,sha256=-lnksbGfHwabeRjbJkceoFd0kHfCu4gK2fud8dkeDTg,18538
|
|
85
|
-
dara/core/umd/dara.core.umd.js,sha256=
|
|
86
|
+
dara/core/umd/dara.core.umd.js,sha256=M-6KfeAB33xEd0BzlZInksx5Ch0IK6B5cXwSg1E-gPc,4730555
|
|
86
87
|
dara/core/umd/style.css,sha256=YQtQ4veiSktnyONl0CU1iU1kKfcQhreH4iASi1MP7Ak,4095007
|
|
87
88
|
dara/core/visual/__init__.py,sha256=QN0wbG9HPQ_vXh8BO8DnBXeYLIENVTNtRmYzZf1lx7c,577
|
|
88
89
|
dara/core/visual/components/__init__.py,sha256=eg6M2YcH1o-I2H3IqLaD32ExfZcXhKuH5KTM52Ow6RM,2359
|
|
@@ -106,8 +107,8 @@ dara/core/visual/themes/__init__.py,sha256=aM4mgoIYo2neBSw5FRzswsht7PUKjLthiHLmF
|
|
|
106
107
|
dara/core/visual/themes/dark.py,sha256=UQGDooOc8ric73eHs9E0ltYP4UCrwqQ3QxqN_fb4PwY,1942
|
|
107
108
|
dara/core/visual/themes/definitions.py,sha256=nS_gQvOzCt5hTmj74d0_siq_9QWuj6wNuir4VCHy0Dk,2779
|
|
108
109
|
dara/core/visual/themes/light.py,sha256=-Tviq8oEwGbdFULoDOqPuHO0UpAZGsBy8qFi0kAGolQ,1944
|
|
109
|
-
dara_core-1.
|
|
110
|
-
dara_core-1.
|
|
111
|
-
dara_core-1.
|
|
112
|
-
dara_core-1.
|
|
113
|
-
dara_core-1.
|
|
110
|
+
dara_core-1.17.0.dist-info/LICENSE,sha256=r9u1w2RvpLMV6YjuXHIKXRBKzia3fx_roPwboGcLqCc,10944
|
|
111
|
+
dara_core-1.17.0.dist-info/METADATA,sha256=EKazJEN18CnxMiVy52kYaZwHlRCYVDRKse9RQmDpT4U,7497
|
|
112
|
+
dara_core-1.17.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
113
|
+
dara_core-1.17.0.dist-info/entry_points.txt,sha256=H__D5sNIGuPIhVam0DChNL-To5k8Y7nY7TAFz9Mz6cc,139
|
|
114
|
+
dara_core-1.17.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|