dara-core 1.21.15__py3-none-any.whl → 1.21.17__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.
Files changed (87) hide show
  1. dara/core/auth/base.py +5 -5
  2. dara/core/auth/basic.py +3 -3
  3. dara/core/auth/definitions.py +13 -14
  4. dara/core/auth/routes.py +7 -5
  5. dara/core/auth/utils.py +11 -10
  6. dara/core/base_definitions.py +30 -36
  7. dara/core/cli.py +7 -8
  8. dara/core/configuration.py +51 -58
  9. dara/core/css.py +2 -2
  10. dara/core/data_utils.py +12 -17
  11. dara/core/defaults.py +3 -3
  12. dara/core/definitions.py +58 -63
  13. dara/core/http.py +4 -4
  14. dara/core/interactivity/actions.py +34 -42
  15. dara/core/interactivity/any_data_variable.py +1 -1
  16. dara/core/interactivity/any_variable.py +6 -5
  17. dara/core/interactivity/client_variable.py +1 -2
  18. dara/core/interactivity/condition.py +2 -2
  19. dara/core/interactivity/data_variable.py +2 -4
  20. dara/core/interactivity/derived_data_variable.py +7 -10
  21. dara/core/interactivity/derived_variable.py +45 -51
  22. dara/core/interactivity/filtering.py +19 -19
  23. dara/core/interactivity/loop_variable.py +2 -4
  24. dara/core/interactivity/non_data_variable.py +1 -1
  25. dara/core/interactivity/plain_variable.py +21 -18
  26. dara/core/interactivity/server_variable.py +13 -15
  27. dara/core/interactivity/state_variable.py +4 -5
  28. dara/core/interactivity/switch_variable.py +16 -16
  29. dara/core/interactivity/tabular_variable.py +3 -3
  30. dara/core/interactivity/url_variable.py +3 -3
  31. dara/core/internal/cache_store/cache_store.py +6 -6
  32. dara/core/internal/cache_store/keep_all.py +3 -3
  33. dara/core/internal/cache_store/lru.py +8 -8
  34. dara/core/internal/cache_store/ttl.py +4 -4
  35. dara/core/internal/custom_response.py +3 -3
  36. dara/core/internal/dependency_resolution.py +6 -10
  37. dara/core/internal/devtools.py +2 -3
  38. dara/core/internal/download.py +5 -6
  39. dara/core/internal/encoder_registry.py +7 -11
  40. dara/core/internal/execute_action.py +5 -5
  41. dara/core/internal/hashing.py +1 -2
  42. dara/core/internal/import_discovery.py +7 -9
  43. dara/core/internal/normalization.py +12 -15
  44. dara/core/internal/pandas_utils.py +6 -6
  45. dara/core/internal/pool/channel.py +3 -4
  46. dara/core/internal/pool/definitions.py +9 -9
  47. dara/core/internal/pool/task_pool.py +8 -8
  48. dara/core/internal/pool/utils.py +4 -3
  49. dara/core/internal/pool/worker.py +3 -3
  50. dara/core/internal/registries.py +4 -4
  51. dara/core/internal/registry.py +3 -3
  52. dara/core/internal/registry_lookup.py +4 -4
  53. dara/core/internal/routing.py +23 -22
  54. dara/core/internal/scheduler.py +8 -8
  55. dara/core/internal/settings.py +1 -2
  56. dara/core/internal/store.py +9 -9
  57. dara/core/internal/tasks.py +30 -30
  58. dara/core/internal/utils.py +9 -15
  59. dara/core/internal/websocket.py +18 -18
  60. dara/core/js_tooling/js_utils.py +19 -19
  61. dara/core/logging.py +13 -13
  62. dara/core/main.py +4 -5
  63. dara/core/metrics/cache.py +2 -4
  64. dara/core/persistence.py +19 -25
  65. dara/core/router/compat.py +1 -3
  66. dara/core/router/components.py +10 -10
  67. dara/core/router/dependency_graph.py +2 -4
  68. dara/core/router/router.py +43 -42
  69. dara/core/visual/components/dynamic_component.py +1 -3
  70. dara/core/visual/components/fallback.py +3 -3
  71. dara/core/visual/components/for_cmp.py +5 -5
  72. dara/core/visual/components/menu.py +1 -3
  73. dara/core/visual/components/router_content.py +1 -3
  74. dara/core/visual/components/sidebar_frame.py +8 -10
  75. dara/core/visual/components/theme_provider.py +3 -3
  76. dara/core/visual/components/topbar_frame.py +8 -10
  77. dara/core/visual/css/__init__.py +277 -277
  78. dara/core/visual/dynamic_component.py +18 -22
  79. dara/core/visual/progress_updater.py +1 -1
  80. dara/core/visual/template.py +10 -12
  81. dara/core/visual/themes/definitions.py +46 -46
  82. {dara_core-1.21.15.dist-info → dara_core-1.21.17.dist-info}/METADATA +13 -14
  83. dara_core-1.21.17.dist-info/RECORD +127 -0
  84. dara_core-1.21.15.dist-info/RECORD +0 -127
  85. {dara_core-1.21.15.dist-info → dara_core-1.21.17.dist-info}/LICENSE +0 -0
  86. {dara_core-1.21.15.dist-info → dara_core-1.21.17.dist-info}/WHEEL +0 -0
  87. {dara_core-1.21.15.dist-info → dara_core-1.21.17.dist-info}/entry_points.txt +0 -0
@@ -21,21 +21,17 @@ import contextlib
21
21
  import inspect
22
22
  import math
23
23
  import uuid
24
- from collections.abc import Awaitable
24
+ from collections.abc import Awaitable, Callable
25
25
  from contextvars import ContextVar
26
26
  from enum import Enum
27
27
  from functools import partial, update_wrapper
28
28
  from typing import (
29
29
  TYPE_CHECKING,
30
30
  Any,
31
- Callable,
32
31
  ClassVar,
33
- Dict,
34
- List,
35
32
  Literal,
36
- Optional,
33
+ TypeAlias,
37
34
  TypeVar,
38
- Union,
39
35
  cast,
40
36
  overload,
41
37
  )
@@ -44,7 +40,7 @@ import anyio
44
40
  from anyio.streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream
45
41
  from pandas import DataFrame
46
42
  from pydantic import ConfigDict
47
- from typing_extensions import TypeAlias, deprecated
43
+ from typing_extensions import deprecated
48
44
 
49
45
  from dara.core.base_definitions import (
50
46
  ActionDef,
@@ -86,7 +82,7 @@ class ActionContext(BaseModel):
86
82
  @deprecated: used in deprecated action wrappers
87
83
  """
88
84
 
89
- extras: List[Any] = []
85
+ extras: list[Any] = []
90
86
  inputs: ActionInputs
91
87
 
92
88
 
@@ -126,7 +122,7 @@ class UpdateVariableImpl(ActionImpl):
126
122
 
127
123
  py_name = 'UpdateVariable'
128
124
 
129
- variable: Union[Variable, ServerVariable]
125
+ variable: Variable | ServerVariable
130
126
  value: Any
131
127
 
132
128
  INPUT: ClassVar[str] = '__dara_input__'
@@ -240,14 +236,14 @@ class UpdateVariable(AnnotatedAction):
240
236
 
241
237
  Ctx: ClassVar[type[UpdateVariableContext]] = UpdateVariableContext
242
238
 
243
- variable: Union[Variable, ServerVariable]
244
- extras: Optional[List[AnyVariable]]
239
+ variable: Variable | ServerVariable
240
+ extras: list[AnyVariable] | None
245
241
 
246
242
  def __init__(
247
243
  self,
248
244
  resolver: Callable[[UpdateVariableContext], Any],
249
- variable: Union[Variable, ServerVariable],
250
- extras: Optional[List[AnyVariable]] = None,
245
+ variable: Variable | ServerVariable,
246
+ extras: list[AnyVariable] | None = None,
251
247
  ):
252
248
  """
253
249
  :param resolver: a function to resolve the new value for the variable. Takes one arguments: containing a context of type `Updatevariable.Ctx`
@@ -374,20 +370,18 @@ class NavigateToImpl(ActionImpl):
374
370
 
375
371
  py_name = 'NavigateTo'
376
372
 
377
- url: Union[str, RouterPath]
373
+ url: str | RouterPath
378
374
 
379
375
  new_tab: bool = False
380
376
 
381
- options: Optional[NavigateOptions] = None
377
+ options: NavigateOptions | None = None
382
378
  """
383
379
  Options for relative navigations
384
380
  """
385
381
 
386
382
 
387
383
  @deprecated('Use @action or `NavigateToImpl` for simple cases')
388
- def NavigateTo(
389
- url: Union[str, Callable[[Any], str]], new_tab: bool = False, extras: Optional[List[AnyVariable]] = None
390
- ):
384
+ def NavigateTo(url: str | Callable[[Any], str], new_tab: bool = False, extras: list[AnyVariable] | None = None):
391
385
  """
392
386
  @deprecated: Passing in resolvers is deprecated, use `ctx.navigate` in an `@action` or `NavigateToImpl` instead.
393
387
 
@@ -526,7 +520,7 @@ class ResetVariables(ActionImpl):
526
520
  :param variables: list of variables to reset
527
521
  """
528
522
 
529
- variables: List[AnyVariable]
523
+ variables: list[AnyVariable]
530
524
 
531
525
 
532
526
  class NotificationStatus(str, Enum):
@@ -578,7 +572,7 @@ class Notify(ActionImpl):
578
572
  ```
579
573
  """
580
574
 
581
- key: Optional[str] = None
575
+ key: str | None = None
582
576
  message: str
583
577
  status: NotificationStatus
584
578
  title: str
@@ -624,7 +618,7 @@ DownloadContentDef = ActionDef(name='DownloadContent', js_module='@darajs/core',
624
618
  @deprecated('Use @action instead')
625
619
  def DownloadContent(
626
620
  resolver: Callable[[ComponentActionContext], str],
627
- extras: Optional[List[AnyVariable]] = None,
621
+ extras: list[AnyVariable] | None = None,
628
622
  cleanup_file: bool = False,
629
623
  ):
630
624
  """
@@ -729,14 +723,14 @@ class DownloadVariable(ActionImpl):
729
723
  """
730
724
 
731
725
  variable: AnyVariable
732
- file_name: Optional[str] = None
726
+ file_name: str | None = None
733
727
  type: Literal['csv', 'xlsx', 'json'] = 'csv'
734
728
 
735
729
 
736
730
  @deprecated('Use @action instead')
737
731
  def SideEffect(
738
732
  function: Callable[[ComponentActionContext], Any],
739
- extras: Optional[List[AnyVariable]] = None,
733
+ extras: list[AnyVariable] | None = None,
740
734
  block: bool = False,
741
735
  ):
742
736
  """
@@ -820,12 +814,12 @@ class ActionCtx:
820
814
  _action_receive_stream: MemoryObjectReceiveStream[ActionImpl]
821
815
  """Memory object receive stream for receiving actions to send to the frontend."""
822
816
 
823
- _on_action: Callable[[Optional[ActionImpl]], Awaitable]
817
+ _on_action: Callable[[ActionImpl | None], Awaitable]
824
818
  """Callback for when an action is pushed to the stream."""
825
819
 
826
820
  input: Any
827
821
 
828
- def __init__(self, _input: Any, _on_action: Callable[[Optional[ActionImpl]], Awaitable]):
822
+ def __init__(self, _input: Any, _on_action: Callable[[ActionImpl | None], Awaitable]):
829
823
  self.input = _input
830
824
  self._action_send_stream, self._action_receive_stream = anyio.create_memory_object_stream[ActionImpl](
831
825
  max_buffer_size=math.inf
@@ -833,12 +827,12 @@ class ActionCtx:
833
827
  self._on_action = _on_action
834
828
 
835
829
  @overload
836
- async def update(self, variable: ServerVariable, value: Optional[DataFrame]): ...
830
+ async def update(self, variable: ServerVariable, value: DataFrame | None): ...
837
831
 
838
832
  @overload
839
833
  async def update(self, variable: Variable[VariableT], value: VariableT): ...
840
834
 
841
- async def update(self, variable: Union[Variable, ServerVariable], value: Any):
835
+ async def update(self, variable: Variable | ServerVariable, value: Any):
842
836
  """
843
837
  Update a given variable to provided value.
844
838
 
@@ -955,9 +949,7 @@ class ActionCtx:
955
949
  """
956
950
  return await TriggerVariable(variable=variable, force=force).execute(self)
957
951
 
958
- async def navigate(
959
- self, url: Union[str, RouterPath], new_tab: bool = False, options: Optional[NavigateOptions] = None
960
- ):
952
+ async def navigate(self, url: str | RouterPath, new_tab: bool = False, options: NavigateOptions | None = None):
961
953
  """
962
954
  Navigate to a given url
963
955
 
@@ -1036,8 +1028,8 @@ class ActionCtx:
1036
1028
  self,
1037
1029
  message: str,
1038
1030
  title: str,
1039
- status: Union[NotificationStatus, NotificationStatusString],
1040
- key: Optional[str] = None,
1031
+ status: NotificationStatus | NotificationStatusString,
1032
+ key: str | None = None,
1041
1033
  ):
1042
1034
  """
1043
1035
  Display a notification toast on the frontend
@@ -1078,7 +1070,7 @@ class ActionCtx:
1078
1070
 
1079
1071
  return await Notify(key=key, message=message, status=status, title=title).execute(self)
1080
1072
 
1081
- async def reset_variables(self, variables: Union[List[AnyVariable], AnyVariable]):
1073
+ async def reset_variables(self, variables: list[AnyVariable] | AnyVariable):
1082
1074
  """
1083
1075
  Reset a list of variables to their default values.
1084
1076
 
@@ -1164,7 +1156,7 @@ class ActionCtx:
1164
1156
  return await NavigateToImpl(url=f'/api/core/download?code={code}', new_tab=True).execute(self)
1165
1157
 
1166
1158
  async def download_variable(
1167
- self, variable: AnyVariable, file_name: Optional[str] = None, type: Literal['csv', 'xlsx', 'json'] = 'csv'
1159
+ self, variable: AnyVariable, file_name: str | None = None, type: Literal['csv', 'xlsx', 'json'] = 'csv'
1168
1160
  ):
1169
1161
  """
1170
1162
  Download the content of a given variable as a file.
@@ -1205,9 +1197,9 @@ class ActionCtx:
1205
1197
  async def run_task(
1206
1198
  self,
1207
1199
  func: Callable,
1208
- args: Union[List[Any], None] = None,
1209
- kwargs: Union[Dict[str, Any], None] = None,
1210
- on_progress: Optional[Callable[[TaskProgressUpdate], Union[None, Awaitable[None]]]] = None,
1200
+ args: list[Any] | None = None,
1201
+ kwargs: dict[str, Any] | None = None,
1202
+ on_progress: Callable[[TaskProgressUpdate], None | Awaitable[None]] | None = None,
1211
1203
  ):
1212
1204
  """
1213
1205
  Run a calculation as a task in a separate process. Recommended for CPU intensive tasks.
@@ -1287,7 +1279,7 @@ class ActionCtx:
1287
1279
  self._action_send_stream.close()
1288
1280
 
1289
1281
 
1290
- ACTION_CONTEXT = ContextVar[Optional[ActionCtx]]('action_context', default=None)
1282
+ ACTION_CONTEXT = ContextVar[ActionCtx | None]('action_context', default=None)
1291
1283
  """Current execution context"""
1292
1284
 
1293
1285
 
@@ -1363,7 +1355,7 @@ class action:
1363
1355
  action_registry.register(self.definition_uid, act_def)
1364
1356
 
1365
1357
  # Modify the function signature
1366
- bound_name: Union[str, None] = None
1358
+ bound_name: str | None = None
1367
1359
 
1368
1360
  # Check if first parameter is 'self' or 'cls' - we have to use the name as otherwise it's
1369
1361
  # not possible to distinguish between a bound method or non-bound method
@@ -1405,7 +1397,7 @@ class action:
1405
1397
  def __call__(self, *args: Any, **kwargs: Any) -> AnnotatedAction: # type: ignore
1406
1398
  ...
1407
1399
 
1408
- def __call__(self, *args, **kwargs) -> Union[AnnotatedAction, Any]:
1400
+ def __call__(self, *args, **kwargs) -> AnnotatedAction | Any:
1409
1401
  from dara.core.interactivity.any_variable import AnyVariable
1410
1402
  from dara.core.internal.registries import static_kwargs_registry
1411
1403
 
@@ -1464,8 +1456,8 @@ class action:
1464
1456
  )
1465
1457
 
1466
1458
  # Split args based on whether they are static or dynamic
1467
- dynamic_kwargs: Dict[str, AnyVariable] = {}
1468
- static_kwargs: Dict[str, Any] = {}
1459
+ dynamic_kwargs: dict[str, AnyVariable] = {}
1460
+ static_kwargs: dict[str, Any] = {}
1469
1461
  for key, kwarg in all_kwargs.items():
1470
1462
  if isinstance(kwarg, StateVariable):
1471
1463
  raise ValueError(
@@ -1,4 +1,4 @@
1
- from typing_extensions import TypeAlias
1
+ from typing import TypeAlias
2
2
 
3
3
  from dara.core.interactivity.any_variable import AnyVariable
4
4
 
@@ -20,10 +20,11 @@ from __future__ import annotations
20
20
  import abc
21
21
  import inspect
22
22
  import uuid
23
+ from collections.abc import Callable
23
24
  from contextlib import contextmanager
24
25
  from contextvars import ContextVar
25
26
  from datetime import datetime
26
- from typing import Any, Callable, Dict, Optional, Set
27
+ from typing import Any
27
28
 
28
29
  import anyio
29
30
  from fastapi.encoders import jsonable_encoder
@@ -40,7 +41,7 @@ from dara.core.logging import dev_logger
40
41
 
41
42
  NOT_REGISTERED = '__NOT_REGISTERED__'
42
43
 
43
- GET_VALUE_OVERRIDE = ContextVar[Optional[Callable[[dict], Any]]]('GET_VALUE_OVERRIDE', default=None)
44
+ GET_VALUE_OVERRIDE = ContextVar[Callable[[dict], Any] | None]('GET_VALUE_OVERRIDE', default=None)
44
45
  """
45
46
  Optional context variable which can be used to override the default behaviour of `get_current_value()`.
46
47
  """
@@ -135,7 +136,7 @@ async def get_current_value(variable: dict, timeout: float = 3, raw: bool = Fals
135
136
  )
136
137
  return None
137
138
 
138
- session_channels: Dict[str, Set[str]] = {}
139
+ session_channels: dict[str, set[str]] = {}
139
140
  saved_ws_channel = WS_CHANNEL.get()
140
141
 
141
142
  # Collect sessions which are active
@@ -154,7 +155,7 @@ async def get_current_value(variable: dict, timeout: float = 3, raw: bool = Fals
154
155
  )
155
156
  return None
156
157
 
157
- raw_results: Dict[str, Any] = {}
158
+ raw_results: dict[str, Any] = {}
158
159
  registered_value_found = False
159
160
 
160
161
  async def retrieve_value(channel: str):
@@ -279,7 +280,7 @@ class AnyVariable(BaseModel, abc.ABC): # noqa: PLW1641 # we override equals to
279
280
 
280
281
  uid: str
281
282
 
282
- def __init__(self, uid: Optional[str] = None, **kwargs) -> None:
283
+ def __init__(self, uid: str | None = None, **kwargs) -> None:
283
284
  new_uid = uid
284
285
  if new_uid is None:
285
286
  new_uid = str(uuid.uuid4())
@@ -18,7 +18,6 @@ limitations under the License.
18
18
  from __future__ import annotations
19
19
 
20
20
  import abc
21
- from typing import Optional
22
21
 
23
22
  from dara.core.interactivity.any_variable import AnyVariable
24
23
 
@@ -32,7 +31,7 @@ class ClientVariable(AnyVariable, abc.ABC):
32
31
 
33
32
  uid: str
34
33
 
35
- def __init__(self, uid: Optional[str] = None, **kwargs) -> None:
34
+ def __init__(self, uid: str | None = None, **kwargs) -> None:
36
35
  super().__init__(uid=uid, **kwargs)
37
36
 
38
37
  @property
@@ -18,7 +18,7 @@ limitations under the License.
18
18
  from __future__ import annotations
19
19
 
20
20
  from enum import Enum
21
- from typing import TYPE_CHECKING, ClassVar, Union
21
+ from typing import TYPE_CHECKING, ClassVar
22
22
 
23
23
  from pydantic import SerializerFunctionWrapHandler, model_serializer
24
24
 
@@ -44,7 +44,7 @@ OperatorType = type[Operator]
44
44
 
45
45
  class Condition(BaseModel):
46
46
  operator: Operator
47
- other: Union[BaseModel, int, float, str, bool, None, AnyVariable]
47
+ other: BaseModel | int | float | str | bool | None | AnyVariable
48
48
  variable: AnyVariable
49
49
 
50
50
  Operator: ClassVar[OperatorType] = Operator
@@ -17,8 +17,6 @@ limitations under the License.
17
17
 
18
18
  from __future__ import annotations
19
19
 
20
- from typing import Optional
21
-
22
20
  from pandas import DataFrame
23
21
 
24
22
  from dara.core.base_definitions import Cache, CacheArgType
@@ -46,9 +44,9 @@ class DataVariable(ServerVariable):
46
44
 
47
45
  def __init__(
48
46
  self,
49
- data: Optional[DataFrame] = None,
47
+ data: DataFrame | None = None,
50
48
  cache: CacheArgType = Cache.Type.GLOBAL,
51
- uid: Optional[str] = None,
49
+ uid: str | None = None,
52
50
  **kwargs,
53
51
  ) -> None:
54
52
  """
@@ -17,8 +17,8 @@ limitations under the License.
17
17
 
18
18
  from __future__ import annotations
19
19
 
20
- from collections.abc import Coroutine
21
- from typing import Any, Callable, List, Optional, Union
20
+ from collections.abc import Callable, Coroutine
21
+ from typing import Any
22
22
 
23
23
  from pandas import DataFrame
24
24
  from typing_extensions import deprecated
@@ -46,16 +46,13 @@ class DerivedDataVariable(DerivedVariable):
46
46
 
47
47
  def __init__(
48
48
  self,
49
- func: Union[
50
- Callable[..., Union[DataFrame, None]],
51
- Callable[..., Coroutine[Any, Any, Union[DataFrame, None]]],
52
- ],
53
- variables: List[AnyVariable],
49
+ func: Callable[..., DataFrame | None] | Callable[..., Coroutine[Any, Any, DataFrame | None]],
50
+ variables: list[AnyVariable],
54
51
  cache: CacheArgType = Cache.Type.GLOBAL,
55
52
  run_as_task: bool = False,
56
- polling_interval: Optional[int] = None,
57
- deps: Optional[List[AnyVariable]] = None,
58
- uid: Optional[str] = None,
53
+ polling_interval: int | None = None,
54
+ deps: list[AnyVariable] | None = None,
55
+ uid: str | None = None,
59
56
  ) -> None:
60
57
  """
61
58
  DerivedDataVariable represents a variable designed to hold datasets computed
@@ -19,18 +19,12 @@ from __future__ import annotations
19
19
 
20
20
  import json
21
21
  import uuid
22
- from collections.abc import Awaitable
22
+ from collections.abc import Awaitable, Callable
23
23
  from inspect import Parameter, signature
24
24
  from typing import (
25
25
  Any,
26
- Callable,
27
26
  Generic,
28
- List,
29
- Optional,
30
27
  Protocol,
31
- Tuple,
32
- TypeVar,
33
- Union,
34
28
  cast,
35
29
  )
36
30
 
@@ -45,7 +39,7 @@ from pydantic import (
45
39
  field_validator,
46
40
  model_serializer,
47
41
  )
48
- from typing_extensions import TypedDict, runtime_checkable
42
+ from typing_extensions import TypedDict, TypeVar, runtime_checkable
49
43
 
50
44
  from dara.core.base_definitions import (
51
45
  BaseCachePolicy,
@@ -69,7 +63,7 @@ from dara.core.internal.utils import get_cache_scope, run_user_handler
69
63
  from dara.core.logging import dev_logger, eng_logger
70
64
  from dara.core.metrics import RUNTIME_METRICS_TRACKER
71
65
 
72
- VariableType = TypeVar('VariableType')
66
+ VariableType = TypeVar('VariableType', default=Any)
73
67
 
74
68
  # Static lock for all DV computations, keyed by cache_key
75
69
  # Explicitly not re-entrant, this prevents variable loops
@@ -88,19 +82,19 @@ Sentinel value to indicate that a value is missing from the cache
88
82
 
89
83
  class DerivedVariableResult(TypedDict):
90
84
  cache_key: str
91
- value: Union[Any, BaseTask]
85
+ value: Any | BaseTask
92
86
 
93
87
 
94
88
  @runtime_checkable
95
89
  class FilterResolver(Protocol):
96
90
  async def __call__(
97
- self, data: Any, filters: Optional[FilterQuery] = None, pagination: Optional[Pagination] = None
98
- ) -> Tuple[DataFrame, int]: ...
91
+ self, data: Any, filters: FilterQuery | None = None, pagination: Pagination | None = None
92
+ ) -> tuple[DataFrame, int]: ...
99
93
 
100
94
 
101
95
  async def default_filter_resolver(
102
- data: Any, filters: Optional[FilterQuery] = None, pagination: Optional[Pagination] = None
103
- ) -> Tuple[DataFrame, int]:
96
+ data: Any, filters: FilterQuery | None = None, pagination: Pagination | None = None
97
+ ) -> tuple[DataFrame, int]:
104
98
  if not isinstance(data, DataFrame):
105
99
  raise NonTabularDataError(
106
100
  f'Default filter resolver expects a DataFrame to be returned from the DerivedVariable function, got {type(data)}'
@@ -174,25 +168,25 @@ class DerivedVariable(ClientVariable, Generic[VariableType]):
174
168
  :param uid: the unique identifier for this variable; if not provided a random one is generated
175
169
  """
176
170
 
177
- cache: Optional[BaseCachePolicy]
178
- variables: List[AnyVariable]
179
- polling_interval: Optional[int]
180
- deps: Optional[List[AnyVariable]] = Field(validate_default=True)
181
- nested: List[str] = Field(default_factory=list)
171
+ cache: BaseCachePolicy | None
172
+ variables: list[AnyVariable]
173
+ polling_interval: int | None
174
+ deps: list[AnyVariable] | None = Field(validate_default=True)
175
+ nested: list[str] = Field(default_factory=list)
182
176
  uid: str
183
177
  model_config = ConfigDict(extra='forbid', use_enum_values=True, arbitrary_types_allowed=True)
184
178
 
185
179
  def __init__(
186
180
  self,
187
- func: Union[Callable[..., VariableType], Callable[..., Awaitable[VariableType]]],
188
- variables: List[AnyVariable],
189
- cache: Optional[CacheArgType] = Cache.Type.GLOBAL,
181
+ func: Callable[..., VariableType] | Callable[..., Awaitable[VariableType]],
182
+ variables: list[AnyVariable],
183
+ cache: CacheArgType | None = Cache.Type.GLOBAL,
190
184
  run_as_task: bool = False,
191
- polling_interval: Optional[int] = None,
192
- deps: Optional[List[AnyVariable]] = None,
193
- uid: Optional[str] = None,
194
- nested: Optional[List[str]] = None,
195
- filter_resolver: Optional[FilterResolver] = None,
185
+ polling_interval: int | None = None,
186
+ deps: list[AnyVariable] | None = None,
187
+ uid: str | None = None,
188
+ nested: list[str] | None = None,
189
+ filter_resolver: FilterResolver | None = None,
196
190
  **kwargs,
197
191
  ):
198
192
  if nested is None:
@@ -241,7 +235,7 @@ class DerivedVariable(ClientVariable, Generic[VariableType]):
241
235
  # Import the registry of variables and register the function at import
242
236
  from dara.core.internal.registries import derived_variable_registry
243
237
 
244
- deps_indexes: Optional[List[int]] = None
238
+ deps_indexes: list[int] | None = None
245
239
 
246
240
  # If deps is provided, compute list of indexes of values which are present in deps
247
241
  if deps is not None:
@@ -267,13 +261,13 @@ class DerivedVariable(ClientVariable, Generic[VariableType]):
267
261
 
268
262
  @field_validator('deps', mode='before')
269
263
  @classmethod
270
- def validate_deps(cls, deps: Any, info: ValidationInfo) -> List[AnyVariable]:
264
+ def validate_deps(cls, deps: Any, info: ValidationInfo) -> list[AnyVariable]:
271
265
  """
272
266
  If deps is not specified, set deps to include all variables used
273
267
  """
274
268
  if deps is None:
275
269
  # This will always be set on the variable with the type verified by pydantic
276
- return cast(List[AnyVariable], info.data.get('variables'))
270
+ return cast(list[AnyVariable], info.data.get('variables'))
277
271
 
278
272
  return deps
279
273
 
@@ -323,7 +317,7 @@ class DerivedVariable(ClientVariable, Generic[VariableType]):
323
317
  return StateVariable(parent_variable=self, property_name='hasValue')
324
318
 
325
319
  @staticmethod
326
- def _get_cache_key(*args, uid: str, deps: Optional[List[int]] = None):
320
+ def _get_cache_key(*args, uid: str, deps: list[int] | None = None):
327
321
  """
328
322
  Convert the set of args that will be passed into the function to a string for use as the cache key. For now this
329
323
  assumes that no classes will be passed in as the underlying values will come from the UI.
@@ -364,14 +358,14 @@ class DerivedVariable(ClientVariable, Generic[VariableType]):
364
358
 
365
359
  # If there is no *args argument then zip the signature with the args
366
360
  if len(var_arg_idx) == 0:
367
- for param, arg in zip(parameters, args):
361
+ for param, arg in zip(parameters, args, strict=False):
368
362
  typ = param.annotation
369
363
  parsed_args.append(deserialize(arg, typ))
370
364
 
371
365
  return parsed_args
372
366
 
373
367
  # If there is a *args argument then zip the signature and args up to that point, then spread the rest
374
- for param, arg in zip(parameters[: var_arg_idx[0]], args[: var_arg_idx[0]]):
368
+ for param, arg in zip(parameters[: var_arg_idx[0]], args[: var_arg_idx[0]], strict=False):
375
369
  typ = param.annotation
376
370
  parsed_args.append(deserialize(arg, typ))
377
371
 
@@ -411,8 +405,8 @@ class DerivedVariable(ClientVariable, Generic[VariableType]):
411
405
  var_entry: DerivedVariableRegistryEntry,
412
406
  store: CacheStore,
413
407
  task_mgr: TaskManager,
414
- args: List[Any],
415
- force_key: Optional[str] = None,
408
+ args: list[Any],
409
+ force_key: str | None = None,
416
410
  _pin_result: bool = False,
417
411
  ) -> DerivedVariableResult:
418
412
  """
@@ -455,7 +449,7 @@ class DerivedVariable(ClientVariable, Generic[VariableType]):
455
449
 
456
450
  with histogram.time():
457
451
  # Extract and process nested derived variables
458
- values: List[Any] = [None] * len(args)
452
+ values: list[Any] = [None] * len(args)
459
453
 
460
454
  eng_logger.info(
461
455
  f'Derived Variable {_uid_short} get_value',
@@ -659,10 +653,10 @@ class DerivedVariable(ClientVariable, Generic[VariableType]):
659
653
  @classmethod
660
654
  async def _filter_data(
661
655
  cls,
662
- data: Union[DataFrame, Any, None],
656
+ data: DataFrame | Any | None,
663
657
  filter_resolver: FilterResolver,
664
- filters: Optional[FilterQuery] = None,
665
- pagination: Optional[Pagination] = None,
658
+ filters: FilterQuery | None = None,
659
+ pagination: Pagination | None = None,
666
660
  ) -> DataResponse:
667
661
  if data is None:
668
662
  return DataResponse(data=None, count=0, schema=None)
@@ -682,11 +676,11 @@ class DerivedVariable(ClientVariable, Generic[VariableType]):
682
676
  var_entry: DerivedVariableRegistryEntry,
683
677
  store: CacheStore,
684
678
  task_mgr: TaskManager,
685
- args: List[Any],
686
- force_key: Optional[str] = None,
687
- pagination: Optional[Pagination] = None,
688
- filters: Optional[FilterQuery] = None,
689
- ) -> Union[MetaTask, DataResponse]:
679
+ args: list[Any],
680
+ force_key: str | None = None,
681
+ pagination: Pagination | None = None,
682
+ filters: FilterQuery | None = None,
683
+ ) -> MetaTask | DataResponse:
690
684
  """
691
685
  Get filtered tabular data from the underlying derived variable.
692
686
 
@@ -714,7 +708,7 @@ class DerivedVariable(ClientVariable, Generic[VariableType]):
714
708
  return await cls._filter_data(result['value'], filter_resolver, filters, pagination)
715
709
 
716
710
  @classmethod
717
- def check_polling(cls, variables: List[AnyVariable]):
711
+ def check_polling(cls, variables: list[AnyVariable]):
718
712
  for variable in variables:
719
713
  if isinstance(variable, DerivedVariable) and (
720
714
  variable.polling_interval or cls.check_polling(variables=variable.variables)
@@ -733,15 +727,15 @@ class DerivedVariable(ClientVariable, Generic[VariableType]):
733
727
 
734
728
 
735
729
  class DerivedVariableRegistryEntry(CachedRegistryEntry):
736
- deps: Optional[List[int]]
737
- func: Optional[Callable[..., Any]]
738
- filter_resolver: Optional[FilterResolver]
730
+ deps: list[int] | None
731
+ func: Callable[..., Any] | None
732
+ filter_resolver: FilterResolver | None
739
733
  run_as_task: bool
740
- variables: List[AnyVariable]
741
- polling_interval: Optional[int]
734
+ variables: list[AnyVariable]
735
+ polling_interval: int | None
742
736
  get_value: Callable[..., Awaitable[Any]]
743
737
  """Handler to get the value of the derived variable. Defaults to DerivedVariable.get_value, should match the signature"""
744
- get_tabular_data: Callable[..., Awaitable[Union[DataResponse, MetaTask]]]
738
+ get_tabular_data: Callable[..., Awaitable[DataResponse | MetaTask]]
745
739
  """Handler to get the tabular data of the derived variable. Defaults to DerivedVariable.get_tabular_data, should match the signature"""
746
740
  model_config = ConfigDict(extra='forbid', arbitrary_types_allowed=True)
747
741