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.
Files changed (40) hide show
  1. streamlit/__init__.py +0 -7
  2. streamlit/elements/arrow.py +7 -264
  3. streamlit/elements/data_editor.py +109 -100
  4. streamlit/elements/file_uploader.py +17 -0
  5. streamlit/elements/layouts.py +0 -5
  6. streamlit/elements/lib/column_config_utils.py +371 -0
  7. streamlit/elements/lib/pandas_styler_utils.py +275 -0
  8. streamlit/runtime/connection_factory.py +5 -5
  9. streamlit/static/asset-manifest.json +20 -20
  10. streamlit/static/index.html +1 -1
  11. streamlit/static/static/js/{14.a19a6cd8.chunk.js → 14.9399e424.chunk.js} +1 -1
  12. streamlit/static/static/js/{227.087adf66.chunk.js → 227.9ccac1d5.chunk.js} +1 -1
  13. streamlit/static/static/js/{242.0daf8b47.chunk.js → 242.1b3289e0.chunk.js} +1 -1
  14. streamlit/static/static/js/{279.fdac58fc.chunk.js → 279.35b01780.chunk.js} +1 -1
  15. streamlit/static/static/js/{289.481fd42d.chunk.js → 289.e6157e40.chunk.js} +1 -1
  16. streamlit/static/static/js/{467.242e14ff.chunk.js → 467.50ac84df.chunk.js} +1 -1
  17. streamlit/static/static/js/{491.d0b710e9.chunk.js → 491.5a33a8ce.chunk.js} +1 -1
  18. streamlit/static/static/js/503.15864587.chunk.js +1 -0
  19. streamlit/static/static/js/{511.9f04ae9e.chunk.js → 511.e6ca580f.chunk.js} +1 -1
  20. streamlit/static/static/js/{578.ceaadcd5.chunk.js → 578.a65fcea0.chunk.js} +1 -1
  21. streamlit/static/static/js/{619.365611c8.chunk.js → 619.0325af0e.chunk.js} +1 -1
  22. streamlit/static/static/js/{628.7f41e2de.chunk.js → 628.9c70196b.chunk.js} +1 -1
  23. streamlit/static/static/js/{681.a2ba76c7.chunk.js → 681.9e30a8cd.chunk.js} +1 -1
  24. streamlit/static/static/js/{745.e2bcf16d.chunk.js → 745.e75ba963.chunk.js} +1 -1
  25. streamlit/static/static/js/{807.6789990f.chunk.js → 807.122f8b05.chunk.js} +1 -1
  26. streamlit/static/static/js/{828.096c1ad3.chunk.js → 828.0fde3da8.chunk.js} +1 -1
  27. streamlit/static/static/js/{871.ba625aee.chunk.js → 871.90a7dbae.chunk.js} +1 -1
  28. streamlit/static/static/js/{main.5e4731c6.js → main.ff35bd72.js} +2 -2
  29. streamlit/testing/element_tree.py +426 -548
  30. streamlit/type_util.py +19 -7
  31. {streamlit_nightly-1.21.1.dev20230423.dist-info → streamlit_nightly-1.21.1.dev20230425.dist-info}/METADATA +1 -1
  32. {streamlit_nightly-1.21.1.dev20230423.dist-info → streamlit_nightly-1.21.1.dev20230425.dist-info}/RECORD +38 -37
  33. streamlit/elements/show.py +0 -105
  34. streamlit/static/static/js/728.82770810.chunk.js +0 -1
  35. /streamlit/static/static/css/{728.23fa976d.chunk.css → 503.23fa976d.chunk.css} +0 -0
  36. /streamlit/static/static/js/{main.5e4731c6.js.LICENSE.txt → main.ff35bd72.js.LICENSE.txt} +0 -0
  37. {streamlit_nightly-1.21.1.dev20230423.data → streamlit_nightly-1.21.1.dev20230425.data}/scripts/streamlit.cmd +0 -0
  38. {streamlit_nightly-1.21.1.dev20230423.dist-info → streamlit_nightly-1.21.1.dev20230425.dist-info}/WHEEL +0 -0
  39. {streamlit_nightly-1.21.1.dev20230423.dist-info → streamlit_nightly-1.21.1.dev20230425.dist-info}/entry_points.txt +0 -0
  40. {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, Protocol, TypeAlias, runtime_checkable
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(init=False)
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(init=False, repr=False)
107
- class Text(Element):
108
- proto: TextProto
109
-
110
- type: str
111
- root: ElementTree = field(repr=False)
112
- key: None = None
113
-
114
- def __init__(self, proto: TextProto, root: ElementTree):
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
- @property
120
- def value(self) -> str:
121
- return self.proto.body
118
+ def set_value(self, v: Any) -> Self:
119
+ self._value = v
120
+ return self
122
121
 
123
122
 
124
- @dataclass(init=False, repr=False)
125
- class HeadingBase(Element, ABC):
126
- proto: HeadingProto
123
+ @dataclass(repr=False)
124
+ class Button(Widget):
125
+ _value: bool
127
126
 
128
- type: str
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: HeadingProto, root: ElementTree, type_: str):
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.type = type_
143
-
144
- @property
145
- def value(self) -> str:
146
- return self.proto.body
147
-
132
+ self._value = False
148
133
 
149
- @dataclass(init=False, repr=False)
150
- class Title(HeadingBase):
151
- def __init__(self, proto: HeadingProto, root: ElementTree):
152
- super().__init__(proto, root, "title")
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
- @dataclass(init=False, repr=False)
156
- class Header(HeadingBase):
157
- def __init__(self, proto: HeadingProto, root: ElementTree):
158
- super().__init__(proto, root, "header")
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
- @dataclass(init=False, repr=False)
162
- class Subheader(HeadingBase):
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(init=False, repr=False)
168
- class Markdown(Element):
169
- proto: MarkdownProto
165
+ @dataclass(repr=False)
166
+ class Checkbox(Widget):
167
+ _value: bool | None
170
168
 
171
- type: str
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: MarkdownProto, root: ElementTree):
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.type = "markdown"
174
+ self._value = None
184
175
 
185
- @property
186
- def value(self) -> str:
187
- return self.proto.body
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
- @dataclass(init=False, repr=False)
191
- class Caption(Markdown):
192
- def __init__(self, proto: MarkdownProto, root: ElementTree):
193
- super().__init__(proto, root)
194
- self.type = "caption"
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
- @dataclass(init=False, repr=False)
198
- class Latex(Markdown):
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
- @dataclass(init=False, repr=False)
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 Exception(Element):
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
- @dataclass(init=False, repr=False)
329
- class Radio(Element, Widget, Generic[T]):
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
- root: ElementTree = field(repr=False)
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: RadioProto, root: ElementTree):
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 = "radio"
297
+ self.type = "date_input"
351
298
  self.id = proto.id
352
299
  self.label = proto.label
353
- self.options = list(proto.options)
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
- @property
361
- def index(self) -> int:
362
- return self.options.index(str(self.value))
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) -> T:
366
- """The currently selected value from the options."""
321
+ def value(self) -> DateWidgetReturn:
367
322
  if self._value is not None:
368
- return self._value
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 cast(T, state[self.id])
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
- def widget_state(self) -> WidgetState:
379
- """Protobuf message representing the state of the widget, including
380
- any interactions that have happened.
381
- Should be the same as the frontend would produce for those interactions.
382
- """
383
- ws = WidgetState()
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
- @dataclass(init=False, repr=False)
390
- class Checkbox(Element, Widget):
391
- _value: bool | None
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
- proto: CheckboxProto
394
- type: str
395
- id: str
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
- def __init__(self, proto: CheckboxProto, root: ElementTree):
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._value = None
370
+ self.type = type_
408
371
 
409
- self.type = "checkbox"
410
- self.id = proto.id
411
- self.label = proto.label
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
- def widget_state(self) -> WidgetState:
418
- ws = WidgetState()
419
- ws.id = self.id
420
- ws.bool_value = self.value
421
- return ws
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) -> bool:
425
- if self._value is not None:
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
- def check(self) -> Checkbox:
437
- return self.set_value(True)
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
- def uncheck(self) -> Checkbox:
440
- return self.set_value(False)
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(init=False, repr=False)
444
- class Multiselect(Element, Widget, Generic[T]):
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
- @dataclass(init=False, repr=False)
533
- class Selectbox(Element, Widget, Generic[T]):
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: SelectboxProto = field(repr=False)
537
- type: str
538
- id: str
539
- label: str
578
+ proto: RadioProto
540
579
  options: list[str]
541
- help: str
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: SelectboxProto, root: ElementTree):
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 = "selectbox"
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) -> Selectbox[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(init=False, repr=False)
606
- class Button(Element, Widget):
607
- _value: bool
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
- root: ElementTree = field(repr=False)
630
+ proto: SelectboxProto = field(repr=False)
631
+ options: list[str]
619
632
 
620
- def __init__(self, proto: ButtonProto, root: ElementTree):
633
+ def __init__(self, proto: SelectboxProto, root: ElementTree):
621
634
  self.proto = proto
622
635
  self.root = root
623
- self._value = False
636
+ self._value = None
624
637
 
625
- self.type = "button"
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
- def widget_state(self) -> WidgetState:
634
- ws = WidgetState()
635
- ws.id = self.id
636
- ws.trigger_value = self._value
637
- return ws
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) -> bool:
641
- if self._value:
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(bool, state[self.id])
661
+ return cast(T, state[self.id])
647
662
 
648
- def set_value(self, v: bool) -> Button:
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 click(self) -> Button:
653
- return self.set_value(True)
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 set_value(
693
- self, v: SliderScalarT | Sequence[SliderScalarT]
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
- data_type = self.proto.data_type
700
- serde = SliderSerde([], data_type, True, None)
701
- v = serde.serialize(self.value)
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.double_array_value.data[:] = v
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(init=False, repr=False)
726
- class SelectSlider(Element, Widget, Generic[T]):
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 TextInput(Element, Widget):
787
- _value: str | None
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
- root: ElementTree = field(repr=False)
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: TextInputProto, root: ElementTree):
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 = "text_input"
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.max_chars = proto.max_chars
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(self, v: str) -> TextInput:
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.string_value = self.value
781
+ ws.double_array_value.data[:] = v
826
782
  return ws
827
783
 
828
784
  @property
829
- def value(self) -> str:
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 input(self, v: str) -> TextInput:
839
- # TODO should input be setting or appending?
840
- if self.max_chars and len(v) > self.max_chars:
841
- return self
842
- return self.set_value(v)
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(Element, Widget):
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 NumberInput(Element, Widget):
909
- _value: Number | None
910
- proto: NumberInputProto
911
- type: str
912
- id: str
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: NumberInputProto, root: ElementTree):
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 = "number_input"
880
+ self.type = "text_input"
931
881
  self.id = proto.id
932
882
  self.label = proto.label
933
- self.min_value = proto.min
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: Number) -> NumberInput:
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.double_value = self.value
898
+ ws.string_value = self.value
949
899
  return ws
950
900
 
951
901
  @property
952
- def value(self) -> Number:
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 increment(self) -> NumberInput:
962
- v = min(self.value + self.step, self.max_value)
963
- return self.set_value(v)
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(Element, Widget):
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(init=False, repr=False)
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["text"]) -> Sequence[Text]:
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["latex"]) -> Sequence[Latex]:
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["divider"]) -> Sequence[Divider]:
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["title"]) -> Sequence[Title]:
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["header"]) -> Sequence[Header]:
1042
+ def get(self, element_type: Literal["divider"]) -> Sequence[Divider]:
1168
1043
  ...
1169
1044
 
1170
1045
  @overload
1171
- def get(self, element_type: Literal["subheader"]) -> Sequence[Subheader]:
1046
+ def get(self, element_type: Literal["exception"]) -> Sequence[Exception]:
1172
1047
  ...
1173
1048
 
1174
1049
  @overload
1175
- def get(self, element_type: Literal["exception"]) -> Sequence[Exception]:
1050
+ def get(self, element_type: Literal["header"]) -> Sequence[Header]:
1176
1051
  ...
1177
1052
 
1178
1053
  @overload
1179
- def get(self, element_type: Literal["radio"]) -> Sequence[Radio[Any]]:
1054
+ def get(self, element_type: Literal["latex"]) -> Sequence[Latex]:
1180
1055
  ...
1181
1056
 
1182
1057
  @overload
1183
- def get(self, element_type: Literal["checkbox"]) -> Sequence[Checkbox]:
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["selectbox"]) -> Sequence[Selectbox[Any]]:
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["slider"]) -> Sequence[Slider[Any]]:
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["button"]) -> Sequence[Button]:
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["text_input"]) -> Sequence[TextInput]:
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["text_area"]) -> Sequence[TextArea]:
1088
+ def get(self, element_type: Literal["subheader"]) -> Sequence[Subheader]:
1214
1089
  ...
1215
1090
 
1216
1091
  @overload
1217
- def get(self, element_type: Literal["color_picker"]) -> Sequence[ColorPicker]:
1092
+ def get(self, element_type: Literal["text"]) -> Sequence[Text]:
1218
1093
  ...
1219
1094
 
1220
1095
  @overload
1221
- def get(self, element_type: Literal["number_input"]) -> Sequence[NumberInput]:
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["date_input"]) -> Sequence[DateInput]:
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(init=False, repr=False)
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 elt.WhichOneof("type") == "text":
1339
- new_node = Text(elt.text, root=root)
1340
- elif elt.WhichOneof("type") == "markdown":
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 elt.WhichOneof("type") == "heading":
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 elt.WhichOneof("type") == "selectbox":
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 elt.WhichOneof("type") == "slider":
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 elt.WhichOneof("type") == "button":
1380
- new_node = Button(elt.button, root=root)
1381
- elif elt.WhichOneof("type") == "text_input":
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 elt.WhichOneof("type") == "number_input":
1386
- new_node = NumberInput(elt.number_input, root=root)
1387
- elif elt.WhichOneof("type") == "code":
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)