dara-core 1.21.13__py3-none-any.whl → 1.21.15__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.
@@ -23,6 +23,7 @@ import abc
23
23
  import uuid
24
24
  from collections.abc import Awaitable, Mapping
25
25
  from enum import Enum
26
+ from inspect import isclass
26
27
  from typing import (
27
28
  TYPE_CHECKING,
28
29
  Annotated,
@@ -72,7 +73,11 @@ def annotation_has_base_model(typ: Any) -> bool:
72
73
  pass
73
74
 
74
75
  # Handle simple types
75
- return typ is BaseModel or issubclass(typ, BaseModel)
76
+ try:
77
+ return typ is BaseModel or (isclass(typ) and issubclass(typ, BaseModel))
78
+ except: # noqa: E722
79
+ # cannot check if it's a subclass, just return false
80
+ return False
76
81
 
77
82
 
78
83
  # This reverts v1->v2 change to make any BaseModel field duck-type serializable.
@@ -440,7 +445,7 @@ class PendingTask(BaseTask):
440
445
 
441
446
 
442
447
  class RouterPath(BaseModel):
443
- path: Optional[str] = None
448
+ pathname: Optional[str] = None
444
449
  """
445
450
  A URL pathname, beginning with '/'.
446
451
  """
@@ -17,6 +17,8 @@ limitations under the License.
17
17
 
18
18
  from __future__ import annotations
19
19
 
20
+ from inspect import isclass
21
+
20
22
  from pydantic import BaseModel
21
23
 
22
24
  from dara.core.interactivity.actions import (
@@ -80,7 +82,7 @@ __all__ = [
80
82
 
81
83
  for symbol in list(globals().values()):
82
84
  try:
83
- if issubclass(symbol, BaseModel) and symbol is not BaseModel:
85
+ if isclass(symbol) and issubclass(symbol, BaseModel) and symbol is not BaseModel:
84
86
  symbol.model_rebuild()
85
87
  except Exception as e:
86
88
  from dara.core.logging import dev_logger
@@ -118,6 +118,19 @@ class BaseRoute(BaseModel):
118
118
  Metadata for the route. This is used to store arbitrary data that can be used by the application.
119
119
  """
120
120
 
121
+ fallback: SerializeAsAny[Optional[ComponentInstance]] = Field(default=None)
122
+ """
123
+ Fallback component to render while `on_load` is running.
124
+ If not set, Dara will wait until `on_load` completes before completing the navigation.
125
+ If provided, Dara will navigate immediately and show the fallback component while `on_load` is running.
126
+
127
+ Note that this impacts the navigation when nested routes are involved. For example,
128
+ when navigating from `/a` to `/b/c` (assuming `b` and `c` both have `on_load` actions),
129
+ Dara will hold the navigation until both `b` and `c` have completed their `on_load` actions.
130
+ If only one of them is slow, you might want to consider setting an explicit `fallback` for it
131
+ if it's desirable to navigate to the other route immediately.
132
+ """
133
+
121
134
  on_load: SerializeAsAny[Optional[Action]] = Field(default=None)
122
135
  """
123
136
  Action to execute when the route is loaded.
@@ -303,6 +316,7 @@ class HasChildRoutes(BaseModel):
303
316
  id: Optional[str] = None,
304
317
  metadata: Optional[dict] = None,
305
318
  on_load: Optional[Action] = None,
319
+ fallback: Optional[ComponentInstance] = None,
306
320
  ):
307
321
  """
308
322
  Standard route with a unique URL segment and content to render
@@ -313,6 +327,8 @@ class HasChildRoutes(BaseModel):
313
327
  :param name: unique name for the route, used for window.name display. If not set, defaults to the route path.
314
328
  :param id: unique id for the route
315
329
  :param metadata: metadata for the route
330
+ :param on_load: action to execute when the route is loaded
331
+ :param fallback: fallback component to render while `on_load` is running
316
332
  """
317
333
  if metadata is None:
318
334
  metadata = {}
@@ -325,6 +341,7 @@ class HasChildRoutes(BaseModel):
325
341
  id=id,
326
342
  metadata=metadata,
327
343
  on_load=on_load,
344
+ fallback=fallback,
328
345
  )
329
346
  route._attach_to_parent(self)
330
347
  self.children.append(route)
@@ -338,6 +355,7 @@ class HasChildRoutes(BaseModel):
338
355
  id: Optional[str] = None,
339
356
  metadata: Optional[dict] = None,
340
357
  on_load: Optional[Action] = None,
358
+ fallback: Optional[ComponentInstance] = None,
341
359
  ):
342
360
  """
343
361
  Layout route creates a route with a layout component to render without adding any segments to the URL
@@ -368,6 +386,8 @@ class HasChildRoutes(BaseModel):
368
386
  :param case_sensitive: whether the route is case sensitive
369
387
  :param id: unique id for the route
370
388
  :param metadata: metadata for the route
389
+ :param on_load: action to execute when the route is loaded
390
+ :param fallback: fallback component to render while `on_load` is running
371
391
  """
372
392
  if metadata is None:
373
393
  metadata = {}
@@ -378,6 +398,7 @@ class HasChildRoutes(BaseModel):
378
398
  id=id,
379
399
  metadata=metadata,
380
400
  on_load=on_load,
401
+ fallback=fallback,
381
402
  )
382
403
  route._attach_to_parent(self)
383
404
  self.children.append(route)
@@ -391,6 +412,7 @@ class HasChildRoutes(BaseModel):
391
412
  id: Optional[str] = None,
392
413
  metadata: Optional[dict] = None,
393
414
  on_load: Optional[Action] = None,
415
+ fallback: Optional[ComponentInstance] = None,
394
416
  ):
395
417
  """
396
418
  Prefix route creates a group of routes with a common prefix without a specific component to render
@@ -413,10 +435,14 @@ class HasChildRoutes(BaseModel):
413
435
  :param case_sensitive: whether the route is case sensitive
414
436
  :param id: unique id for the route
415
437
  :param metadata: metadata for the route
438
+ :param on_load: action to execute when the route is loaded
439
+ :param fallback: fallback component to render while `on_load` is running
416
440
  """
417
441
  if metadata is None:
418
442
  metadata = {}
419
- route = PrefixRoute(path=path, case_sensitive=case_sensitive, id=id, metadata=metadata, on_load=on_load)
443
+ route = PrefixRoute(
444
+ path=path, case_sensitive=case_sensitive, id=id, metadata=metadata, on_load=on_load, fallback=fallback
445
+ )
420
446
  route._attach_to_parent(self)
421
447
  self.children.append(route)
422
448
  return route
@@ -430,6 +456,7 @@ class HasChildRoutes(BaseModel):
430
456
  id: Optional[str] = None,
431
457
  metadata: Optional[dict] = None,
432
458
  on_load: Optional[Action] = None,
459
+ fallback: Optional[ComponentInstance] = None,
433
460
  ):
434
461
  """
435
462
  Index routes render into their parent's Outlet() at their parent URL (like a default child route).
@@ -457,7 +484,13 @@ class HasChildRoutes(BaseModel):
457
484
  if metadata is None:
458
485
  metadata = {}
459
486
  route = IndexRoute(
460
- content=content, case_sensitive=case_sensitive, id=id, metadata=metadata, on_load=on_load, name=name
487
+ content=content,
488
+ case_sensitive=case_sensitive,
489
+ id=id,
490
+ metadata=metadata,
491
+ on_load=on_load,
492
+ name=name,
493
+ fallback=fallback,
461
494
  )
462
495
  route._attach_to_parent(self)
463
496
  self.children.append(route)
@@ -74485,15 +74485,8 @@ body,
74485
74485
  [routeDefMap, routeObjects, currentMatches]
74486
74486
  );
74487
74487
  }
74488
- function hasServerActions(route) {
74489
- if (!route.on_load) {
74490
- return false;
74491
- }
74492
- const actions = Array.isArray(route.on_load) ? route.on_load : [route.on_load];
74493
- return actions.some(isAnnotatedAction);
74494
- }
74495
74488
  function shouldHoldPromise(route) {
74496
- return !((route.__typename === "IndexRoute" || route.__typename === "PageRoute") && hasServerActions(route));
74489
+ return !route.fallback;
74497
74490
  }
74498
74491
  function createRouteLoader(route, snapshot) {
74499
74492
  return async function loader({ request: loaderRequest, params }) {
@@ -74508,7 +74501,7 @@ body,
74508
74501
  if (shouldHoldPromise(route)) {
74509
74502
  result = await result;
74510
74503
  }
74511
- return { data: result };
74504
+ return { data: result, fallback: route.fallback };
74512
74505
  };
74513
74506
  }
74514
74507
  function Content({
@@ -74561,9 +74554,13 @@ body,
74561
74554
  return /* @__PURE__ */ React__namespace.createElement(DynamicComponent$1, { component: template });
74562
74555
  }
74563
74556
  function RouteContent(props) {
74564
- const { data: data2 } = useLoaderData();
74557
+ const { data: data2, fallback } = useLoaderData();
74558
+ const fallbackComponent = React__namespace.useMemo(
74559
+ () => fallback ? /* @__PURE__ */ React__namespace.createElement(DynamicComponent$1, { component: fallback }) : /* @__PURE__ */ React__namespace.createElement(DefaultFallbackStatic, null),
74560
+ [fallback]
74561
+ );
74565
74562
  if (data2 instanceof Promise) {
74566
- return /* @__PURE__ */ React__namespace.createElement(React__namespace.Suspense, { fallback: /* @__PURE__ */ React__namespace.createElement(DefaultFallbackStatic, null) }, /* @__PURE__ */ React__namespace.createElement(Await, { resolve: data2 }, (resolved) => /* @__PURE__ */ React__namespace.createElement(Content, { ...resolved, route: props.route })));
74563
+ return /* @__PURE__ */ React__namespace.createElement(React__namespace.Suspense, { fallback: fallbackComponent }, /* @__PURE__ */ React__namespace.createElement(Await, { resolve: data2 }, (resolved) => /* @__PURE__ */ React__namespace.createElement(Content, { ...resolved, route: props.route })));
74567
74564
  }
74568
74565
  return /* @__PURE__ */ React__namespace.createElement(Content, { ...data2, route: props.route });
74569
74566
  }
@@ -74794,6 +74791,16 @@ body,
74794
74791
  const basename = getBasename();
74795
74792
  let isExternal = false;
74796
74793
  let to = actionImpl.url;
74794
+ if (actionImpl.new_tab) {
74795
+ if (typeof to === "string") {
74796
+ window.open(to, "_blank");
74797
+ } else {
74798
+ const url = createPath(to);
74799
+ const targetUrl = new URL(url, window.location.origin);
74800
+ window.open(targetUrl.toString(), "_blank");
74801
+ }
74802
+ return;
74803
+ }
74797
74804
  if (typeof actionImpl.url === "string" && ABSOLUTE_URL_REGEX.test(actionImpl.url)) {
74798
74805
  try {
74799
74806
  const currentUrl = new URL(window.location.href);
@@ -74809,11 +74816,7 @@ body,
74809
74816
  }
74810
74817
  }
74811
74818
  if (isExternal && typeof to === "string") {
74812
- if (actionImpl.new_tab) {
74813
- window.open(to, "_blank");
74814
- } else {
74815
- window.location.href = to;
74816
- }
74819
+ window.location.href = to;
74817
74820
  return;
74818
74821
  }
74819
74822
  ctx.navigate(to, actionImpl.options);
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dara-core
3
- Version: 1.21.13
3
+ Version: 1.21.15
4
4
  Summary: Dara Framework Core
5
5
  Home-page: https://dara.causalens.com/
6
6
  License: Apache-2.0
@@ -21,10 +21,10 @@ Requires-Dist: cachetools (>=5.0.0,<6.0.0)
21
21
  Requires-Dist: certifi (>=2024.7.4)
22
22
  Requires-Dist: click (==8.1.3)
23
23
  Requires-Dist: colorama (>=0.4.6,<0.5.0)
24
- Requires-Dist: create-dara-app (==1.21.13)
24
+ Requires-Dist: create-dara-app (==1.21.15)
25
25
  Requires-Dist: croniter (>=1.0.15,<3.0.0)
26
26
  Requires-Dist: cryptography (>=42.0.4)
27
- Requires-Dist: dara-components (==1.21.13) ; extra == "all"
27
+ Requires-Dist: dara-components (==1.21.15) ; extra == "all"
28
28
  Requires-Dist: exceptiongroup (>=1.1.3,<2.0.0)
29
29
  Requires-Dist: fastapi (>=0.115.0,<0.116.0)
30
30
  Requires-Dist: fastapi_vite_dara (==0.4.0)
@@ -38,7 +38,7 @@ Requires-Dist: packaging (>=23.1)
38
38
  Requires-Dist: pandas (>=1.1.0,<3.0.0)
39
39
  Requires-Dist: prometheus-client (>=0.14.1,<0.15.0)
40
40
  Requires-Dist: pyarrow
41
- Requires-Dist: pydantic (>=2.10.0,<3.0.0)
41
+ Requires-Dist: pydantic (>=2.12.0,<3.0.0)
42
42
  Requires-Dist: pydantic-settings (>=2.8.1,<3.0.0)
43
43
  Requires-Dist: pyjwt (>=2.3.0,<3.0.0)
44
44
  Requires-Dist: python-dotenv (>=0.19.2)
@@ -55,7 +55,7 @@ Description-Content-Type: text/markdown
55
55
 
56
56
  # Dara Application Framework
57
57
 
58
- <img src="https://github.com/causalens/dara/blob/v1.21.13/img/dara_light.svg?raw=true">
58
+ <img src="https://github.com/causalens/dara/blob/v1.21.15/img/dara_light.svg?raw=true">
59
59
 
60
60
  ![Master tests](https://github.com/causalens/dara/actions/workflows/tests.yml/badge.svg?branch=master)
61
61
  [![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0)
@@ -100,7 +100,7 @@ source .venv/bin/activate
100
100
  dara start
101
101
  ```
102
102
 
103
- ![Dara App](https://github.com/causalens/dara/blob/v1.21.13/img/components_gallery.png?raw=true)
103
+ ![Dara App](https://github.com/causalens/dara/blob/v1.21.15/img/components_gallery.png?raw=true)
104
104
 
105
105
  Note: `pip` installation uses [PEP 660](https://peps.python.org/pep-0660/) `pyproject.toml`-based editable installs which require `pip >= 21.3` and `setuptools >= 64.0.0`. You can upgrade both with:
106
106
 
@@ -117,9 +117,9 @@ Explore some of our favorite apps - a great way of getting started and getting t
117
117
 
118
118
  | Dara App | Description |
119
119
  | -------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
120
- | ![Large Language Model](https://github.com/causalens/dara/blob/v1.21.13/img/llm.png?raw=true) | Demonstrates how to use incorporate a LLM chat box into your decision app to understand model insights |
121
- | ![Plot Interactivity](https://github.com/causalens/dara/blob/v1.21.13/img/plot_interactivity.png?raw=true) | Demonstrates how to enable the user to interact with plots, trigger actions based on clicks, mouse movements and other interactions with `Bokeh` or `Plotly` plots |
122
- | ![Graph Editor](https://github.com/causalens/dara/blob/v1.21.13/img/graph_viewer.png?raw=true) | Demonstrates how to use the `CausalGraphViewer` component to display your graphs or networks, customising the displayed information through colors and tooltips, and updating the page based on user interaction. |
120
+ | ![Large Language Model](https://github.com/causalens/dara/blob/v1.21.15/img/llm.png?raw=true) | Demonstrates how to use incorporate a LLM chat box into your decision app to understand model insights |
121
+ | ![Plot Interactivity](https://github.com/causalens/dara/blob/v1.21.15/img/plot_interactivity.png?raw=true) | Demonstrates how to enable the user to interact with plots, trigger actions based on clicks, mouse movements and other interactions with `Bokeh` or `Plotly` plots |
122
+ | ![Graph Editor](https://github.com/causalens/dara/blob/v1.21.15/img/graph_viewer.png?raw=true) | Demonstrates how to use the `CausalGraphViewer` component to display your graphs or networks, customising the displayed information through colors and tooltips, and updating the page based on user interaction. |
123
123
 
124
124
  Check out our [App Gallery](https://dara.causalens.com/gallery) for more inspiration!
125
125
 
@@ -146,9 +146,9 @@ And the supporting UI packages and tools.
146
146
  - `ui-utils` - miscellaneous utility functions
147
147
  - `ui-widgets` - widget components
148
148
 
149
- More information on the repository structure can be found in the [CONTRIBUTING.md](https://github.com/causalens/dara/blob/v1.21.13/CONTRIBUTING.md) file.
149
+ More information on the repository structure can be found in the [CONTRIBUTING.md](https://github.com/causalens/dara/blob/v1.21.15/CONTRIBUTING.md) file.
150
150
 
151
151
  ## License
152
152
 
153
- Dara is open-source and licensed under the [Apache 2.0 License](https://github.com/causalens/dara/blob/v1.21.13/LICENSE).
153
+ Dara is open-source and licensed under the [Apache 2.0 License](https://github.com/causalens/dara/blob/v1.21.15/LICENSE).
154
154
 
@@ -6,7 +6,7 @@ dara/core/auth/basic.py,sha256=8ebWpHx53ObkuzTHIKSRdtsmKq0R5v8RuQXhZcnpTsA,4933
6
6
  dara/core/auth/definitions.py,sha256=wTsFWzX7bGHTU_vxGW50pqcmB_AmhETIIUdGB5UrMBU,3467
7
7
  dara/core/auth/routes.py,sha256=0o5KXApRbkL0F5qFsarQk_cq5lbQ3QfIHR_mwLRgBEY,7217
8
8
  dara/core/auth/utils.py,sha256=iEWP5qwfH17Mi-5t3sP-DNMUrWN0oSRk96NhieY2Zw4,7334
9
- dara/core/base_definitions.py,sha256=wDeXoKro7WcMB8RXImaAZrwbBYdhnN_jgd2s7eDDO2M,18386
9
+ dara/core/base_definitions.py,sha256=jtQQ9YRtDAtPnTIf1O7hRmajuZwEm65S1KHbHiNk5kY,18558
10
10
  dara/core/cli.py,sha256=V__LAK3ozWGsVTEQHqvJwqSfpC3o6R76YGABJ-YVoSE,8185
11
11
  dara/core/configuration.py,sha256=caPebHNUmYqh9czEBwQiIDjGrH8ltsphayZICj1CRhc,23489
12
12
  dara/core/css.py,sha256=UkNZ6n7RDBLsHmpZvn_a3K2nAwxVggQJbQMKNbgXONA,1753
@@ -14,7 +14,7 @@ dara/core/data_utils.py,sha256=RD5_GdyGyGr1LVThCo8mpuOMWrd9_c1iyRqjuyoarXM,12578
14
14
  dara/core/defaults.py,sha256=y-PU4DhF3uEEfrFmlJnenM8jhnQDTDaOU5kuAYZE2gw,4740
15
15
  dara/core/definitions.py,sha256=I4TUJ6zu968T4PNmeqbC-u-DfiKay-4XxurLNASkDz0,18358
16
16
  dara/core/http.py,sha256=-OzbCHlYSnfVnw2492C_UmaWOI5oSONfWk03eEGxSRI,4761
17
- dara/core/interactivity/__init__.py,sha256=ZppwTvxaCsaAdf0qX6j1qTcmbj6wxVcbiaMZfwTVKtU,2679
17
+ dara/core/interactivity/__init__.py,sha256=LTH2OOGtJSE4684xVrkjQXpxUMlf7_re8joIOm0EjV8,2728
18
18
  dara/core/interactivity/actions.py,sha256=_guOKc5VkXH1J91-pdTeIQumCFHkve6G0ES5rFBm1vY,48478
19
19
  dara/core/interactivity/any_data_variable.py,sha256=GhT6lzCDRlQtYG2gNNUHq4th7K3RacqDfkjaq7o4mCc,317
20
20
  dara/core/interactivity/any_variable.py,sha256=b6aMOZZc9Q4IFPPjuIbFgqYdw52-6QRsxNRj5ohZeL0,13648
@@ -92,8 +92,8 @@ dara/core/router/__init__.py,sha256=yGI_MgLQU37ircCtYVNjnhqCjWQxKd5amoNqvMyrhOs,
92
92
  dara/core/router/compat.py,sha256=WAVzDcJFJOVoIQ5inplIhXD58TWsWwTTebTCqpG4nGs,3137
93
93
  dara/core/router/components.py,sha256=lnh8dCin6BunI0KILdua-zJZOuwbDbniLGb6eF_V9hM,6183
94
94
  dara/core/router/dependency_graph.py,sha256=AyjSk3DuvCgACrgpID4oSpms1X6GQJUbt-scY5X_LN4,2305
95
- dara/core/router/router.py,sha256=1r3rFGiftOXC6GP66hKqTdcVNDRJsZWBWvL74wNG4dA,29719
96
- dara/core/umd/dara.core.umd.cjs,sha256=KXoJu_06chU79sKcrZPHoEvtC7o20QLfE98puoxlvcA,5152119
95
+ dara/core/router/router.py,sha256=XiJHuEdmDVKD_AXt89v1Kg2hE3LMded2mj5Yiq7WAxY,31373
96
+ dara/core/umd/dara.core.umd.cjs,sha256=CAfqSc0a7SEK9gTJUoKr0bksjFjfeCpKlq0Ls5XSDp0,5152269
97
97
  dara/core/umd/style.css,sha256=yT3PKpi2sKI2-kQIF8xtVbTPQqgpK7-Ua7tfzDPuSsI,4095881
98
98
  dara/core/visual/__init__.py,sha256=QN0wbG9HPQ_vXh8BO8DnBXeYLIENVTNtRmYzZf1lx7c,577
99
99
  dara/core/visual/components/__init__.py,sha256=nmCsnMLXeZAjkhMYz-mIFodpVY-69IO1fvwwXbFlMQ4,2447
@@ -120,8 +120,8 @@ dara/core/visual/themes/__init__.py,sha256=aM4mgoIYo2neBSw5FRzswsht7PUKjLthiHLmF
120
120
  dara/core/visual/themes/dark.py,sha256=UQGDooOc8ric73eHs9E0ltYP4UCrwqQ3QxqN_fb4PwY,1942
121
121
  dara/core/visual/themes/definitions.py,sha256=5g83t24w8Ar51Cl9REBJfCU7_DtlashBQeUTKDg3D1M,2862
122
122
  dara/core/visual/themes/light.py,sha256=-Tviq8oEwGbdFULoDOqPuHO0UpAZGsBy8qFi0kAGolQ,1944
123
- dara_core-1.21.13.dist-info/LICENSE,sha256=r9u1w2RvpLMV6YjuXHIKXRBKzia3fx_roPwboGcLqCc,10944
124
- dara_core-1.21.13.dist-info/METADATA,sha256=TrgbUFRw_sb5zVZux8BKLvN_iDKIhlg-gx3hBBepjfA,7544
125
- dara_core-1.21.13.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
126
- dara_core-1.21.13.dist-info/entry_points.txt,sha256=H__D5sNIGuPIhVam0DChNL-To5k8Y7nY7TAFz9Mz6cc,139
127
- dara_core-1.21.13.dist-info/RECORD,,
123
+ dara_core-1.21.15.dist-info/LICENSE,sha256=r9u1w2RvpLMV6YjuXHIKXRBKzia3fx_roPwboGcLqCc,10944
124
+ dara_core-1.21.15.dist-info/METADATA,sha256=ts8ZxsLQkR0KrlAAHdF_SM-lGZtReMJdwzVQm_TumPk,7544
125
+ dara_core-1.21.15.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
126
+ dara_core-1.21.15.dist-info/entry_points.txt,sha256=H__D5sNIGuPIhVam0DChNL-To5k8Y7nY7TAFz9Mz6cc,139
127
+ dara_core-1.21.15.dist-info/RECORD,,