dara-core 1.21.12__py3-none-any.whl → 1.21.14__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/base_definitions.py +6 -1
- dara/core/interactivity/__init__.py +3 -1
- dara/core/internal/pool/utils.py +2 -1
- dara/core/internal/tasks.py +43 -23
- {dara_core-1.21.12.dist-info → dara_core-1.21.14.dist-info}/METADATA +11 -11
- {dara_core-1.21.12.dist-info → dara_core-1.21.14.dist-info}/RECORD +9 -9
- {dara_core-1.21.12.dist-info → dara_core-1.21.14.dist-info}/LICENSE +0 -0
- {dara_core-1.21.12.dist-info → dara_core-1.21.14.dist-info}/WHEEL +0 -0
- {dara_core-1.21.12.dist-info → dara_core-1.21.14.dist-info}/entry_points.txt +0 -0
dara/core/base_definitions.py
CHANGED
|
@@ -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
|
-
|
|
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.
|
|
@@ -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
|
dara/core/internal/pool/utils.py
CHANGED
|
@@ -68,7 +68,7 @@ def store_in_shared_memory(content: Any) -> SharedMemoryPointer:
|
|
|
68
68
|
data_size = len(pickled_args)
|
|
69
69
|
|
|
70
70
|
shared_mem = SharedMemory(create=True, size=data_size)
|
|
71
|
-
|
|
71
|
+
assert shared_mem.buf
|
|
72
72
|
shared_mem.buf[0:data_size] = pickled_args
|
|
73
73
|
shared_mem.close()
|
|
74
74
|
|
|
@@ -88,6 +88,7 @@ def read_from_shared_memory(pointer: SharedMemoryPointer) -> Any:
|
|
|
88
88
|
|
|
89
89
|
# Read from memory
|
|
90
90
|
shared_mem = SharedMemory(name=shared_mem_name)
|
|
91
|
+
assert shared_mem.buf
|
|
91
92
|
data = shared_mem.buf[:data_size]
|
|
92
93
|
|
|
93
94
|
# Unpickle and deepcopy
|
dara/core/internal/tasks.py
CHANGED
|
@@ -19,7 +19,7 @@ import contextlib
|
|
|
19
19
|
import inspect
|
|
20
20
|
import math
|
|
21
21
|
from collections.abc import Awaitable
|
|
22
|
-
from typing import Any, Callable, Dict, List, Optional, Set, Union, overload
|
|
22
|
+
from typing import Any, Callable, Dict, List, Optional, Set, Union, cast, overload
|
|
23
23
|
|
|
24
24
|
from anyio import (
|
|
25
25
|
BrokenResourceError,
|
|
@@ -453,8 +453,8 @@ class TaskManager:
|
|
|
453
453
|
|
|
454
454
|
# Notify channels that this specific task was cancelled
|
|
455
455
|
if notify:
|
|
456
|
-
await self.
|
|
457
|
-
|
|
456
|
+
await self._send_notification_for_task(
|
|
457
|
+
task=pending_task,
|
|
458
458
|
messages=[{'status': 'CANCELED', 'task_id': task_id_to_cancel}],
|
|
459
459
|
)
|
|
460
460
|
|
|
@@ -556,12 +556,14 @@ class TaskManager:
|
|
|
556
556
|
|
|
557
557
|
return task_ids
|
|
558
558
|
|
|
559
|
-
async def _multicast_notification(self, task_id: str, messages: List[dict]):
|
|
559
|
+
async def _multicast_notification(self, task_id: str, messages: List[dict], variable_task_id: bool = True):
|
|
560
560
|
"""
|
|
561
561
|
Send notifications to all task IDs that are related to a given task
|
|
562
562
|
|
|
563
563
|
:param task: the task the notifications are related to
|
|
564
564
|
:param messages: List of message dictionaries to send to all related tasks
|
|
565
|
+
:param variable_task_id: whether the task_id in messages should be replaced with the task being notified
|
|
566
|
+
or if False, the task_id should be left as is
|
|
565
567
|
"""
|
|
566
568
|
# prevent cancellation, we need the notifications to be sent
|
|
567
569
|
with CancelScope(shield=True):
|
|
@@ -581,28 +583,33 @@ class TaskManager:
|
|
|
581
583
|
if pending_task_id not in self.tasks:
|
|
582
584
|
continue
|
|
583
585
|
pending_task = self.tasks[pending_task_id]
|
|
584
|
-
task_tg.start_soon(self.
|
|
586
|
+
task_tg.start_soon(self._send_notification_for_task, pending_task, messages, variable_task_id)
|
|
585
587
|
|
|
586
|
-
async def
|
|
588
|
+
async def _send_notification_for_task(self, task: BaseTask, messages: List[dict], variable_task_id: bool = True):
|
|
587
589
|
"""
|
|
588
590
|
Send notifications for a specific PendingTask
|
|
589
591
|
|
|
590
592
|
:param pending_task: The PendingTask to send notifications for
|
|
591
593
|
:param messages: The messages to send
|
|
594
|
+
:param variable_task_id: whether the task_id in messages should be replaced with the task being notified
|
|
592
595
|
"""
|
|
593
596
|
# Collect channels for this PendingTask
|
|
594
|
-
channels_to_notify = set(
|
|
595
|
-
|
|
597
|
+
channels_to_notify = set(task.notify_channels)
|
|
598
|
+
if isinstance(task, PendingTask):
|
|
599
|
+
channels_to_notify.update(task.task_def.notify_channels)
|
|
596
600
|
|
|
597
601
|
if not channels_to_notify:
|
|
598
602
|
return
|
|
599
603
|
|
|
600
|
-
# Send to all channels for this
|
|
604
|
+
# Send to all channels for this Task in parallel
|
|
601
605
|
async def _send_to_channel(channel: str):
|
|
602
606
|
async with create_task_group() as channel_tg:
|
|
603
607
|
for message in messages:
|
|
604
|
-
|
|
605
|
-
|
|
608
|
+
if variable_task_id:
|
|
609
|
+
# Create message with this Task's task_id (if message has task_id)
|
|
610
|
+
message_for_task = {**message, 'task_id': task.task_id} if 'task_id' in message else message
|
|
611
|
+
else:
|
|
612
|
+
message_for_task = message
|
|
606
613
|
channel_tg.start_soon(self.ws_manager.send_message, channel, message_for_task)
|
|
607
614
|
|
|
608
615
|
async with create_task_group() as channel_tg:
|
|
@@ -633,13 +640,18 @@ class TaskManager:
|
|
|
633
640
|
async for message in receive_stream:
|
|
634
641
|
if isinstance(message, TaskProgressUpdate):
|
|
635
642
|
# Send progress notifications to related tasks
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
+
await self._multicast_notification(
|
|
644
|
+
task_id=message.task_id,
|
|
645
|
+
messages=[
|
|
646
|
+
{
|
|
647
|
+
# Will be updated per task ID in multicast
|
|
648
|
+
'task_id': message.task_id,
|
|
649
|
+
'status': 'PROGRESS',
|
|
650
|
+
'progress': message.progress,
|
|
651
|
+
'message': message.message,
|
|
652
|
+
}
|
|
653
|
+
],
|
|
654
|
+
)
|
|
643
655
|
if isinstance(task, Task) and task.on_progress:
|
|
644
656
|
await run_user_handler(task.on_progress, args=(message,))
|
|
645
657
|
elif isinstance(message, TaskResult):
|
|
@@ -659,10 +671,17 @@ class TaskManager:
|
|
|
659
671
|
# Set final result
|
|
660
672
|
await self.set_result(message.task_id, message.result)
|
|
661
673
|
|
|
662
|
-
#
|
|
674
|
+
# NOTE: this is still multicasting to all related channels to ensure
|
|
675
|
+
# all interested parties are notified, but notably we use `variable_task_id=False`
|
|
676
|
+
# to only notify about the task that actually completed,
|
|
677
|
+
# as opposed to e.g. progress, errors and cancellations which
|
|
678
|
+
# we 'bubble up' by updating the task_id in the message to the respective related task
|
|
663
679
|
await self._multicast_notification(
|
|
664
680
|
task_id=message.task_id,
|
|
665
|
-
messages=[
|
|
681
|
+
messages=[
|
|
682
|
+
{'result': message.result, 'status': 'COMPLETE', 'task_id': message.task_id},
|
|
683
|
+
],
|
|
684
|
+
variable_task_id=False,
|
|
666
685
|
)
|
|
667
686
|
|
|
668
687
|
# Remove the task from the registered tasks - it finished running
|
|
@@ -726,7 +745,8 @@ class TaskManager:
|
|
|
726
745
|
eng_logger.info(f'TaskManager finished task {task.task_id}', {'result': result})
|
|
727
746
|
finally:
|
|
728
747
|
with CancelScope(shield=True):
|
|
729
|
-
# pyright
|
|
748
|
+
# cast explicitly as otherwise pyright thinks it's always None here
|
|
749
|
+
task_error = cast(Optional[ExceptionGroup], task_error)
|
|
730
750
|
if task_error is not None:
|
|
731
751
|
err = task_error
|
|
732
752
|
# Mark pending task as failed
|
|
@@ -755,8 +775,8 @@ class TaskManager:
|
|
|
755
775
|
error = get_error_for_channel(err)
|
|
756
776
|
message = {'status': 'ERROR', 'task_id': task.task_id, 'error': error['error']}
|
|
757
777
|
# Notify about this task failing, and a server broadcast error
|
|
758
|
-
await self.
|
|
759
|
-
|
|
778
|
+
await self._send_notification_for_task(
|
|
779
|
+
task=pending_task,
|
|
760
780
|
messages=[message, error],
|
|
761
781
|
)
|
|
762
782
|
# notify related tasks
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: dara-core
|
|
3
|
-
Version: 1.21.
|
|
3
|
+
Version: 1.21.14
|
|
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.
|
|
24
|
+
Requires-Dist: create-dara-app (==1.21.14)
|
|
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.
|
|
27
|
+
Requires-Dist: dara-components (==1.21.14) ; 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.
|
|
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.
|
|
58
|
+
<img src="https://github.com/causalens/dara/blob/v1.21.14/img/dara_light.svg?raw=true">
|
|
59
59
|
|
|
60
60
|

|
|
61
61
|
[](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
|
-

|
|
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
|
-
|  | Demonstrates how to use incorporate a LLM chat box into your decision app to understand model insights |
|
|
121
|
+
|  | 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
|
+
|  | 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.
|
|
149
|
+
More information on the repository structure can be found in the [CONTRIBUTING.md](https://github.com/causalens/dara/blob/v1.21.14/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.
|
|
153
|
+
Dara is open-source and licensed under the [Apache 2.0 License](https://github.com/causalens/dara/blob/v1.21.14/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=
|
|
9
|
+
dara/core/base_definitions.py,sha256=WvVUpKux8pecSDSd8MynDS9QhGNk5SJYlR5mwxdL9kg,18554
|
|
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=
|
|
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
|
|
@@ -55,7 +55,7 @@ dara/core/internal/pool/__init__.py,sha256=pBbXE5GR3abVC9Lg3i0QxfdmsrBDMJUYAYb0S
|
|
|
55
55
|
dara/core/internal/pool/channel.py,sha256=TbyIE-PnfzzsQYhl3INOs5UIHHbF_h9bMFne5FjbWlQ,4948
|
|
56
56
|
dara/core/internal/pool/definitions.py,sha256=27dtsyHsztc7zgr2axMWCn1O9pBNI_VKByGxjvKHBGc,4649
|
|
57
57
|
dara/core/internal/pool/task_pool.py,sha256=MqzUtoGEjeXdpCdTmBXQmQt582u0suiL5vwrsj1slhY,17780
|
|
58
|
-
dara/core/internal/pool/utils.py,sha256=
|
|
58
|
+
dara/core/internal/pool/utils.py,sha256=7M8A3lYfp3TVB6yPf-6-nnSr5j6TCqHzdT9I639lUS0,5470
|
|
59
59
|
dara/core/internal/pool/worker.py,sha256=eBi3FS652goZxu9chaRT89eHDvqJW0aHjt8I5UgyESA,6808
|
|
60
60
|
dara/core/internal/port_utils.py,sha256=3NN94CubNrIYQKmPM4SEwstY-UMqsbbe1M_JhyPcncA,1654
|
|
61
61
|
dara/core/internal/registries.py,sha256=1lY9xrggiyUlM32pPyzFEfflW3_37QGOxTDrfWQ4CN4,3659
|
|
@@ -65,7 +65,7 @@ dara/core/internal/routing.py,sha256=El2rRuJODoTuZvyay1LSbxCX8IvGDos3dwXYn1RIHZs
|
|
|
65
65
|
dara/core/internal/scheduler.py,sha256=rmj-NnHHToWBPuteKlf0RmKcav2Hz0Z9-l4uyrAGKSI,13069
|
|
66
66
|
dara/core/internal/settings.py,sha256=DxRvXcelawaKemTcX6JIVIilibn0XO5Bd98dCXau4zg,3937
|
|
67
67
|
dara/core/internal/store.py,sha256=Z4EUMwHR0DR-TVCL9csSGYE3toxh15iRpBP2c7MUgr8,6442
|
|
68
|
-
dara/core/internal/tasks.py,sha256=
|
|
68
|
+
dara/core/internal/tasks.py,sha256=84-87FtxsoCp-SrhE3w-rcMuj-yiaNs2itPYt0n-0dQ,36098
|
|
69
69
|
dara/core/internal/utils.py,sha256=nUnwy1BLW9HUQro9ASAYb-AlNJkbaT_bQ1bE2e1q1wo,9088
|
|
70
70
|
dara/core/internal/websocket.py,sha256=rcipt5XY48akMuLHFdvUUIgNLqzJx7ovLeiPsYVMELM,21953
|
|
71
71
|
dara/core/jinja/index.html,sha256=5Sq_FwXn0F4dOyRFprfoh_tn0GUq6_aLYyYdpzQLdeM,3312
|
|
@@ -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.
|
|
124
|
-
dara_core-1.21.
|
|
125
|
-
dara_core-1.21.
|
|
126
|
-
dara_core-1.21.
|
|
127
|
-
dara_core-1.21.
|
|
123
|
+
dara_core-1.21.14.dist-info/LICENSE,sha256=r9u1w2RvpLMV6YjuXHIKXRBKzia3fx_roPwboGcLqCc,10944
|
|
124
|
+
dara_core-1.21.14.dist-info/METADATA,sha256=JslUc0pvrvAletjdM8pEegcpBExpuCmmxTXtx0G4GjU,7544
|
|
125
|
+
dara_core-1.21.14.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
126
|
+
dara_core-1.21.14.dist-info/entry_points.txt,sha256=H__D5sNIGuPIhVam0DChNL-To5k8Y7nY7TAFz9Mz6cc,139
|
|
127
|
+
dara_core-1.21.14.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|