chainlit 2.7.0__py3-none-any.whl → 2.7.1__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.
Potentially problematic release.
This version of chainlit might be problematic. Click here for more details.
- {chainlit-2.7.0.dist-info → chainlit-2.7.1.dist-info}/METADATA +1 -1
- chainlit-2.7.1.dist-info/RECORD +4 -0
- chainlit/__init__.py +0 -207
- chainlit/__main__.py +0 -4
- chainlit/_utils.py +0 -8
- chainlit/action.py +0 -33
- chainlit/auth/__init__.py +0 -95
- chainlit/auth/cookie.py +0 -197
- chainlit/auth/jwt.py +0 -42
- chainlit/cache.py +0 -45
- chainlit/callbacks.py +0 -433
- chainlit/chat_context.py +0 -64
- chainlit/chat_settings.py +0 -34
- chainlit/cli/__init__.py +0 -235
- chainlit/config.py +0 -621
- chainlit/context.py +0 -112
- chainlit/data/__init__.py +0 -111
- chainlit/data/acl.py +0 -19
- chainlit/data/base.py +0 -107
- chainlit/data/chainlit_data_layer.py +0 -687
- chainlit/data/dynamodb.py +0 -616
- chainlit/data/literalai.py +0 -501
- chainlit/data/sql_alchemy.py +0 -741
- chainlit/data/storage_clients/__init__.py +0 -0
- chainlit/data/storage_clients/azure.py +0 -84
- chainlit/data/storage_clients/azure_blob.py +0 -94
- chainlit/data/storage_clients/base.py +0 -28
- chainlit/data/storage_clients/gcs.py +0 -101
- chainlit/data/storage_clients/s3.py +0 -88
- chainlit/data/utils.py +0 -29
- chainlit/discord/__init__.py +0 -6
- chainlit/discord/app.py +0 -364
- chainlit/element.py +0 -454
- chainlit/emitter.py +0 -450
- chainlit/hello.py +0 -12
- chainlit/input_widget.py +0 -182
- chainlit/langchain/__init__.py +0 -6
- chainlit/langchain/callbacks.py +0 -682
- chainlit/langflow/__init__.py +0 -25
- chainlit/llama_index/__init__.py +0 -6
- chainlit/llama_index/callbacks.py +0 -206
- chainlit/logger.py +0 -16
- chainlit/markdown.py +0 -57
- chainlit/mcp.py +0 -99
- chainlit/message.py +0 -619
- chainlit/mistralai/__init__.py +0 -50
- chainlit/oauth_providers.py +0 -835
- chainlit/openai/__init__.py +0 -53
- chainlit/py.typed +0 -0
- chainlit/secret.py +0 -9
- chainlit/semantic_kernel/__init__.py +0 -111
- chainlit/server.py +0 -1616
- chainlit/session.py +0 -304
- chainlit/sidebar.py +0 -55
- chainlit/slack/__init__.py +0 -6
- chainlit/slack/app.py +0 -427
- chainlit/socket.py +0 -381
- chainlit/step.py +0 -490
- chainlit/sync.py +0 -43
- chainlit/teams/__init__.py +0 -6
- chainlit/teams/app.py +0 -348
- chainlit/translations/bn.json +0 -214
- chainlit/translations/el-GR.json +0 -214
- chainlit/translations/en-US.json +0 -214
- chainlit/translations/fr-FR.json +0 -214
- chainlit/translations/gu.json +0 -214
- chainlit/translations/he-IL.json +0 -214
- chainlit/translations/hi.json +0 -214
- chainlit/translations/ja.json +0 -214
- chainlit/translations/kn.json +0 -214
- chainlit/translations/ml.json +0 -214
- chainlit/translations/mr.json +0 -214
- chainlit/translations/nl.json +0 -214
- chainlit/translations/ta.json +0 -214
- chainlit/translations/te.json +0 -214
- chainlit/translations/zh-CN.json +0 -214
- chainlit/translations.py +0 -60
- chainlit/types.py +0 -334
- chainlit/user.py +0 -43
- chainlit/user_session.py +0 -153
- chainlit/utils.py +0 -173
- chainlit/version.py +0 -8
- chainlit-2.7.0.dist-info/RECORD +0 -84
- {chainlit-2.7.0.dist-info → chainlit-2.7.1.dist-info}/WHEEL +0 -0
- {chainlit-2.7.0.dist-info → chainlit-2.7.1.dist-info}/entry_points.txt +0 -0
chainlit/element.py
DELETED
|
@@ -1,454 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
import mimetypes
|
|
3
|
-
import uuid
|
|
4
|
-
from enum import Enum
|
|
5
|
-
from io import BytesIO
|
|
6
|
-
from typing import (
|
|
7
|
-
Any,
|
|
8
|
-
ClassVar,
|
|
9
|
-
Dict,
|
|
10
|
-
List,
|
|
11
|
-
Literal,
|
|
12
|
-
Optional,
|
|
13
|
-
TypedDict,
|
|
14
|
-
TypeVar,
|
|
15
|
-
Union,
|
|
16
|
-
)
|
|
17
|
-
|
|
18
|
-
import filetype
|
|
19
|
-
from pydantic import Field
|
|
20
|
-
from pydantic.dataclasses import dataclass
|
|
21
|
-
from syncer import asyncio
|
|
22
|
-
|
|
23
|
-
from chainlit.context import context
|
|
24
|
-
from chainlit.data import get_data_layer
|
|
25
|
-
from chainlit.logger import logger
|
|
26
|
-
|
|
27
|
-
mime_types = {
|
|
28
|
-
"text": "text/plain",
|
|
29
|
-
"tasklist": "application/json",
|
|
30
|
-
"plotly": "application/json",
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
ElementType = Literal[
|
|
34
|
-
"image",
|
|
35
|
-
"text",
|
|
36
|
-
"pdf",
|
|
37
|
-
"tasklist",
|
|
38
|
-
"audio",
|
|
39
|
-
"video",
|
|
40
|
-
"file",
|
|
41
|
-
"plotly",
|
|
42
|
-
"dataframe",
|
|
43
|
-
"custom",
|
|
44
|
-
]
|
|
45
|
-
ElementDisplay = Literal["inline", "side", "page"]
|
|
46
|
-
ElementSize = Literal["small", "medium", "large"]
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
class ElementDict(TypedDict, total=False):
|
|
50
|
-
id: str
|
|
51
|
-
threadId: Optional[str]
|
|
52
|
-
type: ElementType
|
|
53
|
-
chainlitKey: Optional[str]
|
|
54
|
-
path: Optional[str]
|
|
55
|
-
url: Optional[str]
|
|
56
|
-
objectKey: Optional[str]
|
|
57
|
-
name: str
|
|
58
|
-
display: ElementDisplay
|
|
59
|
-
size: Optional[ElementSize]
|
|
60
|
-
language: Optional[str]
|
|
61
|
-
page: Optional[int]
|
|
62
|
-
props: Optional[Dict]
|
|
63
|
-
autoPlay: Optional[bool]
|
|
64
|
-
playerConfig: Optional[dict]
|
|
65
|
-
forId: Optional[str]
|
|
66
|
-
mime: Optional[str]
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
@dataclass
|
|
70
|
-
class Element:
|
|
71
|
-
# Thread id
|
|
72
|
-
thread_id: str = Field(default_factory=lambda: context.session.thread_id)
|
|
73
|
-
# The type of the element. This will be used to determine how to display the element in the UI.
|
|
74
|
-
type: ClassVar[ElementType]
|
|
75
|
-
# Name of the element, this will be used to reference the element in the UI.
|
|
76
|
-
name: str = ""
|
|
77
|
-
# The ID of the element. This is set automatically when the element is sent to the UI.
|
|
78
|
-
id: str = Field(default_factory=lambda: str(uuid.uuid4()))
|
|
79
|
-
# The key of the element hosted on Chainlit.
|
|
80
|
-
chainlit_key: Optional[str] = None
|
|
81
|
-
# The URL of the element if already hosted somewhere else.
|
|
82
|
-
url: Optional[str] = None
|
|
83
|
-
# The S3 object key.
|
|
84
|
-
object_key: Optional[str] = None
|
|
85
|
-
# The local path of the element.
|
|
86
|
-
path: Optional[str] = None
|
|
87
|
-
# The byte content of the element.
|
|
88
|
-
content: Optional[Union[bytes, str]] = None
|
|
89
|
-
# Controls how the image element should be displayed in the UI. Choices are “side” (default), “inline”, or “page”.
|
|
90
|
-
display: ElementDisplay = Field(default="inline")
|
|
91
|
-
# Controls element size
|
|
92
|
-
size: Optional[ElementSize] = None
|
|
93
|
-
# The ID of the message this element is associated with.
|
|
94
|
-
for_id: Optional[str] = None
|
|
95
|
-
# The language, if relevant
|
|
96
|
-
language: Optional[str] = None
|
|
97
|
-
# Mime type, inferred based on content if not provided
|
|
98
|
-
mime: Optional[str] = None
|
|
99
|
-
|
|
100
|
-
def __post_init__(self) -> None:
|
|
101
|
-
self.persisted = False
|
|
102
|
-
self.updatable = False
|
|
103
|
-
|
|
104
|
-
if not self.url and not self.path and not self.content:
|
|
105
|
-
raise ValueError("Must provide url, path or content to instantiate element")
|
|
106
|
-
|
|
107
|
-
def to_dict(self) -> ElementDict:
|
|
108
|
-
_dict = ElementDict(
|
|
109
|
-
{
|
|
110
|
-
"id": self.id,
|
|
111
|
-
"threadId": self.thread_id,
|
|
112
|
-
"type": self.type,
|
|
113
|
-
"url": self.url,
|
|
114
|
-
"chainlitKey": self.chainlit_key,
|
|
115
|
-
"name": self.name,
|
|
116
|
-
"display": self.display,
|
|
117
|
-
"objectKey": getattr(self, "object_key", None),
|
|
118
|
-
"size": getattr(self, "size", None),
|
|
119
|
-
"props": getattr(self, "props", None),
|
|
120
|
-
"page": getattr(self, "page", None),
|
|
121
|
-
"autoPlay": getattr(self, "auto_play", None),
|
|
122
|
-
"playerConfig": getattr(self, "player_config", None),
|
|
123
|
-
"language": getattr(self, "language", None),
|
|
124
|
-
"forId": getattr(self, "for_id", None),
|
|
125
|
-
"mime": getattr(self, "mime", None),
|
|
126
|
-
}
|
|
127
|
-
)
|
|
128
|
-
return _dict
|
|
129
|
-
|
|
130
|
-
@classmethod
|
|
131
|
-
def from_dict(cls, e_dict: ElementDict):
|
|
132
|
-
"""
|
|
133
|
-
Create an Element instance from a dictionary representation.
|
|
134
|
-
|
|
135
|
-
Args:
|
|
136
|
-
_dict (ElementDict): Dictionary containing element data
|
|
137
|
-
|
|
138
|
-
Returns:
|
|
139
|
-
Element: An instance of the appropriate Element subclass
|
|
140
|
-
"""
|
|
141
|
-
element_id = e_dict.get("id", str(uuid.uuid4()))
|
|
142
|
-
for_id = e_dict.get("forId")
|
|
143
|
-
name = e_dict.get("name", "")
|
|
144
|
-
type = e_dict.get("type", "file")
|
|
145
|
-
path = str(e_dict.get("path")) if e_dict.get("path") else None
|
|
146
|
-
url = str(e_dict.get("url")) if e_dict.get("url") else None
|
|
147
|
-
content = str(e_dict.get("content")) if e_dict.get("content") else None
|
|
148
|
-
object_key = e_dict.get("objectKey")
|
|
149
|
-
chainlit_key = e_dict.get("chainlitKey")
|
|
150
|
-
display = e_dict.get("display", "inline")
|
|
151
|
-
mime_type = e_dict.get("mime", "")
|
|
152
|
-
|
|
153
|
-
# Common parameters for all element types
|
|
154
|
-
common_params = {
|
|
155
|
-
"id": element_id,
|
|
156
|
-
"for_id": for_id,
|
|
157
|
-
"name": name,
|
|
158
|
-
"content": content,
|
|
159
|
-
"path": path,
|
|
160
|
-
"url": url,
|
|
161
|
-
"object_key": object_key,
|
|
162
|
-
"chainlit_key": chainlit_key,
|
|
163
|
-
"display": display,
|
|
164
|
-
"mime": mime_type,
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
if type == "image":
|
|
168
|
-
return Image(size="medium", **common_params) # type: ignore[arg-type]
|
|
169
|
-
|
|
170
|
-
elif type == "audio":
|
|
171
|
-
return Audio(auto_play=e_dict.get("autoPlay", False), **common_params) # type: ignore[arg-type]
|
|
172
|
-
|
|
173
|
-
elif type == "video":
|
|
174
|
-
return Video(
|
|
175
|
-
player_config=e_dict.get("playerConfig"),
|
|
176
|
-
**common_params, # type: ignore[arg-type]
|
|
177
|
-
)
|
|
178
|
-
|
|
179
|
-
elif type == "plotly":
|
|
180
|
-
return Plotly(size=e_dict.get("size", "medium"), **common_params) # type: ignore[arg-type]
|
|
181
|
-
|
|
182
|
-
elif type == "custom":
|
|
183
|
-
return CustomElement(props=e_dict.get("props", {}), **common_params) # type: ignore[arg-type]
|
|
184
|
-
else:
|
|
185
|
-
# Default to File for any other type
|
|
186
|
-
return File(**common_params) # type: ignore[arg-type]
|
|
187
|
-
|
|
188
|
-
@classmethod
|
|
189
|
-
def infer_type_from_mime(cls, mime_type: str):
|
|
190
|
-
"""Infer the element type from a mime type. Useful to know which element to instantiate from a file upload."""
|
|
191
|
-
if "image" in mime_type:
|
|
192
|
-
return "image"
|
|
193
|
-
|
|
194
|
-
elif mime_type == "application/pdf":
|
|
195
|
-
return "pdf"
|
|
196
|
-
|
|
197
|
-
elif "audio" in mime_type:
|
|
198
|
-
return "audio"
|
|
199
|
-
|
|
200
|
-
elif "video" in mime_type:
|
|
201
|
-
return "video"
|
|
202
|
-
|
|
203
|
-
else:
|
|
204
|
-
return "file"
|
|
205
|
-
|
|
206
|
-
async def _create(self, persist=True) -> bool:
|
|
207
|
-
if self.persisted and not self.updatable:
|
|
208
|
-
return True
|
|
209
|
-
|
|
210
|
-
if (data_layer := get_data_layer()) and persist:
|
|
211
|
-
try:
|
|
212
|
-
asyncio.create_task(data_layer.create_element(self))
|
|
213
|
-
except Exception as e:
|
|
214
|
-
logger.error(f"Failed to create element: {e!s}")
|
|
215
|
-
if not self.url and (not self.chainlit_key or self.updatable):
|
|
216
|
-
file_dict = await context.session.persist_file(
|
|
217
|
-
name=self.name,
|
|
218
|
-
path=self.path,
|
|
219
|
-
content=self.content,
|
|
220
|
-
mime=self.mime or "",
|
|
221
|
-
)
|
|
222
|
-
self.chainlit_key = file_dict["id"]
|
|
223
|
-
|
|
224
|
-
self.persisted = True
|
|
225
|
-
|
|
226
|
-
return True
|
|
227
|
-
|
|
228
|
-
async def remove(self):
|
|
229
|
-
data_layer = get_data_layer()
|
|
230
|
-
if data_layer:
|
|
231
|
-
await data_layer.delete_element(self.id, self.thread_id)
|
|
232
|
-
await context.emitter.emit("remove_element", {"id": self.id})
|
|
233
|
-
|
|
234
|
-
async def send(self, for_id: str, persist=True):
|
|
235
|
-
self.for_id = for_id
|
|
236
|
-
|
|
237
|
-
if not self.mime:
|
|
238
|
-
if self.type in mime_types:
|
|
239
|
-
self.mime = mime_types[self.type]
|
|
240
|
-
elif self.path or isinstance(self.content, (bytes, bytearray)):
|
|
241
|
-
file_type = filetype.guess(self.path or self.content)
|
|
242
|
-
if file_type:
|
|
243
|
-
self.mime = file_type.mime
|
|
244
|
-
elif self.url:
|
|
245
|
-
self.mime = mimetypes.guess_type(self.url)[0]
|
|
246
|
-
|
|
247
|
-
await self._create(persist=persist)
|
|
248
|
-
|
|
249
|
-
if not self.url and not self.chainlit_key:
|
|
250
|
-
raise ValueError("Must provide url or chainlit key to send element")
|
|
251
|
-
|
|
252
|
-
await context.emitter.send_element(self.to_dict())
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
ElementBased = TypeVar("ElementBased", bound=Element)
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
@dataclass
|
|
259
|
-
class Image(Element):
|
|
260
|
-
type: ClassVar[ElementType] = "image"
|
|
261
|
-
|
|
262
|
-
size: ElementSize = "medium"
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
@dataclass
|
|
266
|
-
class Text(Element):
|
|
267
|
-
"""Useful to send a text (not a message) to the UI."""
|
|
268
|
-
|
|
269
|
-
type: ClassVar[ElementType] = "text"
|
|
270
|
-
language: Optional[str] = None
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
@dataclass
|
|
274
|
-
class Pdf(Element):
|
|
275
|
-
"""Useful to send a pdf to the UI."""
|
|
276
|
-
|
|
277
|
-
mime: str = "application/pdf"
|
|
278
|
-
page: Optional[int] = None
|
|
279
|
-
type: ClassVar[ElementType] = "pdf"
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
@dataclass
|
|
283
|
-
class Pyplot(Element):
|
|
284
|
-
"""Useful to send a pyplot to the UI."""
|
|
285
|
-
|
|
286
|
-
# We reuse the frontend image element to display the chart
|
|
287
|
-
type: ClassVar[ElementType] = "image"
|
|
288
|
-
|
|
289
|
-
size: ElementSize = "medium"
|
|
290
|
-
# The type is set to Any because the figure is not serializable
|
|
291
|
-
# and its actual type is checked in __post_init__.
|
|
292
|
-
figure: Any = None
|
|
293
|
-
|
|
294
|
-
def __post_init__(self) -> None:
|
|
295
|
-
from matplotlib.figure import Figure
|
|
296
|
-
|
|
297
|
-
if not isinstance(self.figure, Figure):
|
|
298
|
-
raise TypeError("figure must be a matplotlib.figure.Figure")
|
|
299
|
-
|
|
300
|
-
image = BytesIO()
|
|
301
|
-
self.figure.savefig(
|
|
302
|
-
image, dpi=200, bbox_inches="tight", backend="Agg", format="png"
|
|
303
|
-
)
|
|
304
|
-
self.content = image.getvalue()
|
|
305
|
-
|
|
306
|
-
super().__post_init__()
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
class TaskStatus(Enum):
|
|
310
|
-
READY = "ready"
|
|
311
|
-
RUNNING = "running"
|
|
312
|
-
FAILED = "failed"
|
|
313
|
-
DONE = "done"
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
@dataclass
|
|
317
|
-
class Task:
|
|
318
|
-
title: str
|
|
319
|
-
status: TaskStatus = TaskStatus.READY
|
|
320
|
-
forId: Optional[str] = None
|
|
321
|
-
|
|
322
|
-
def __init__(
|
|
323
|
-
self,
|
|
324
|
-
title: str,
|
|
325
|
-
status: TaskStatus = TaskStatus.READY,
|
|
326
|
-
forId: Optional[str] = None,
|
|
327
|
-
):
|
|
328
|
-
self.title = title
|
|
329
|
-
self.status = status
|
|
330
|
-
self.forId = forId
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
@dataclass
|
|
334
|
-
class TaskList(Element):
|
|
335
|
-
type: ClassVar[ElementType] = "tasklist"
|
|
336
|
-
tasks: List[Task] = Field(default_factory=list, exclude=True)
|
|
337
|
-
status: str = "Ready"
|
|
338
|
-
name: str = "tasklist"
|
|
339
|
-
content: str = "dummy content to pass validation"
|
|
340
|
-
|
|
341
|
-
def __post_init__(self) -> None:
|
|
342
|
-
super().__post_init__()
|
|
343
|
-
self.updatable = True
|
|
344
|
-
|
|
345
|
-
async def add_task(self, task: Task):
|
|
346
|
-
self.tasks.append(task)
|
|
347
|
-
|
|
348
|
-
async def update(self):
|
|
349
|
-
await self.send()
|
|
350
|
-
|
|
351
|
-
async def send(self):
|
|
352
|
-
await self.preprocess_content()
|
|
353
|
-
await super().send(for_id="")
|
|
354
|
-
|
|
355
|
-
async def preprocess_content(self):
|
|
356
|
-
# serialize enum
|
|
357
|
-
tasks = [
|
|
358
|
-
{"title": task.title, "status": task.status.value, "forId": task.forId}
|
|
359
|
-
for task in self.tasks
|
|
360
|
-
]
|
|
361
|
-
|
|
362
|
-
# store stringified json in content so that it's correctly stored in the database
|
|
363
|
-
self.content = json.dumps(
|
|
364
|
-
{
|
|
365
|
-
"status": self.status,
|
|
366
|
-
"tasks": tasks,
|
|
367
|
-
},
|
|
368
|
-
indent=4,
|
|
369
|
-
ensure_ascii=False,
|
|
370
|
-
)
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
@dataclass
|
|
374
|
-
class Audio(Element):
|
|
375
|
-
type: ClassVar[ElementType] = "audio"
|
|
376
|
-
auto_play: bool = False
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
@dataclass
|
|
380
|
-
class Video(Element):
|
|
381
|
-
type: ClassVar[ElementType] = "video"
|
|
382
|
-
|
|
383
|
-
size: ElementSize = "medium"
|
|
384
|
-
# Override settings for each type of player in ReactPlayer
|
|
385
|
-
# https://github.com/cookpete/react-player?tab=readme-ov-file#config-prop
|
|
386
|
-
player_config: Optional[dict] = None
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
@dataclass
|
|
390
|
-
class File(Element):
|
|
391
|
-
type: ClassVar[ElementType] = "file"
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
@dataclass
|
|
395
|
-
class Plotly(Element):
|
|
396
|
-
"""Useful to send a plotly to the UI."""
|
|
397
|
-
|
|
398
|
-
type: ClassVar[ElementType] = "plotly"
|
|
399
|
-
|
|
400
|
-
size: ElementSize = "medium"
|
|
401
|
-
# The type is set to Any because the figure is not serializable
|
|
402
|
-
# and its actual type is checked in __post_init__.
|
|
403
|
-
figure: Any = None
|
|
404
|
-
content: str = ""
|
|
405
|
-
|
|
406
|
-
def __post_init__(self) -> None:
|
|
407
|
-
from plotly import graph_objects as go, io as pio
|
|
408
|
-
|
|
409
|
-
if not isinstance(self.figure, go.Figure):
|
|
410
|
-
raise TypeError("figure must be a plotly.graph_objects.Figure")
|
|
411
|
-
|
|
412
|
-
self.figure.layout.autosize = True
|
|
413
|
-
self.figure.layout.width = None
|
|
414
|
-
self.figure.layout.height = None
|
|
415
|
-
self.content = pio.to_json(self.figure, validate=True)
|
|
416
|
-
self.mime = "application/json"
|
|
417
|
-
|
|
418
|
-
super().__post_init__()
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
@dataclass
|
|
422
|
-
class Dataframe(Element):
|
|
423
|
-
"""Useful to send a pandas DataFrame to the UI."""
|
|
424
|
-
|
|
425
|
-
type: ClassVar[ElementType] = "dataframe"
|
|
426
|
-
size: ElementSize = "large"
|
|
427
|
-
data: Any = None # The type is Any because it is checked in __post_init__.
|
|
428
|
-
|
|
429
|
-
def __post_init__(self) -> None:
|
|
430
|
-
"""Ensures the data is a pandas DataFrame and converts it to JSON."""
|
|
431
|
-
from pandas import DataFrame
|
|
432
|
-
|
|
433
|
-
if not isinstance(self.data, DataFrame):
|
|
434
|
-
raise TypeError("data must be a pandas.DataFrame")
|
|
435
|
-
|
|
436
|
-
self.content = self.data.to_json(orient="split", date_format="iso")
|
|
437
|
-
super().__post_init__()
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
@dataclass
|
|
441
|
-
class CustomElement(Element):
|
|
442
|
-
"""Useful to send a custom element to the UI."""
|
|
443
|
-
|
|
444
|
-
type: ClassVar[ElementType] = "custom"
|
|
445
|
-
mime: str = "application/json"
|
|
446
|
-
props: Dict = Field(default_factory=dict)
|
|
447
|
-
|
|
448
|
-
def __post_init__(self) -> None:
|
|
449
|
-
self.content = json.dumps(self.props)
|
|
450
|
-
super().__post_init__()
|
|
451
|
-
self.updatable = True
|
|
452
|
-
|
|
453
|
-
async def update(self):
|
|
454
|
-
await super().send(self.for_id)
|