streamlit-nightly 1.21.1.dev20230423__py2.py3-none-any.whl → 1.21.1.dev20230425__py2.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.
- streamlit/__init__.py +0 -7
- streamlit/elements/arrow.py +7 -264
- streamlit/elements/data_editor.py +109 -100
- streamlit/elements/file_uploader.py +17 -0
- streamlit/elements/layouts.py +0 -5
- streamlit/elements/lib/column_config_utils.py +371 -0
- streamlit/elements/lib/pandas_styler_utils.py +275 -0
- streamlit/runtime/connection_factory.py +5 -5
- streamlit/static/asset-manifest.json +20 -20
- streamlit/static/index.html +1 -1
- streamlit/static/static/js/{14.a19a6cd8.chunk.js → 14.9399e424.chunk.js} +1 -1
- streamlit/static/static/js/{227.087adf66.chunk.js → 227.9ccac1d5.chunk.js} +1 -1
- streamlit/static/static/js/{242.0daf8b47.chunk.js → 242.1b3289e0.chunk.js} +1 -1
- streamlit/static/static/js/{279.fdac58fc.chunk.js → 279.35b01780.chunk.js} +1 -1
- streamlit/static/static/js/{289.481fd42d.chunk.js → 289.e6157e40.chunk.js} +1 -1
- streamlit/static/static/js/{467.242e14ff.chunk.js → 467.50ac84df.chunk.js} +1 -1
- streamlit/static/static/js/{491.d0b710e9.chunk.js → 491.5a33a8ce.chunk.js} +1 -1
- streamlit/static/static/js/503.15864587.chunk.js +1 -0
- streamlit/static/static/js/{511.9f04ae9e.chunk.js → 511.e6ca580f.chunk.js} +1 -1
- streamlit/static/static/js/{578.ceaadcd5.chunk.js → 578.a65fcea0.chunk.js} +1 -1
- streamlit/static/static/js/{619.365611c8.chunk.js → 619.0325af0e.chunk.js} +1 -1
- streamlit/static/static/js/{628.7f41e2de.chunk.js → 628.9c70196b.chunk.js} +1 -1
- streamlit/static/static/js/{681.a2ba76c7.chunk.js → 681.9e30a8cd.chunk.js} +1 -1
- streamlit/static/static/js/{745.e2bcf16d.chunk.js → 745.e75ba963.chunk.js} +1 -1
- streamlit/static/static/js/{807.6789990f.chunk.js → 807.122f8b05.chunk.js} +1 -1
- streamlit/static/static/js/{828.096c1ad3.chunk.js → 828.0fde3da8.chunk.js} +1 -1
- streamlit/static/static/js/{871.ba625aee.chunk.js → 871.90a7dbae.chunk.js} +1 -1
- streamlit/static/static/js/{main.5e4731c6.js → main.ff35bd72.js} +2 -2
- streamlit/testing/element_tree.py +426 -548
- streamlit/type_util.py +19 -7
- {streamlit_nightly-1.21.1.dev20230423.dist-info → streamlit_nightly-1.21.1.dev20230425.dist-info}/METADATA +1 -1
- {streamlit_nightly-1.21.1.dev20230423.dist-info → streamlit_nightly-1.21.1.dev20230425.dist-info}/RECORD +38 -37
- streamlit/elements/show.py +0 -105
- streamlit/static/static/js/728.82770810.chunk.js +0 -1
- /streamlit/static/static/css/{728.23fa976d.chunk.css → 503.23fa976d.chunk.css} +0 -0
- /streamlit/static/static/js/{main.5e4731c6.js.LICENSE.txt → main.ff35bd72.js.LICENSE.txt} +0 -0
- {streamlit_nightly-1.21.1.dev20230423.data → streamlit_nightly-1.21.1.dev20230425.data}/scripts/streamlit.cmd +0 -0
- {streamlit_nightly-1.21.1.dev20230423.dist-info → streamlit_nightly-1.21.1.dev20230425.dist-info}/WHEEL +0 -0
- {streamlit_nightly-1.21.1.dev20230423.dist-info → streamlit_nightly-1.21.1.dev20230425.dist-info}/entry_points.txt +0 -0
- {streamlit_nightly-1.21.1.dev20230423.dist-info → streamlit_nightly-1.21.1.dev20230425.dist-info}/top_level.txt +0 -0
@@ -18,7 +18,7 @@ from dataclasses import dataclass, field
|
|
18
18
|
from datetime import date, datetime, time, timedelta
|
19
19
|
from typing import Any, Generic, List, Sequence, TypeVar, Union, cast, overload
|
20
20
|
|
21
|
-
from typing_extensions import Literal,
|
21
|
+
from typing_extensions import Literal, Self, TypeAlias
|
22
22
|
|
23
23
|
from streamlit import util
|
24
24
|
from streamlit.elements.heading import HeadingProtoTag
|
@@ -54,6 +54,8 @@ from streamlit.proto.WidgetStates_pb2 import WidgetState, WidgetStates
|
|
54
54
|
from streamlit.runtime.state.common import user_key_from_widget_id
|
55
55
|
from streamlit.runtime.state.session_state import SessionState
|
56
56
|
|
57
|
+
T = TypeVar("T")
|
58
|
+
|
57
59
|
|
58
60
|
# TODO This class serves as a fallback option for elements that have not
|
59
61
|
# been implemented yet, as well as providing implementations of some
|
@@ -64,7 +66,7 @@ from streamlit.runtime.state.session_state import SessionState
|
|
64
66
|
# WidgetState and provide higher level interaction interfaces, and other elements
|
65
67
|
# have enough variation in how to get their values that most will need their
|
66
68
|
# own classes too.
|
67
|
-
@dataclass
|
69
|
+
@dataclass
|
68
70
|
class Element:
|
69
71
|
type: str
|
70
72
|
proto: Any = field(repr=False)
|
@@ -103,112 +105,114 @@ class Element:
|
|
103
105
|
return util.repr_(self)
|
104
106
|
|
105
107
|
|
106
|
-
@dataclass(
|
107
|
-
class
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
self.proto = proto
|
116
|
-
self.root = root
|
117
|
-
self.type = "text"
|
108
|
+
@dataclass(repr=False)
|
109
|
+
class Widget(ABC, Element):
|
110
|
+
id: str
|
111
|
+
label: str
|
112
|
+
help: str
|
113
|
+
form_id: str
|
114
|
+
disabled: bool
|
115
|
+
key: str | None
|
116
|
+
_value: Any
|
118
117
|
|
119
|
-
|
120
|
-
|
121
|
-
return self
|
118
|
+
def set_value(self, v: Any) -> Self:
|
119
|
+
self._value = v
|
120
|
+
return self
|
122
121
|
|
123
122
|
|
124
|
-
@dataclass(
|
125
|
-
class
|
126
|
-
|
123
|
+
@dataclass(repr=False)
|
124
|
+
class Button(Widget):
|
125
|
+
_value: bool
|
127
126
|
|
128
|
-
|
129
|
-
tag: str
|
130
|
-
anchor: str | None
|
131
|
-
hide_anchor: bool
|
132
|
-
root: ElementTree = field(repr=False)
|
133
|
-
key: None
|
127
|
+
proto: ButtonProto
|
134
128
|
|
135
|
-
def __init__(self, proto:
|
129
|
+
def __init__(self, proto: ButtonProto, root: ElementTree):
|
136
130
|
self.proto = proto
|
137
|
-
self.key = None
|
138
|
-
self.tag = proto.tag
|
139
|
-
self.anchor = proto.anchor
|
140
|
-
self.hide_anchor = proto.hide_anchor
|
141
131
|
self.root = root
|
142
|
-
self.
|
143
|
-
|
144
|
-
@property
|
145
|
-
def value(self) -> str:
|
146
|
-
return self.proto.body
|
147
|
-
|
132
|
+
self._value = False
|
148
133
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
134
|
+
self.type = "button"
|
135
|
+
self.id = proto.id
|
136
|
+
self.label = proto.label
|
137
|
+
self.help = proto.help
|
138
|
+
self.form_id = proto.form_id
|
139
|
+
self.disabled = proto.disabled
|
140
|
+
self.key = user_key_from_widget_id(self.id)
|
153
141
|
|
142
|
+
def widget_state(self) -> WidgetState:
|
143
|
+
ws = WidgetState()
|
144
|
+
ws.id = self.id
|
145
|
+
ws.trigger_value = self._value
|
146
|
+
return ws
|
154
147
|
|
155
|
-
@
|
156
|
-
|
157
|
-
|
158
|
-
|
148
|
+
@property
|
149
|
+
def value(self) -> bool:
|
150
|
+
if self._value:
|
151
|
+
return self._value
|
152
|
+
else:
|
153
|
+
state = self.root.session_state
|
154
|
+
assert state
|
155
|
+
return cast(bool, state[self.id])
|
159
156
|
|
157
|
+
def set_value(self, v: bool) -> Button:
|
158
|
+
self._value = v
|
159
|
+
return self
|
160
160
|
|
161
|
-
|
162
|
-
|
163
|
-
def __init__(self, proto: HeadingProto, root: ElementTree):
|
164
|
-
super().__init__(proto, root, "subheader")
|
161
|
+
def click(self) -> Button:
|
162
|
+
return self.set_value(True)
|
165
163
|
|
166
164
|
|
167
|
-
@dataclass(
|
168
|
-
class
|
169
|
-
|
165
|
+
@dataclass(repr=False)
|
166
|
+
class Checkbox(Widget):
|
167
|
+
_value: bool | None
|
170
168
|
|
171
|
-
|
172
|
-
is_caption: bool
|
173
|
-
allow_html: bool
|
174
|
-
root: ElementTree = field(repr=False)
|
175
|
-
key: None
|
169
|
+
proto: CheckboxProto
|
176
170
|
|
177
|
-
def __init__(self, proto:
|
171
|
+
def __init__(self, proto: CheckboxProto, root: ElementTree):
|
178
172
|
self.proto = proto
|
179
|
-
self.key = None
|
180
|
-
self.is_caption = proto.is_caption
|
181
|
-
self.allow_html = proto.allow_html
|
182
173
|
self.root = root
|
183
|
-
self.
|
174
|
+
self._value = None
|
184
175
|
|
185
|
-
|
186
|
-
|
187
|
-
|
176
|
+
self.type = "checkbox"
|
177
|
+
self.id = proto.id
|
178
|
+
self.label = proto.label
|
179
|
+
self.help = proto.help
|
180
|
+
self.form_id = proto.form_id
|
181
|
+
self.disabled = proto.disabled
|
182
|
+
self.key = user_key_from_widget_id(self.id)
|
188
183
|
|
184
|
+
def widget_state(self) -> WidgetState:
|
185
|
+
ws = WidgetState()
|
186
|
+
ws.id = self.id
|
187
|
+
ws.bool_value = self.value
|
188
|
+
return ws
|
189
189
|
|
190
|
-
@
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
190
|
+
@property
|
191
|
+
def value(self) -> bool:
|
192
|
+
if self._value is not None:
|
193
|
+
return self._value
|
194
|
+
else:
|
195
|
+
state = self.root.session_state
|
196
|
+
assert state
|
197
|
+
return cast(bool, state[self.id])
|
195
198
|
|
199
|
+
def set_value(self, v: bool) -> Checkbox:
|
200
|
+
self._value = v
|
201
|
+
return self
|
196
202
|
|
197
|
-
|
198
|
-
|
199
|
-
def __init__(self, proto: MarkdownProto, root: ElementTree):
|
200
|
-
super().__init__(proto, root)
|
201
|
-
self.type = "latex"
|
203
|
+
def check(self) -> Checkbox:
|
204
|
+
return self.set_value(True)
|
202
205
|
|
206
|
+
def uncheck(self) -> Checkbox:
|
207
|
+
return self.set_value(False)
|
203
208
|
|
204
|
-
|
209
|
+
|
210
|
+
@dataclass(repr=False)
|
205
211
|
class Code(Element):
|
206
212
|
proto: CodeProto
|
207
213
|
|
208
|
-
type: str
|
209
214
|
language: str
|
210
215
|
show_line_numbers: bool
|
211
|
-
root: ElementTree = field(repr=False)
|
212
216
|
key: None
|
213
217
|
|
214
218
|
def __init__(self, proto: CodeProto, root: ElementTree):
|
@@ -225,62 +229,10 @@ class Code(Element):
|
|
225
229
|
|
226
230
|
|
227
231
|
@dataclass(repr=False)
|
228
|
-
class
|
229
|
-
type: str
|
230
|
-
message: str
|
231
|
-
is_markdown: bool
|
232
|
-
stack_trace: list[str]
|
233
|
-
is_warning: bool
|
234
|
-
|
235
|
-
def __init__(self, proto: ExceptionProto, root: ElementTree):
|
236
|
-
self.key = None
|
237
|
-
self.root = root
|
238
|
-
self.proto = proto
|
239
|
-
self.type = "exception"
|
240
|
-
|
241
|
-
self.message = proto.message
|
242
|
-
self.is_markdown = proto.message_is_markdown
|
243
|
-
self.stack_trace = list(proto.stack_trace)
|
244
|
-
self.is_warning = proto.is_warning
|
245
|
-
|
246
|
-
@property
|
247
|
-
def value(self) -> str:
|
248
|
-
return self.message
|
249
|
-
|
250
|
-
|
251
|
-
@dataclass(init=False, repr=False)
|
252
|
-
class Divider(Markdown):
|
253
|
-
def __init__(self, proto: MarkdownProto, root: ElementTree):
|
254
|
-
super().__init__(proto, root)
|
255
|
-
self.type = "divider"
|
256
|
-
|
257
|
-
|
258
|
-
@runtime_checkable
|
259
|
-
class Widget(Protocol):
|
260
|
-
id: str
|
261
|
-
key: str | None
|
262
|
-
|
263
|
-
def set_value(self, v: Any):
|
264
|
-
...
|
265
|
-
|
266
|
-
|
267
|
-
T = TypeVar("T")
|
268
|
-
|
269
|
-
|
270
|
-
@dataclass(repr=False)
|
271
|
-
class ColorPicker(Element, Widget):
|
232
|
+
class ColorPicker(Widget):
|
272
233
|
_value: str | None
|
273
234
|
|
274
235
|
proto: ColorPickerProto
|
275
|
-
type: str
|
276
|
-
id: str
|
277
|
-
label: str
|
278
|
-
help: str
|
279
|
-
form_id: str
|
280
|
-
disabled: bool
|
281
|
-
key: str | None
|
282
|
-
|
283
|
-
root: ElementTree = field(repr=False)
|
284
236
|
|
285
237
|
def __init__(self, proto: ColorPickerProto, root: ElementTree):
|
286
238
|
self.proto = proto
|
@@ -325,137 +277,170 @@ class ColorPicker(Element, Widget):
|
|
325
277
|
return self.set_value(v)
|
326
278
|
|
327
279
|
|
328
|
-
|
329
|
-
|
330
|
-
_value: T | None
|
280
|
+
SingleDateValue: TypeAlias = Union[date, datetime]
|
281
|
+
DateValue: TypeAlias = Union[SingleDateValue, Sequence[SingleDateValue]]
|
331
282
|
|
332
|
-
proto: RadioProto
|
333
|
-
type: str
|
334
|
-
id: str
|
335
|
-
label: str
|
336
|
-
options: list[str]
|
337
|
-
help: str
|
338
|
-
form_id: str
|
339
|
-
disabled: bool
|
340
|
-
horizontal: bool
|
341
|
-
key: str | None
|
342
283
|
|
343
|
-
|
284
|
+
@dataclass(repr=False)
|
285
|
+
class DateInput(Widget):
|
286
|
+
_value: DateValue | None
|
287
|
+
proto: DateInputProto
|
288
|
+
min: date
|
289
|
+
max: date
|
290
|
+
is_range: bool
|
344
291
|
|
345
|
-
def __init__(self, proto:
|
292
|
+
def __init__(self, proto: DateInputProto, root: ElementTree):
|
346
293
|
self.proto = proto
|
347
294
|
self.root = root
|
348
295
|
self._value = None
|
349
296
|
|
350
|
-
self.type = "
|
297
|
+
self.type = "date_input"
|
351
298
|
self.id = proto.id
|
352
299
|
self.label = proto.label
|
353
|
-
self.
|
300
|
+
self.min = datetime.strptime(proto.min, "%Y/%m/%d").date()
|
301
|
+
self.max = datetime.strptime(proto.max, "%Y/%m/%d").date()
|
302
|
+
self.is_range = proto.is_range
|
354
303
|
self.help = proto.help
|
355
304
|
self.form_id = proto.form_id
|
356
305
|
self.disabled = proto.disabled
|
357
|
-
self.horizontal = proto.horizontal
|
358
306
|
self.key = user_key_from_widget_id(self.id)
|
359
307
|
|
360
|
-
|
361
|
-
|
362
|
-
return self
|
308
|
+
def set_value(self, v: DateValue) -> DateInput:
|
309
|
+
self._value = v
|
310
|
+
return self
|
311
|
+
|
312
|
+
def widget_state(self) -> WidgetState:
|
313
|
+
ws = WidgetState()
|
314
|
+
ws.id = self.id
|
315
|
+
|
316
|
+
serde = DateInputSerde(None) # type: ignore
|
317
|
+
ws.string_array_value.data[:] = serde.serialize(self.value)
|
318
|
+
return ws
|
363
319
|
|
364
320
|
@property
|
365
|
-
def value(self) ->
|
366
|
-
"""The currently selected value from the options."""
|
321
|
+
def value(self) -> DateWidgetReturn:
|
367
322
|
if self._value is not None:
|
368
|
-
|
323
|
+
parsed, _ = _parse_date_value(self._value)
|
324
|
+
return tuple(parsed) # type: ignore
|
369
325
|
else:
|
370
326
|
state = self.root.session_state
|
371
327
|
assert state
|
372
|
-
return
|
328
|
+
return state[self.id] # type: ignore
|
373
329
|
|
374
|
-
def set_value(self, v: T) -> Radio[T]:
|
375
|
-
self._value = v
|
376
|
-
return self
|
377
330
|
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
ws.id = self.id
|
385
|
-
ws.int_value = self.index
|
386
|
-
return ws
|
331
|
+
@dataclass(repr=False)
|
332
|
+
class Exception(Element):
|
333
|
+
message: str
|
334
|
+
is_markdown: bool
|
335
|
+
stack_trace: list[str]
|
336
|
+
is_warning: bool
|
387
337
|
|
338
|
+
def __init__(self, proto: ExceptionProto, root: ElementTree):
|
339
|
+
self.key = None
|
340
|
+
self.root = root
|
341
|
+
self.proto = proto
|
342
|
+
self.type = "exception"
|
388
343
|
|
389
|
-
|
390
|
-
|
391
|
-
|
344
|
+
self.message = proto.message
|
345
|
+
self.is_markdown = proto.message_is_markdown
|
346
|
+
self.stack_trace = list(proto.stack_trace)
|
347
|
+
self.is_warning = proto.is_warning
|
392
348
|
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
label: str
|
397
|
-
help: str
|
398
|
-
form_id: str
|
399
|
-
disabled: bool
|
400
|
-
key: str | None
|
349
|
+
@property
|
350
|
+
def value(self) -> str:
|
351
|
+
return self.message
|
401
352
|
|
402
|
-
root: ElementTree = field(repr=False)
|
403
353
|
|
404
|
-
|
354
|
+
@dataclass(repr=False)
|
355
|
+
class HeadingBase(Element, ABC):
|
356
|
+
proto: HeadingProto
|
357
|
+
|
358
|
+
tag: str
|
359
|
+
anchor: str | None
|
360
|
+
hide_anchor: bool
|
361
|
+
key: None
|
362
|
+
|
363
|
+
def __init__(self, proto: HeadingProto, root: ElementTree, type_: str):
|
405
364
|
self.proto = proto
|
365
|
+
self.key = None
|
366
|
+
self.tag = proto.tag
|
367
|
+
self.anchor = proto.anchor
|
368
|
+
self.hide_anchor = proto.hide_anchor
|
406
369
|
self.root = root
|
407
|
-
self.
|
370
|
+
self.type = type_
|
408
371
|
|
409
|
-
|
410
|
-
|
411
|
-
self.
|
412
|
-
self.help = proto.help
|
413
|
-
self.form_id = proto.form_id
|
414
|
-
self.disabled = proto.disabled
|
415
|
-
self.key = user_key_from_widget_id(self.id)
|
372
|
+
@property
|
373
|
+
def value(self) -> str:
|
374
|
+
return self.proto.body
|
416
375
|
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
376
|
+
|
377
|
+
@dataclass(repr=False)
|
378
|
+
class Header(HeadingBase):
|
379
|
+
def __init__(self, proto: HeadingProto, root: ElementTree):
|
380
|
+
super().__init__(proto, root, "header")
|
381
|
+
|
382
|
+
|
383
|
+
@dataclass(repr=False)
|
384
|
+
class Subheader(HeadingBase):
|
385
|
+
def __init__(self, proto: HeadingProto, root: ElementTree):
|
386
|
+
super().__init__(proto, root, "subheader")
|
387
|
+
|
388
|
+
|
389
|
+
@dataclass(repr=False)
|
390
|
+
class Title(HeadingBase):
|
391
|
+
def __init__(self, proto: HeadingProto, root: ElementTree):
|
392
|
+
super().__init__(proto, root, "title")
|
393
|
+
|
394
|
+
|
395
|
+
@dataclass(repr=False)
|
396
|
+
class Markdown(Element):
|
397
|
+
proto: MarkdownProto
|
398
|
+
|
399
|
+
is_caption: bool
|
400
|
+
allow_html: bool
|
401
|
+
key: None
|
402
|
+
|
403
|
+
def __init__(self, proto: MarkdownProto, root: ElementTree):
|
404
|
+
self.proto = proto
|
405
|
+
self.key = None
|
406
|
+
self.is_caption = proto.is_caption
|
407
|
+
self.allow_html = proto.allow_html
|
408
|
+
self.root = root
|
409
|
+
self.type = "markdown"
|
422
410
|
|
423
411
|
@property
|
424
|
-
def value(self) ->
|
425
|
-
|
426
|
-
return self._value
|
427
|
-
else:
|
428
|
-
state = self.root.session_state
|
429
|
-
assert state
|
430
|
-
return cast(bool, state[self.id])
|
412
|
+
def value(self) -> str:
|
413
|
+
return self.proto.body
|
431
414
|
|
432
|
-
def set_value(self, v: bool) -> Checkbox:
|
433
|
-
self._value = v
|
434
|
-
return self
|
435
415
|
|
436
|
-
|
437
|
-
|
416
|
+
@dataclass(repr=False)
|
417
|
+
class Caption(Markdown):
|
418
|
+
def __init__(self, proto: MarkdownProto, root: ElementTree):
|
419
|
+
super().__init__(proto, root)
|
420
|
+
self.type = "caption"
|
421
|
+
|
422
|
+
|
423
|
+
@dataclass(repr=False)
|
424
|
+
class Divider(Markdown):
|
425
|
+
def __init__(self, proto: MarkdownProto, root: ElementTree):
|
426
|
+
super().__init__(proto, root)
|
427
|
+
self.type = "divider"
|
428
|
+
|
438
429
|
|
439
|
-
|
440
|
-
|
430
|
+
@dataclass(repr=False)
|
431
|
+
class Latex(Markdown):
|
432
|
+
def __init__(self, proto: MarkdownProto, root: ElementTree):
|
433
|
+
super().__init__(proto, root)
|
434
|
+
self.type = "latex"
|
441
435
|
|
442
436
|
|
443
|
-
@dataclass(
|
444
|
-
class Multiselect(
|
437
|
+
@dataclass(repr=False)
|
438
|
+
class Multiselect(Widget, Generic[T]):
|
445
439
|
_value: list[T] | None
|
446
440
|
|
447
441
|
proto: MultiSelectProto
|
448
|
-
type: str
|
449
|
-
id: str
|
450
|
-
label: str
|
451
442
|
options: list[str]
|
452
|
-
help: str
|
453
|
-
form_id: str
|
454
|
-
disabled: bool
|
455
443
|
max_selections: int
|
456
|
-
key: str | None
|
457
|
-
|
458
|
-
root: ElementTree = field(repr=False)
|
459
444
|
|
460
445
|
def __init__(self, proto: MultiSelectProto, root: ElementTree):
|
461
446
|
self.proto = proto
|
@@ -529,40 +514,88 @@ class Multiselect(Element, Widget, Generic[T]):
|
|
529
514
|
return self
|
530
515
|
|
531
516
|
|
532
|
-
|
533
|
-
|
517
|
+
Number = Union[int, float]
|
518
|
+
|
519
|
+
|
520
|
+
@dataclass(repr=False)
|
521
|
+
class NumberInput(Widget):
|
522
|
+
_value: Number | None
|
523
|
+
proto: NumberInputProto
|
524
|
+
min_value: Number
|
525
|
+
max_value: Number
|
526
|
+
step: Number
|
527
|
+
placeholder: str
|
528
|
+
|
529
|
+
def __init__(self, proto: NumberInputProto, root: ElementTree):
|
530
|
+
self.proto = proto
|
531
|
+
self.root = root
|
532
|
+
self._value = None
|
533
|
+
|
534
|
+
self.type = "number_input"
|
535
|
+
self.id = proto.id
|
536
|
+
self.label = proto.label
|
537
|
+
self.min_value = proto.min
|
538
|
+
self.max_value = proto.max
|
539
|
+
self.step = proto.step
|
540
|
+
self.help = proto.help
|
541
|
+
self.form_id = proto.form_id
|
542
|
+
self.disabled = proto.disabled
|
543
|
+
self.key = user_key_from_widget_id(self.id)
|
544
|
+
|
545
|
+
def set_value(self, v: Number) -> NumberInput:
|
546
|
+
self._value = v
|
547
|
+
return self
|
548
|
+
|
549
|
+
def widget_state(self) -> WidgetState:
|
550
|
+
ws = WidgetState()
|
551
|
+
ws.id = self.id
|
552
|
+
ws.double_value = self.value
|
553
|
+
return ws
|
554
|
+
|
555
|
+
@property
|
556
|
+
def value(self) -> Number:
|
557
|
+
if self._value is not None:
|
558
|
+
return self._value
|
559
|
+
else:
|
560
|
+
state = self.root.session_state
|
561
|
+
assert state
|
562
|
+
# Awkward to do this with `cast`
|
563
|
+
return state[self.id] # type: ignore
|
564
|
+
|
565
|
+
def increment(self) -> NumberInput:
|
566
|
+
v = min(self.value + self.step, self.max_value)
|
567
|
+
return self.set_value(v)
|
568
|
+
|
569
|
+
def decrement(self) -> NumberInput:
|
570
|
+
v = max(self.value - self.step, self.min_value)
|
571
|
+
return self.set_value(v)
|
572
|
+
|
573
|
+
|
574
|
+
@dataclass(repr=False)
|
575
|
+
class Radio(Widget, Generic[T]):
|
534
576
|
_value: T | None
|
535
577
|
|
536
|
-
proto:
|
537
|
-
type: str
|
538
|
-
id: str
|
539
|
-
label: str
|
578
|
+
proto: RadioProto
|
540
579
|
options: list[str]
|
541
|
-
|
542
|
-
form_id: str
|
543
|
-
disabled: bool
|
544
|
-
key: str | None
|
545
|
-
|
546
|
-
root: ElementTree = field(repr=False)
|
580
|
+
horizontal: bool
|
547
581
|
|
548
|
-
def __init__(self, proto:
|
582
|
+
def __init__(self, proto: RadioProto, root: ElementTree):
|
549
583
|
self.proto = proto
|
550
584
|
self.root = root
|
551
585
|
self._value = None
|
552
586
|
|
553
|
-
self.type = "
|
587
|
+
self.type = "radio"
|
554
588
|
self.id = proto.id
|
555
589
|
self.label = proto.label
|
556
590
|
self.options = list(proto.options)
|
557
591
|
self.help = proto.help
|
558
592
|
self.form_id = proto.form_id
|
559
593
|
self.disabled = proto.disabled
|
594
|
+
self.horizontal = proto.horizontal
|
560
595
|
self.key = user_key_from_widget_id(self.id)
|
561
596
|
|
562
597
|
@property
|
563
598
|
def index(self) -> int:
|
564
|
-
if len(self.options) == 0:
|
565
|
-
return 0
|
566
599
|
return self.options.index(str(self.value))
|
567
600
|
|
568
601
|
@property
|
@@ -575,22 +608,10 @@ class Selectbox(Element, Widget, Generic[T]):
|
|
575
608
|
assert state
|
576
609
|
return cast(T, state[self.id])
|
577
610
|
|
578
|
-
def set_value(self, v: T) ->
|
579
|
-
"""
|
580
|
-
Set the value of the selectbox.
|
581
|
-
Implementation note: set_value not work correctly if `format_func` is also
|
582
|
-
passed to the selectbox. This is because we send options via proto with applied
|
583
|
-
`format_func`, but keep original values in session state as widget value.
|
584
|
-
"""
|
611
|
+
def set_value(self, v: T) -> Radio[T]:
|
585
612
|
self._value = v
|
586
613
|
return self
|
587
614
|
|
588
|
-
def select(self, v: T) -> Selectbox[T]:
|
589
|
-
return self.set_value(v)
|
590
|
-
|
591
|
-
def select_index(self, index: int) -> Selectbox[T]:
|
592
|
-
return self.set_value(cast(T, self.options[index]))
|
593
|
-
|
594
615
|
def widget_state(self) -> WidgetState:
|
595
616
|
"""Protobuf message representing the state of the widget, including
|
596
617
|
any interactions that have happened.
|
@@ -602,142 +623,77 @@ class Selectbox(Element, Widget, Generic[T]):
|
|
602
623
|
return ws
|
603
624
|
|
604
625
|
|
605
|
-
@dataclass(
|
606
|
-
class
|
607
|
-
_value:
|
608
|
-
|
609
|
-
proto: ButtonProto
|
610
|
-
type: str
|
611
|
-
id: str
|
612
|
-
label: str
|
613
|
-
help: str
|
614
|
-
form_id: str
|
615
|
-
disabled: bool
|
616
|
-
key: str | None
|
626
|
+
@dataclass(repr=False)
|
627
|
+
class Selectbox(Widget, Generic[T]):
|
628
|
+
_value: T | None
|
617
629
|
|
618
|
-
|
630
|
+
proto: SelectboxProto = field(repr=False)
|
631
|
+
options: list[str]
|
619
632
|
|
620
|
-
def __init__(self, proto:
|
633
|
+
def __init__(self, proto: SelectboxProto, root: ElementTree):
|
621
634
|
self.proto = proto
|
622
635
|
self.root = root
|
623
|
-
self._value =
|
636
|
+
self._value = None
|
624
637
|
|
625
|
-
self.type = "
|
638
|
+
self.type = "selectbox"
|
626
639
|
self.id = proto.id
|
627
640
|
self.label = proto.label
|
641
|
+
self.options = list(proto.options)
|
628
642
|
self.help = proto.help
|
629
643
|
self.form_id = proto.form_id
|
630
644
|
self.disabled = proto.disabled
|
631
645
|
self.key = user_key_from_widget_id(self.id)
|
632
646
|
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
return
|
647
|
+
@property
|
648
|
+
def index(self) -> int:
|
649
|
+
if len(self.options) == 0:
|
650
|
+
return 0
|
651
|
+
return self.options.index(str(self.value))
|
638
652
|
|
639
653
|
@property
|
640
|
-
def value(self) ->
|
641
|
-
|
654
|
+
def value(self) -> T:
|
655
|
+
"""The currently selected value from the options."""
|
656
|
+
if self._value is not None:
|
642
657
|
return self._value
|
643
658
|
else:
|
644
659
|
state = self.root.session_state
|
645
660
|
assert state
|
646
|
-
return cast(
|
661
|
+
return cast(T, state[self.id])
|
647
662
|
|
648
|
-
def set_value(self, v:
|
663
|
+
def set_value(self, v: T) -> Selectbox[T]:
|
664
|
+
"""
|
665
|
+
Set the value of the selectbox.
|
666
|
+
Implementation note: set_value not work correctly if `format_func` is also
|
667
|
+
passed to the selectbox. This is because we send options via proto with applied
|
668
|
+
`format_func`, but keep original values in session state as widget value.
|
669
|
+
"""
|
649
670
|
self._value = v
|
650
671
|
return self
|
651
672
|
|
652
|
-
def
|
653
|
-
return self.set_value(
|
654
|
-
|
655
|
-
|
656
|
-
@dataclass(init=False, repr=False)
|
657
|
-
class Slider(Element, Widget, Generic[SliderScalarT]):
|
658
|
-
_value: SliderScalarT | Sequence[SliderScalarT] | None
|
659
|
-
|
660
|
-
proto: SliderProto
|
661
|
-
type: str
|
662
|
-
data_type: SliderProto.DataType.ValueType
|
663
|
-
id: str
|
664
|
-
label: str
|
665
|
-
min_value: SliderScalar
|
666
|
-
max_value: SliderScalar
|
667
|
-
step: Step
|
668
|
-
help: str
|
669
|
-
form_id: str
|
670
|
-
disabled: bool
|
671
|
-
key: str | None
|
672
|
-
|
673
|
-
root: ElementTree = field(repr=False)
|
674
|
-
|
675
|
-
def __init__(self, proto: SliderProto, root: ElementTree):
|
676
|
-
self.proto = proto
|
677
|
-
self.root = root
|
678
|
-
self._value = None
|
679
|
-
|
680
|
-
self.type = "slider"
|
681
|
-
self.data_type = proto.data_type
|
682
|
-
self.id = proto.id
|
683
|
-
self.label = proto.label
|
684
|
-
self.min_value = proto.min
|
685
|
-
self.max_value = proto.max
|
686
|
-
self.step = proto.step
|
687
|
-
self.help = proto.help
|
688
|
-
self.form_id = proto.form_id
|
689
|
-
self.disabled = proto.disabled
|
690
|
-
self.key = user_key_from_widget_id(self.id)
|
673
|
+
def select(self, v: T) -> Selectbox[T]:
|
674
|
+
return self.set_value(v)
|
691
675
|
|
692
|
-
def
|
693
|
-
self,
|
694
|
-
) -> Slider[SliderScalarT]:
|
695
|
-
self._value = v
|
696
|
-
return self
|
676
|
+
def select_index(self, index: int) -> Selectbox[T]:
|
677
|
+
return self.set_value(cast(T, self.options[index]))
|
697
678
|
|
698
679
|
def widget_state(self) -> WidgetState:
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
680
|
+
"""Protobuf message representing the state of the widget, including
|
681
|
+
any interactions that have happened.
|
682
|
+
Should be the same as the frontend would produce for those interactions.
|
683
|
+
"""
|
703
684
|
ws = WidgetState()
|
704
685
|
ws.id = self.id
|
705
|
-
ws.
|
686
|
+
ws.int_value = self.index
|
706
687
|
return ws
|
707
688
|
|
708
|
-
@property
|
709
|
-
def value(self) -> SliderScalarT | Sequence[SliderScalarT]:
|
710
|
-
"""The currently selected value or range."""
|
711
|
-
if self._value is not None:
|
712
|
-
return self._value
|
713
|
-
else:
|
714
|
-
state = self.root.session_state
|
715
|
-
assert state
|
716
|
-
# Awkward to do this with `cast`
|
717
|
-
return state[self.id] # type: ignore
|
718
|
-
|
719
|
-
def set_range(
|
720
|
-
self, lower: SliderScalarT, upper: SliderScalarT
|
721
|
-
) -> Slider[SliderScalarT]:
|
722
|
-
return self.set_value([lower, upper])
|
723
|
-
|
724
689
|
|
725
|
-
@dataclass(
|
726
|
-
class SelectSlider(
|
690
|
+
@dataclass(repr=False)
|
691
|
+
class SelectSlider(Widget, Generic[T]):
|
727
692
|
_value: T | Sequence[T] | None
|
728
693
|
|
729
694
|
proto: SliderProto
|
730
|
-
type: str
|
731
695
|
data_type: SliderProto.DataType.ValueType
|
732
|
-
id: str
|
733
|
-
label: str
|
734
696
|
options: list[str]
|
735
|
-
help: str
|
736
|
-
form_id: str
|
737
|
-
disabled: bool
|
738
|
-
key: str | None
|
739
|
-
|
740
|
-
root: ElementTree = field(repr=False)
|
741
697
|
|
742
698
|
def __init__(self, proto: SliderProto, root: ElementTree):
|
743
699
|
self.proto = proto
|
@@ -783,50 +739,51 @@ class SelectSlider(Element, Widget, Generic[T]):
|
|
783
739
|
|
784
740
|
|
785
741
|
@dataclass(repr=False)
|
786
|
-
class
|
787
|
-
_value:
|
788
|
-
proto: TextInputProto
|
789
|
-
type: str
|
790
|
-
id: str
|
791
|
-
label: str
|
792
|
-
max_chars: int
|
793
|
-
help: str
|
794
|
-
form_id: str
|
795
|
-
autocomplete: str
|
796
|
-
placeholder: str
|
797
|
-
disabled: bool
|
798
|
-
key: str | None
|
742
|
+
class Slider(Widget, Generic[SliderScalarT]):
|
743
|
+
_value: SliderScalarT | Sequence[SliderScalarT] | None
|
799
744
|
|
800
|
-
|
745
|
+
proto: SliderProto
|
746
|
+
data_type: SliderProto.DataType.ValueType
|
747
|
+
min_value: SliderScalar
|
748
|
+
max_value: SliderScalar
|
749
|
+
step: Step
|
801
750
|
|
802
|
-
def __init__(self, proto:
|
751
|
+
def __init__(self, proto: SliderProto, root: ElementTree):
|
803
752
|
self.proto = proto
|
804
753
|
self.root = root
|
805
754
|
self._value = None
|
806
755
|
|
807
|
-
self.type = "
|
756
|
+
self.type = "slider"
|
757
|
+
self.data_type = proto.data_type
|
808
758
|
self.id = proto.id
|
809
759
|
self.label = proto.label
|
810
|
-
self.
|
760
|
+
self.min_value = proto.min
|
761
|
+
self.max_value = proto.max
|
762
|
+
self.step = proto.step
|
811
763
|
self.help = proto.help
|
812
764
|
self.form_id = proto.form_id
|
813
|
-
self.autocomplete = proto.autocomplete
|
814
|
-
self.placeholder = proto.placeholder
|
815
765
|
self.disabled = proto.disabled
|
816
766
|
self.key = user_key_from_widget_id(self.id)
|
817
767
|
|
818
|
-
def set_value(
|
768
|
+
def set_value(
|
769
|
+
self, v: SliderScalarT | Sequence[SliderScalarT]
|
770
|
+
) -> Slider[SliderScalarT]:
|
819
771
|
self._value = v
|
820
772
|
return self
|
821
773
|
|
822
774
|
def widget_state(self) -> WidgetState:
|
775
|
+
data_type = self.proto.data_type
|
776
|
+
serde = SliderSerde([], data_type, True, None)
|
777
|
+
v = serde.serialize(self.value)
|
778
|
+
|
823
779
|
ws = WidgetState()
|
824
780
|
ws.id = self.id
|
825
|
-
ws.
|
781
|
+
ws.double_array_value.data[:] = v
|
826
782
|
return ws
|
827
783
|
|
828
784
|
@property
|
829
|
-
def value(self) ->
|
785
|
+
def value(self) -> SliderScalarT | Sequence[SliderScalarT]:
|
786
|
+
"""The currently selected value or range."""
|
830
787
|
if self._value is not None:
|
831
788
|
return self._value
|
832
789
|
else:
|
@@ -835,29 +792,35 @@ class TextInput(Element, Widget):
|
|
835
792
|
# Awkward to do this with `cast`
|
836
793
|
return state[self.id] # type: ignore
|
837
794
|
|
838
|
-
def
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
795
|
+
def set_range(
|
796
|
+
self, lower: SliderScalarT, upper: SliderScalarT
|
797
|
+
) -> Slider[SliderScalarT]:
|
798
|
+
return self.set_value([lower, upper])
|
799
|
+
|
800
|
+
|
801
|
+
@dataclass(repr=False)
|
802
|
+
class Text(Element):
|
803
|
+
proto: TextProto
|
804
|
+
|
805
|
+
key: None = None
|
806
|
+
|
807
|
+
def __init__(self, proto: TextProto, root: ElementTree):
|
808
|
+
self.proto = proto
|
809
|
+
self.root = root
|
810
|
+
self.type = "text"
|
811
|
+
|
812
|
+
@property
|
813
|
+
def value(self) -> str:
|
814
|
+
return self.proto.body
|
843
815
|
|
844
816
|
|
845
817
|
@dataclass(repr=False)
|
846
|
-
class TextArea(
|
818
|
+
class TextArea(Widget):
|
847
819
|
_value: str | None
|
848
820
|
|
849
821
|
proto: TextAreaProto
|
850
|
-
type: str
|
851
|
-
id: str
|
852
|
-
label: str
|
853
822
|
max_chars: int
|
854
|
-
help: str
|
855
|
-
form_id: str
|
856
823
|
placeholder: str
|
857
|
-
disabled: bool
|
858
|
-
key: str | None
|
859
|
-
|
860
|
-
root: ElementTree = field(repr=False)
|
861
824
|
|
862
825
|
def __init__(self, proto: TextAreaProto, root: ElementTree):
|
863
826
|
self.proto = proto
|
@@ -901,55 +864,42 @@ class TextArea(Element, Widget):
|
|
901
864
|
return self.set_value(v)
|
902
865
|
|
903
866
|
|
904
|
-
Number = Union[int, float]
|
905
|
-
|
906
|
-
|
907
867
|
@dataclass(repr=False)
|
908
|
-
class
|
909
|
-
_value:
|
910
|
-
proto:
|
911
|
-
|
912
|
-
|
913
|
-
label: str
|
914
|
-
min_value: Number
|
915
|
-
max_value: Number
|
916
|
-
step: Number
|
917
|
-
help: str
|
918
|
-
form_id: str
|
868
|
+
class TextInput(Widget):
|
869
|
+
_value: str | None
|
870
|
+
proto: TextInputProto
|
871
|
+
max_chars: int
|
872
|
+
autocomplete: str
|
919
873
|
placeholder: str
|
920
|
-
disabled: bool
|
921
|
-
key: str | None
|
922
|
-
|
923
|
-
root: ElementTree = field(repr=False)
|
924
874
|
|
925
|
-
def __init__(self, proto:
|
875
|
+
def __init__(self, proto: TextInputProto, root: ElementTree):
|
926
876
|
self.proto = proto
|
927
877
|
self.root = root
|
928
878
|
self._value = None
|
929
879
|
|
930
|
-
self.type = "
|
880
|
+
self.type = "text_input"
|
931
881
|
self.id = proto.id
|
932
882
|
self.label = proto.label
|
933
|
-
self.
|
934
|
-
self.max_value = proto.max
|
935
|
-
self.step = proto.step
|
883
|
+
self.max_chars = proto.max_chars
|
936
884
|
self.help = proto.help
|
937
885
|
self.form_id = proto.form_id
|
886
|
+
self.autocomplete = proto.autocomplete
|
887
|
+
self.placeholder = proto.placeholder
|
938
888
|
self.disabled = proto.disabled
|
939
889
|
self.key = user_key_from_widget_id(self.id)
|
940
890
|
|
941
|
-
def set_value(self, v:
|
891
|
+
def set_value(self, v: str) -> TextInput:
|
942
892
|
self._value = v
|
943
893
|
return self
|
944
894
|
|
945
895
|
def widget_state(self) -> WidgetState:
|
946
896
|
ws = WidgetState()
|
947
897
|
ws.id = self.id
|
948
|
-
ws.
|
898
|
+
ws.string_value = self.value
|
949
899
|
return ws
|
950
900
|
|
951
901
|
@property
|
952
|
-
def value(self) ->
|
902
|
+
def value(self) -> str:
|
953
903
|
if self._value is not None:
|
954
904
|
return self._value
|
955
905
|
else:
|
@@ -958,92 +908,21 @@ class NumberInput(Element, Widget):
|
|
958
908
|
# Awkward to do this with `cast`
|
959
909
|
return state[self.id] # type: ignore
|
960
910
|
|
961
|
-
def
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
def decrement(self) -> NumberInput:
|
966
|
-
v = max(self.value - self.step, self.min_value)
|
911
|
+
def input(self, v: str) -> TextInput:
|
912
|
+
# TODO should input be setting or appending?
|
913
|
+
if self.max_chars and len(v) > self.max_chars:
|
914
|
+
return self
|
967
915
|
return self.set_value(v)
|
968
916
|
|
969
917
|
|
970
|
-
SingleDateValue: TypeAlias = Union[date, datetime]
|
971
|
-
DateValue: TypeAlias = Union[SingleDateValue, Sequence[SingleDateValue]]
|
972
|
-
|
973
|
-
|
974
|
-
@dataclass(repr=False)
|
975
|
-
class DateInput(Element, Widget):
|
976
|
-
_value: DateValue | None
|
977
|
-
proto: DateInputProto
|
978
|
-
type: str
|
979
|
-
id: str
|
980
|
-
label: str
|
981
|
-
min: date
|
982
|
-
max: date
|
983
|
-
is_range: bool
|
984
|
-
help: str
|
985
|
-
form_id: str
|
986
|
-
disabled: bool
|
987
|
-
key: str | None
|
988
|
-
|
989
|
-
root: ElementTree = field(repr=False)
|
990
|
-
|
991
|
-
def __init__(self, proto: DateInputProto, root: ElementTree):
|
992
|
-
self.proto = proto
|
993
|
-
self.root = root
|
994
|
-
self._value = None
|
995
|
-
|
996
|
-
self.type = "date_input"
|
997
|
-
self.id = proto.id
|
998
|
-
self.label = proto.label
|
999
|
-
self.min = datetime.strptime(proto.min, "%Y/%m/%d").date()
|
1000
|
-
self.max = datetime.strptime(proto.max, "%Y/%m/%d").date()
|
1001
|
-
self.is_range = proto.is_range
|
1002
|
-
self.help = proto.help
|
1003
|
-
self.form_id = proto.form_id
|
1004
|
-
self.disabled = proto.disabled
|
1005
|
-
self.key = user_key_from_widget_id(self.id)
|
1006
|
-
|
1007
|
-
def set_value(self, v: DateValue) -> DateInput:
|
1008
|
-
self._value = v
|
1009
|
-
return self
|
1010
|
-
|
1011
|
-
def widget_state(self) -> WidgetState:
|
1012
|
-
ws = WidgetState()
|
1013
|
-
ws.id = self.id
|
1014
|
-
|
1015
|
-
serde = DateInputSerde(None) # type: ignore
|
1016
|
-
ws.string_array_value.data[:] = serde.serialize(self.value)
|
1017
|
-
return ws
|
1018
|
-
|
1019
|
-
@property
|
1020
|
-
def value(self) -> DateWidgetReturn:
|
1021
|
-
if self._value is not None:
|
1022
|
-
parsed, _ = _parse_date_value(self._value)
|
1023
|
-
return tuple(parsed) # type: ignore
|
1024
|
-
else:
|
1025
|
-
state = self.root.session_state
|
1026
|
-
assert state
|
1027
|
-
return state[self.id] # type: ignore
|
1028
|
-
|
1029
|
-
|
1030
918
|
TimeValue: TypeAlias = Union[time, datetime]
|
1031
919
|
|
1032
920
|
|
1033
921
|
@dataclass(repr=False)
|
1034
|
-
class TimeInput(
|
922
|
+
class TimeInput(Widget):
|
1035
923
|
_value: TimeValue | None
|
1036
924
|
proto: TimeInputProto
|
1037
|
-
type: str
|
1038
|
-
id: str
|
1039
|
-
label: str
|
1040
925
|
step: int
|
1041
|
-
help: str
|
1042
|
-
form_id: str
|
1043
|
-
disabled: bool
|
1044
|
-
key: str | None
|
1045
|
-
|
1046
|
-
root: ElementTree = field(repr=False)
|
1047
926
|
|
1048
927
|
def __init__(self, proto: TimeInputProto, root: ElementTree):
|
1049
928
|
self.proto = proto
|
@@ -1093,7 +972,7 @@ class TimeInput(Element, Widget):
|
|
1093
972
|
return self.set_value(dt.time())
|
1094
973
|
|
1095
974
|
|
1096
|
-
@dataclass(
|
975
|
+
@dataclass(repr=False)
|
1097
976
|
class Block:
|
1098
977
|
type: str
|
1099
978
|
children: dict[int, Node]
|
@@ -1136,11 +1015,7 @@ class Block:
|
|
1136
1015
|
return None
|
1137
1016
|
|
1138
1017
|
@overload
|
1139
|
-
def get(self, element_type: Literal["
|
1140
|
-
...
|
1141
|
-
|
1142
|
-
@overload
|
1143
|
-
def get(self, element_type: Literal["markdown"]) -> Sequence[Markdown]:
|
1018
|
+
def get(self, element_type: Literal["button"]) -> Sequence[Button]:
|
1144
1019
|
...
|
1145
1020
|
|
1146
1021
|
@overload
|
@@ -1148,7 +1023,7 @@ class Block:
|
|
1148
1023
|
...
|
1149
1024
|
|
1150
1025
|
@overload
|
1151
|
-
def get(self, element_type: Literal["
|
1026
|
+
def get(self, element_type: Literal["checkbox"]) -> Sequence[Checkbox]:
|
1152
1027
|
...
|
1153
1028
|
|
1154
1029
|
@overload
|
@@ -1156,31 +1031,31 @@ class Block:
|
|
1156
1031
|
...
|
1157
1032
|
|
1158
1033
|
@overload
|
1159
|
-
def get(self, element_type: Literal["
|
1034
|
+
def get(self, element_type: Literal["color_picker"]) -> Sequence[ColorPicker]:
|
1160
1035
|
...
|
1161
1036
|
|
1162
1037
|
@overload
|
1163
|
-
def get(self, element_type: Literal["
|
1038
|
+
def get(self, element_type: Literal["date_input"]) -> Sequence[DateInput]:
|
1164
1039
|
...
|
1165
1040
|
|
1166
1041
|
@overload
|
1167
|
-
def get(self, element_type: Literal["
|
1042
|
+
def get(self, element_type: Literal["divider"]) -> Sequence[Divider]:
|
1168
1043
|
...
|
1169
1044
|
|
1170
1045
|
@overload
|
1171
|
-
def get(self, element_type: Literal["
|
1046
|
+
def get(self, element_type: Literal["exception"]) -> Sequence[Exception]:
|
1172
1047
|
...
|
1173
1048
|
|
1174
1049
|
@overload
|
1175
|
-
def get(self, element_type: Literal["
|
1050
|
+
def get(self, element_type: Literal["header"]) -> Sequence[Header]:
|
1176
1051
|
...
|
1177
1052
|
|
1178
1053
|
@overload
|
1179
|
-
def get(self, element_type: Literal["
|
1054
|
+
def get(self, element_type: Literal["latex"]) -> Sequence[Latex]:
|
1180
1055
|
...
|
1181
1056
|
|
1182
1057
|
@overload
|
1183
|
-
def get(self, element_type: Literal["
|
1058
|
+
def get(self, element_type: Literal["markdown"]) -> Sequence[Markdown]:
|
1184
1059
|
...
|
1185
1060
|
|
1186
1061
|
@overload
|
@@ -1188,11 +1063,11 @@ class Block:
|
|
1188
1063
|
...
|
1189
1064
|
|
1190
1065
|
@overload
|
1191
|
-
def get(self, element_type: Literal["
|
1066
|
+
def get(self, element_type: Literal["number_input"]) -> Sequence[NumberInput]:
|
1192
1067
|
...
|
1193
1068
|
|
1194
1069
|
@overload
|
1195
|
-
def get(self, element_type: Literal["
|
1070
|
+
def get(self, element_type: Literal["radio"]) -> Sequence[Radio[Any]]:
|
1196
1071
|
...
|
1197
1072
|
|
1198
1073
|
@overload
|
@@ -1202,33 +1077,37 @@ class Block:
|
|
1202
1077
|
...
|
1203
1078
|
|
1204
1079
|
@overload
|
1205
|
-
def get(self, element_type: Literal["
|
1080
|
+
def get(self, element_type: Literal["selectbox"]) -> Sequence[Selectbox[Any]]:
|
1206
1081
|
...
|
1207
1082
|
|
1208
1083
|
@overload
|
1209
|
-
def get(self, element_type: Literal["
|
1084
|
+
def get(self, element_type: Literal["slider"]) -> Sequence[Slider[Any]]:
|
1210
1085
|
...
|
1211
1086
|
|
1212
1087
|
@overload
|
1213
|
-
def get(self, element_type: Literal["
|
1088
|
+
def get(self, element_type: Literal["subheader"]) -> Sequence[Subheader]:
|
1214
1089
|
...
|
1215
1090
|
|
1216
1091
|
@overload
|
1217
|
-
def get(self, element_type: Literal["
|
1092
|
+
def get(self, element_type: Literal["text"]) -> Sequence[Text]:
|
1218
1093
|
...
|
1219
1094
|
|
1220
1095
|
@overload
|
1221
|
-
def get(self, element_type: Literal["
|
1096
|
+
def get(self, element_type: Literal["text_area"]) -> Sequence[TextArea]:
|
1222
1097
|
...
|
1223
1098
|
|
1224
1099
|
@overload
|
1225
|
-
def get(self, element_type: Literal["
|
1100
|
+
def get(self, element_type: Literal["text_input"]) -> Sequence[TextInput]:
|
1226
1101
|
...
|
1227
1102
|
|
1228
1103
|
@overload
|
1229
1104
|
def get(self, element_type: Literal["time_input"]) -> Sequence[TimeInput]:
|
1230
1105
|
...
|
1231
1106
|
|
1107
|
+
@overload
|
1108
|
+
def get(self, element_type: Literal["title"]) -> Sequence[Title]:
|
1109
|
+
...
|
1110
|
+
|
1232
1111
|
def get(self, element_type: str) -> Sequence[Node]:
|
1233
1112
|
return [e for e in self if e.type == element_type]
|
1234
1113
|
|
@@ -1252,7 +1131,7 @@ class Block:
|
|
1252
1131
|
Node: TypeAlias = Union[Element, Block]
|
1253
1132
|
|
1254
1133
|
|
1255
|
-
@dataclass(
|
1134
|
+
@dataclass(repr=False)
|
1256
1135
|
class ElementTree(Block):
|
1257
1136
|
"""A tree of the elements produced by running a streamlit script.
|
1258
1137
|
|
@@ -1280,8 +1159,6 @@ class ElementTree(Block):
|
|
1280
1159
|
the rerun.
|
1281
1160
|
"""
|
1282
1161
|
|
1283
|
-
type: str
|
1284
|
-
|
1285
1162
|
script_path: str | None = field(repr=False, default=None)
|
1286
1163
|
_session_state: SessionState | None = field(repr=False, default=None)
|
1287
1164
|
|
@@ -1334,10 +1211,30 @@ def parse_tree_from_messages(messages: list[ForwardMsg]) -> ElementTree:
|
|
1334
1211
|
delta = msg.delta
|
1335
1212
|
if delta.WhichOneof("type") == "new_element":
|
1336
1213
|
elt = delta.new_element
|
1214
|
+
ty = elt.WhichOneof("type")
|
1337
1215
|
new_node: Node
|
1338
|
-
if
|
1339
|
-
new_node =
|
1340
|
-
elif
|
1216
|
+
if ty == "button":
|
1217
|
+
new_node = Button(elt.button, root=root)
|
1218
|
+
elif ty == "checkbox":
|
1219
|
+
new_node = Checkbox(elt.checkbox, root=root)
|
1220
|
+
elif ty == "code":
|
1221
|
+
new_node = Code(elt.code, root=root)
|
1222
|
+
elif ty == "color_picker":
|
1223
|
+
new_node = ColorPicker(elt.color_picker, root=root)
|
1224
|
+
elif ty == "date_input":
|
1225
|
+
new_node = DateInput(elt.date_input, root=root)
|
1226
|
+
elif ty == "exception":
|
1227
|
+
new_node = Exception(elt.exception, root=root)
|
1228
|
+
elif ty == "heading":
|
1229
|
+
if elt.heading.tag == HeadingProtoTag.TITLE_TAG.value:
|
1230
|
+
new_node = Title(elt.heading, root=root)
|
1231
|
+
elif elt.heading.tag == HeadingProtoTag.HEADER_TAG.value:
|
1232
|
+
new_node = Header(elt.heading, root=root)
|
1233
|
+
elif elt.heading.tag == HeadingProtoTag.SUBHEADER_TAG.value:
|
1234
|
+
new_node = Subheader(elt.heading, root=root)
|
1235
|
+
else:
|
1236
|
+
raise ValueError(f"Unknown heading type with tag {elt.heading.tag}")
|
1237
|
+
elif ty == "markdown":
|
1341
1238
|
if elt.markdown.element_type == MarkdownProto.Type.NATIVE:
|
1342
1239
|
new_node = Markdown(elt.markdown, root=root)
|
1343
1240
|
elif elt.markdown.element_type == MarkdownProto.Type.CAPTION:
|
@@ -1350,47 +1247,28 @@ def parse_tree_from_messages(messages: list[ForwardMsg]) -> ElementTree:
|
|
1350
1247
|
raise ValueError(
|
1351
1248
|
f"Unknown markdown type {elt.markdown.element_type}"
|
1352
1249
|
)
|
1353
|
-
elif
|
1354
|
-
if elt.heading.tag == HeadingProtoTag.TITLE_TAG.value:
|
1355
|
-
new_node = Title(elt.heading, root=root)
|
1356
|
-
elif elt.heading.tag == HeadingProtoTag.HEADER_TAG.value:
|
1357
|
-
new_node = Header(elt.heading, root=root)
|
1358
|
-
elif elt.heading.tag == HeadingProtoTag.SUBHEADER_TAG.value:
|
1359
|
-
new_node = Subheader(elt.heading, root=root)
|
1360
|
-
else:
|
1361
|
-
raise ValueError(f"Unknown heading type with tag {elt.heading.tag}")
|
1362
|
-
elif elt.WhichOneof("type") == "exception":
|
1363
|
-
new_node = Exception(elt.exception, root=root)
|
1364
|
-
elif elt.WhichOneof("type") == "radio":
|
1365
|
-
new_node = Radio(elt.radio, root=root)
|
1366
|
-
elif elt.WhichOneof("type") == "checkbox":
|
1367
|
-
new_node = Checkbox(elt.checkbox, root=root)
|
1368
|
-
elif elt.WhichOneof("type") == "multiselect":
|
1250
|
+
elif ty == "multiselect":
|
1369
1251
|
new_node = Multiselect(elt.multiselect, root=root)
|
1370
|
-
elif
|
1252
|
+
elif ty == "number_input":
|
1253
|
+
new_node = NumberInput(elt.number_input, root=root)
|
1254
|
+
elif ty == "radio":
|
1255
|
+
new_node = Radio(elt.radio, root=root)
|
1256
|
+
elif ty == "selectbox":
|
1371
1257
|
new_node = Selectbox(elt.selectbox, root=root)
|
1372
|
-
elif
|
1258
|
+
elif ty == "slider":
|
1373
1259
|
if elt.slider.type == SliderProto.Type.SLIDER:
|
1374
1260
|
new_node = Slider(elt.slider, root=root)
|
1375
1261
|
elif elt.slider.type == SliderProto.Type.SELECT_SLIDER:
|
1376
1262
|
new_node = SelectSlider(elt.slider, root=root)
|
1377
1263
|
else:
|
1378
1264
|
raise ValueError(f"Slider with unknown type {elt.slider}")
|
1379
|
-
elif
|
1380
|
-
new_node =
|
1381
|
-
elif
|
1382
|
-
new_node = TextInput(elt.text_input, root=root)
|
1383
|
-
elif elt.WhichOneof("type") == "text_area":
|
1265
|
+
elif ty == "text":
|
1266
|
+
new_node = Text(elt.text, root=root)
|
1267
|
+
elif ty == "text_area":
|
1384
1268
|
new_node = TextArea(elt.text_area, root=root)
|
1385
|
-
elif
|
1386
|
-
new_node =
|
1387
|
-
elif
|
1388
|
-
new_node = Code(elt.code, root=root)
|
1389
|
-
elif elt.WhichOneof("type") == "color_picker":
|
1390
|
-
new_node = ColorPicker(elt.color_picker, root=root)
|
1391
|
-
elif elt.WhichOneof("type") == "date_input":
|
1392
|
-
new_node = DateInput(elt.date_input, root=root)
|
1393
|
-
elif elt.WhichOneof("type") == "time_input":
|
1269
|
+
elif ty == "text_input":
|
1270
|
+
new_node = TextInput(elt.text_input, root=root)
|
1271
|
+
elif ty == "time_input":
|
1394
1272
|
new_node = TimeInput(elt.time_input, root=root)
|
1395
1273
|
else:
|
1396
1274
|
new_node = Element(elt, root=root)
|