streamlit 1.50.0__py3-none-any.whl → 1.52.0__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 (406) hide show
  1. streamlit/__init__.py +5 -1
  2. streamlit/commands/execution_control.py +89 -14
  3. streamlit/commands/navigation.py +4 -6
  4. streamlit/commands/page_config.py +4 -6
  5. streamlit/components/v1/component_arrow.py +7 -7
  6. streamlit/components/v2/__init__.py +514 -0
  7. streamlit/components/v2/bidi_component/__init__.py +20 -0
  8. streamlit/components/v2/bidi_component/constants.py +29 -0
  9. streamlit/components/v2/bidi_component/main.py +534 -0
  10. streamlit/components/v2/bidi_component/serialization.py +272 -0
  11. streamlit/components/v2/bidi_component/state.py +92 -0
  12. streamlit/components/v2/component_definition_resolver.py +143 -0
  13. streamlit/components/v2/component_file_watcher.py +403 -0
  14. streamlit/components/v2/component_manager.py +439 -0
  15. streamlit/components/v2/component_manifest_handler.py +122 -0
  16. streamlit/components/v2/component_path_utils.py +245 -0
  17. streamlit/components/v2/component_registry.py +426 -0
  18. streamlit/components/v2/get_bidi_component_manager.py +51 -0
  19. streamlit/components/v2/manifest_scanner.py +615 -0
  20. streamlit/components/v2/presentation.py +198 -0
  21. streamlit/components/v2/types.py +324 -0
  22. streamlit/config.py +456 -53
  23. streamlit/config_option.py +4 -1
  24. streamlit/config_util.py +650 -1
  25. streamlit/connections/snowflake_connection.py +1 -1
  26. streamlit/connections/snowpark_connection.py +1 -1
  27. streamlit/dataframe_util.py +33 -26
  28. streamlit/delta_generator.py +13 -4
  29. streamlit/delta_generator_singletons.py +11 -15
  30. streamlit/deprecation_util.py +17 -6
  31. streamlit/elements/alert.py +16 -0
  32. streamlit/elements/arrow.py +68 -10
  33. streamlit/elements/bokeh_chart.py +10 -78
  34. streamlit/elements/code.py +2 -2
  35. streamlit/elements/deck_gl_json_chart.py +98 -40
  36. streamlit/elements/dialog_decorator.py +2 -1
  37. streamlit/elements/exception.py +4 -2
  38. streamlit/elements/form.py +27 -0
  39. streamlit/elements/graphviz_chart.py +1 -3
  40. streamlit/elements/heading.py +63 -10
  41. streamlit/elements/html.py +13 -2
  42. streamlit/elements/image.py +3 -5
  43. streamlit/elements/layouts.py +59 -33
  44. streamlit/elements/lib/built_in_chart_utils.py +50 -19
  45. streamlit/elements/lib/color_util.py +9 -19
  46. streamlit/elements/lib/column_config_utils.py +9 -12
  47. streamlit/elements/lib/column_types.py +40 -12
  48. streamlit/elements/lib/dialog.py +2 -2
  49. streamlit/elements/lib/image_utils.py +3 -5
  50. streamlit/elements/lib/layout_utils.py +100 -13
  51. streamlit/elements/lib/mutable_status_container.py +2 -2
  52. streamlit/elements/lib/options_selector_utils.py +2 -2
  53. streamlit/elements/lib/pandas_styler_utils.py +17 -9
  54. streamlit/elements/lib/shortcut_utils.py +152 -0
  55. streamlit/elements/lib/utils.py +4 -4
  56. streamlit/elements/map.py +80 -37
  57. streamlit/elements/markdown.py +50 -3
  58. streamlit/elements/media.py +5 -7
  59. streamlit/elements/metric.py +34 -6
  60. streamlit/elements/pdf.py +2 -4
  61. streamlit/elements/plotly_chart.py +197 -20
  62. streamlit/elements/progress.py +2 -4
  63. streamlit/elements/space.py +113 -0
  64. streamlit/elements/spinner.py +1 -1
  65. streamlit/elements/text.py +20 -3
  66. streamlit/elements/toast.py +2 -0
  67. streamlit/elements/vega_charts.py +356 -149
  68. streamlit/elements/widgets/audio_input.py +12 -11
  69. streamlit/elements/widgets/button.py +280 -43
  70. streamlit/elements/widgets/button_group.py +60 -9
  71. streamlit/elements/widgets/camera_input.py +3 -5
  72. streamlit/elements/widgets/chat.py +307 -43
  73. streamlit/elements/widgets/color_picker.py +8 -1
  74. streamlit/elements/widgets/data_editor.py +88 -44
  75. streamlit/elements/widgets/file_uploader.py +9 -11
  76. streamlit/elements/widgets/multiselect.py +4 -3
  77. streamlit/elements/widgets/number_input.py +4 -4
  78. streamlit/elements/widgets/radio.py +10 -3
  79. streamlit/elements/widgets/select_slider.py +8 -5
  80. streamlit/elements/widgets/selectbox.py +6 -3
  81. streamlit/elements/widgets/slider.py +38 -42
  82. streamlit/elements/widgets/text_widgets.py +2 -0
  83. streamlit/elements/widgets/time_widgets.py +587 -21
  84. streamlit/elements/write.py +27 -6
  85. streamlit/emojis.py +1 -1
  86. streamlit/errors.py +137 -0
  87. streamlit/git_util.py +1 -1
  88. streamlit/hello/hello.py +8 -0
  89. streamlit/hello/utils.py +2 -1
  90. streamlit/material_icon_names.py +1 -1
  91. streamlit/navigation/page.py +11 -1
  92. streamlit/net_util.py +2 -2
  93. streamlit/proto/Alert_pb2.pyi +3 -3
  94. streamlit/proto/AppPage_pb2.pyi +7 -1
  95. streamlit/proto/ArrowData_pb2.py +27 -0
  96. streamlit/proto/ArrowData_pb2.pyi +52 -0
  97. streamlit/proto/ArrowNamedDataSet_pb2.pyi +7 -1
  98. streamlit/proto/ArrowVegaLiteChart_pb2.pyi +7 -1
  99. streamlit/proto/Arrow_pb2.py +10 -10
  100. streamlit/proto/Arrow_pb2.pyi +19 -12
  101. streamlit/proto/AudioInput_pb2.pyi +7 -1
  102. streamlit/proto/Audio_pb2.pyi +7 -1
  103. streamlit/proto/AuthRedirect_pb2.pyi +7 -1
  104. streamlit/proto/AutoRerun_pb2.pyi +7 -1
  105. streamlit/proto/BackMsg_pb2.py +4 -2
  106. streamlit/proto/BackMsg_pb2.pyi +34 -4
  107. streamlit/proto/Balloons_pb2.pyi +7 -1
  108. streamlit/proto/BidiComponent_pb2.py +34 -0
  109. streamlit/proto/BidiComponent_pb2.pyi +159 -0
  110. streamlit/proto/Block_pb2.py +7 -7
  111. streamlit/proto/Block_pb2.pyi +39 -36
  112. streamlit/proto/BokehChart_pb2.pyi +7 -1
  113. streamlit/proto/ButtonGroup_pb2.pyi +9 -9
  114. streamlit/proto/Button_pb2.py +2 -2
  115. streamlit/proto/Button_pb2.pyi +11 -2
  116. streamlit/proto/CameraInput_pb2.pyi +7 -1
  117. streamlit/proto/ChatInput_pb2.py +6 -6
  118. streamlit/proto/ChatInput_pb2.pyi +18 -6
  119. streamlit/proto/Checkbox_pb2.pyi +3 -3
  120. streamlit/proto/ClientState_pb2.pyi +10 -4
  121. streamlit/proto/Code_pb2.pyi +7 -1
  122. streamlit/proto/ColorPicker_pb2.pyi +7 -1
  123. streamlit/proto/Common_pb2.py +3 -3
  124. streamlit/proto/Common_pb2.pyi +35 -23
  125. streamlit/proto/Components_pb2.pyi +19 -13
  126. streamlit/proto/DataFrame_pb2.pyi +55 -49
  127. streamlit/proto/DateInput_pb2.pyi +7 -1
  128. streamlit/proto/DateTimeInput_pb2.py +28 -0
  129. streamlit/proto/DateTimeInput_pb2.pyi +92 -0
  130. streamlit/proto/DeckGlJsonChart_pb2.py +10 -4
  131. streamlit/proto/DeckGlJsonChart_pb2.pyi +12 -6
  132. streamlit/proto/Delta_pb2.pyi +7 -1
  133. streamlit/proto/DocString_pb2.pyi +10 -4
  134. streamlit/proto/DownloadButton_pb2.py +2 -2
  135. streamlit/proto/DownloadButton_pb2.pyi +16 -2
  136. streamlit/proto/Element_pb2.py +7 -3
  137. streamlit/proto/Element_pb2.pyi +33 -5
  138. streamlit/proto/Empty_pb2.pyi +7 -1
  139. streamlit/proto/Exception_pb2.pyi +7 -1
  140. streamlit/proto/Favicon_pb2.pyi +7 -1
  141. streamlit/proto/FileUploader_pb2.pyi +7 -1
  142. streamlit/proto/ForwardMsg_pb2.py +12 -10
  143. streamlit/proto/ForwardMsg_pb2.pyi +42 -15
  144. streamlit/proto/GapSize_pb2.pyi +4 -4
  145. streamlit/proto/GitInfo_pb2.pyi +3 -3
  146. streamlit/proto/GraphVizChart_pb2.pyi +7 -1
  147. streamlit/proto/Heading_pb2.pyi +7 -1
  148. streamlit/proto/HeightConfig_pb2.py +2 -2
  149. streamlit/proto/HeightConfig_pb2.pyi +13 -4
  150. streamlit/proto/Html_pb2.py +2 -2
  151. streamlit/proto/Html_pb2.pyi +11 -2
  152. streamlit/proto/IFrame_pb2.pyi +7 -1
  153. streamlit/proto/Image_pb2.pyi +10 -4
  154. streamlit/proto/Json_pb2.pyi +7 -1
  155. streamlit/proto/LabelVisibilityMessage_pb2.pyi +3 -3
  156. streamlit/proto/LinkButton_pb2.py +2 -2
  157. streamlit/proto/LinkButton_pb2.pyi +15 -2
  158. streamlit/proto/Logo_pb2.pyi +7 -1
  159. streamlit/proto/Markdown_pb2.pyi +3 -3
  160. streamlit/proto/Metric_pb2.pyi +7 -7
  161. streamlit/proto/MetricsEvent_pb2.pyi +10 -4
  162. streamlit/proto/MultiSelect_pb2.pyi +7 -1
  163. streamlit/proto/NamedDataSet_pb2.pyi +7 -1
  164. streamlit/proto/Navigation_pb2.pyi +3 -3
  165. streamlit/proto/NewSession_pb2.py +18 -18
  166. streamlit/proto/NewSession_pb2.pyi +59 -40
  167. streamlit/proto/NumberInput_pb2.pyi +3 -3
  168. streamlit/proto/PageConfig_pb2.pyi +7 -7
  169. streamlit/proto/PageInfo_pb2.pyi +7 -1
  170. streamlit/proto/PageLink_pb2.py +2 -2
  171. streamlit/proto/PageLink_pb2.pyi +11 -2
  172. streamlit/proto/PageNotFound_pb2.pyi +7 -1
  173. streamlit/proto/PageProfile_pb2.pyi +13 -7
  174. streamlit/proto/PagesChanged_pb2.pyi +7 -1
  175. streamlit/proto/ParentMessage_pb2.pyi +7 -1
  176. streamlit/proto/PlotlyChart_pb2.py +8 -6
  177. streamlit/proto/PlotlyChart_pb2.pyi +9 -7
  178. streamlit/proto/Progress_pb2.pyi +7 -1
  179. streamlit/proto/Radio_pb2.pyi +7 -1
  180. streamlit/proto/RootContainer_pb2.pyi +1 -1
  181. streamlit/proto/Selectbox_pb2.pyi +7 -1
  182. streamlit/proto/SessionEvent_pb2.pyi +7 -1
  183. streamlit/proto/SessionStatus_pb2.pyi +7 -1
  184. streamlit/proto/Skeleton_pb2.pyi +3 -3
  185. streamlit/proto/Slider_pb2.pyi +5 -5
  186. streamlit/proto/Snow_pb2.pyi +7 -1
  187. streamlit/proto/Space_pb2.py +27 -0
  188. streamlit/proto/Space_pb2.pyi +48 -0
  189. streamlit/proto/Spinner_pb2.pyi +7 -1
  190. streamlit/proto/TextAlignmentConfig_pb2.py +29 -0
  191. streamlit/proto/TextAlignmentConfig_pb2.pyi +68 -0
  192. streamlit/proto/TextArea_pb2.pyi +7 -1
  193. streamlit/proto/TextInput_pb2.pyi +3 -3
  194. streamlit/proto/Text_pb2.pyi +7 -1
  195. streamlit/proto/TimeInput_pb2.pyi +7 -1
  196. streamlit/proto/Toast_pb2.pyi +7 -1
  197. streamlit/proto/VegaLiteChart_pb2.pyi +7 -1
  198. streamlit/proto/Video_pb2.pyi +6 -6
  199. streamlit/proto/WidgetStates_pb2.py +2 -2
  200. streamlit/proto/WidgetStates_pb2.pyi +23 -7
  201. streamlit/proto/WidthConfig_pb2.py +2 -2
  202. streamlit/proto/WidthConfig_pb2.pyi +13 -4
  203. streamlit/proto/openmetrics_data_model_pb2.pyi +52 -52
  204. streamlit/runtime/app_session.py +65 -2
  205. streamlit/runtime/caching/cache_data_api.py +5 -5
  206. streamlit/runtime/caching/cache_errors.py +4 -1
  207. streamlit/runtime/caching/cache_resource_api.py +5 -4
  208. streamlit/runtime/caching/cache_utils.py +3 -2
  209. streamlit/runtime/caching/cached_message_replay.py +3 -3
  210. streamlit/runtime/caching/hashing.py +4 -5
  211. streamlit/runtime/caching/legacy_cache_api.py +2 -1
  212. streamlit/runtime/connection_factory.py +1 -3
  213. streamlit/runtime/download_data_util.py +53 -0
  214. streamlit/runtime/forward_msg_queue.py +5 -1
  215. streamlit/runtime/fragment.py +2 -1
  216. streamlit/runtime/media_file_manager.py +178 -2
  217. streamlit/runtime/memory_media_file_storage.py +1 -1
  218. streamlit/runtime/metrics_util.py +91 -3
  219. streamlit/runtime/runtime.py +14 -0
  220. streamlit/runtime/scriptrunner/exec_code.py +2 -1
  221. streamlit/runtime/scriptrunner/script_runner.py +5 -3
  222. streamlit/runtime/scriptrunner_utils/script_run_context.py +3 -6
  223. streamlit/runtime/secrets.py +2 -4
  224. streamlit/runtime/session_manager.py +3 -1
  225. streamlit/runtime/state/common.py +30 -5
  226. streamlit/runtime/state/presentation.py +85 -0
  227. streamlit/runtime/state/query_params.py +80 -29
  228. streamlit/runtime/state/safe_session_state.py +2 -2
  229. streamlit/runtime/state/session_state.py +221 -17
  230. streamlit/runtime/state/widgets.py +19 -3
  231. streamlit/runtime/websocket_session_manager.py +3 -1
  232. streamlit/source_util.py +2 -2
  233. streamlit/static/index.html +2 -2
  234. streamlit/static/manifest.json +557 -239
  235. streamlit/static/static/css/{index.CIiu7Ygf.css → index.BpABIXK9.css} +1 -1
  236. streamlit/static/static/css/index.DgR7E2CV.css +1 -0
  237. streamlit/static/static/js/{ErrorOutline.esm.DUpR0_Ka.js → ErrorOutline.esm.ZJDbmVTx.js} +1 -1
  238. streamlit/static/static/js/{FileDownload.esm.CN4j9-1w.js → FileDownload.esm.Dx0vI3vH.js} +1 -1
  239. streamlit/static/static/js/{FileHelper.CaIUKG91.js → FileHelper.B7Ero7qQ.js} +3 -3
  240. streamlit/static/static/js/{FormClearHelper.DTcdrasw.js → FormClearHelper.CG2XN1_g.js} +1 -1
  241. streamlit/static/static/js/IFrameUtil.DefezniK.js +1 -0
  242. streamlit/static/static/js/InputInstructions.Cj5-1zf6.js +1 -0
  243. streamlit/static/static/js/Particles.BfWfv0Aw.js +1 -0
  244. streamlit/static/static/js/{ProgressBar.DetlP5aY.js → ProgressBar.CGQ8OgfO.js} +2 -2
  245. streamlit/static/static/js/StreamlitSyntaxHighlighter.DTKLpwhl.js +20 -0
  246. streamlit/static/static/js/{Toolbar.C77ar7rq.js → Toolbar.B2qFUmd9.js} +1 -1
  247. streamlit/static/static/js/_arrayIncludes.B19Iyn2B.js +1 -0
  248. streamlit/static/static/js/_baseIndexOf.BTknn6Gb.js +1 -0
  249. streamlit/static/static/js/{base-input.BQft14La.js → base-input.o9tL8MDP.js} +4 -4
  250. streamlit/static/static/js/{checkbox.yZOfXCeX.js → checkbox.0BeV1IBL.js} +1 -1
  251. streamlit/static/static/js/{createSuper.Dh9w1cs8.js → createSuper.RBO59fEm.js} +1 -1
  252. streamlit/static/static/js/data-grid-overlay-editor.CiTkUy0t.js +1 -0
  253. streamlit/static/static/js/{downloader.MeHtkq8r.js → downloader.DwNZg3Mw.js} +1 -1
  254. streamlit/static/static/js/embed.XT9xNd3F.js +195 -0
  255. streamlit/static/static/js/{es6.VpBPGCnM.js → es6.x9KsYQg-.js} +2 -2
  256. streamlit/static/static/js/{iframeResizer.contentWindow.yMw_ARIL.js → iframeResizer.contentWindow.ZVXpMPi0.js} +1 -1
  257. streamlit/static/static/js/index.5VPOamri.js +1 -0
  258. streamlit/static/static/js/index.8HslT92O.js +14 -0
  259. streamlit/static/static/js/index.AnXMIBz3.js +7 -0
  260. streamlit/static/static/js/index.B0yp3bM1.js +6 -0
  261. streamlit/static/static/js/index.B1fRb5wF.js +1 -0
  262. streamlit/static/static/js/index.B527JZdO.js +3 -0
  263. streamlit/static/static/js/index.BHgV-yW4.js +1 -0
  264. streamlit/static/static/js/index.BQr-XwGV.js +1 -0
  265. streamlit/static/static/js/index.BTtmaLDB.js +1 -0
  266. streamlit/static/static/js/index.BWB_91TA.js +1 -0
  267. streamlit/static/static/js/index.BfEKaEmw.js +1 -0
  268. streamlit/static/static/js/index.BfXjTO8b.js +1 -0
  269. streamlit/static/static/js/index.Bjy4NRu9.js +3 -0
  270. streamlit/static/static/js/index.Bu5JWpT_.js +1 -0
  271. streamlit/static/static/js/index.BuCx76ZV.js +1 -0
  272. streamlit/static/static/js/index.BxjzhVUb.js +2 -0
  273. streamlit/static/static/js/index.By55VdPY.js +1 -0
  274. streamlit/static/static/js/index.CF5MxTbK.js +1 -0
  275. streamlit/static/static/js/index.CLmq_z9K.js +1 -0
  276. streamlit/static/static/js/index.CNH4rdSz.js +1 -0
  277. streamlit/static/static/js/{index.B0H9IXUJ.js → index.CTgm_-jO.js} +10 -41
  278. streamlit/static/static/js/index.C_rK-Swb.js +188 -0
  279. streamlit/static/static/js/index.CjozwSzS.js +1 -0
  280. streamlit/static/static/js/{index.CH1tqnSs.js → index.CkGVt6-G.js} +1 -1
  281. streamlit/static/static/js/index.CuvXOyER.js +2 -0
  282. streamlit/static/static/js/{index.FFOzOWzC.js → index.CyUHWoCC.js} +2 -2
  283. streamlit/static/static/js/index.CyroQtI4.js +2 -0
  284. streamlit/static/static/js/index.D6HmkoDm.js +263 -0
  285. streamlit/static/static/js/index.DAqCNvsO.js +1 -0
  286. streamlit/static/static/js/index.DB_w_CZQ.js +1 -0
  287. streamlit/static/static/js/index.DBalctjj.js +2 -0
  288. streamlit/static/static/js/index.DK0RFJUG.js +11 -0
  289. streamlit/static/static/js/index.DMxc2XFp.js +151 -0
  290. streamlit/static/static/js/index.DO5utP74.js +2 -0
  291. streamlit/static/static/js/index.DS7lf09n.js +1 -0
  292. streamlit/static/static/js/index.DWexTVLY.js +1 -0
  293. streamlit/static/static/js/index.DXxnU5ej.js +1 -0
  294. streamlit/static/static/js/index.DcU3uDvB.js +2 -0
  295. streamlit/static/static/js/index.DlltaH7J.js +1 -0
  296. streamlit/static/static/js/index.DpNTZz82.js +27 -0
  297. streamlit/static/static/js/index.Dr9HIhQw.js +1 -0
  298. streamlit/static/static/js/index.DsgAU5lc.js +1 -0
  299. streamlit/static/static/js/{index.64ejlaaT.js → index.KfXqjDYy.js} +1 -1
  300. streamlit/static/static/js/index.PaidgjCs.js +1 -0
  301. streamlit/static/static/js/index.RJZuWCGA.js +1 -0
  302. streamlit/static/static/js/{index.Ctn27_AE.js → index.hbeqcRTn.js} +53 -122
  303. streamlit/static/static/js/index.q5hIQwAY.js +1 -0
  304. streamlit/static/static/js/index.rORSX6IW.js +1 -0
  305. streamlit/static/static/js/index.uSX757_v.js +1 -0
  306. streamlit/static/static/js/index.x_QRaLMd.js +1 -0
  307. streamlit/static/static/js/{input.s6pjQ49A.js → input.D5oh9-aB.js} +2 -2
  308. streamlit/static/static/js/main.q9oGOg0H.js +13 -0
  309. streamlit/static/static/js/{memory.Cuvsdfrl.js → memory.5kCSFUJS.js} +1 -1
  310. streamlit/static/static/js/moment.C3j7ZXd7.js +4 -0
  311. streamlit/static/static/js/number-overlay-editor.Cn_LsK8N.js +9 -0
  312. streamlit/static/static/js/pandasStylerUtils.BqhXt51_.js +1 -0
  313. streamlit/static/static/js/{possibleConstructorReturn.CqidKeei.js → possibleConstructorReturn.DD9NK1Z8.js} +1 -1
  314. streamlit/static/static/js/record.B-tDciZb.js +1 -0
  315. streamlit/static/static/js/{sandbox.CCQREcJx.js → sandbox.DACSyz29.js} +1 -1
  316. streamlit/static/static/js/styled-components.C3R090At.js +1 -0
  317. streamlit/static/static/js/threshold.Q1mXg5rX.js +1 -0
  318. streamlit/static/static/js/throttle.B0GR3Iyz.js +1 -0
  319. streamlit/static/static/js/{timepicker.mkJF97Bb.js → timepicker.BdhzPxrv.js} +1 -1
  320. streamlit/static/static/js/timer.C2hYhUse.js +1 -0
  321. streamlit/static/static/js/{toConsumableArray.De7I7KVR.js → toConsumableArray.Db2pdqM2.js} +1 -1
  322. streamlit/static/static/js/uniqueId.CtqIr-Yh.js +1 -0
  323. streamlit/static/static/js/urls.BwSlolu9.js +1 -0
  324. streamlit/static/static/js/{useBasicWidgetState.CedkNjUW.js → useBasicWidgetState.Bfp6TnSw.js} +1 -1
  325. streamlit/static/static/js/useIntlLocale.hRV75Xgj.js +12 -0
  326. streamlit/static/static/js/{useTextInputAutoExpand.Ca7w8dVs.js → useTextInputAutoExpand.QepX7n8Y.js} +1 -1
  327. streamlit/static/static/js/useUpdateUiValue.DHx8TzX6.js +1 -0
  328. streamlit/static/static/js/useWaveformController.WxVzpzEX.js +1 -0
  329. streamlit/static/static/js/value.B4vHRSi7.js +1 -0
  330. streamlit/static/static/js/wavesurfer.esm.vI8Eid4k.js +73 -0
  331. streamlit/static/static/js/withCalculatedWidth.DcKeRSWJ.js +1 -0
  332. streamlit/static/static/js/withFullScreenWrapper.CrHddARq.js +1 -0
  333. streamlit/static/static/media/MaterialSymbols-Rounded.C7IFxh57.woff2 +0 -0
  334. streamlit/string_util.py +9 -4
  335. streamlit/testing/v1/app_test.py +17 -2
  336. streamlit/testing/v1/element_tree.py +85 -9
  337. streamlit/testing/v1/util.py +2 -2
  338. streamlit/type_util.py +3 -4
  339. streamlit/url_util.py +1 -3
  340. streamlit/user_info.py +1 -2
  341. streamlit/util.py +3 -1
  342. streamlit/watcher/event_based_path_watcher.py +23 -12
  343. streamlit/watcher/local_sources_watcher.py +11 -1
  344. streamlit/watcher/path_watcher.py +9 -6
  345. streamlit/watcher/polling_path_watcher.py +4 -1
  346. streamlit/watcher/util.py +2 -2
  347. streamlit/web/bootstrap.py +24 -0
  348. streamlit/web/cli.py +51 -22
  349. streamlit/web/server/bidi_component_request_handler.py +193 -0
  350. streamlit/web/server/component_file_utils.py +97 -0
  351. streamlit/web/server/component_request_handler.py +8 -21
  352. streamlit/web/server/oauth_authlib_routes.py +5 -2
  353. streamlit/web/server/oidc_mixin.py +3 -1
  354. streamlit/web/server/routes.py +2 -2
  355. streamlit/web/server/server.py +9 -0
  356. streamlit/web/server/server_util.py +3 -1
  357. streamlit/web/server/upload_file_request_handler.py +19 -1
  358. {streamlit-1.50.0.dist-info → streamlit-1.52.0.dist-info}/METADATA +10 -7
  359. streamlit-1.52.0.dist-info/RECORD +620 -0
  360. streamlit/static/static/css/index.CHEnSPGk.css +0 -1
  361. streamlit/static/static/js/Hooks.BRba_Own.js +0 -1
  362. streamlit/static/static/js/InputInstructions.xnSDuYeQ.js +0 -1
  363. streamlit/static/static/js/Particles.CElH0XX2.js +0 -1
  364. streamlit/static/static/js/data-grid-overlay-editor.DcuHuCyW.js +0 -1
  365. streamlit/static/static/js/index.6xX1278W.js +0 -975
  366. streamlit/static/static/js/index.B-hiXRzw.js +0 -1
  367. streamlit/static/static/js/index.B4cAbHP6.js +0 -1
  368. streamlit/static/static/js/index.B4dUQfni.js +0 -1
  369. streamlit/static/static/js/index.BPQo7BKk.js +0 -1
  370. streamlit/static/static/js/index.Baqa90pe.js +0 -2
  371. streamlit/static/static/js/index.Bj9JgOEC.js +0 -1
  372. streamlit/static/static/js/index.BjCwMzj4.js +0 -3
  373. streamlit/static/static/js/index.Bm3VbPB5.js +0 -1
  374. streamlit/static/static/js/index.Bxz2yX3P.js +0 -1
  375. streamlit/static/static/js/index.BycLveZ4.js +0 -1
  376. streamlit/static/static/js/index.C9BdUqTi.js +0 -1
  377. streamlit/static/static/js/index.CFMf5_ez.js +0 -197
  378. streamlit/static/static/js/index.CGYqqs6j.js +0 -1
  379. streamlit/static/static/js/index.CMItVsFA.js +0 -1
  380. streamlit/static/static/js/index.CTBk8Vk2.js +0 -1
  381. streamlit/static/static/js/index.CiAQIz1H.js +0 -7
  382. streamlit/static/static/js/index.Cj7DSzVR.js +0 -73
  383. streamlit/static/static/js/index.Ck8rQ9OL.js +0 -1
  384. streamlit/static/static/js/index.ClELlchS.js +0 -1617
  385. streamlit/static/static/js/index.Cnpi3o3E.js +0 -1
  386. streamlit/static/static/js/index.D2QEXQq_.js +0 -1
  387. streamlit/static/static/js/index.DH71Ezyj.js +0 -1
  388. streamlit/static/static/js/index.DHh-U0dK.js +0 -3
  389. streamlit/static/static/js/index.DK7hD7_w.js +0 -1
  390. streamlit/static/static/js/index.DKv_lNO7.js +0 -2
  391. streamlit/static/static/js/index.DNLrMXgm.js +0 -12
  392. streamlit/static/static/js/index.DW0Grddz.js +0 -1
  393. streamlit/static/static/js/index.Dbe-Q3C-.js +0 -2
  394. streamlit/static/static/js/index.DcPNYEUo.js +0 -1
  395. streamlit/static/static/js/index.DuxqVQpd.js +0 -1
  396. streamlit/static/static/js/index.GRUzrudl.js +0 -1
  397. streamlit/static/static/js/number-overlay-editor.DdgVR5m3.js +0 -9
  398. streamlit/static/static/js/uniqueId.RI1LJdtz.js +0 -1
  399. streamlit/static/static/js/useUpdateUiValue.DeXelfRH.js +0 -1
  400. streamlit/static/static/js/withFullScreenWrapper.C3561XxJ.js +0 -1
  401. streamlit/static/static/media/MaterialSymbols-Rounded.DeCZgS-4.woff2 +0 -0
  402. streamlit-1.50.0.dist-info/RECORD +0 -557
  403. {streamlit-1.50.0.data → streamlit-1.52.0.data}/scripts/streamlit.cmd +0 -0
  404. {streamlit-1.50.0.dist-info → streamlit-1.52.0.dist-info}/WHEEL +0 -0
  405. {streamlit-1.50.0.dist-info → streamlit-1.52.0.dist-info}/entry_points.txt +0 -0
  406. {streamlit-1.50.0.dist-info → streamlit-1.52.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,534 @@
1
+ # Copyright (c) Streamlit Inc. (2018-2022) Snowflake Inc. (2022-2025)
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from __future__ import annotations
16
+
17
+ import json
18
+ from collections.abc import Mapping
19
+ from typing import TYPE_CHECKING, Any, cast
20
+
21
+ from streamlit.components.v2.bidi_component.constants import (
22
+ EVENT_DELIM,
23
+ INTERNAL_COMPONENT_NAME,
24
+ )
25
+ from streamlit.components.v2.bidi_component.serialization import (
26
+ BidiComponentSerde,
27
+ deserialize_trigger_list,
28
+ serialize_mixed_data,
29
+ )
30
+ from streamlit.components.v2.bidi_component.state import (
31
+ BidiComponentResult,
32
+ unwrap_component_state,
33
+ )
34
+ from streamlit.components.v2.presentation import make_bidi_component_presenter
35
+ from streamlit.dataframe_util import (
36
+ DataFormat,
37
+ convert_anything_to_arrow_bytes,
38
+ determine_data_format,
39
+ )
40
+ from streamlit.elements.lib.form_utils import current_form_id
41
+ from streamlit.elements.lib.layout_utils import (
42
+ Height,
43
+ LayoutConfig,
44
+ Width,
45
+ validate_width,
46
+ )
47
+ from streamlit.elements.lib.policies import check_cache_replay_rules
48
+ from streamlit.elements.lib.utils import compute_and_register_element_id, to_key
49
+ from streamlit.errors import (
50
+ BidiComponentInvalidCallbackNameError,
51
+ BidiComponentInvalidDefaultKeyError,
52
+ BidiComponentInvalidIdError,
53
+ BidiComponentMissingContentError,
54
+ BidiComponentUnserializableDataError,
55
+ )
56
+ from streamlit.proto.ArrowData_pb2 import ArrowData as ArrowDataProto
57
+ from streamlit.proto.BidiComponent_pb2 import BidiComponent as BidiComponentProto
58
+ from streamlit.proto.BidiComponent_pb2 import MixedData as MixedDataProto
59
+ from streamlit.runtime.metrics_util import gather_metrics
60
+ from streamlit.runtime.scriptrunner_utils.script_run_context import get_script_run_ctx
61
+ from streamlit.runtime.state import register_widget
62
+ from streamlit.util import calc_md5
63
+
64
+ if TYPE_CHECKING:
65
+ from streamlit.components.v2.types import (
66
+ BidiComponentData,
67
+ BidiComponentDefaults,
68
+ BidiComponentKey,
69
+ ComponentIsolateStyles,
70
+ )
71
+
72
+ if TYPE_CHECKING:
73
+ # Define DeltaGenerator for type checking the dg property
74
+ from streamlit.delta_generator import DeltaGenerator
75
+ from streamlit.runtime.state.common import WidgetCallback
76
+
77
+
78
+ def _make_trigger_id(base: str, event: str) -> str:
79
+ """Construct the per-event *trigger widget* identifier.
80
+
81
+ The widget ID for a trigger is derived from the *base* component ID plus
82
+ an *event* name. We join those two parts with :py:const:`EVENT_DELIM` and
83
+ perform a couple of validations so that downstream logic can always split
84
+ the identifier unambiguously.
85
+
86
+ Trigger widgets are marked as internal by prefixing with an internal key prefix,
87
+ so they won't be exposed in `st.session_state` to end users.
88
+
89
+ Parameters
90
+ ----------
91
+ base
92
+ The unique, framework-assigned ID of the component instance.
93
+ event
94
+ The event name as provided by either the frontend or the developer
95
+ (e.g., "click", "change").
96
+
97
+ Returns
98
+ -------
99
+ str
100
+ The composite widget ID in the form ``"$$STREAMLIT_INTERNAL_KEY_{base}__{event}"``
101
+ where ``__`` is the delimiter.
102
+
103
+ Raises
104
+ ------
105
+ StreamlitAPIException
106
+ If either `base` or `event` already contains the delimiter sequence.
107
+
108
+ """
109
+ from streamlit.runtime.state.session_state import STREAMLIT_INTERNAL_KEY_PREFIX
110
+
111
+ if EVENT_DELIM in base:
112
+ raise BidiComponentInvalidIdError("base", EVENT_DELIM)
113
+ if EVENT_DELIM in event:
114
+ raise BidiComponentInvalidIdError("event", EVENT_DELIM)
115
+
116
+ return f"{STREAMLIT_INTERNAL_KEY_PREFIX}_{base}{EVENT_DELIM}{event}"
117
+
118
+
119
+ class BidiComponentMixin:
120
+ """Mixin class for the bidi_component DeltaGenerator method."""
121
+
122
+ def _canonicalize_json_for_identity(self, payload: str) -> str:
123
+ """Return a deterministic JSON string for identity comparisons.
124
+
125
+ Payloads that cannot be parsed (or re-serialized) are returned as-is to
126
+ avoid mutating developer data.
127
+ """
128
+
129
+ if not payload:
130
+ return payload
131
+
132
+ try:
133
+ parsed = json.loads(payload)
134
+ except (TypeError, ValueError):
135
+ return payload
136
+
137
+ try:
138
+ return json.dumps(parsed, sort_keys=True)
139
+ except (TypeError, ValueError):
140
+ return payload
141
+
142
+ def _canonical_json_digest_for_identity(self, payload: str) -> str:
143
+ """Return the hash of the canonicalized JSON payload for identity use.
144
+
145
+ Hashing keeps the kwargs passed to ``compute_and_register_element_id``
146
+ small even when the JSON payload is very large, while still changing the
147
+ identity whenever the canonical JSON content changes.
148
+ """
149
+
150
+ canonical = self._canonicalize_json_for_identity(payload)
151
+ return calc_md5(canonical)
152
+
153
+ def _build_bidi_identity_kwargs(
154
+ self,
155
+ *,
156
+ component_name: str,
157
+ isolate_styles: bool,
158
+ width: Width,
159
+ height: Height,
160
+ proto: BidiComponentProto,
161
+ data: BidiComponentData = None,
162
+ ) -> dict[str, Any]:
163
+ """Build deterministic identity kwargs for ID computation.
164
+
165
+ Construct a stable mapping of identity-relevant properties for
166
+ ``compute_and_register_element_id``. This includes structural
167
+ properties (name, style isolation, layout) and an explicit, typed
168
+ handling of the ``BidiComponent`` ``oneof data`` field to ensure
169
+ unkeyed components change identity when their serialized payload
170
+ changes.
171
+
172
+ Parameters
173
+ ----------
174
+ component_name : str
175
+ The registered component name.
176
+ isolate_styles : bool
177
+ Whether the component styles are rendered in a Shadow DOM.
178
+ width : Width
179
+ Desired width configuration passed to the component.
180
+ height : Height
181
+ Desired height configuration passed to the component.
182
+ proto : BidiComponentProto
183
+ The populated component protobuf. Its ``data`` oneof determines
184
+ which serialized payload (JSON, Arrow, bytes, or Mixed) contributes
185
+ to identity.
186
+ data : BidiComponentData
187
+ The raw data passed to the component. Used to optimize identity
188
+ calculation for JSON payloads by avoiding a parse/serialize cycle.
189
+
190
+ Returns
191
+ -------
192
+ dict[str, Any]
193
+ A mapping of deterministic values to be forwarded into
194
+ ``compute_and_register_element_id``.
195
+
196
+ Raises
197
+ ------
198
+ RuntimeError
199
+ If an unhandled ``oneof data`` variant is encountered (guards
200
+ against adding new fields without updating identity computation).
201
+ """
202
+ identity: dict[str, Any] = {
203
+ "component_name": component_name,
204
+ "isolate_styles": isolate_styles,
205
+ "width": width,
206
+ "height": height,
207
+ }
208
+
209
+ data_field = proto.WhichOneof("data")
210
+ if data_field is None:
211
+ return identity
212
+
213
+ if data_field == "json":
214
+ # Canonicalize only for identity so unkeyed widgets don't churn when
215
+ # dict insertion order changes.
216
+ #
217
+ # Optimization: Use raw `data` if available to avoid the overhead of
218
+ # parsing `proto.json` back into a dict.
219
+ canonical_digest = None
220
+
221
+ if data is not None:
222
+ try:
223
+ canonical = json.dumps(data, sort_keys=True)
224
+ canonical_digest = calc_md5(canonical)
225
+ except (TypeError, ValueError):
226
+ # Fallback to existing logic if direct dump fails
227
+ pass
228
+
229
+ if canonical_digest is None:
230
+ canonical_digest = self._canonical_json_digest_for_identity(proto.json)
231
+
232
+ identity["json"] = canonical_digest
233
+ elif data_field == "arrow_data":
234
+ # Hash large payloads instead of shoving raw bytes through the ID
235
+ # hasher for performance.
236
+ identity["arrow_data"] = calc_md5(proto.arrow_data.data)
237
+ elif data_field == "bytes":
238
+ # Same story for arbitrary bytes payloads: content-address the data
239
+ # so identity changes track real mutations without re-hashing the
240
+ # whole blob every run.
241
+ identity["bytes"] = calc_md5(proto.bytes)
242
+ elif data_field == "mixed":
243
+ mixed: MixedDataProto = proto.mixed
244
+ # Add the JSON content of the MixedData to the identity.
245
+ identity["mixed_json"] = self._canonical_json_digest_for_identity(
246
+ mixed.json
247
+ )
248
+ # Add the sorted content-addressed ref IDs of the Arrow blobs to the identity.
249
+ # Unlike other data types where we include actual bytes, here we only include
250
+ # the blob keys. This is sufficient because keys are MD5 hashes of the blob
251
+ # content (content-addressed), so identical content produces identical keys.
252
+ identity["mixed_arrow_blobs"] = ",".join(sorted(mixed.arrow_blobs.keys()))
253
+ else:
254
+ raise RuntimeError(
255
+ f"Unhandled BidiComponent.data oneof field: {data_field}"
256
+ )
257
+
258
+ return identity
259
+
260
+ @gather_metrics("_bidi_component")
261
+ def _bidi_component(
262
+ self,
263
+ component_name: str,
264
+ key: BidiComponentKey = None,
265
+ isolate_styles: ComponentIsolateStyles = True,
266
+ data: BidiComponentData = None,
267
+ default: BidiComponentDefaults = None,
268
+ width: Width = "stretch",
269
+ height: Height = "content",
270
+ **kwargs: WidgetCallback | None,
271
+ ) -> BidiComponentResult:
272
+ """Add a bidirectional component instance to the app.
273
+
274
+ This method uses a component that has already been registered with the
275
+ application.
276
+
277
+ Parameters
278
+ ----------
279
+ component_name
280
+ The name of the registered component to use. The component's HTML,
281
+ CSS, and JavaScript will be loaded from the registry.
282
+ key
283
+ An optional string to use as the unique key for the component.
284
+ If this is omitted, a key will be generated based on the
285
+ component's execution sequence.
286
+ isolate_styles
287
+ Whether to sandbox the component's styles in a shadow root.
288
+ Defaults to True.
289
+ data
290
+ Data to pass to the component. This can be any JSON-serializable
291
+ data, or a pandas DataFrame, NumPy array, or other dataframe-like
292
+ object that can be serialized to Arrow.
293
+ default
294
+ A dictionary of default values for the component's state properties.
295
+ These defaults are applied only when the state key doesn't exist
296
+ in session state. Keys must correspond to valid state names (those
297
+ with `on_*_change` callbacks). Trigger values do not support
298
+ defaults.
299
+ width
300
+ The desired width of the component. This can be one of "stretch",
301
+ "content", or a number of pixels.
302
+ height
303
+ The desired height of the component. This can be one of "stretch",
304
+ "content", or a number of pixels.
305
+ **kwargs
306
+ Keyword arguments to pass to the component. Callbacks can be passed
307
+ here, with the naming convention `on_{event_name}_change`.
308
+
309
+ Returns
310
+ -------
311
+ BidiComponentResult
312
+ A dictionary-like object that holds the component's state and
313
+ trigger values.
314
+
315
+ Raises
316
+ ------
317
+ ValueError
318
+ If the component name is not found in the registry.
319
+ StreamlitAPIException
320
+ If the component does not have the required JavaScript or HTML
321
+ content, or if the provided data cannot be serialized.
322
+
323
+ """
324
+ check_cache_replay_rules()
325
+
326
+ key = to_key(key)
327
+ ctx = get_script_run_ctx()
328
+
329
+ if ctx is None:
330
+ # Create an empty state with the default value and return it
331
+ return BidiComponentResult({}, {})
332
+
333
+ # Get the component definition from the registry
334
+ from streamlit.runtime import Runtime
335
+
336
+ registry = Runtime.instance().bidi_component_registry
337
+ component_def = registry.get(component_name)
338
+
339
+ if component_def is None:
340
+ raise ValueError(f"Component '{component_name}' is not registered")
341
+
342
+ # Validate that the component has the required content
343
+ has_js = bool(component_def.js_content or component_def.js_url)
344
+ has_html = bool(component_def.html_content)
345
+
346
+ if not has_js and not has_html:
347
+ raise BidiComponentMissingContentError(component_name)
348
+
349
+ # ------------------------------------------------------------------
350
+ # 1. Parse user-supplied callbacks
351
+ # ------------------------------------------------------------------
352
+ # Event-specific callbacks follow the pattern ``on_<event>_change``.
353
+ # We deliberately *do not* support the legacy generic ``on_change``
354
+ # or ``on_<event>`` forms.
355
+ callbacks_by_event: dict[str, WidgetCallback] = {}
356
+ for kwarg_key, kwarg_value in list(kwargs.items()):
357
+ if not callable(kwarg_value):
358
+ continue
359
+
360
+ if kwarg_key.startswith("on_") and kwarg_key.endswith("_change"):
361
+ # Preferred pattern: on_<event>_change
362
+ event_name = kwarg_key[3:-7] # strip prefix + suffix
363
+ else:
364
+ # Not an event callback we recognize - skip.
365
+ continue
366
+
367
+ if not event_name or event_name == "_":
368
+ raise BidiComponentInvalidCallbackNameError(kwarg_key)
369
+
370
+ callbacks_by_event[event_name] = kwarg_value
371
+
372
+ # ------------------------------------------------------------------
373
+ # 2. Validate default keys against registered callbacks
374
+ # ------------------------------------------------------------------
375
+ if default is not None:
376
+ for state_key in default:
377
+ if state_key not in callbacks_by_event:
378
+ raise BidiComponentInvalidDefaultKeyError(
379
+ state_key, list(callbacks_by_event.keys())
380
+ )
381
+
382
+ # Set up the component proto
383
+ bidi_component_proto = BidiComponentProto()
384
+ bidi_component_proto.component_name = component_name
385
+ bidi_component_proto.isolate_styles = isolate_styles
386
+ bidi_component_proto.js_content = component_def.js_content or ""
387
+ bidi_component_proto.js_source_path = component_def.js_url or ""
388
+ bidi_component_proto.html_content = component_def.html_content or ""
389
+ bidi_component_proto.css_content = component_def.css_content or ""
390
+ bidi_component_proto.css_source_path = component_def.css_url or ""
391
+
392
+ validate_width(width, allow_content=True)
393
+ layout_config = LayoutConfig(width=width, height=height)
394
+
395
+ if data is not None:
396
+ try:
397
+ # 1. Raw byte payloads - forward as-is.
398
+ if isinstance(data, (bytes, bytearray)):
399
+ bidi_component_proto.bytes = bytes(data)
400
+
401
+ # 2. Mapping-like structures (e.g. plain dict) - check for mixed data.
402
+ elif isinstance(data, (Mapping, list, tuple)):
403
+ serialize_mixed_data(data, bidi_component_proto)
404
+
405
+ # 3. Dataframe-like structures - attempt Arrow serialization.
406
+ else:
407
+ data_format = determine_data_format(data)
408
+
409
+ if data_format != DataFormat.UNKNOWN:
410
+ arrow_bytes = convert_anything_to_arrow_bytes(data)
411
+
412
+ arrow_data_proto = ArrowDataProto()
413
+ arrow_data_proto.data = arrow_bytes
414
+
415
+ bidi_component_proto.arrow_data.CopyFrom(arrow_data_proto)
416
+ else:
417
+ # Fallback to JSON.
418
+ bidi_component_proto.json = json.dumps(data)
419
+ except Exception:
420
+ # As a last resort attempt JSON serialization so that we don't
421
+ # silently drop developer data.
422
+ try:
423
+ bidi_component_proto.json = json.dumps(data)
424
+ except Exception:
425
+ raise BidiComponentUnserializableDataError()
426
+ bidi_component_proto.form_id = current_form_id(self.dg)
427
+
428
+ # Build identity kwargs for the component instance now that the proto is
429
+ # populated.
430
+ identity_kwargs = self._build_bidi_identity_kwargs(
431
+ component_name=component_name,
432
+ isolate_styles=isolate_styles,
433
+ width=width,
434
+ height=height,
435
+ proto=bidi_component_proto,
436
+ data=data,
437
+ )
438
+ # Compute a unique ID for this component instance now that the proto is
439
+ # populated.
440
+ computed_id = compute_and_register_element_id(
441
+ "bidi_component",
442
+ user_key=key,
443
+ key_as_main_identity=True,
444
+ dg=self.dg,
445
+ **identity_kwargs,
446
+ )
447
+ bidi_component_proto.id = computed_id
448
+
449
+ # Instantiate the Serde for this component instance
450
+ serde = BidiComponentSerde(default=default)
451
+
452
+ # ------------------------------------------------------------------
453
+ # 3. Prepare IDs and register widgets
454
+ # ------------------------------------------------------------------
455
+
456
+ # Compute trigger aggregator id from the base id
457
+ def _make_trigger_aggregator_id(base: str) -> str:
458
+ return _make_trigger_id(base, "events")
459
+
460
+ aggregator_id = _make_trigger_aggregator_id(computed_id)
461
+
462
+ # With generalized runtime dispatch, we can attach per-key callbacks
463
+ # directly to the state widget by passing the callbacks mapping.
464
+ # We also register a presenter to shape the user-visible session_state.
465
+ # Allowed state keys are the ones that have callbacks registered.
466
+ allowed_state_keys = (
467
+ set(callbacks_by_event.keys()) if callbacks_by_event else None
468
+ )
469
+ presenter = make_bidi_component_presenter(
470
+ aggregator_id,
471
+ computed_id,
472
+ allowed_state_keys,
473
+ )
474
+
475
+ component_state = register_widget(
476
+ bidi_component_proto.id,
477
+ deserializer=serde.deserialize,
478
+ serializer=serde.serialize,
479
+ ctx=ctx,
480
+ callbacks=callbacks_by_event if callbacks_by_event else None,
481
+ value_type="json_value",
482
+ presenter=presenter,
483
+ )
484
+
485
+ # ------------------------------------------------------------------
486
+ # 4. Register a single *trigger aggregator* widget
487
+ # ------------------------------------------------------------------
488
+ trigger_vals: dict[str, Any] = {}
489
+
490
+ trig_state = register_widget(
491
+ aggregator_id,
492
+ deserializer=deserialize_trigger_list, # always returns list or None
493
+ serializer=lambda v: json.dumps(v), # send dict as JSON
494
+ ctx=ctx,
495
+ callbacks=callbacks_by_event if callbacks_by_event else None,
496
+ value_type="json_trigger_value",
497
+ )
498
+
499
+ # Surface per-event trigger values derived from the aggregator payload list.
500
+ payloads: list[object] = trig_state.value or []
501
+
502
+ event_to_value: dict[str, Any] = {}
503
+ for payload in payloads:
504
+ if isinstance(payload, dict):
505
+ ev = payload.get("event")
506
+ if isinstance(ev, str):
507
+ event_to_value[ev] = payload.get("value")
508
+
509
+ for evt_name in callbacks_by_event:
510
+ trigger_vals[evt_name] = event_to_value.get(evt_name)
511
+
512
+ # Note: We intentionally do not inspect SessionState for additional
513
+ # trigger widget IDs here because doing so can raise KeyErrors when
514
+ # widgets are freshly registered but their values haven't been
515
+ # populated yet. Only the triggers explicitly registered above are
516
+ # included in the result object.
517
+
518
+ # ------------------------------------------------------------------
519
+ # 5. Enqueue proto and assemble the result object
520
+ # ------------------------------------------------------------------
521
+ self.dg._enqueue(
522
+ INTERNAL_COMPONENT_NAME,
523
+ bidi_component_proto,
524
+ layout_config=layout_config,
525
+ )
526
+
527
+ state_vals = unwrap_component_state(component_state.value)
528
+
529
+ return BidiComponentResult(state_vals, trigger_vals)
530
+
531
+ @property
532
+ def dg(self) -> DeltaGenerator:
533
+ """Get our DeltaGenerator."""
534
+ return cast("DeltaGenerator", self)