dara-core 1.15.7__py3-none-any.whl → 1.16.0a1__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 (49) hide show
  1. dara/core/__init__.py +16 -27
  2. dara/core/auth/base.py +3 -2
  3. dara/core/auth/definitions.py +0 -3
  4. dara/core/auth/utils.py +1 -1
  5. dara/core/base_definitions.py +122 -65
  6. dara/core/configuration.py +5 -8
  7. dara/core/defaults.py +0 -3
  8. dara/core/definitions.py +95 -231
  9. dara/core/interactivity/__init__.py +12 -18
  10. dara/core/interactivity/actions.py +22 -19
  11. dara/core/interactivity/any_data_variable.py +2 -4
  12. dara/core/interactivity/any_variable.py +10 -2
  13. dara/core/interactivity/condition.py +7 -10
  14. dara/core/interactivity/data_variable.py +11 -12
  15. dara/core/interactivity/derived_data_variable.py +7 -7
  16. dara/core/interactivity/derived_variable.py +20 -17
  17. dara/core/interactivity/filtering.py +1 -1
  18. dara/core/interactivity/plain_variable.py +10 -6
  19. dara/core/interactivity/url_variable.py +7 -6
  20. dara/core/internal/download.py +1 -1
  21. dara/core/internal/hashing.py +1 -1
  22. dara/core/internal/normalization.py +0 -24
  23. dara/core/internal/routing.py +10 -10
  24. dara/core/internal/scheduler.py +3 -2
  25. dara/core/internal/settings.py +2 -4
  26. dara/core/internal/store.py +0 -3
  27. dara/core/internal/tasks.py +2 -2
  28. dara/core/internal/websocket.py +29 -20
  29. dara/core/js_tooling/js_utils.py +1 -1
  30. dara/core/main.py +2 -2
  31. dara/core/persistence.py +12 -4
  32. dara/core/umd/dara.core.umd.js +13 -277
  33. dara/core/visual/components/__init__.py +0 -3
  34. dara/core/visual/components/fallback.py +3 -3
  35. dara/core/visual/components/invalid_component.py +3 -3
  36. dara/core/visual/components/menu.py +3 -3
  37. dara/core/visual/components/progress_tracker.py +3 -2
  38. dara/core/visual/components/raw_string.py +3 -3
  39. dara/core/visual/components/router_content.py +3 -3
  40. dara/core/visual/components/sidebar_frame.py +3 -3
  41. dara/core/visual/components/topbar_frame.py +3 -3
  42. dara/core/visual/css/__init__.py +2 -6
  43. dara/core/visual/dynamic_component.py +3 -6
  44. {dara_core-1.15.7.dist-info → dara_core-1.16.0a1.dist-info}/METADATA +13 -12
  45. {dara_core-1.15.7.dist-info → dara_core-1.16.0a1.dist-info}/RECORD +48 -49
  46. dara/core/visual/components/for_cmp.py +0 -150
  47. {dara_core-1.15.7.dist-info → dara_core-1.16.0a1.dist-info}/LICENSE +0 -0
  48. {dara_core-1.15.7.dist-info → dara_core-1.16.0a1.dist-info}/WHEEL +0 -0
  49. {dara_core-1.15.7.dist-info → dara_core-1.16.0a1.dist-info}/entry_points.txt +0 -0
@@ -35,13 +35,14 @@ from typing import (
35
35
  Optional,
36
36
  TypeVar,
37
37
  Union,
38
+ cast,
38
39
  overload,
39
40
  )
40
41
 
41
42
  import anyio
42
43
  from anyio.streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream
43
44
  from pandas import DataFrame
44
- from pydantic import BaseModel
45
+ from pydantic import BaseModel, ConfigDict
45
46
  from typing_extensions import deprecated
46
47
 
47
48
  from dara.core.base_definitions import (
@@ -49,7 +50,6 @@ from dara.core.base_definitions import (
49
50
  ActionImpl,
50
51
  ActionResolverDef,
51
52
  AnnotatedAction,
52
- TemplateMarker,
53
53
  )
54
54
  from dara.core.interactivity.data_variable import DataVariable
55
55
  from dara.core.internal.download import generate_download_code
@@ -72,8 +72,7 @@ class ActionInputs(BaseModel):
72
72
  Base class for all action inputs
73
73
  """
74
74
 
75
- class Config:
76
- extra = 'allow'
75
+ model_config = ConfigDict(extra='allow')
77
76
 
78
77
 
79
78
  class ActionContext(BaseModel):
@@ -96,7 +95,7 @@ class ComponentActionContext(ActionContext):
96
95
  ActionContext for actions that only require component value
97
96
  """
98
97
 
99
- inputs: ComponentActionInputs
98
+ inputs: ComponentActionInputs # type: ignore
100
99
 
101
100
 
102
101
  class UpdateVariableImpl(ActionImpl):
@@ -161,7 +160,7 @@ class UpdateVariableInputs(ActionInputs):
161
160
 
162
161
 
163
162
  class UpdateVariableContext(ActionContext):
164
- inputs: UpdateVariableInputs
163
+ inputs: UpdateVariableInputs # type: ignore
165
164
 
166
165
 
167
166
  @deprecated('Use @action or `UpdateVariableImpl` for simple cases')
@@ -236,16 +235,16 @@ class UpdateVariable(AnnotatedAction):
236
235
  ```
237
236
  """
238
237
 
239
- Ctx = UpdateVariableContext
238
+ Ctx: ClassVar[type[UpdateVariableContext]] = UpdateVariableContext
240
239
 
241
240
  variable: Union[Variable, DataVariable, UrlVariable]
242
- extras: Optional[List[Union[AnyVariable, TemplateMarker]]]
241
+ extras: Optional[List[AnyVariable]]
243
242
 
244
243
  def __init__(
245
244
  self,
246
245
  resolver: Callable[[UpdateVariableContext], Any],
247
246
  variable: Union[Variable, DataVariable, UrlVariable],
248
- extras: Optional[List[Union[AnyVariable, TemplateMarker]]] = None,
247
+ extras: Optional[List[AnyVariable]] = None,
249
248
  ):
250
249
  """
251
250
  :param resolver: a function to resolve the new value for the variable. Takes one arguments: containing a context of type `Updatevariable.Ctx`
@@ -253,7 +252,8 @@ class UpdateVariable(AnnotatedAction):
253
252
  :param extras: any extra variables to resolve and pass to the resolution function context
254
253
  """
255
254
 
256
- async def _update(ctx: action.Ctx, **kwargs):
255
+ async def _update(ctx: action.Ctx, **kwargs): # type: ignore
256
+ ctx = cast(ActionCtx, ctx) # type: ignore
257
257
  old = kwargs.pop('old')
258
258
  extras = [kwargs[f'kwarg_{idx}'] for idx in range(len(kwargs))]
259
259
  old_ctx = UpdateVariableContext(inputs=UpdateVariableInputs(old=old, new=ctx.input), extras=extras)
@@ -371,7 +371,7 @@ class NavigateToImpl(ActionImpl):
371
371
 
372
372
  py_name = 'NavigateTo'
373
373
 
374
- url: Optional[str]
374
+ url: Optional[str] = None
375
375
  new_tab: bool
376
376
 
377
377
 
@@ -426,7 +426,8 @@ def NavigateTo(
426
426
  return NavigateToImpl(url=url, new_tab=new_tab)
427
427
 
428
428
  # Otherwise create a new @action with the provided resolver
429
- async def _navigate(ctx: action.Ctx, **kwargs):
429
+ async def _navigate(ctx: action.Ctx, **kwargs): # type: ignore
430
+ ctx = cast(ActionCtx, ctx) # type: ignore
430
431
  extras = [kwargs[f'kwarg_{idx}'] for idx in range(len(kwargs))]
431
432
  old_ctx = ComponentActionContext(inputs=ComponentActionInputs(value=ctx.input), extras=extras)
432
433
  result = await run_user_handler(url, args=(old_ctx,)) # type: ignore
@@ -573,8 +574,8 @@ class Notify(ActionImpl):
573
574
  status: NotificationStatus
574
575
  title: str
575
576
 
576
- Status = NotificationStatus
577
- Ctx = ComponentActionContext
577
+ Status: ClassVar[type[NotificationStatus]] = NotificationStatus
578
+ Ctx: ClassVar[type[ComponentActionContext]] = ComponentActionContext
578
579
  """@deprecated retained for backwards compatibility, to be removed in 2.0"""
579
580
 
580
581
 
@@ -660,7 +661,8 @@ def DownloadContent(
660
661
  ```
661
662
  """
662
663
 
663
- async def _download(ctx: action.Ctx, **kwargs):
664
+ async def _download(ctx: action.Ctx, **kwargs): # type: ignore
665
+ ctx = cast(ActionCtx, ctx) # type: ignore
664
666
  extras = [kwargs[f'kwarg_{idx}'] for idx in range(len(kwargs))]
665
667
  old_ctx = ComponentActionContext(inputs=ComponentActionInputs(value=ctx.input), extras=extras)
666
668
  result = await run_user_handler(resolver, args=(old_ctx,))
@@ -725,7 +727,7 @@ class DownloadVariable(ActionImpl):
725
727
  @deprecated('Use @action instead')
726
728
  def SideEffect(
727
729
  function: Callable[[ComponentActionContext], Any],
728
- extras: Optional[List[Union[AnyVariable, TemplateMarker]]] = None,
730
+ extras: Optional[List[AnyVariable]] = None,
729
731
  block: bool = False,
730
732
  ):
731
733
  """
@@ -765,7 +767,8 @@ def SideEffect(
765
767
  ```
766
768
  """
767
769
 
768
- async def _effect(ctx: action.Ctx, **kwargs):
770
+ async def _effect(ctx: action.Ctx, **kwargs): # type: ignore
771
+ ctx = cast(ActionCtx, ctx) # type: ignore
769
772
  extras = [kwargs[f'kwarg_{idx}'] for idx in range(len(kwargs))]
770
773
  old_ctx = ComponentActionContext(inputs=ComponentActionInputs(value=ctx.input), extras=extras)
771
774
  # Simply run the user handler
@@ -1274,7 +1277,7 @@ class action:
1274
1277
  ```
1275
1278
  """
1276
1279
 
1277
- Ctx: ClassVar = ActionCtx
1280
+ Ctx: ClassVar[type[ActionContext]] = ActionContext
1278
1281
 
1279
1282
  def __init__(self, func: Callable[..., Any]):
1280
1283
  from dara.core.internal.execute_action import execute_action
@@ -1337,7 +1340,7 @@ class action:
1337
1340
  ...
1338
1341
 
1339
1342
  @overload
1340
- def __call__(self, *args: Any, **kwargs: Any) -> AnnotatedAction:
1343
+ def __call__(self, *args: Any, **kwargs: Any) -> AnnotatedAction: # type: ignore
1341
1344
  ...
1342
1345
 
1343
1346
  def __call__(self, *args, **kwargs) -> Union[AnnotatedAction, Any]:
@@ -22,6 +22,7 @@ from typing import Any, Awaitable, Callable, Literal, Optional, TypedDict, Union
22
22
 
23
23
  import pandas
24
24
  from fastapi import UploadFile
25
+ from pydantic import ConfigDict
25
26
 
26
27
  from dara.core.base_definitions import CachedRegistryEntry, UploadResolverDef
27
28
  from dara.core.interactivity.any_variable import AnyVariable
@@ -73,10 +74,7 @@ class DataVariableRegistryEntry(CachedRegistryEntry):
73
74
 
74
75
  get_schema: Callable[..., Awaitable[DataFrameSchema]]
75
76
  """Handler to get the schema for data variable. Defaults to DataVariable.get_schema for type=plain, and DerivedDataVariable.get_schema for type=derived"""
76
-
77
- class Config:
78
- extra = 'forbid'
79
- arbitrary_types_allowed = True
77
+ model_config = ConfigDict(extra='forbid', arbitrary_types_allowed=True)
80
78
 
81
79
 
82
80
  async def upload(data: UploadFile, data_uid: Optional[str] = None, resolver_id: Optional[str] = None):
@@ -27,10 +27,12 @@ from typing import Any, Callable, Dict, Optional, Set
27
27
 
28
28
  import anyio
29
29
  from fastapi.encoders import jsonable_encoder
30
- from pydantic import BaseModel
30
+ from pydantic import ConfigDict
31
31
 
32
32
  from dara.core.auth.definitions import SESSION_ID, USER, UserData
33
- from dara.core.base_definitions import BaseTask, PendingTask
33
+ from dara.core.base_definitions import BaseTask
34
+ from dara.core.base_definitions import DaraBaseModel as BaseModel
35
+ from dara.core.base_definitions import PendingTask
34
36
  from dara.core.interactivity.condition import Condition, Operator
35
37
  from dara.core.internal.cache_store import CacheStore
36
38
  from dara.core.internal.tasks import TaskManager
@@ -275,6 +277,8 @@ class AnyVariable(BaseModel, abc.ABC):
275
277
  Base class for all variables. Used for typing to specify that any variable can be provided.
276
278
  """
277
279
 
280
+ model_config = ConfigDict(arbitrary_types_allowed=True)
281
+
278
282
  uid: str
279
283
 
280
284
  def __init__(self, uid: Optional[str] = None, **kwargs) -> None:
@@ -328,6 +332,10 @@ class AnyVariable(BaseModel, abc.ABC):
328
332
  assert_no_context('ctx.reset')
329
333
  return ResetVariables(variables=[self])
330
334
 
335
+ @classmethod
336
+ def isinstance(cls, obj: Any) -> bool:
337
+ return isinstance(obj, cls)
338
+
331
339
  async def get_current_value(self, timeout: float = 3) -> Any:
332
340
  """
333
341
  Retrieve the current value of the variable for the current user
@@ -18,11 +18,9 @@ limitations under the License.
18
18
  from __future__ import annotations
19
19
 
20
20
  from enum import Enum
21
- from typing import TYPE_CHECKING, Union
21
+ from typing import TYPE_CHECKING, ClassVar, Union
22
22
 
23
- from pydantic import BaseModel
24
-
25
- from dara.core.base_definitions import TemplateMarker
23
+ from dara.core.base_definitions import DaraBaseModel as BaseModel
26
24
 
27
25
  # Type-only imports
28
26
  if TYPE_CHECKING:
@@ -39,13 +37,12 @@ class Operator(Enum):
39
37
  TRUTHY = 'truthy'
40
38
 
41
39
 
40
+ OperatorType = type[Operator]
41
+
42
+
42
43
  class Condition(BaseModel):
43
44
  operator: Operator
44
45
  other: Union[BaseModel, int, float, str, bool, None, AnyVariable]
45
- variable: Union[AnyVariable, TemplateMarker]
46
-
47
- Operator = Operator
46
+ variable: AnyVariable
48
47
 
49
- class Config:
50
- # This makes it properly check the union type rather than coercing to variable type
51
- smart_union = True
48
+ Operator: ClassVar[OperatorType] = Operator
@@ -23,7 +23,12 @@ from typing import Optional, Union, cast
23
23
  from anyio.abc import TaskGroup
24
24
  from pandas import DataFrame
25
25
  from pandas.io.json._table_schema import build_table_schema
26
- from pydantic import BaseModel
26
+ from pydantic import (
27
+ BaseModel,
28
+ ConfigDict,
29
+ SerializerFunctionWrapHandler,
30
+ model_serializer,
31
+ )
27
32
 
28
33
  from dara.core.base_definitions import BaseCachePolicy, Cache, CacheArgType
29
34
  from dara.core.interactivity.any_data_variable import (
@@ -67,11 +72,7 @@ class DataVariable(AnyDataVariable):
67
72
  uid: str
68
73
  filters: Optional[FilterQuery] = None
69
74
  cache: Optional[BaseCachePolicy] = None
70
-
71
- class Config:
72
- extra = 'forbid'
73
- arbitrary_types_allowed = True
74
- use_enum_values = True
75
+ model_config = ConfigDict(extra='forbid', arbitrary_types_allowed=True, use_enum_values=True)
75
76
 
76
77
  def __init__(
77
78
  self,
@@ -304,8 +305,9 @@ class DataVariable(AnyDataVariable):
304
305
 
305
306
  return UpdateVariableImpl(variable=self, value=value)
306
307
 
307
- def dict(self, *args, **kwargs):
308
- parent_dict = super().dict(*args, **kwargs)
308
+ @model_serializer(mode='wrap')
309
+ def ser_model(self, nxt: SerializerFunctionWrapHandler) -> dict:
310
+ parent_dict = nxt(self)
309
311
  if 'data' in parent_dict:
310
312
  parent_dict.pop('data') # make sure data is not included in the serialised dict
311
313
  return {**parent_dict, '__typename': 'DataVariable', 'uid': str(parent_dict['uid'])}
@@ -319,7 +321,4 @@ class DataStoreEntry(BaseModel):
319
321
 
320
322
  data: Optional[DataFrame] = None
321
323
  path: Optional[str] = None
322
-
323
- class Config:
324
- extra = 'forbid'
325
- arbitrary_types_allowed = True
324
+ model_config = ConfigDict(extra='forbid', arbitrary_types_allowed=True)
@@ -23,6 +23,7 @@ from uuid import uuid4
23
23
 
24
24
  from pandas import DataFrame
25
25
  from pandas.io.json._table_schema import build_table_schema
26
+ from pydantic import ConfigDict, SerializerFunctionWrapHandler, model_serializer
26
27
 
27
28
  from dara.core.base_definitions import (
28
29
  BaseTask,
@@ -66,11 +67,9 @@ class DerivedDataVariable(AnyDataVariable, DerivedVariable):
66
67
  uid: str
67
68
  filters: Optional[FilterQuery] = None
68
69
  variables: List[AnyVariable]
69
- polling_interval: Optional[int]
70
- deps: Optional[List[AnyVariable]]
71
-
72
- class Config:
73
- extra = 'forbid'
70
+ polling_interval: Optional[int] = None
71
+ deps: Optional[List[AnyVariable]] = None
72
+ model_config = ConfigDict(extra='forbid')
74
73
 
75
74
  def __init__(
76
75
  self,
@@ -365,8 +364,9 @@ class DerivedDataVariable(AnyDataVariable, DerivedVariable):
365
364
 
366
365
  return await cls.get_data(dv_entry, data_entry, dv_result['cache_key'], store, filters)
367
366
 
368
- def dict(self, *args, **kwargs):
369
- parent_dict = super().dict(*args, **kwargs)
367
+ @model_serializer(mode='wrap')
368
+ def ser_model(self, nxt: SerializerFunctionWrapHandler) -> dict:
369
+ parent_dict = nxt(self)
370
370
  # nested is not supported for DerivedDataVariable so remove from serialised form
371
371
  # it's included because we inherit from DV which has the field
372
372
  parent_dict.pop('nested')
@@ -24,15 +24,22 @@ from typing import (
24
24
  Any,
25
25
  Awaitable,
26
26
  Callable,
27
- Dict,
28
27
  Generic,
29
28
  List,
30
29
  Optional,
31
30
  TypeVar,
32
31
  Union,
32
+ cast,
33
33
  )
34
34
 
35
- from pydantic import validator
35
+ from pydantic import (
36
+ ConfigDict,
37
+ Field,
38
+ SerializerFunctionWrapHandler,
39
+ ValidationInfo,
40
+ field_validator,
41
+ model_serializer,
42
+ )
36
43
  from typing_extensions import TypedDict
37
44
 
38
45
  from dara.core.base_definitions import (
@@ -76,13 +83,10 @@ class DerivedVariable(NonDataVariable, Generic[VariableType]):
76
83
  cache: Optional[BaseCachePolicy]
77
84
  variables: List[AnyVariable]
78
85
  polling_interval: Optional[int]
79
- deps: Optional[List[AnyVariable]]
86
+ deps: Optional[List[AnyVariable]] = Field(validate_default=True)
80
87
  nested: List[str] = []
81
88
  uid: str
82
-
83
- class Config:
84
- extra = 'forbid'
85
- use_enum_values = True
89
+ model_config = ConfigDict(extra='forbid', use_enum_values=True)
86
90
 
87
91
  def __init__(
88
92
  self,
@@ -130,7 +134,7 @@ class DerivedVariable(NonDataVariable, Generic[VariableType]):
130
134
  # Explicitly disallow run_as_task within a Jupyter environment
131
135
  if run_as_task:
132
136
  try:
133
- from IPython import get_ipython
137
+ from IPython import get_ipython # type: ignore
134
138
  except ImportError:
135
139
  pass
136
140
  else:
@@ -164,20 +168,20 @@ class DerivedVariable(NonDataVariable, Generic[VariableType]):
164
168
  ),
165
169
  )
166
170
 
167
- @validator('deps', pre=True, always=True)
171
+ @field_validator('deps', mode='before')
168
172
  @classmethod
169
- def validate_deps(cls, deps: Any, values: Dict) -> List[AnyVariable]:
173
+ def validate_deps(cls, deps: Any, info: ValidationInfo) -> List[AnyVariable]:
170
174
  """
171
175
  If deps is not specified, set deps to include all variables used
172
176
  """
173
177
  if deps is None:
174
178
  # This will always be set on the variable with the type verified by pydantic
175
- return values.get('variables') # type: ignore
179
+ return cast(List[AnyVariable], info.data.get('variables'))
176
180
 
177
181
  return deps
178
182
 
179
183
  def get(self, key: str):
180
- return self.copy(update={'nested': [*self.nested, key]}, deep=True)
184
+ return self.model_copy(update={'nested': [*self.nested, key]}, deep=True)
181
185
 
182
186
  def trigger(self, force: bool = True):
183
187
  """
@@ -479,8 +483,9 @@ class DerivedVariable(NonDataVariable, Generic[VariableType]):
479
483
  return True
480
484
  return False
481
485
 
482
- def dict(self, *args, **kwargs):
483
- parent_dict = super().dict(*args, **kwargs)
486
+ @model_serializer(mode='wrap')
487
+ def ser_model(self, nxt: SerializerFunctionWrapHandler) -> dict:
488
+ parent_dict = nxt(self)
484
489
  return {**parent_dict, '__typename': 'DerivedVariable', 'uid': str(parent_dict['uid'])}
485
490
 
486
491
 
@@ -492,9 +497,7 @@ class DerivedVariableRegistryEntry(CachedRegistryEntry):
492
497
  polling_interval: Optional[int]
493
498
  get_value: Callable[..., Awaitable[Any]]
494
499
  """Handler to get the value of the derived variable. Defaults to DerivedVariable.get_value, should match the signature"""
495
-
496
- class Config:
497
- extra = 'forbid'
500
+ model_config = ConfigDict(extra='forbid')
498
501
 
499
502
 
500
503
  class LatestValueRegistryEntry(CachedRegistryEntry):
@@ -86,7 +86,7 @@ FilterQuery = Union[ClauseQuery, ValueQuery]
86
86
  Filter query to be applied
87
87
  """
88
88
 
89
- ClauseQuery.update_forward_refs()
89
+ ClauseQuery.model_rebuild()
90
90
 
91
91
 
92
92
  def coerce_to_filter_query(filters: Union[ClauseQuery, ValueQuery, dict, None]) -> Optional[FilterQuery]:
@@ -21,6 +21,8 @@ from contextlib import contextmanager
21
21
  from contextvars import ContextVar
22
22
  from typing import Any, Callable, Generic, List, Optional, TypeVar
23
23
 
24
+ from pydantic import ConfigDict, SerializerFunctionWrapHandler, model_serializer
25
+
24
26
  from dara.core.interactivity.derived_data_variable import DerivedDataVariable
25
27
  from dara.core.interactivity.derived_variable import DerivedVariable
26
28
  from dara.core.interactivity.non_data_variable import NonDataVariable
@@ -38,14 +40,12 @@ class Variable(NonDataVariable, Generic[VariableType]):
38
40
  A Variable represents a dynamic value in the system that can be read and written to by components and actions
39
41
  """
40
42
 
41
- default: Optional[VariableType]
43
+ default: Optional[VariableType] = None
42
44
  persist_value: bool = False
43
45
  store: Optional[PersistenceStore] = None
44
46
  uid: str
45
47
  nested: List[str] = []
46
-
47
- class Config:
48
- extra = 'forbid'
48
+ model_config = ConfigDict(extra='forbid')
49
49
 
50
50
  def __init__(
51
51
  self,
@@ -53,6 +53,7 @@ class Variable(NonDataVariable, Generic[VariableType]):
53
53
  persist_value: Optional[bool] = False,
54
54
  uid: Optional[str] = None,
55
55
  store: Optional[PersistenceStoreType_co] = None,
56
+ nested: Optional[List[str]] = None,
56
57
  ):
57
58
  """
58
59
  A Variable represents a dynamic value in the system that can be read and written to by components and actions
@@ -62,6 +63,8 @@ class Variable(NonDataVariable, Generic[VariableType]):
62
63
  :param uid: the unique identifier for this variable; if not provided a random one is generated
63
64
  :param store: a persistence store to attach to the variable; modifies where the source of truth for the variable is
64
65
  """
66
+ if nested is None:
67
+ nested = []
65
68
  kwargs = {'default': default, 'persist_value': persist_value, 'uid': uid, 'store': store}
66
69
 
67
70
  # If an override is active, run the kwargs through it
@@ -229,7 +232,8 @@ class Variable(NonDataVariable, Generic[VariableType]):
229
232
 
230
233
  return cls(default=other) # type: ignore
231
234
 
232
- def dict(self, *args, **kwargs):
233
- parent_dict = super().dict(*args, **kwargs)
235
+ @model_serializer(mode='wrap')
236
+ def ser_model(self, nxt: SerializerFunctionWrapHandler) -> dict:
237
+ parent_dict = nxt(self)
234
238
 
235
239
  return {**parent_dict, '__typename': 'Variable', 'uid': str(parent_dict['uid'])}
@@ -19,6 +19,8 @@ from __future__ import annotations
19
19
 
20
20
  from typing import Any, Generic, Optional, TypeVar
21
21
 
22
+ from pydantic import ConfigDict, SerializerFunctionWrapHandler, model_serializer
23
+
22
24
  from dara.core.interactivity.non_data_variable import NonDataVariable
23
25
 
24
26
  VariableType = TypeVar('VariableType')
@@ -31,12 +33,10 @@ class UrlVariable(NonDataVariable, Generic[VariableType]):
31
33
  pages as you switch from one to the other.
32
34
  """
33
35
 
34
- default: Optional[VariableType]
36
+ default: Optional[VariableType] = None
35
37
  query: str
36
38
  uid: str
37
-
38
- class Config:
39
- extra = 'forbid'
39
+ model_config = ConfigDict(extra='forbid')
40
40
 
41
41
  def __init__(self, query: str, default: Optional[VariableType] = None, uid: Optional[str] = None):
42
42
  """
@@ -130,6 +130,7 @@ class UrlVariable(NonDataVariable, Generic[VariableType]):
130
130
  assert_no_context('ctx.update')
131
131
  return UpdateVariableImpl(variable=self, value=value)
132
132
 
133
- def dict(self, *args, **kwargs):
134
- parent_dict = super().dict(*args, **kwargs)
133
+ @model_serializer(mode='wrap')
134
+ def ser_model(self, nxt: SerializerFunctionWrapHandler) -> dict:
135
+ parent_dict = nxt(self)
135
136
  return {**parent_dict, '__typename': 'UrlVariable', 'uid': str(parent_dict['uid'])}
@@ -36,7 +36,7 @@ class DownloadDataEntry(BaseModel):
36
36
  uid: str
37
37
  file_path: str
38
38
  cleanup_file: bool
39
- identity_name: Optional[str]
39
+ identity_name: Optional[str] = None
40
40
  download: Callable[['DownloadDataEntry'], Awaitable[Tuple[anyio.AsyncFile, Callable[..., Awaitable]]]]
41
41
  """Handler for getting the file from the entry"""
42
42
 
@@ -29,7 +29,7 @@ def hash_object(obj: Union[BaseModel, dict, None]):
29
29
  :param object: object to create a hash for
30
30
  """
31
31
  if isinstance(obj, BaseModel):
32
- obj = obj.dict()
32
+ obj = obj.model_dump()
33
33
 
34
34
  filter_hash = hashlib.sha1(
35
35
  usedforsecurity=False
@@ -68,27 +68,6 @@ class ReferrableWithFilters(Referrable):
68
68
  filters: dict
69
69
 
70
70
 
71
- def _has_template_marker(obj: Any) -> bool:
72
- """
73
- Check if an object has a TemplateMarker
74
- anywhere in its data
75
- """
76
- if isinstance(obj, dict):
77
- if obj.get('__typename') == 'TemplateMarker':
78
- return True
79
-
80
- for val in obj.values():
81
- if _has_template_marker(val):
82
- return True
83
-
84
- if isinstance(obj, list):
85
- for item in obj:
86
- if _has_template_marker(item):
87
- return True
88
-
89
- return False
90
-
91
-
92
71
  def _get_identifier(obj: Referrable) -> str:
93
72
  """
94
73
  Get a unique identifier from a 'referrable' object
@@ -112,15 +91,12 @@ def _get_identifier(obj: Referrable) -> str:
112
91
  def _is_referrable(obj: Any) -> TypeGuard[Referrable]:
113
92
  """
114
93
  Check if a dict is a Referrable type with a '__typename' field and 'uid'
115
-
116
- Bails out if the object has a TemplateMarker
117
94
  """
118
95
  return (
119
96
  isinstance(obj, dict)
120
97
  and '__typename' in obj
121
98
  and 'Variable' in obj['__typename'] # Right now this is meant for Variable objects only
122
99
  and 'uid' in obj
123
- and not _has_template_marker(obj)
124
100
  )
125
101
 
126
102
 
@@ -120,7 +120,7 @@ def create_router(config: Configuration):
120
120
  values: NormalizedPayload[Mapping[str, Any]]
121
121
  """Dynamic kwarg values"""
122
122
 
123
- input: Any
123
+ input: Any = None
124
124
  """Input from the component"""
125
125
 
126
126
  ws_channel: str
@@ -194,7 +194,7 @@ def create_router(config: Configuration):
194
194
  @core_api_router.get('/config', dependencies=[Depends(verify_session)])
195
195
  async def get_config(): # pylint: disable=unused-variable
196
196
  return {
197
- **config.dict(
197
+ **config.model_dump(
198
198
  include={
199
199
  'enable_devtools',
200
200
  'live_reload',
@@ -211,7 +211,7 @@ def create_router(config: Configuration):
211
211
  @core_api_router.get('/auth-config')
212
212
  async def get_auth_config(): # pylint: disable=unused-variable
213
213
  return {
214
- 'auth_components': config.auth_config.component_config.dict(),
214
+ 'auth_components': config.auth_config.component_config.model_dump(),
215
215
  }
216
216
 
217
217
  @core_api_router.get('/components', dependencies=[Depends(verify_session)])
@@ -225,7 +225,7 @@ def create_router(config: Configuration):
225
225
  registry_mgr: RegistryLookup = utils_registry.get('RegistryLookup')
226
226
  await registry_mgr.get(component_registry, name)
227
227
 
228
- return {k: comp.dict(exclude={'func'}) for k, comp in component_registry.get_all().items()}
228
+ return {k: comp.model_dump(exclude={'func'}) for k, comp in component_registry.get_all().items()}
229
229
 
230
230
  class ComponentRequestBody(BaseModel):
231
231
  # Dynamic kwarg values
@@ -294,9 +294,9 @@ def create_router(config: Configuration):
294
294
  )
295
295
 
296
296
  class DataVariableRequestBody(BaseModel):
297
- filters: Optional[FilterQuery]
298
- cache_key: Optional[str]
299
- ws_channel: Optional[str]
297
+ filters: Optional[FilterQuery] = None
298
+ cache_key: Optional[str] = None
299
+ ws_channel: Optional[str] = None
300
300
 
301
301
  @core_api_router.post('/data-variable/{uid}', dependencies=[Depends(verify_session)])
302
302
  async def get_data_variable(
@@ -366,8 +366,8 @@ def create_router(config: Configuration):
366
366
  raise HTTPException(status_code=400, detail=str(e))
367
367
 
368
368
  class DataVariableCountRequestBody(BaseModel):
369
- cache_key: Optional[str]
370
- filters: Optional[FilterQuery]
369
+ cache_key: Optional[str] = None
370
+ filters: Optional[FilterQuery] = None
371
371
 
372
372
  @core_api_router.post('/data-variable/{uid}/count', dependencies=[Depends(verify_session)])
373
373
  async def get_data_variable_count(uid: str, body: Optional[DataVariableCountRequestBody] = None):
@@ -538,7 +538,7 @@ def create_router(config: Configuration):
538
538
  async def get_template(template: str): # pylint: disable=unused-variable
539
539
  try:
540
540
  selected_template = template_registry.get(template)
541
- normalized_template, lookup = normalize(selected_template.dict())
541
+ normalized_template, lookup = normalize(jsonable_encoder(selected_template))
542
542
  return {'data': normalized_template, 'lookup': lookup}
543
543
  except KeyError:
544
544
  raise HTTPException(status_code=404, detail=f'Template: {template}, not found in registry')
@@ -23,7 +23,7 @@ from pickle import PicklingError
23
23
  from typing import Any, List, Optional, Union
24
24
 
25
25
  from croniter import croniter
26
- from pydantic import BaseModel, validator
26
+ from pydantic import BaseModel, field_validator
27
27
 
28
28
 
29
29
  class ScheduledJob(BaseModel):
@@ -174,7 +174,8 @@ class ScheduledJobFactory(BaseModel):
174
174
  weekday: Optional[datetime] = None
175
175
  run_once: bool
176
176
 
177
- @validator('weekday', pre=True)
177
+ @field_validator('weekday', mode='before')
178
+ @classmethod
178
179
  def validate_weekday(cls, weekday: Any) -> datetime: # pylint: disable=E0213
179
180
  if isinstance(weekday, datetime):
180
181
  return weekday