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.
- dara/core/auth/base.py +5 -5
- dara/core/auth/basic.py +3 -3
- dara/core/auth/definitions.py +13 -14
- dara/core/auth/routes.py +7 -5
- dara/core/auth/utils.py +11 -10
- dara/core/base_definitions.py +30 -36
- dara/core/cli.py +7 -8
- dara/core/configuration.py +51 -58
- dara/core/css.py +2 -2
- dara/core/data_utils.py +12 -17
- dara/core/defaults.py +3 -3
- dara/core/definitions.py +58 -63
- dara/core/http.py +4 -4
- dara/core/interactivity/actions.py +34 -42
- dara/core/interactivity/any_data_variable.py +1 -1
- dara/core/interactivity/any_variable.py +6 -5
- dara/core/interactivity/client_variable.py +1 -2
- dara/core/interactivity/condition.py +2 -2
- dara/core/interactivity/data_variable.py +2 -4
- dara/core/interactivity/derived_data_variable.py +7 -10
- dara/core/interactivity/derived_variable.py +45 -51
- dara/core/interactivity/filtering.py +19 -19
- dara/core/interactivity/loop_variable.py +2 -4
- dara/core/interactivity/non_data_variable.py +1 -1
- dara/core/interactivity/plain_variable.py +21 -18
- dara/core/interactivity/server_variable.py +13 -15
- dara/core/interactivity/state_variable.py +4 -5
- dara/core/interactivity/switch_variable.py +16 -16
- dara/core/interactivity/tabular_variable.py +3 -3
- dara/core/interactivity/url_variable.py +3 -3
- dara/core/internal/cache_store/cache_store.py +6 -6
- dara/core/internal/cache_store/keep_all.py +3 -3
- dara/core/internal/cache_store/lru.py +8 -8
- dara/core/internal/cache_store/ttl.py +4 -4
- dara/core/internal/custom_response.py +3 -3
- dara/core/internal/dependency_resolution.py +6 -10
- dara/core/internal/devtools.py +2 -3
- dara/core/internal/download.py +5 -6
- dara/core/internal/encoder_registry.py +7 -11
- dara/core/internal/execute_action.py +5 -5
- dara/core/internal/hashing.py +1 -2
- dara/core/internal/import_discovery.py +7 -9
- dara/core/internal/normalization.py +12 -15
- dara/core/internal/pandas_utils.py +6 -6
- dara/core/internal/pool/channel.py +3 -4
- dara/core/internal/pool/definitions.py +9 -9
- dara/core/internal/pool/task_pool.py +8 -8
- dara/core/internal/pool/utils.py +4 -3
- dara/core/internal/pool/worker.py +3 -3
- dara/core/internal/registries.py +4 -4
- dara/core/internal/registry.py +3 -3
- dara/core/internal/registry_lookup.py +4 -4
- dara/core/internal/routing.py +23 -22
- dara/core/internal/scheduler.py +8 -8
- dara/core/internal/settings.py +1 -2
- dara/core/internal/store.py +9 -9
- dara/core/internal/tasks.py +30 -30
- dara/core/internal/utils.py +9 -15
- dara/core/internal/websocket.py +18 -18
- dara/core/js_tooling/js_utils.py +19 -19
- dara/core/logging.py +13 -13
- dara/core/main.py +4 -5
- dara/core/metrics/cache.py +2 -4
- dara/core/persistence.py +19 -25
- dara/core/router/compat.py +1 -3
- dara/core/router/components.py +10 -10
- dara/core/router/dependency_graph.py +2 -4
- dara/core/router/router.py +43 -42
- dara/core/visual/components/dynamic_component.py +1 -3
- dara/core/visual/components/fallback.py +3 -3
- dara/core/visual/components/for_cmp.py +5 -5
- dara/core/visual/components/menu.py +1 -3
- dara/core/visual/components/router_content.py +1 -3
- dara/core/visual/components/sidebar_frame.py +8 -10
- dara/core/visual/components/theme_provider.py +3 -3
- dara/core/visual/components/topbar_frame.py +8 -10
- dara/core/visual/css/__init__.py +277 -277
- dara/core/visual/dynamic_component.py +18 -22
- dara/core/visual/progress_updater.py +1 -1
- dara/core/visual/template.py +10 -12
- dara/core/visual/themes/definitions.py +46 -46
- {dara_core-1.21.16.dist-info → dara_core-1.21.17.dist-info}/METADATA +12 -13
- dara_core-1.21.17.dist-info/RECORD +127 -0
- dara_core-1.21.16.dist-info/RECORD +0 -127
- {dara_core-1.21.16.dist-info → dara_core-1.21.17.dist-info}/LICENSE +0 -0
- {dara_core-1.21.16.dist-info → dara_core-1.21.17.dist-info}/WHEEL +0 -0
- {dara_core-1.21.16.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,
|
|
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:
|
|
51
|
-
limit:
|
|
52
|
-
orderBy:
|
|
53
|
-
index:
|
|
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:
|
|
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 =
|
|
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:
|
|
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) ->
|
|
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,
|
|
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,
|
|
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,
|
|
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) ->
|
|
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:
|
|
252
|
-
) ->
|
|
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:
|
|
258
|
-
) ->
|
|
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:
|
|
263
|
-
) ->
|
|
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:
|
|
48
|
+
nested: list[str] = Field(default_factory=list)
|
|
51
49
|
|
|
52
|
-
def __init__(self, uid:
|
|
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)
|
|
@@ -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,
|
|
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[
|
|
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(
|
|
45
|
+
PersistenceStoreType_co = TypeVar(
|
|
46
|
+
'PersistenceStoreType_co', bound=PersistenceStore, covariant=True, default=PersistenceStore
|
|
47
|
+
)
|
|
44
48
|
|
|
45
49
|
|
|
46
|
-
|
|
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:
|
|
53
|
-
store:
|
|
55
|
+
default: VariableType | None = None
|
|
56
|
+
store: PersistenceStoreType_co | None = None
|
|
54
57
|
uid: str
|
|
55
|
-
nested:
|
|
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:
|
|
61
|
-
persist_value:
|
|
62
|
-
uid:
|
|
63
|
-
store:
|
|
64
|
-
nested:
|
|
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:
|
|
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:
|
|
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:
|
|
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) ->
|
|
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,
|
|
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:
|
|
42
|
-
) ->
|
|
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:
|
|
58
|
-
sequence_number:
|
|
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:
|
|
73
|
-
) ->
|
|
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:
|
|
145
|
-
backend:
|
|
144
|
+
default: Any | None = None,
|
|
145
|
+
backend: ServerBackend | None = None,
|
|
146
146
|
scope: Literal['user', 'global'] = 'global',
|
|
147
|
-
uid:
|
|
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:
|
|
196
|
-
pagination:
|
|
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,
|
|
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:
|
|
40
|
+
parent_variable: DerivedVariable
|
|
42
41
|
property_name: Literal['loading', 'error', 'hasValue']
|
|
43
42
|
|
|
44
43
|
def __init__(
|
|
45
44
|
self,
|
|
46
|
-
parent_variable:
|
|
45
|
+
parent_variable: DerivedVariable,
|
|
47
46
|
property_name: Literal['loading', 'error', 'hasValue'],
|
|
48
|
-
uid:
|
|
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
|
|
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:
|
|
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:
|
|
228
|
-
default:
|
|
227
|
+
value_map: Any | None = None
|
|
228
|
+
default: Any | None = None
|
|
229
229
|
|
|
230
230
|
def __init__(
|
|
231
231
|
self,
|
|
232
|
-
value:
|
|
233
|
-
value_map:
|
|
234
|
-
default:
|
|
235
|
-
uid:
|
|
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:
|
|
274
|
-
true_value:
|
|
275
|
-
false_value:
|
|
276
|
-
uid:
|
|
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:
|
|
350
|
-
mapping:
|
|
351
|
-
default:
|
|
352
|
-
uid:
|
|
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,
|
|
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:
|
|
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:
|
|
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
|
|
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:
|
|
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:
|
|
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,
|
|
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:
|
|
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:
|
|
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) ->
|
|
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:
|
|
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
|
-
) ->
|
|
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
|
|
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:
|
|
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) ->
|
|
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
|
|
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:
|
|
24
|
-
self.next:
|
|
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:
|
|
39
|
-
self.head:
|
|
40
|
-
self.tail:
|
|
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) ->
|
|
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:
|
|
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
|
|
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:
|
|
42
|
-
self.unpinned_cache:
|
|
43
|
-
self.expiration_heap:
|
|
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:
|
|
20
|
-
media_type:
|
|
21
|
-
background:
|
|
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
|
|