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
@@ -20,7 +20,7 @@ from __future__ import annotations
20
20
  import re
21
21
  from datetime import datetime, timezone
22
22
  from enum import Enum
23
- from typing import Any, List, Optional, Tuple, Union, cast, overload
23
+ from typing import Any, cast, overload
24
24
 
25
25
  import numpy
26
26
  from pandas import DataFrame, Series
@@ -47,10 +47,10 @@ class Pagination(BaseModel):
47
47
  If index is defined, retrieves only the row of the specified index
48
48
  """
49
49
 
50
- offset: Optional[int] = None
51
- limit: Optional[int] = None
52
- orderBy: Optional[str] = None
53
- index: Optional[str] = None
50
+ offset: int | None = None
51
+ limit: int | None = None
52
+ orderBy: str | None = None
53
+ index: str | None = None
54
54
 
55
55
  @field_validator('orderBy', mode='before')
56
56
  @classmethod
@@ -83,7 +83,7 @@ class ClauseQuery(BaseModel):
83
83
  """
84
84
 
85
85
  combinator: QueryCombinator
86
- clauses: List[FilterQuery]
86
+ clauses: list[FilterQuery]
87
87
 
88
88
 
89
89
  class ValueQuery(BaseModel):
@@ -96,7 +96,7 @@ class ValueQuery(BaseModel):
96
96
  value: Any
97
97
 
98
98
 
99
- FilterQuery = Union[ClauseQuery, ValueQuery]
99
+ FilterQuery = ClauseQuery | ValueQuery
100
100
  """
101
101
  Filter query to be applied
102
102
  """
@@ -104,7 +104,7 @@ Filter query to be applied
104
104
  ClauseQuery.model_rebuild()
105
105
 
106
106
 
107
- def coerce_to_filter_query(filters: Union[ClauseQuery, ValueQuery, dict, None]) -> Optional[FilterQuery]:
107
+ def coerce_to_filter_query(filters: ClauseQuery | ValueQuery | dict | None) -> FilterQuery | None:
108
108
  """
109
109
  Coerce a filter query to a FilterQuery object. Converts dict representation to the correct query type.
110
110
  """
@@ -172,7 +172,7 @@ def infer_column_type(series: Series) -> ColumnType:
172
172
  return ColumnType.CATEGORICAL
173
173
 
174
174
 
175
- def _filter_to_series(data: DataFrame, column: str, operator: QueryOperator, value: Any) -> Optional[Series]:
175
+ def _filter_to_series(data: DataFrame, column: str, operator: QueryOperator, value: Any) -> Series | None:
176
176
  """
177
177
  Convert a single filter to a Series[bool] for filtering
178
178
  """
@@ -186,14 +186,14 @@ def _filter_to_series(data: DataFrame, column: str, operator: QueryOperator, val
186
186
 
187
187
  try:
188
188
  # In the case of categorical filter we get a List for value
189
- if isinstance(value, List):
189
+ if isinstance(value, list):
190
190
  return series.isin(value)
191
191
  # Converts date passed from frontend to the right format to compare with pandas
192
192
  if col_type == ColumnType.DATETIME:
193
- value = [parseISO(value[0]), parseISO(value[1])] if isinstance(value, List) else parseISO(value)
193
+ value = [parseISO(value[0]), parseISO(value[1])] if isinstance(value, list) else parseISO(value)
194
194
  elif col_type == ColumnType.CATEGORICAL:
195
195
  value = str(value)
196
- elif isinstance(value, List):
196
+ elif isinstance(value, list):
197
197
  lower_bound = float(value[0]) if '.' in str(value[0]) else int(value[0])
198
198
  upper_bound = float(value[1]) if '.' in str(value[1]) else int(value[1])
199
199
  value = [lower_bound, upper_bound]
@@ -219,7 +219,7 @@ def _filter_to_series(data: DataFrame, column: str, operator: QueryOperator, val
219
219
  return None
220
220
 
221
221
 
222
- def _resolve_filter_query(data: DataFrame, query: FilterQuery) -> Optional[Series]:
222
+ def _resolve_filter_query(data: DataFrame, query: FilterQuery) -> Series | None:
223
223
  """
224
224
  Resolve a FilterQuery to a Series[bool] for filtering. Strips the internal column index from the query.
225
225
  """
@@ -248,19 +248,19 @@ def _resolve_filter_query(data: DataFrame, query: FilterQuery) -> Optional[Serie
248
248
 
249
249
  @overload
250
250
  def apply_filters(
251
- data: DataFrame, filters: Optional[FilterQuery] = None, pagination: Optional[Pagination] = None
252
- ) -> Tuple[DataFrame, int]: ...
251
+ data: DataFrame, filters: FilterQuery | None = None, pagination: Pagination | None = None
252
+ ) -> tuple[DataFrame, int]: ...
253
253
 
254
254
 
255
255
  @overload
256
256
  def apply_filters(
257
- data: None, filters: Optional[FilterQuery] = None, pagination: Optional[Pagination] = None
258
- ) -> Tuple[None, int]: ...
257
+ data: None, filters: FilterQuery | None = None, pagination: Pagination | None = None
258
+ ) -> tuple[None, int]: ...
259
259
 
260
260
 
261
261
  def apply_filters(
262
- data: Optional[DataFrame], filters: Optional[FilterQuery] = None, pagination: Optional[Pagination] = None
263
- ) -> Tuple[Optional[DataFrame], int]:
262
+ data: DataFrame | None, filters: FilterQuery | None = None, pagination: Pagination | None = None
263
+ ) -> tuple[DataFrame | None, int]:
264
264
  """
265
265
  Apply filtering and pagination to a DataFrame.
266
266
  """
@@ -1,5 +1,3 @@
1
- from typing import List, Optional
2
-
3
1
  from pydantic import Field, SerializerFunctionWrapHandler, model_serializer
4
2
 
5
3
  from .client_variable import ClientVariable
@@ -47,9 +45,9 @@ class LoopVariable(ClientVariable):
47
45
  Both `get` and `[]` are equivalent.
48
46
  """
49
47
 
50
- nested: List[str] = Field(default_factory=list)
48
+ nested: list[str] = Field(default_factory=list)
51
49
 
52
- def __init__(self, uid: Optional[str] = None, nested: Optional[List[str]] = None):
50
+ def __init__(self, uid: str | None = None, nested: list[str] | None = None):
53
51
  if nested is None:
54
52
  nested = []
55
53
  super().__init__(uid=uid, nested=nested)
@@ -1,4 +1,4 @@
1
- from typing_extensions import TypeAlias
1
+ from typing import TypeAlias
2
2
 
3
3
  from .client_variable import * # noqa: F403
4
4
 
@@ -18,9 +18,10 @@ limitations under the License.
18
18
  from __future__ import annotations
19
19
 
20
20
  import warnings
21
+ from collections.abc import Callable
21
22
  from contextlib import contextmanager
22
23
  from contextvars import ContextVar
23
- from typing import Any, Callable, Dict, Generic, List, Optional, TypeVar, Union
24
+ from typing import Any, Generic
24
25
 
25
26
  from fastapi.encoders import jsonable_encoder
26
27
  from pydantic import (
@@ -30,6 +31,7 @@ from pydantic import (
30
31
  field_serializer,
31
32
  model_serializer,
32
33
  )
34
+ from typing_extensions import TypeVar
33
35
 
34
36
  from dara.core.interactivity.client_variable import ClientVariable
35
37
  from dara.core.interactivity.derived_variable import DerivedVariable
@@ -37,31 +39,32 @@ from dara.core.internal.utils import call_async
37
39
  from dara.core.logging import dev_logger
38
40
  from dara.core.persistence import BackendStore, BrowserStore, PersistenceStore
39
41
 
40
- VARIABLE_INIT_OVERRIDE = ContextVar[Optional[Callable[[dict], dict]]]('VARIABLE_INIT_OVERRIDE', default=None)
42
+ VARIABLE_INIT_OVERRIDE = ContextVar[Callable[[dict], dict] | None]('VARIABLE_INIT_OVERRIDE', default=None)
41
43
 
42
44
  VariableType = TypeVar('VariableType')
43
- PersistenceStoreType_co = TypeVar('PersistenceStoreType_co', bound=PersistenceStore, covariant=True)
45
+ PersistenceStoreType_co = TypeVar(
46
+ 'PersistenceStoreType_co', bound=PersistenceStore, covariant=True, default=PersistenceStore
47
+ )
44
48
 
45
49
 
46
- # TODO: once Python supports a default value for a generic type properly we can make PersistenceStoreType a second generic param
47
- class Variable(ClientVariable, Generic[VariableType]):
50
+ class Variable(ClientVariable, Generic[VariableType, PersistenceStoreType_co]):
48
51
  """
49
52
  A Variable represents a dynamic value in the system that can be read and written to by components and actions
50
53
  """
51
54
 
52
- default: Optional[VariableType] = None
53
- store: Optional[PersistenceStore] = None
55
+ default: VariableType | None = None
56
+ store: PersistenceStoreType_co | None = None
54
57
  uid: str
55
- nested: List[str] = Field(default_factory=list)
58
+ nested: list[str] = Field(default_factory=list)
56
59
  model_config = ConfigDict(extra='forbid')
57
60
 
58
61
  def __init__(
59
62
  self,
60
- default: Optional[VariableType] = None,
61
- persist_value: Optional[bool] = False,
62
- uid: Optional[str] = None,
63
- store: Optional[PersistenceStoreType_co] = None,
64
- nested: Optional[List[str]] = None,
63
+ default: VariableType | None = None,
64
+ persist_value: bool | None = False,
65
+ uid: str | None = None,
66
+ store: PersistenceStoreType_co | None = None,
67
+ nested: list[str] | None = None,
65
68
  **kwargs,
66
69
  ):
67
70
  """
@@ -233,7 +236,7 @@ class Variable(ClientVariable, Generic[VariableType]):
233
236
  assert_no_context('ctx.update')
234
237
  return UpdateVariableImpl(variable=self, value=UpdateVariableImpl.TOGGLE)
235
238
 
236
- def update(self, value: Any):
239
+ def update(self, value: VariableType):
237
240
  """
238
241
  Create an action to update the value of this Variable to a provided value.
239
242
 
@@ -269,7 +272,7 @@ class Variable(ClientVariable, Generic[VariableType]):
269
272
  """
270
273
  return cls(default=other) # type: ignore
271
274
 
272
- async def write(self, value: Any, notify=True, ignore_channel: Optional[str] = None):
275
+ async def write(self, value: VariableType, notify=True, ignore_channel: str | None = None):
273
276
  """
274
277
  Persist a value to the variable's BackendStore.
275
278
  Raises an error if the variable does not have a BackendStore attached.
@@ -284,7 +287,7 @@ class Variable(ClientVariable, Generic[VariableType]):
284
287
  assert isinstance(self.store, BackendStore), 'This method can only be used with a BackendStore'
285
288
  return await self.store.write(value, notify=notify, ignore_channel=ignore_channel)
286
289
 
287
- async def write_partial(self, data: Union[List[Dict[str, Any]], Any], notify: bool = True, in_place: bool = False):
290
+ async def write_partial(self, data: list[dict[str, Any]] | Any, notify: bool = True, in_place: bool = False):
288
291
  """
289
292
  Apply partial updates to the variable's BackendStore using JSON Patch operations or automatic diffing.
290
293
  Raises an error if the variable does not have a BackendStore attached.
@@ -302,7 +305,7 @@ class Variable(ClientVariable, Generic[VariableType]):
302
305
  assert isinstance(self.store, BackendStore), 'This method can only be used with a BackendStore'
303
306
  return await self.store.write_partial(data, notify=notify, in_place=in_place)
304
307
 
305
- async def read(self):
308
+ async def read(self) -> VariableType:
306
309
  """
307
310
  Read a value from the variable's BackendStore.
308
311
  Raises an error if the variable does not have a BackendStore attached.
@@ -326,7 +329,7 @@ class Variable(ClientVariable, Generic[VariableType]):
326
329
  assert isinstance(self.store, BackendStore), 'This method can only be used with a BackendStore'
327
330
  return await self.store.delete(notify=notify)
328
331
 
329
- async def get_all(self) -> Dict[str, Any]:
332
+ async def get_all(self) -> dict[str, VariableType]:
330
333
  """
331
334
  Get all the values from the variable's BackendStore as a dictionary of key-value pairs.
332
335
  Raises an error if the variable does not have a BackendStore attached.
@@ -1,6 +1,6 @@
1
1
  import abc
2
2
  from collections import defaultdict
3
- from typing import Any, DefaultDict, Dict, Literal, Optional, Tuple, Union
3
+ from typing import Any, Literal
4
4
 
5
5
  from pandas import DataFrame
6
6
  from pydantic import BaseModel, ConfigDict, Field, SerializerFunctionWrapHandler, model_serializer
@@ -38,8 +38,8 @@ class ServerBackend(BaseModel, abc.ABC):
38
38
 
39
39
  @abc.abstractmethod
40
40
  async def read_filtered(
41
- self, key: str, filters: Optional[Union[FilterQuery, dict]] = None, pagination: Optional[Pagination] = None
42
- ) -> Tuple[Optional[DataFrame], int]:
41
+ self, key: str, filters: FilterQuery | dict | None = None, pagination: Pagination | None = None
42
+ ) -> tuple[DataFrame | None, int]:
43
43
  """
44
44
  Read a value
45
45
  :param filters: filters to apply
@@ -54,8 +54,8 @@ class ServerBackend(BaseModel, abc.ABC):
54
54
 
55
55
 
56
56
  class MemoryBackend(ServerBackend):
57
- data: Dict[str, Any] = Field(default_factory=dict)
58
- sequence_number: DefaultDict[str, int] = Field(default_factory=lambda: defaultdict(int))
57
+ data: dict[str, Any] = Field(default_factory=dict)
58
+ sequence_number: defaultdict[str, int] = Field(default_factory=lambda: defaultdict(int))
59
59
 
60
60
  def __init__(self, scope: Literal['user', 'global'] = 'user'):
61
61
  super().__init__(scope=scope)
@@ -69,8 +69,8 @@ class MemoryBackend(ServerBackend):
69
69
  return self.data.get(key)
70
70
 
71
71
  async def read_filtered(
72
- self, key: str, filters: Optional[Union[FilterQuery, dict]] = None, pagination: Optional[Pagination] = None
73
- ) -> Tuple[Optional[DataFrame], int]:
72
+ self, key: str, filters: FilterQuery | dict | None = None, pagination: Pagination | None = None
73
+ ) -> tuple[DataFrame | None, int]:
74
74
  dataset = self.data.get(key)
75
75
 
76
76
  # print user-friendly error message if the data is not a DataFrame
@@ -141,10 +141,10 @@ class ServerVariable(AnyVariable):
141
141
 
142
142
  def __init__(
143
143
  self,
144
- default: Optional[Any] = None,
145
- backend: Optional[ServerBackend] = None,
144
+ default: Any | None = None,
145
+ backend: ServerBackend | None = None,
146
146
  scope: Literal['user', 'global'] = 'global',
147
- uid: Optional[str] = None,
147
+ uid: str | None = None,
148
148
  **kwargs,
149
149
  ) -> None:
150
150
  from dara.core.internal.registries import server_variable_registry
@@ -192,8 +192,8 @@ class ServerVariable(AnyVariable):
192
192
  async def get_tabular_data(
193
193
  cls,
194
194
  entry: 'ServerVariableRegistryEntry',
195
- filters: Optional[FilterQuery] = None,
196
- pagination: Optional[Pagination] = None,
195
+ filters: FilterQuery | None = None,
196
+ pagination: Pagination | None = None,
197
197
  ) -> DataResponse:
198
198
  """
199
199
  Internal method to get tabular data from the backend
@@ -294,9 +294,7 @@ class ServerVariable(AnyVariable):
294
294
  await self._notify(self.uid, self.key, self.backend)
295
295
  return value
296
296
 
297
- async def read_filtered(
298
- self, filters: Optional[Union[FilterQuery, dict]] = None, pagination: Optional[Pagination] = None
299
- ):
297
+ async def read_filtered(self, filters: FilterQuery | dict | None = None, pagination: Pagination | None = None):
300
298
  """
301
299
  Read a filtered value from the backend.
302
300
  Depending on the scope, the value will be global or user-specific.
@@ -17,10 +17,9 @@ limitations under the License.
17
17
 
18
18
  from __future__ import annotations
19
19
 
20
- from typing import TYPE_CHECKING, Optional
20
+ from typing import TYPE_CHECKING, Literal
21
21
 
22
22
  from pydantic import SerializerFunctionWrapHandler, model_serializer
23
- from typing_extensions import Literal
24
23
 
25
24
  from dara.core.interactivity.client_variable import ClientVariable
26
25
 
@@ -38,14 +37,14 @@ class StateVariable(ClientVariable):
38
37
  like loading state, error state, etc.
39
38
  """
40
39
 
41
- parent_variable: 'DerivedVariable'
40
+ parent_variable: DerivedVariable
42
41
  property_name: Literal['loading', 'error', 'hasValue']
43
42
 
44
43
  def __init__(
45
44
  self,
46
- parent_variable: 'DerivedVariable',
45
+ parent_variable: DerivedVariable,
47
46
  property_name: Literal['loading', 'error', 'hasValue'],
48
- uid: Optional[str] = None,
47
+ uid: str | None = None,
49
48
  **kwargs,
50
49
  ):
51
50
  """
@@ -17,7 +17,7 @@ limitations under the License.
17
17
 
18
18
  from __future__ import annotations
19
19
 
20
- from typing import Any, Dict, Optional, Union
20
+ from typing import Any
21
21
 
22
22
  from pydantic import SerializerFunctionWrapHandler, field_validator, model_serializer
23
23
 
@@ -222,17 +222,17 @@ class SwitchVariable(ClientVariable):
222
222
  - Other values use standard string conversion to match JavaScript's String() behavior
223
223
  """
224
224
 
225
- value: Optional[Union[Condition, ClientVariable, Any]] = None
225
+ value: Condition | ClientVariable | Any | None = None
226
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
227
+ value_map: Any | None = None
228
+ default: Any | None = None
229
229
 
230
230
  def __init__(
231
231
  self,
232
- value: Union[Condition, ClientVariable, Any],
233
- value_map: Dict[Any, Any] | ClientVariable,
234
- default: Optional[Any] = None,
235
- uid: Optional[str] = None,
232
+ value: Condition | ClientVariable | Any,
233
+ value_map: dict[Any, Any] | ClientVariable,
234
+ default: Any | None = None,
235
+ uid: str | None = None,
236
236
  ):
237
237
  """
238
238
  Create a SwitchVariable with a mapping of values.
@@ -270,10 +270,10 @@ class SwitchVariable(ClientVariable):
270
270
  @classmethod
271
271
  def when(
272
272
  cls,
273
- condition: Union[Condition, ClientVariable, Any],
274
- true_value: Union[Any, ClientVariable],
275
- false_value: Union[Any, ClientVariable],
276
- uid: Optional[str] = None,
273
+ condition: Condition | ClientVariable | Any,
274
+ true_value: Any | ClientVariable,
275
+ false_value: Any | ClientVariable,
276
+ uid: str | None = None,
277
277
  ) -> SwitchVariable:
278
278
  """
279
279
  Create a SwitchVariable for boolean conditions.
@@ -346,10 +346,10 @@ class SwitchVariable(ClientVariable):
346
346
  @classmethod
347
347
  def match(
348
348
  cls,
349
- value: Union[ClientVariable, Any],
350
- mapping: Union[Dict[Any, Any], ClientVariable],
351
- default: Optional[Union[Any, ClientVariable]] = None,
352
- uid: Optional[str] = None,
349
+ value: ClientVariable | Any,
350
+ mapping: dict[Any, Any] | ClientVariable,
351
+ default: Any | ClientVariable | None = None,
352
+ uid: str | None = None,
353
353
  ) -> SwitchVariable:
354
354
  """
355
355
  Create a SwitchVariable with a custom mapping.
@@ -17,7 +17,7 @@ limitations under the License.
17
17
 
18
18
  import io
19
19
  import os
20
- from typing import Literal, Optional, TypedDict, Union, cast
20
+ from typing import Literal, TypedDict, cast
21
21
 
22
22
  import pandas
23
23
  from fastapi import UploadFile
@@ -28,7 +28,7 @@ from dara.core.internal.utils import run_user_handler
28
28
 
29
29
 
30
30
  class FieldType(TypedDict):
31
- name: Union[str, tuple[str, ...]]
31
+ name: str | tuple[str, ...]
32
32
  type: Literal['integer', 'number', 'boolean', 'datetime', 'duration', 'any', 'str']
33
33
 
34
34
 
@@ -37,7 +37,7 @@ class DataFrameSchema(TypedDict):
37
37
  primaryKey: list[str]
38
38
 
39
39
 
40
- async def upload(data: UploadFile, data_uid: Optional[str] = None, resolver_id: Optional[str] = None):
40
+ async def upload(data: UploadFile, data_uid: str | None = None, resolver_id: str | None = None):
41
41
  """
42
42
  Handler for uploading data.
43
43
 
@@ -17,7 +17,7 @@ limitations under the License.
17
17
 
18
18
  from __future__ import annotations
19
19
 
20
- from typing import Optional, TypeVar
20
+ from typing import TypeVar
21
21
 
22
22
  from pydantic import ConfigDict
23
23
  from typing_extensions import deprecated
@@ -38,12 +38,12 @@ class UrlVariable(Variable[VariableType]):
38
38
  pages as you switch from one to the other.
39
39
  """
40
40
 
41
- default: Optional[VariableType] = None
41
+ default: VariableType | None = None
42
42
  query: str
43
43
  uid: str
44
44
  model_config = ConfigDict(extra='forbid')
45
45
 
46
- def __init__(self, query: str, default: Optional[VariableType] = None, uid: Optional[str] = None):
46
+ def __init__(self, query: str, default: VariableType | None = None, uid: str | None = None):
47
47
  """
48
48
  A UrlVariable is very similar to a normal Variable however rather than it's state being stored in the memory of
49
49
  the client it's value is stored in the url of page as a query parameter. This is very useful for parameterizing
@@ -1,4 +1,4 @@
1
- from typing import Any, Dict, Generic, Optional, cast
1
+ from typing import Any, Generic, cast
2
2
 
3
3
  from dara.core.base_definitions import (
4
4
  CachedRegistryEntry,
@@ -20,7 +20,7 @@ def cache_impl_for_policy(policy: PolicyT) -> CacheStoreImpl[PolicyT]:
20
20
  """
21
21
  Get a cache implementation depending on the policy
22
22
  """
23
- impl: Optional[CacheStoreImpl] = None
23
+ impl: CacheStoreImpl | None = None
24
24
 
25
25
  if isinstance(policy, (LruCachePolicy, MostRecentCachePolicy)):
26
26
  impl = LRUCache(policy)
@@ -43,7 +43,7 @@ class CacheScopeStore(Generic[PolicyT]):
43
43
  """
44
44
 
45
45
  def __init__(self, policy: PolicyT):
46
- self.caches: Dict[CacheScope, CacheStoreImpl[PolicyT]] = {}
46
+ self.caches: dict[CacheScope, CacheStoreImpl[PolicyT]] = {}
47
47
  self.policy = policy
48
48
 
49
49
  async def delete(self, key: str) -> Any:
@@ -61,7 +61,7 @@ class CacheScopeStore(Generic[PolicyT]):
61
61
 
62
62
  return await cache.delete(key)
63
63
 
64
- async def get(self, key: str, unpin: bool = False, raise_for_missing: bool = False) -> Optional[Any]:
64
+ async def get(self, key: str, unpin: bool = False, raise_for_missing: bool = False) -> Any | None:
65
65
  """
66
66
  Retrieve an entry from the cache.
67
67
 
@@ -115,7 +115,7 @@ class CacheStore:
115
115
  """
116
116
 
117
117
  def __init__(self):
118
- self.registry_stores: Dict[str, CacheScopeStore] = {}
118
+ self.registry_stores: dict[str, CacheScopeStore] = {}
119
119
  # The size is not totally accurate as we only add/subtract values stored, without accounting for keys
120
120
  # or extra memory due to hash collisions, internal cache implementation; its a 'good enough' approximation
121
121
  # of just the values stored
@@ -158,7 +158,7 @@ class CacheStore:
158
158
  key: str,
159
159
  unpin: bool = False,
160
160
  raise_for_missing: bool = False,
161
- ) -> Optional[Any]:
161
+ ) -> Any | None:
162
162
  """
163
163
  Retrieve an entry from the cache for the given registry entry and cache key.
164
164
 
@@ -1,4 +1,4 @@
1
- from typing import Any, Dict, Optional
1
+ from typing import Any
2
2
 
3
3
  import anyio
4
4
 
@@ -23,7 +23,7 @@ class KeepAllCache(CacheStoreImpl[KeepAllCachePolicy]):
23
23
 
24
24
  def __init__(self, policy: KeepAllCachePolicy):
25
25
  super().__init__(policy)
26
- self.cache: Dict[str, Any] = {}
26
+ self.cache: dict[str, Any] = {}
27
27
  self.lock = anyio.Lock()
28
28
 
29
29
  async def delete(self, key: str) -> Any:
@@ -42,7 +42,7 @@ class KeepAllCache(CacheStoreImpl[KeepAllCachePolicy]):
42
42
  del self.cache[key]
43
43
  return entry
44
44
 
45
- async def get(self, key: str, unpin: bool = False, raise_for_missing: bool = False) -> Optional[Any]:
45
+ async def get(self, key: str, unpin: bool = False, raise_for_missing: bool = False) -> Any | None:
46
46
  """
47
47
  Retrieve a value from the cache.
48
48
 
@@ -1,4 +1,4 @@
1
- from typing import Any, Dict, Optional
1
+ from typing import Any
2
2
 
3
3
  import anyio
4
4
 
@@ -20,8 +20,8 @@ class Node:
20
20
  self.key = key
21
21
  self.value = value
22
22
  self.pin = pin
23
- self.prev: Optional[Node] = None
24
- self.next: Optional[Node] = None
23
+ self.prev: Node | None = None
24
+ self.next: Node | None = None
25
25
 
26
26
  def __repr__(self) -> str:
27
27
  return f'Node({self.key}, {self.value}, {self.pin})'
@@ -35,9 +35,9 @@ class LRUCache(CacheStoreImpl[LruCachePolicy]):
35
35
 
36
36
  def __init__(self, policy: LruCachePolicy):
37
37
  super().__init__(policy)
38
- self.cache: Dict[str, Node] = {}
39
- self.head: Optional[Node] = None # No sentinel, can be None
40
- self.tail: Optional[Node] = None # No sentinel, can be None
38
+ self.cache: dict[str, Node] = {}
39
+ self.head: Node | None = None # No sentinel, can be None
40
+ self.tail: Node | None = None # No sentinel, can be None
41
41
  self.lock = anyio.Lock()
42
42
 
43
43
  def _move_to_front(self, node: Node):
@@ -88,7 +88,7 @@ class LRUCache(CacheStoreImpl[LruCachePolicy]):
88
88
  self.cache.pop(key, None)
89
89
  return node.value
90
90
 
91
- async def get(self, key: str, unpin: bool = False, raise_for_missing: bool = False) -> Optional[Any]:
91
+ async def get(self, key: str, unpin: bool = False, raise_for_missing: bool = False) -> Any | None:
92
92
  """
93
93
  Retrieve a value from the cache.
94
94
 
@@ -136,7 +136,7 @@ class LRUCache(CacheStoreImpl[LruCachePolicy]):
136
136
 
137
137
  # Check and perform eviction
138
138
  while len(self.cache) > self.policy.max_size:
139
- evict_node: Optional[Node] = self.tail
139
+ evict_node: Node | None = self.tail
140
140
 
141
141
  # Skip over pinned nodes
142
142
  while evict_node and evict_node.pin:
@@ -1,6 +1,6 @@
1
1
  import heapq
2
2
  import time
3
- from typing import Any, Dict, List, Tuple
3
+ from typing import Any
4
4
 
5
5
  import anyio
6
6
 
@@ -38,9 +38,9 @@ class TTLCache(CacheStoreImpl[TTLCachePolicy]):
38
38
 
39
39
  def __init__(self, policy: TTLCachePolicy):
40
40
  super().__init__(policy)
41
- self.pinned_cache: Dict[str, Node] = {}
42
- self.unpinned_cache: Dict[str, Node] = {}
43
- self.expiration_heap: List[Tuple[float, str]] = [] # Stores (expiration_time, key) for unpinned items
41
+ self.pinned_cache: dict[str, Node] = {}
42
+ self.unpinned_cache: dict[str, Node] = {}
43
+ self.expiration_heap: list[tuple[float, str]] = [] # Stores (expiration_time, key) for unpinned items
44
44
  self.lock = anyio.Lock()
45
45
 
46
46
  async def _cleanup(self):
@@ -16,9 +16,9 @@ class CustomResponse(Response):
16
16
  self,
17
17
  content: typing.Any,
18
18
  status_code: int = 200,
19
- headers: typing.Optional[typing.Dict[str, str]] = None,
20
- media_type: typing.Optional[str] = None,
21
- background: typing.Optional[BackgroundTask] = None,
19
+ headers: dict[str, str] | None = None,
20
+ media_type: str | None = None,
21
+ background: BackgroundTask | None = None,
22
22
  ) -> None:
23
23
  super().__init__(content, status_code, headers, media_type, background)
24
24