dara-core 1.21.16__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.16.dist-info → dara_core-1.21.17.dist-info}/METADATA +12 -13
  83. dara_core-1.21.17.dist-info/RECORD +127 -0
  84. dara_core-1.21.16.dist-info/RECORD +0 -127
  85. {dara_core-1.21.16.dist-info → dara_core-1.21.17.dist-info}/LICENSE +0 -0
  86. {dara_core-1.21.16.dist-info → dara_core-1.21.17.dist-info}/WHEEL +0 -0
  87. {dara_core-1.21.16.dist-info → dara_core-1.21.17.dist-info}/entry_points.txt +0 -0
@@ -17,20 +17,13 @@ limitations under the License.
17
17
 
18
18
  import os
19
19
  import pathlib
20
+ from collections.abc import Callable
20
21
  from inspect import isclass, isfunction
21
22
  from types import ModuleType
22
23
  from typing import (
23
24
  Any,
24
- Callable,
25
- Dict,
26
- List,
27
25
  Literal,
28
- Optional,
29
- Set,
30
- Tuple,
31
- Type,
32
26
  TypeVar,
33
- Union,
34
27
  )
35
28
 
36
29
  from fastapi.middleware import Middleware
@@ -75,34 +68,34 @@ class Configuration(BaseModel):
75
68
 
76
69
  auth_config: BaseAuthConfig
77
70
  registry_lookup: CustomRegistryLookup
78
- actions: List[ActionDef]
79
- endpoint_configurations: List[EndpointConfiguration]
80
- components: List[ComponentTypeAnnotation]
81
- context_components: List[ComponentInstance]
71
+ actions: list[ActionDef]
72
+ endpoint_configurations: list[EndpointConfiguration]
73
+ components: list[ComponentTypeAnnotation]
74
+ context_components: list[ComponentInstance]
82
75
  enable_devtools: bool
83
- module_dependencies: Dict[str, str]
76
+ module_dependencies: dict[str, str]
84
77
  live_reload: bool
85
78
  powered_by_causalens: bool
86
79
  router: Router
87
- pages: Dict[str, Page]
88
- routes: Set[ApiRoute]
89
- scheduled_jobs: List[Tuple[Union[ScheduledJob, ScheduledJobFactory], Callable, Optional[List[Any]]]] = []
90
- startup_functions: List[Callable]
91
- static_folders: List[str]
80
+ pages: dict[str, Page]
81
+ routes: set[ApiRoute]
82
+ scheduled_jobs: list[tuple[ScheduledJob | ScheduledJobFactory, Callable, list[Any] | None]] = []
83
+ startup_functions: list[Callable]
84
+ static_folders: list[str]
92
85
  static_files_dir: str
93
- package_tag_processors: List[Callable[[Dict[str, List[str]]], Dict[str, List[str]]]]
86
+ package_tag_processors: list[Callable[[dict[str, list[str]]], dict[str, list[str]]]]
94
87
  template_extra_js: str
95
- task_module: Optional[str] = None
88
+ task_module: str | None = None
96
89
  template: str
97
- template_renderers: Dict[str, Callable[..., Template]]
98
- theme: Union[BaseTheme, str]
90
+ template_renderers: dict[str, Callable[..., Template]]
91
+ theme: BaseTheme | str
99
92
  title: str
100
- ws_handlers: Dict[str, Callable[[str, Any], Any]]
101
- encoders: Dict[Type[Any], Encoder]
102
- middlewares: List[Middleware]
93
+ ws_handlers: dict[str, Callable[[str, Any], Any]]
94
+ encoders: dict[type[Any], Encoder]
95
+ middlewares: list[Middleware]
103
96
  model_config = ConfigDict(extra='forbid', arbitrary_types_allowed=True)
104
97
 
105
- def get_package_map(self) -> Dict[str, str]:
98
+ def get_package_map(self) -> dict[str, str]:
106
99
  """
107
100
  Get a map of python package names to js package names, based on currently
108
101
  registered components, actions etc.
@@ -145,28 +138,28 @@ class ConfigurationBuilder:
145
138
 
146
139
  auth_config: BaseAuthConfig
147
140
  registry_lookup: CustomRegistryLookup
148
- _actions: List[ActionDef]
149
- _components: List[ComponentTypeAnnotation]
150
- _module_dependencies: Dict[str, str]
151
- _errors: List[str]
141
+ _actions: list[ActionDef]
142
+ _components: list[ComponentTypeAnnotation]
143
+ _module_dependencies: dict[str, str]
144
+ _errors: list[str]
152
145
  enable_devtools: bool
153
146
  live_reload: bool
154
- _pages: Dict[str, Page]
155
- _template_renderers: Dict[str, Callable[..., Template]]
156
- _endpoint_configurations: List[EndpointConfiguration]
157
- _static_folders: List[str]
158
- _package_tags_processors: List[Callable[[Dict[str, List[str]]], Dict[str, List[str]]]]
147
+ _pages: dict[str, Page]
148
+ _template_renderers: dict[str, Callable[..., Template]]
149
+ _endpoint_configurations: list[EndpointConfiguration]
150
+ _static_folders: list[str]
151
+ _package_tags_processors: list[Callable[[dict[str, list[str]]], dict[str, list[str]]]]
159
152
  _template_extra_js: str
160
- _custom_ws_handlers: Dict[str, Callable[[str, Any], Any]]
161
- _custom_encoders: Dict[Type[Any], Encoder]
162
- _middlewares: List[Middleware]
163
- routes: Set[ApiRoute]
153
+ _custom_ws_handlers: dict[str, Callable[[str, Any], Any]]
154
+ _custom_encoders: dict[type[Any], Encoder]
155
+ _middlewares: list[Middleware]
156
+ routes: set[ApiRoute]
164
157
  router: Router
165
158
  static_files_dir: str
166
- scheduled_jobs: List[Tuple[Union[ScheduledJob, ScheduledJobFactory], Callable, Optional[List[Any]]]] = []
167
- startup_functions: List[Callable]
168
- context_components: List[ComponentInstance]
169
- task_module: Optional[str]
159
+ scheduled_jobs: list[tuple[ScheduledJob | ScheduledJobFactory, Callable, list[Any] | None]] = []
160
+ startup_functions: list[Callable]
161
+ context_components: list[ComponentInstance]
162
+ task_module: str | None
170
163
  _template: str
171
164
  theme: BaseTheme
172
165
  title: str
@@ -224,7 +217,7 @@ class ConfigurationBuilder:
224
217
  def powered_by_causalens(self, value):
225
218
  self._powered_by_causalens = value
226
219
 
227
- def add_action(self, action: Type[ActionImpl], local: bool = False):
220
+ def add_action(self, action: type[ActionImpl], local: bool = False):
228
221
  """
229
222
  Register an Action with the application.
230
223
 
@@ -276,7 +269,7 @@ class ConfigurationBuilder:
276
269
  self.context_components.append(component)
277
270
  self.add_component(component.__class__)
278
271
 
279
- def add_component(self, component: Type[ComponentInstance], local: bool = False):
272
+ def add_component(self, component: type[ComponentInstance], local: bool = False):
280
273
  """
281
274
  Register a Component with the application.
282
275
 
@@ -381,7 +374,7 @@ class ConfigurationBuilder:
381
374
  EncoderType = TypeVar('EncoderType')
382
375
 
383
376
  def add_encoder(
384
- self, typ: Type[EncoderType], serialize: Callable[[EncoderType], Any], deserialize: Callable[[Any], EncoderType]
377
+ self, typ: type[EncoderType], serialize: Callable[[EncoderType], Any], deserialize: Callable[[Any], EncoderType]
385
378
  ):
386
379
  """
387
380
  Register a custom encoder, which serialize and deserialize the type
@@ -398,7 +391,7 @@ class ConfigurationBuilder:
398
391
  self._custom_encoders[typ] = encoder
399
392
  return encoder
400
393
 
401
- def add_package_tags_processor(self, processor: Callable[[Dict[str, List[str]]], Dict[str, List[str]]]):
394
+ def add_package_tags_processor(self, processor: Callable[[dict[str, list[str]]], dict[str, list[str]]]):
402
395
  """
403
396
  Append a package tag processor. This is a function that takes a dictionary of package names to lists of script/link tags included
404
397
  when running in the UMD mode.
@@ -411,12 +404,12 @@ class ConfigurationBuilder:
411
404
  def add_page(
412
405
  self,
413
406
  name: str,
414
- content: Union[ComponentInstanceType, Type[CallableClassComponent], str],
415
- icon: Optional[str] = None,
416
- route: Optional[str] = None,
417
- include_in_menu: Optional[bool] = True,
418
- reset_vars_on_load: Optional[List[AnyVariable]] = None,
419
- on_load: Optional[Action] = None,
407
+ content: ComponentInstanceType | type[CallableClassComponent] | str,
408
+ icon: str | None = None,
409
+ route: str | None = None,
410
+ include_in_menu: bool | None = True,
411
+ reset_vars_on_load: list[AnyVariable] | None = None,
412
+ on_load: Action | None = None,
420
413
  ):
421
414
  """
422
415
  Add a new page to the layout of the platform. Switching between pages relies on the template implementing a
@@ -508,7 +501,7 @@ class ConfigurationBuilder:
508
501
 
509
502
  return registry_lookup
510
503
 
511
- def add_middleware(self, middleware: Union[type, Callable], **options: Any):
504
+ def add_middleware(self, middleware: type | Callable, **options: Any):
512
505
  """
513
506
  Add a middleware to the application. The middleware can be a class or a callable.
514
507
  """
@@ -526,8 +519,8 @@ class ConfigurationBuilder:
526
519
 
527
520
  def set_theme(
528
521
  self,
529
- main_theme: Optional[Union[ThemeDef, ClientVariable, Literal['light'], Literal['dark']]] = None,
530
- base_theme: Optional[Union[Literal['light'], Literal['dark']]] = None,
522
+ main_theme: ThemeDef | ClientVariable | Literal['light'] | Literal['dark'] | None = None,
523
+ base_theme: Literal['light'] | Literal['dark'] | None = None,
531
524
  ):
532
525
  """
533
526
  Sets the color theme of the app. Takes ThemeDef models for the app, and reverts
@@ -554,7 +547,7 @@ class ConfigurationBuilder:
554
547
  """
555
548
  self.startup_functions.append(startup_function)
556
549
 
557
- def scheduler(self, job: ScheduledJob, args: Union[None, List[Any]] = None):
550
+ def scheduler(self, job: ScheduledJob, args: None | list[Any] = None):
558
551
  if args is None:
559
552
  args = []
560
553
 
@@ -563,7 +556,7 @@ class ConfigurationBuilder:
563
556
 
564
557
  return _wrapper_func
565
558
 
566
- def _run_discovery(self, module: Union[ModuleType, dict]):
559
+ def _run_discovery(self, module: ModuleType | dict):
567
560
  """
568
561
  Run import discovery in a given module, adding actions and components found to the config
569
562
 
dara/core/css.py CHANGED
@@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
15
15
  limitations under the License.
16
16
  """
17
17
 
18
- from typing import Literal, Optional
18
+ from typing import Literal
19
19
 
20
20
  # Re-export CSSProperties for easier importing
21
21
  from dara.core.visual.css import CSSProperties # noqa: F401
@@ -27,7 +27,7 @@ IconSize = Literal['1x', '2x', '3x', '4x', '5x', '6x', '7x', '8x', '9x', '10x',
27
27
  def get_icon(
28
28
  name: str,
29
29
  style: IconStyle = 'solid',
30
- size: Optional[IconSize] = None,
30
+ size: IconSize | None = None,
31
31
  ):
32
32
  """
33
33
  Get FontAwesome icon class string. Can be used for components requiring an icon name. The size be any one of the
dara/core/data_utils.py CHANGED
@@ -17,7 +17,6 @@ limitations under the License.
17
17
 
18
18
  import io
19
19
  import os
20
- from typing import List, Optional, Union
21
20
 
22
21
  import pandas
23
22
  from pandas import DataFrame
@@ -75,7 +74,7 @@ class FileStore(BaseModel):
75
74
  scope = get_cache_scope(cache_type)
76
75
  return os.path.join(self.root_path, scope)
77
76
 
78
- def list_files(self, cache_type: CacheType) -> List[str]:
77
+ def list_files(self, cache_type: CacheType) -> list[str]:
79
78
  """
80
79
  List files in a directory for a given cache type
81
80
 
@@ -101,7 +100,7 @@ class FileStore(BaseModel):
101
100
  file_path = os.path.join(scope_path, name)
102
101
  return os.path.exists(file_path)
103
102
 
104
- def get_file(self, cache_type: CacheType, name: str) -> Optional[io.BufferedReader]:
103
+ def get_file(self, cache_type: CacheType, name: str) -> io.BufferedReader | None:
105
104
  """
106
105
  Get a BufferedReader to read a file from the data store
107
106
 
@@ -160,7 +159,7 @@ class DataFactory(BaseModel):
160
159
  file_store = FileStore(root_path=root_path)
161
160
  super().__init__(file_store=file_store)
162
161
 
163
- def list_datasets(self, cache: CacheType = CacheType.GLOBAL) -> List[str]:
162
+ def list_datasets(self, cache: CacheType = CacheType.GLOBAL) -> list[str]:
164
163
  """
165
164
  Get a list of datasets (filenames) available for a given cache type
166
165
 
@@ -171,9 +170,9 @@ class DataFactory(BaseModel):
171
170
 
172
171
  def list_datasets_var(
173
172
  self,
174
- cache: Union[CacheType, ClientVariable] = CacheType.GLOBAL,
175
- polling_interval: Optional[int] = None,
176
- ) -> DerivedVariable[List[str]]:
173
+ cache: CacheType | ClientVariable = CacheType.GLOBAL,
174
+ polling_interval: int | None = None,
175
+ ) -> DerivedVariable[list[str]]:
177
176
  """
178
177
  Create a DerivedVariable which stores a list of datasets (filenames) available for a given cache type
179
178
 
@@ -262,7 +261,7 @@ class DataFactory(BaseModel):
262
261
  """
263
262
  return os.path.join(self.file_store.get_scoped_path(cache), name)
264
263
 
265
- def read_dataset(self, name: str, cache: CacheType = CacheType.GLOBAL) -> Optional[DataFrame]:
264
+ def read_dataset(self, name: str, cache: CacheType = CacheType.GLOBAL) -> DataFrame | None:
266
265
  """
267
266
  Read a dataset from disk to a DataFrame.
268
267
 
@@ -288,9 +287,9 @@ class DataFactory(BaseModel):
288
287
 
289
288
  def read_dataset_var(
290
289
  self,
291
- name: Union[str, ClientVariable],
292
- cache: Union[CacheType, ClientVariable] = CacheType.GLOBAL,
293
- polling_interval: Optional[int] = None,
290
+ name: str | ClientVariable,
291
+ cache: CacheType | ClientVariable = CacheType.GLOBAL,
292
+ polling_interval: int | None = None,
294
293
  ) -> DerivedVariable:
295
294
  """
296
295
  Create a DerivedVariable which reads a specific dataset from disk
@@ -318,9 +317,7 @@ class DataFactory(BaseModel):
318
317
  """
319
318
  self.file_store.delete_file(cache, name)
320
319
 
321
- def delete_dataset_action(
322
- self, name: Union[str, ClientVariable], cache: Union[CacheType, ClientVariable] = CacheType.GLOBAL
323
- ):
320
+ def delete_dataset_action(self, name: str | ClientVariable, cache: CacheType | ClientVariable = CacheType.GLOBAL):
324
321
  """
325
322
  Get a SideEffect action which deletes a given dataset
326
323
 
@@ -332,9 +329,7 @@ class DataFactory(BaseModel):
332
329
 
333
330
  return SideEffect(lambda ctx: self.delete_dataset(ctx.extras[0], ctx.extras[1]), extras=[name_var, cache_var])
334
331
 
335
- def download_dataset_action(
336
- self, name: Union[str, ClientVariable], cache: Union[CacheType, ClientVariable] = CacheType.GLOBAL
337
- ):
332
+ def download_dataset_action(self, name: str | ClientVariable, cache: CacheType | ClientVariable = CacheType.GLOBAL):
338
333
  """
339
334
  Get a DownloadContent action which downloads a dataset with a given name as a .csv
340
335
 
dara/core/defaults.py CHANGED
@@ -17,7 +17,7 @@ limitations under the License.
17
17
 
18
18
  from __future__ import annotations
19
19
 
20
- from typing import TYPE_CHECKING, Dict, cast
20
+ from typing import TYPE_CHECKING, cast
21
21
 
22
22
  from dara.core.base_definitions import ActionDef
23
23
  from dara.core.interactivity.actions import (
@@ -76,7 +76,7 @@ INITIAL_CORE_INTERNALS = {'Store': _store}
76
76
 
77
77
 
78
78
  # These components are provided by the core JS of this module
79
- CORE_COMPONENTS: Dict[str, ComponentTypeAnnotation] = {
79
+ CORE_COMPONENTS: dict[str, ComponentTypeAnnotation] = {
80
80
  DynamicComponent.__name__: DynamicComponentDef,
81
81
  Menu.__name__: MenuDef,
82
82
  MenuLink.__name__: MenuLinkDef,
@@ -96,7 +96,7 @@ CORE_COMPONENTS: Dict[str, ComponentTypeAnnotation] = {
96
96
  }
97
97
 
98
98
  # These actions are provided by the core JS of this module
99
- CORE_ACTIONS: Dict[str, ActionDef] = {
99
+ CORE_ACTIONS: dict[str, ActionDef] = {
100
100
  'NavigateTo': NavigateToDef,
101
101
  'UpdateVariable': UpdateVariableDef,
102
102
  TriggerVariable.__name__: TriggerVariableDef,
dara/core/definitions.py CHANGED
@@ -19,19 +19,15 @@ from __future__ import annotations
19
19
 
20
20
  import json
21
21
  import uuid
22
- from collections.abc import Awaitable, Mapping
22
+ from collections.abc import Awaitable, Callable, Mapping
23
23
  from enum import Enum
24
24
  from typing import (
25
+ Annotated,
25
26
  Any,
26
- Callable,
27
27
  ClassVar,
28
- List,
29
28
  Literal,
30
- Optional,
31
29
  Protocol,
32
- Type,
33
30
  TypeVar,
34
- Union,
35
31
  runtime_checkable,
36
32
  )
37
33
 
@@ -45,7 +41,6 @@ from pydantic import (
45
41
  field_validator,
46
42
  model_serializer,
47
43
  )
48
- from typing_extensions import Annotated
49
44
 
50
45
  from dara.core.base_definitions import Action, ComponentType
51
46
  from dara.core.base_definitions import DaraBaseModel as BaseModel
@@ -64,7 +59,7 @@ class HttpMethod(Enum):
64
59
 
65
60
 
66
61
  class Session(BaseModel):
67
- session_id: Optional[str] = None
62
+ session_id: str | None = None
68
63
 
69
64
 
70
65
  DEFAULT_ERROR_TITLE = 'Unexpected error occurred'
@@ -99,7 +94,7 @@ class ErrorHandlingConfig(BaseModel):
99
94
  description: str = DEFAULT_ERROR_DESCRIPTION
100
95
  """Description to display in the error boundary"""
101
96
 
102
- raw_css: Annotated[Optional[Any], BeforeValidator(transform_raw_css)] = None
97
+ raw_css: Annotated[Any | None, BeforeValidator(transform_raw_css)] = None
103
98
  """
104
99
  Raw styling to apply to the displayed error boundary.
105
100
  Accepts a CSSProperties, dict, str, or ClientVariable.
@@ -125,27 +120,27 @@ class ComponentInstance(BaseModel):
125
120
 
126
121
  uid: str = Field(default_factory=lambda: str(uuid.uuid4()))
127
122
 
128
- js_module: ClassVar[Optional[str]] = None
123
+ js_module: ClassVar[str | None] = None
129
124
  """
130
125
  JS module including the implementation of the component.
131
126
 
132
127
  Required for non-local components.
133
128
  """
134
129
 
135
- py_component: ClassVar[Optional[str]] = None
130
+ py_component: ClassVar[str | None] = None
136
131
  """
137
132
  Python unique component name. If not set, defaults to the class name.
138
133
  """
139
134
 
140
- js_component: ClassVar[Optional[str]] = None
135
+ js_component: ClassVar[str | None] = None
141
136
  """
142
137
  JS component name. If not set, defaults to the class name.
143
138
  """
144
139
 
145
- required_routes: ClassVar[List[ApiRoute]] = []
140
+ required_routes: ClassVar[list[ApiRoute]] = []
146
141
  """List of routes the component depends on. Will be implicitly added to the app if this component is used"""
147
142
 
148
- raw_css: Annotated[Optional[Any], BeforeValidator(transform_raw_css)] = None
143
+ raw_css: Annotated[Any | None, BeforeValidator(transform_raw_css)] = None
149
144
  """
150
145
  Raw styling to apply to the component.
151
146
  Can be an dict/CSSProperties instance representing the `styles` tag, a string injected directly into the CSS of the wrapping component,
@@ -172,25 +167,25 @@ class ComponentInstance(BaseModel):
172
167
  ```
173
168
  """
174
169
 
175
- track_progress: Optional[bool] = False
170
+ track_progress: bool | None = False
176
171
  """Whether to use ProgressTracker to display progress updates from a task the component is subscribed to"""
177
172
 
178
- error_handler: Optional[ErrorHandlingConfig] = None
173
+ error_handler: ErrorHandlingConfig | None = None
179
174
  """Configure the error handling for the component"""
180
175
 
181
- fallback: Optional[Union[BaseFallback, ComponentInstance]] = None
176
+ fallback: BaseFallback | ComponentInstance | None = None
182
177
  """
183
178
  Fallback component to render in place of the actual UI if it has not finished loading
184
179
  """
185
180
 
186
- id_: Optional[str] = None
181
+ id_: str | None = None
187
182
  """
188
183
  An optional unique identifier for the component, defaults to None
189
184
 
190
185
  This is intended to help identify components with human-readable names in the serialized trees, and is also set as the `id` attribute of the DOM element
191
186
  """
192
187
 
193
- for_: Optional[str] = None
188
+ for_: str | None = None
194
189
  """
195
190
  An optional for attribute for the component, defaults to None
196
191
 
@@ -270,7 +265,7 @@ class CallableClassComponent(Protocol):
270
265
  def __call__(self) -> ComponentInstance: ...
271
266
 
272
267
 
273
- DiscoverTarget = Union[Callable[..., ComponentInstance], ComponentInstance, Type[CallableClassComponent]]
268
+ DiscoverTarget = Callable[..., ComponentInstance] | ComponentInstance | type[CallableClassComponent]
274
269
  DiscoverT = TypeVar('DiscoverT', bound=DiscoverTarget)
275
270
 
276
271
 
@@ -335,32 +330,32 @@ class StyledComponentInstance(ComponentInstance):
335
330
  :param width: the width of the component, can be an number, which will be converted to pixels, or a string
336
331
  """
337
332
 
338
- align: Optional[AlignItems] = None
339
- background: Optional[str] = None
340
- basis: Optional[Union[int, str, bool]] = None
333
+ align: AlignItems | None = None
334
+ background: str | None = None
335
+ basis: int | str | bool | None = None
341
336
  bold: bool = False
342
- border: Optional[str] = None
343
- border_radius: Optional[Union[float, int, str]] = None
344
- children: Optional[List[ComponentInstance]] = None
345
- color: Optional[str] = None
346
- font: Optional[str] = None
347
- font_size: Optional[str] = None
348
- gap: Optional[Union[float, int, str]] = None
349
- grow: Optional[Union[int, str, float, bool]] = None
350
- height: Optional[Union[float, int, str]] = None
351
- hug: Optional[bool] = None
337
+ border: str | None = None
338
+ border_radius: float | int | str | None = None
339
+ children: list[ComponentInstance] | None = None
340
+ color: str | None = None
341
+ font: str | None = None
342
+ font_size: str | None = None
343
+ gap: float | int | str | None = None
344
+ grow: int | str | float | bool | None = None
345
+ height: float | int | str | None = None
346
+ hug: bool | None = None
352
347
  italic: bool = False
353
- margin: Optional[Union[float, int, str]] = None
354
- max_height: Optional[Union[float, int, str]] = None
355
- max_width: Optional[Union[float, int, str]] = None
356
- min_height: Optional[Union[float, int, str]] = None
357
- min_width: Optional[Union[float, int, str]] = None
358
- overflow: Optional[str] = None
359
- position: Optional[str] = None
360
- padding: Optional[Union[float, int, str]] = None
361
- shrink: Optional[Union[int, str, float, bool]] = None
348
+ margin: float | int | str | None = None
349
+ max_height: float | int | str | None = None
350
+ max_width: float | int | str | None = None
351
+ min_height: float | int | str | None = None
352
+ min_width: float | int | str | None = None
353
+ overflow: str | None = None
354
+ position: str | None = None
355
+ padding: float | int | str | None = None
356
+ shrink: int | str | float | bool | None = None
362
357
  underline: bool = False
363
- width: Optional[Union[float, int, str]] = None
358
+ width: float | int | str | None = None
364
359
 
365
360
  @field_validator(
366
361
  'height',
@@ -401,7 +396,7 @@ class StyledComponentInstance(ComponentInstance):
401
396
 
402
397
 
403
398
  class BaseFallback(StyledComponentInstance):
404
- suspend_render: Union[bool, int] = 200
399
+ suspend_render: bool | int = 200
405
400
  """
406
401
  :param suspend_render: bool or int, optional
407
402
  Determines the suspense behavior of the component during state updates.
@@ -429,20 +424,20 @@ class BaseFallback(StyledComponentInstance):
429
424
 
430
425
  ComponentInstance.model_rebuild()
431
426
 
432
- ComponentInstanceType = Union[ComponentInstance, Callable[..., ComponentInstance]]
427
+ ComponentInstanceType = ComponentInstance | Callable[..., ComponentInstance]
433
428
 
434
429
 
435
430
  class JsComponentDef(BaseModel):
436
431
  """Definition of a JS Component"""
437
432
 
438
- js_module: Optional[str] = None
433
+ js_module: str | None = None
439
434
  """
440
435
  JS module where the component implementation lives.
441
436
 
442
437
  Not required for local components as they are located via dara.config.json
443
438
  """
444
439
 
445
- js_component: Optional[str] = None
440
+ js_component: str | None = None
446
441
  """
447
442
  JS component name. If not set, defaults to `name` property.
448
443
  """
@@ -459,11 +454,11 @@ class JsComponentDef(BaseModel):
459
454
  class PyComponentDef(BaseModel):
460
455
  """Definition of a Python Component"""
461
456
 
462
- func: Optional[Callable[..., Any]] = None
457
+ func: Callable[..., Any] | None = None
463
458
  name: str
464
- dynamic_kwargs: Optional[Mapping[str, AnyVariable]] = None
465
- fallback: Optional[Union[BaseFallback, ComponentInstance]] = None
466
- polling_interval: Optional[int] = None
459
+ dynamic_kwargs: Mapping[str, AnyVariable] | None = None
460
+ fallback: BaseFallback | ComponentInstance | None = None
461
+ polling_interval: int | None = None
467
462
  render_component: Callable[..., Awaitable[Any]]
468
463
  """Handler to render the component. Defaults to dara.core.visual.dynamic_component.render_component"""
469
464
 
@@ -488,7 +483,7 @@ class PyComponentDef(BaseModel):
488
483
 
489
484
 
490
485
  # Helper type annotation for working with components
491
- ComponentTypeAnnotation = Union[PyComponentDef, JsComponentDef]
486
+ ComponentTypeAnnotation = PyComponentDef | JsComponentDef
492
487
 
493
488
 
494
489
  class EndpointConfiguration(BaseModel):
@@ -507,7 +502,7 @@ class EndpointConfiguration(BaseModel):
507
502
  class ApiRoute(BaseModel):
508
503
  """Definition of a route for the application's api"""
509
504
 
510
- dependencies: List[Depends] = []
505
+ dependencies: list[Depends] = []
511
506
  handler: Callable
512
507
  method: HttpMethod
513
508
  url: str
@@ -520,13 +515,13 @@ class ApiRoute(BaseModel):
520
515
  class Page(BaseModel):
521
516
  """Definition of a Page"""
522
517
 
523
- icon: Optional[str] = None
518
+ icon: str | None = None
524
519
  content: ComponentInstanceType
525
520
  name: str
526
- sub_pages: Optional[List[Page]] = []
521
+ sub_pages: list[Page] | None = []
527
522
  url_safe_name: str
528
- include_in_menu: Optional[bool] = None
529
- on_load: Optional[Action] = None
523
+ include_in_menu: bool | None = None
524
+ on_load: Action | None = None
530
525
  model_config = ConfigDict(extra='forbid')
531
526
 
532
527
 
@@ -534,17 +529,17 @@ class TemplateRoute(BaseModel):
534
529
  """Definition of a route for the TemplateRouter"""
535
530
 
536
531
  content: ComponentInstance
537
- icon: Optional[str] = None
532
+ icon: str | None = None
538
533
  name: str
539
534
  route: str
540
- include_in_menu: Optional[bool] = None
541
- on_load: Optional[Action] = None
535
+ include_in_menu: bool | None = None
536
+ on_load: Action | None = None
542
537
 
543
538
 
544
539
  class TemplateRouterLink(BaseModel):
545
540
  """Definition of a link for the TemplateRouter"""
546
541
 
547
- icon: Optional[str] = None
542
+ icon: str | None = None
548
543
  name: str
549
544
  route: str
550
545
 
@@ -554,8 +549,8 @@ class TemplateRouterContent(BaseModel):
554
549
 
555
550
  content: ComponentInstance
556
551
  route: str
557
- on_load: Optional[Action] = None
558
- name: Optional[str] = None
552
+ on_load: Action | None = None
553
+ name: str | None = None
559
554
 
560
555
 
561
556
  class Template(BaseModel):
dara/core/http.py CHANGED
@@ -17,8 +17,8 @@ limitations under the License.
17
17
 
18
18
  import inspect
19
19
  from collections import OrderedDict
20
+ from collections.abc import Callable
20
21
  from functools import wraps
21
- from typing import Callable, Dict, List, Type, Union
22
22
 
23
23
  from fastapi import Depends
24
24
  from fastapi.params import Depends as DependsType
@@ -26,7 +26,7 @@ from fastapi.params import Depends as DependsType
26
26
  from dara.core.definitions import ApiRoute, EndpointConfiguration, HttpMethod
27
27
 
28
28
 
29
- def _get_config_instances(annotations: Dict[str, type]) -> Dict[str, EndpointConfiguration]:
29
+ def _get_config_instances(annotations: dict[str, type]) -> dict[str, EndpointConfiguration]:
30
30
  """
31
31
  Get EndpointConfiguration instances to inject given the function annotations
32
32
 
@@ -54,7 +54,7 @@ def _get_config_instances(annotations: Dict[str, type]) -> Dict[str, EndpointCon
54
54
  def _method_decorator(method: HttpMethod):
55
55
  """Create a decorator for a given HTTP method"""
56
56
 
57
- def _decorator(url: str, dependencies: Union[List[DependsType], None] = None, authenticated: bool = True):
57
+ def _decorator(url: str, dependencies: list[DependsType] | None = None, authenticated: bool = True):
58
58
  if dependencies is None:
59
59
  dependencies = []
60
60
 
@@ -73,7 +73,7 @@ def _method_decorator(method: HttpMethod):
73
73
  new_annotations = {}
74
74
  params = OrderedDict()
75
75
 
76
- configurations: List[Type[EndpointConfiguration]] = []
76
+ configurations: list[type[EndpointConfiguration]] = []
77
77
  sig = inspect.signature(func)
78
78
  for var_name, typ in func.__annotations__.items():
79
79
  if inspect.isclass(typ) and issubclass(typ, EndpointConfiguration):