streamlit 1.51.0__py3-none-any.whl → 1.52.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (314) hide show
  1. streamlit/__init__.py +1 -0
  2. streamlit/commands/execution_control.py +89 -14
  3. streamlit/components/v1/component_arrow.py +7 -7
  4. streamlit/components/v2/__init__.py +59 -3
  5. streamlit/components/v2/bidi_component/main.py +161 -13
  6. streamlit/components/v2/bidi_component/serialization.py +13 -6
  7. streamlit/components/v2/component_manager.py +11 -3
  8. streamlit/components/v2/component_registry.py +18 -1
  9. streamlit/components/v2/types.py +2 -2
  10. streamlit/connections/snowflake_connection.py +1 -1
  11. streamlit/connections/snowpark_connection.py +1 -1
  12. streamlit/dataframe_util.py +18 -18
  13. streamlit/delta_generator.py +7 -0
  14. streamlit/delta_generator_singletons.py +8 -14
  15. streamlit/elements/alert.py +16 -0
  16. streamlit/elements/arrow.py +36 -6
  17. streamlit/elements/bokeh_chart.py +10 -78
  18. streamlit/elements/code.py +2 -2
  19. streamlit/elements/deck_gl_json_chart.py +1 -1
  20. streamlit/elements/exception.py +1 -1
  21. streamlit/elements/form.py +27 -0
  22. streamlit/elements/heading.py +60 -5
  23. streamlit/elements/html.py +13 -2
  24. streamlit/elements/image.py +1 -1
  25. streamlit/elements/layouts.py +28 -22
  26. streamlit/elements/lib/built_in_chart_utils.py +49 -16
  27. streamlit/elements/lib/color_util.py +1 -1
  28. streamlit/elements/lib/column_config_utils.py +6 -5
  29. streamlit/elements/lib/layout_utils.py +50 -0
  30. streamlit/elements/lib/pandas_styler_utils.py +17 -9
  31. streamlit/elements/lib/shortcut_utils.py +152 -0
  32. streamlit/elements/markdown.py +50 -3
  33. streamlit/elements/metric.py +31 -1
  34. streamlit/elements/plotly_chart.py +75 -6
  35. streamlit/elements/spinner.py +1 -1
  36. streamlit/elements/text.py +20 -3
  37. streamlit/elements/toast.py +2 -0
  38. streamlit/elements/vega_charts.py +17 -1
  39. streamlit/elements/widgets/audio_input.py +8 -7
  40. streamlit/elements/widgets/button.py +279 -40
  41. streamlit/elements/widgets/button_group.py +27 -2
  42. streamlit/elements/widgets/camera_input.py +1 -1
  43. streamlit/elements/widgets/chat.py +300 -42
  44. streamlit/elements/widgets/color_picker.py +7 -0
  45. streamlit/elements/widgets/data_editor.py +68 -28
  46. streamlit/elements/widgets/file_uploader.py +4 -1
  47. streamlit/elements/widgets/number_input.py +2 -0
  48. streamlit/elements/widgets/text_widgets.py +2 -0
  49. streamlit/elements/widgets/time_widgets.py +581 -9
  50. streamlit/errors.py +22 -0
  51. streamlit/git_util.py +1 -1
  52. streamlit/navigation/page.py +7 -0
  53. streamlit/net_util.py +2 -2
  54. streamlit/proto/Alert_pb2.pyi +3 -3
  55. streamlit/proto/AppPage_pb2.pyi +7 -1
  56. streamlit/proto/ArrowData_pb2.pyi +7 -1
  57. streamlit/proto/ArrowNamedDataSet_pb2.pyi +7 -1
  58. streamlit/proto/ArrowVegaLiteChart_pb2.pyi +7 -1
  59. streamlit/proto/Arrow_pb2.py +10 -10
  60. streamlit/proto/Arrow_pb2.pyi +19 -12
  61. streamlit/proto/AudioInput_pb2.pyi +7 -1
  62. streamlit/proto/Audio_pb2.pyi +7 -1
  63. streamlit/proto/AuthRedirect_pb2.pyi +7 -1
  64. streamlit/proto/AutoRerun_pb2.pyi +7 -1
  65. streamlit/proto/BackMsg_pb2.py +4 -2
  66. streamlit/proto/BackMsg_pb2.pyi +34 -4
  67. streamlit/proto/Balloons_pb2.pyi +7 -1
  68. streamlit/proto/BidiComponent_pb2.pyi +10 -4
  69. streamlit/proto/Block_pb2.pyi +35 -35
  70. streamlit/proto/BokehChart_pb2.pyi +7 -1
  71. streamlit/proto/ButtonGroup_pb2.pyi +9 -9
  72. streamlit/proto/Button_pb2.py +2 -2
  73. streamlit/proto/Button_pb2.pyi +11 -2
  74. streamlit/proto/CameraInput_pb2.pyi +7 -1
  75. streamlit/proto/ChatInput_pb2.py +6 -6
  76. streamlit/proto/ChatInput_pb2.pyi +18 -6
  77. streamlit/proto/Checkbox_pb2.pyi +3 -3
  78. streamlit/proto/ClientState_pb2.pyi +10 -4
  79. streamlit/proto/Code_pb2.pyi +7 -1
  80. streamlit/proto/ColorPicker_pb2.pyi +7 -1
  81. streamlit/proto/Common_pb2.py +3 -3
  82. streamlit/proto/Common_pb2.pyi +35 -23
  83. streamlit/proto/Components_pb2.pyi +19 -13
  84. streamlit/proto/DataFrame_pb2.pyi +55 -49
  85. streamlit/proto/DateInput_pb2.pyi +7 -1
  86. streamlit/proto/DateTimeInput_pb2.py +28 -0
  87. streamlit/proto/DateTimeInput_pb2.pyi +92 -0
  88. streamlit/proto/DeckGlJsonChart_pb2.pyi +3 -3
  89. streamlit/proto/Delta_pb2.pyi +7 -1
  90. streamlit/proto/DocString_pb2.pyi +10 -4
  91. streamlit/proto/DownloadButton_pb2.py +2 -2
  92. streamlit/proto/DownloadButton_pb2.pyi +16 -2
  93. streamlit/proto/Element_pb2.py +5 -3
  94. streamlit/proto/Element_pb2.pyi +23 -5
  95. streamlit/proto/Empty_pb2.pyi +7 -1
  96. streamlit/proto/Exception_pb2.pyi +7 -1
  97. streamlit/proto/Favicon_pb2.pyi +7 -1
  98. streamlit/proto/FileUploader_pb2.pyi +7 -1
  99. streamlit/proto/ForwardMsg_pb2.py +12 -10
  100. streamlit/proto/ForwardMsg_pb2.pyi +42 -15
  101. streamlit/proto/GapSize_pb2.pyi +4 -4
  102. streamlit/proto/GitInfo_pb2.pyi +3 -3
  103. streamlit/proto/GraphVizChart_pb2.pyi +7 -1
  104. streamlit/proto/Heading_pb2.pyi +7 -1
  105. streamlit/proto/HeightConfig_pb2.pyi +7 -1
  106. streamlit/proto/Html_pb2.py +2 -2
  107. streamlit/proto/Html_pb2.pyi +11 -2
  108. streamlit/proto/IFrame_pb2.pyi +7 -1
  109. streamlit/proto/Image_pb2.pyi +10 -4
  110. streamlit/proto/Json_pb2.pyi +7 -1
  111. streamlit/proto/LabelVisibilityMessage_pb2.pyi +3 -3
  112. streamlit/proto/LinkButton_pb2.py +2 -2
  113. streamlit/proto/LinkButton_pb2.pyi +15 -2
  114. streamlit/proto/Logo_pb2.pyi +7 -1
  115. streamlit/proto/Markdown_pb2.pyi +3 -3
  116. streamlit/proto/Metric_pb2.pyi +7 -7
  117. streamlit/proto/MetricsEvent_pb2.pyi +10 -4
  118. streamlit/proto/MultiSelect_pb2.pyi +7 -1
  119. streamlit/proto/NamedDataSet_pb2.pyi +7 -1
  120. streamlit/proto/Navigation_pb2.pyi +3 -3
  121. streamlit/proto/NewSession_pb2.pyi +40 -40
  122. streamlit/proto/NumberInput_pb2.pyi +3 -3
  123. streamlit/proto/PageConfig_pb2.pyi +7 -7
  124. streamlit/proto/PageInfo_pb2.pyi +7 -1
  125. streamlit/proto/PageLink_pb2.py +2 -2
  126. streamlit/proto/PageLink_pb2.pyi +11 -2
  127. streamlit/proto/PageNotFound_pb2.pyi +7 -1
  128. streamlit/proto/PageProfile_pb2.pyi +13 -7
  129. streamlit/proto/PagesChanged_pb2.pyi +7 -1
  130. streamlit/proto/ParentMessage_pb2.pyi +7 -1
  131. streamlit/proto/PlotlyChart_pb2.pyi +6 -6
  132. streamlit/proto/Progress_pb2.pyi +7 -1
  133. streamlit/proto/Radio_pb2.pyi +7 -1
  134. streamlit/proto/RootContainer_pb2.pyi +1 -1
  135. streamlit/proto/Selectbox_pb2.pyi +7 -1
  136. streamlit/proto/SessionEvent_pb2.pyi +7 -1
  137. streamlit/proto/SessionStatus_pb2.pyi +7 -1
  138. streamlit/proto/Skeleton_pb2.pyi +3 -3
  139. streamlit/proto/Slider_pb2.pyi +5 -5
  140. streamlit/proto/Snow_pb2.pyi +7 -1
  141. streamlit/proto/Space_pb2.pyi +7 -1
  142. streamlit/proto/Spinner_pb2.pyi +7 -1
  143. streamlit/proto/TextAlignmentConfig_pb2.py +29 -0
  144. streamlit/proto/TextAlignmentConfig_pb2.pyi +68 -0
  145. streamlit/proto/TextArea_pb2.pyi +7 -1
  146. streamlit/proto/TextInput_pb2.pyi +3 -3
  147. streamlit/proto/Text_pb2.pyi +7 -1
  148. streamlit/proto/TimeInput_pb2.pyi +7 -1
  149. streamlit/proto/Toast_pb2.pyi +7 -1
  150. streamlit/proto/VegaLiteChart_pb2.pyi +7 -1
  151. streamlit/proto/Video_pb2.pyi +6 -6
  152. streamlit/proto/WidgetStates_pb2.pyi +10 -4
  153. streamlit/proto/WidthConfig_pb2.pyi +7 -1
  154. streamlit/proto/openmetrics_data_model_pb2.pyi +52 -52
  155. streamlit/runtime/app_session.py +38 -1
  156. streamlit/runtime/caching/cache_data_api.py +1 -1
  157. streamlit/runtime/caching/cache_resource_api.py +2 -2
  158. streamlit/runtime/caching/cache_utils.py +1 -1
  159. streamlit/runtime/caching/hashing.py +1 -1
  160. streamlit/runtime/download_data_util.py +53 -0
  161. streamlit/runtime/forward_msg_queue.py +1 -0
  162. streamlit/runtime/media_file_manager.py +178 -2
  163. streamlit/runtime/metrics_util.py +87 -3
  164. streamlit/runtime/scriptrunner/script_runner.py +3 -1
  165. streamlit/runtime/state/query_params.py +80 -29
  166. streamlit/runtime/state/session_state.py +2 -2
  167. streamlit/static/index.html +1 -1
  168. streamlit/static/manifest.json +530 -229
  169. streamlit/static/static/js/{ErrorOutline.esm.YoJdlW1p.js → ErrorOutline.esm.sMJdFExW.js} +1 -1
  170. streamlit/static/static/js/{FileDownload.esm.Ddx8VEYy.js → FileDownload.esm.CV-WYqBn.js} +1 -1
  171. streamlit/static/static/js/{FileHelper.90EtOmj9.js → FileHelper.5nCh9KDY.js} +3 -3
  172. streamlit/static/static/js/{FormClearHelper.BB1Km6eP.js → FormClearHelper.-9RbsnV0.js} +1 -1
  173. streamlit/static/static/js/IFrameUtil.DefezniK.js +1 -0
  174. streamlit/static/static/js/InputInstructions.2R3tBtW9.js +1 -0
  175. streamlit/static/static/js/Particles.DDHoXFxh.js +1 -0
  176. streamlit/static/static/js/{ProgressBar.DLY8H6nE.js → ProgressBar.BxmfHxKu.js} +2 -2
  177. streamlit/static/static/js/StreamlitSyntaxHighlighter.BFWV0oqR.js +20 -0
  178. streamlit/static/static/js/{Toolbar.D8nHCkuz.js → Toolbar.DMgU0Vgw.js} +1 -1
  179. streamlit/static/static/js/_arrayIncludes.B19Iyn2B.js +1 -0
  180. streamlit/static/static/js/_baseIndexOf.BTknn6Gb.js +1 -0
  181. streamlit/static/static/js/{base-input.CJGiNqed.js → base-input.BXTqYbyG.js} +4 -4
  182. streamlit/static/static/js/{checkbox.Cpdd482O.js → checkbox.5xWaqPqm.js} +1 -1
  183. streamlit/static/static/js/{createSuper.CuQIogbW.js → createSuper.OIgV8wc-.js} +1 -1
  184. streamlit/static/static/js/data-grid-overlay-editor.B4RIu9cw.js +1 -0
  185. streamlit/static/static/js/{downloader.CN0K7xlu.js → downloader.DwCJck8O.js} +1 -1
  186. streamlit/static/static/js/embed.HKcgTiLB.js +195 -0
  187. streamlit/static/static/js/{es6.BJcsVXQ0.js → es6.4AP97RGk.js} +2 -2
  188. streamlit/static/static/js/{iframeResizer.contentWindow.XzUvQqcZ.js → iframeResizer.contentWindow.BZAsvL9q.js} +1 -1
  189. streamlit/static/static/js/index.-3selq_5.js +2 -0
  190. streamlit/static/static/js/index.1ylynMAS.js +7 -0
  191. streamlit/static/static/js/{index.CxIUUfab.js → index.6UunrySF.js} +53 -122
  192. streamlit/static/static/js/index.8HslT92O.js +14 -0
  193. streamlit/static/static/js/index.B0TPxAZ1.js +1 -0
  194. streamlit/static/static/js/index.B0yp3bM1.js +6 -0
  195. streamlit/static/static/js/index.BHWBaOWH.js +1 -0
  196. streamlit/static/static/js/index.BJas6XzW.js +1 -0
  197. streamlit/static/static/js/index.BKIlG7Ng.js +3 -0
  198. streamlit/static/static/js/index.BMU6zZRk.js +1 -0
  199. streamlit/static/static/js/index.BNMLO-0p.js +2 -0
  200. streamlit/static/static/js/index.BPmBNTel.js +1 -0
  201. streamlit/static/static/js/index.BVuohWM1.js +1 -0
  202. streamlit/static/static/js/index.B_AvdOKC.js +1 -0
  203. streamlit/static/static/js/index.BjQIH-3U.js +1 -0
  204. streamlit/static/static/js/index.BrqtKtSu.js +2 -0
  205. streamlit/static/static/js/index.Buc7XrOl.js +188 -0
  206. streamlit/static/static/js/index.CIC9pLsG.js +2 -0
  207. streamlit/static/static/js/index.CP2YZ73v.js +1 -0
  208. streamlit/static/static/js/index.CSbah0y4.js +27 -0
  209. streamlit/static/static/js/index.CbiYVMT1.js +1 -0
  210. streamlit/static/static/js/index.CbxllBj8.js +1 -0
  211. streamlit/static/static/js/index.Cd1D2eGF.js +263 -0
  212. streamlit/static/static/js/index.Ckcqwai8.js +2 -0
  213. streamlit/static/static/js/index.CqTPbV5Y.js +151 -0
  214. streamlit/static/static/js/index.CxXo5UKy.js +1 -0
  215. streamlit/static/static/js/index.CxbL5FgL.js +1 -0
  216. streamlit/static/static/js/index.D52dMvK5.js +1 -0
  217. streamlit/static/static/js/index.DBUdji-9.js +3 -0
  218. streamlit/static/static/js/index.DMU3coc2.js +1 -0
  219. streamlit/static/static/js/index.DN4sfQLP.js +1 -0
  220. streamlit/static/static/js/{index.DPUXkcQL.js → index.DRDE9rnx.js} +1 -1
  221. streamlit/static/static/js/{index.B_dWA3vd.js → index.DY9Ac89e.js} +2 -2
  222. streamlit/static/static/js/index.DYKCsDvl.js +1 -0
  223. streamlit/static/static/js/index.Da9gznCC.js +1 -0
  224. streamlit/static/static/js/index.DfIRibXG.js +1 -0
  225. streamlit/static/static/js/{index.D3GPA5k4.js → index.Dg5zbEp2.js} +9 -40
  226. streamlit/static/static/js/index.Di9I2cid.js +1 -0
  227. streamlit/static/static/js/index.DkpEv0uV.js +1 -0
  228. streamlit/static/static/js/index.DwJ9Vhsl.js +1 -0
  229. streamlit/static/static/js/index.L7erTnMm.js +1 -0
  230. streamlit/static/static/js/{index.DOFlg3dS.js → index.NaDyAN1s.js} +1 -1
  231. streamlit/static/static/js/index.RNTPpVde.js +1 -0
  232. streamlit/static/static/js/index.VFDFuf_7.js +1 -0
  233. streamlit/static/static/js/index.W-bl3NDo.js +1 -0
  234. streamlit/static/static/js/index.XYozEjwK.js +1 -0
  235. streamlit/static/static/js/index.oyLQ4pue.js +1 -0
  236. streamlit/static/static/js/index.q4fLUQtC.js +11 -0
  237. streamlit/static/static/js/index.q9puCQgK.js +2 -0
  238. streamlit/static/static/js/index.xZBTXGNC.js +1 -0
  239. streamlit/static/static/js/{input.D4MN_FzN.js → input.CcvrgErO.js} +2 -2
  240. streamlit/static/static/js/main.eVHOp4Th.js +13 -0
  241. streamlit/static/static/js/{memory.DrZjtdGT.js → memory.Ck_sLv5Y.js} +1 -1
  242. streamlit/static/static/js/moment.C3j7ZXd7.js +4 -0
  243. streamlit/static/static/js/number-overlay-editor.DgcLMWOy.js +9 -0
  244. streamlit/static/static/js/pandasStylerUtils.DqP0h70z.js +1 -0
  245. streamlit/static/static/js/{possibleConstructorReturn.exeeJQEP.js → possibleConstructorReturn.C_51n46K.js} +1 -1
  246. streamlit/static/static/js/{sandbox.ClO3IuUr.js → sandbox.Q-g3QIZJ.js} +1 -1
  247. streamlit/static/static/js/styled-components.e0V96rJw.js +1 -0
  248. streamlit/static/static/js/threshold.Q1mXg5rX.js +1 -0
  249. streamlit/static/static/js/throttle.D3b5WILl.js +1 -0
  250. streamlit/static/static/js/{timepicker.DAhu-vcF.js → timepicker.Bpn70xGc.js} +1 -1
  251. streamlit/static/static/js/timer.C2hYhUse.js +1 -0
  252. streamlit/static/static/js/{toConsumableArray.DNbljYEC.js → toConsumableArray.DIN_ys1J.js} +1 -1
  253. streamlit/static/static/js/uniqueId.B27POWT6.js +1 -0
  254. streamlit/static/static/js/urls.BwSlolu9.js +1 -0
  255. streamlit/static/static/js/{useBasicWidgetState.D6sOH6oI.js → useBasicWidgetState.DA3_qaXD.js} +1 -1
  256. streamlit/static/static/js/useIntlLocale.BSq6SANa.js +12 -0
  257. streamlit/static/static/js/{useTextInputAutoExpand.4u3_GcuN.js → useTextInputAutoExpand.ytEW5QmA.js} +1 -1
  258. streamlit/static/static/js/useUpdateUiValue.DOxWBNiI.js +1 -0
  259. streamlit/static/static/js/useWaveformController.BCmk6WLk.js +1 -0
  260. streamlit/static/static/js/value.B4vHRSi7.js +1 -0
  261. streamlit/static/static/js/withCalculatedWidth.ChdrMItN.js +1 -0
  262. streamlit/static/static/js/withFullScreenWrapper.7j_lzlaF.js +1 -0
  263. streamlit/string_util.py +8 -1
  264. streamlit/testing/v1/app_test.py +15 -0
  265. streamlit/testing/v1/element_tree.py +62 -0
  266. streamlit/web/bootstrap.py +24 -0
  267. streamlit/web/server/oauth_authlib_routes.py +5 -2
  268. streamlit/web/server/upload_file_request_handler.py +16 -0
  269. {streamlit-1.51.0.dist-info → streamlit-1.52.1.dist-info}/METADATA +9 -5
  270. {streamlit-1.51.0.dist-info → streamlit-1.52.1.dist-info}/RECORD +274 -239
  271. streamlit/static/static/js/InputInstructions.jhH15PqV.js +0 -1
  272. streamlit/static/static/js/Particles.DUsputn1.js +0 -1
  273. streamlit/static/static/js/data-grid-overlay-editor.2Ufgxc6y.js +0 -1
  274. streamlit/static/static/js/index.B1ZQh4P1.js +0 -1
  275. streamlit/static/static/js/index.BKstZk0M.js +0 -27
  276. streamlit/static/static/js/index.BMcFsUee.js +0 -1
  277. streamlit/static/static/js/index.BR-IdcTb.js +0 -2
  278. streamlit/static/static/js/index.BgnZEMVh.js +0 -1
  279. streamlit/static/static/js/index.BohqXifI.js +0 -1
  280. streamlit/static/static/js/index.Br5nxKNj.js +0 -2
  281. streamlit/static/static/js/index.BrIKVbNc.js +0 -3
  282. streamlit/static/static/js/index.BtWUPzle.js +0 -1
  283. streamlit/static/static/js/index.C0RLraek.js +0 -1
  284. streamlit/static/static/js/index.CAIjskgG.js +0 -1
  285. streamlit/static/static/js/index.CAj-7vWz.js +0 -949
  286. streamlit/static/static/js/index.CMtEit2O.js +0 -1
  287. streamlit/static/static/js/index.CkRlykEE.js +0 -12
  288. streamlit/static/static/js/index.CmN3FXfI.js +0 -1617
  289. streamlit/static/static/js/index.CwbFI1_-.js +0 -1
  290. streamlit/static/static/js/index.D2KPNy7e.js +0 -1
  291. streamlit/static/static/js/index.DGAh7DMq.js +0 -1
  292. streamlit/static/static/js/index.DKb_NvmG.js +0 -197
  293. streamlit/static/static/js/index.DMqgUYKq.js +0 -1
  294. streamlit/static/static/js/index.DX1xY89g.js +0 -1
  295. streamlit/static/static/js/index.DYATBCsq.js +0 -2
  296. streamlit/static/static/js/index.DaSmGJ76.js +0 -3
  297. streamlit/static/static/js/index.Dd7bMeLP.js +0 -1
  298. streamlit/static/static/js/index.DjmmgI5U.js +0 -1
  299. streamlit/static/static/js/index.Dq56CyM2.js +0 -1
  300. streamlit/static/static/js/index.DuiXaS5_.js +0 -7
  301. streamlit/static/static/js/index.DvFidMLe.js +0 -2
  302. streamlit/static/static/js/index.DwkhC5Pc.js +0 -1
  303. streamlit/static/static/js/index.Q-3sFn1v.js +0 -1
  304. streamlit/static/static/js/index.QJ5QO9sJ.js +0 -1
  305. streamlit/static/static/js/index.VwTaeety.js +0 -1
  306. streamlit/static/static/js/index.YOqQbeX8.js +0 -1
  307. streamlit/static/static/js/number-overlay-editor.DRwAw1In.js +0 -9
  308. streamlit/static/static/js/uniqueId.oG4Gvj1v.js +0 -1
  309. streamlit/static/static/js/useUpdateUiValue.F2R3eTeR.js +0 -1
  310. streamlit/static/static/js/withFullScreenWrapper.zothJIsI.js +0 -1
  311. {streamlit-1.51.0.data → streamlit-1.52.1.data}/scripts/streamlit.cmd +0 -0
  312. {streamlit-1.51.0.dist-info → streamlit-1.52.1.dist-info}/WHEEL +0 -0
  313. {streamlit-1.51.0.dist-info → streamlit-1.52.1.dist-info}/entry_points.txt +0 -0
  314. {streamlit-1.51.0.dist-info → streamlit-1.52.1.dist-info}/top_level.txt +0 -0
streamlit/__init__.py CHANGED
@@ -180,6 +180,7 @@ container = _main.container
180
180
  dataframe = _main.dataframe
181
181
  data_editor = _main.data_editor
182
182
  date_input = _main.date_input
183
+ datetime_input = _main.datetime_input
183
184
  divider = _main.divider
184
185
  download_button = _main.download_button
185
186
  expander = _main.expander
@@ -15,9 +15,11 @@
15
15
  from __future__ import annotations
16
16
 
17
17
  import os
18
+ import time
19
+ from collections.abc import Iterable, Mapping
18
20
  from itertools import dropwhile
19
21
  from pathlib import Path
20
- from typing import Literal, NoReturn
22
+ from typing import TYPE_CHECKING, Literal, NoReturn
21
23
 
22
24
  import streamlit as st
23
25
  from streamlit.errors import NoSessionContext, StreamlitAPIException
@@ -30,6 +32,9 @@ from streamlit.runtime.scriptrunner import (
30
32
  get_script_run_ctx,
31
33
  )
32
34
 
35
+ if TYPE_CHECKING:
36
+ from streamlit.runtime.state.query_params import QueryParams, QueryParamsInput
37
+
33
38
 
34
39
  @gather_metrics("stop")
35
40
  def stop() -> NoReturn: # type: ignore[misc]
@@ -99,6 +104,31 @@ def _new_fragment_id_queue(
99
104
  return new_queue
100
105
 
101
106
 
107
+ def _set_query_params_for_switch(
108
+ query_params_state: QueryParams,
109
+ new_query_params: QueryParamsInput | None,
110
+ ) -> None:
111
+ """Set query params for a switch page."""
112
+
113
+ if new_query_params is None:
114
+ query_params_state.clear()
115
+ return
116
+
117
+ if isinstance(new_query_params, Mapping) or (
118
+ isinstance(new_query_params, Iterable)
119
+ and not isinstance(
120
+ new_query_params, # type: ignore[unreachable]
121
+ (str, bytes),
122
+ )
123
+ ):
124
+ query_params_state.from_dict(new_query_params)
125
+ return
126
+
127
+ raise StreamlitAPIException(
128
+ f"`query_params` must be a mapping or an iterable of (key, value) pairs not a `{type(new_query_params)}`."
129
+ )
130
+
131
+
102
132
  @gather_metrics("rerun")
103
133
  def rerun( # type: ignore[misc]
104
134
  *, # The scope argument can only be passed via keyword.
@@ -155,7 +185,11 @@ def rerun( # type: ignore[misc]
155
185
 
156
186
 
157
187
  @gather_metrics("switch_page")
158
- def switch_page(page: str | Path | StreamlitPage) -> NoReturn: # type: ignore[misc]
188
+ def switch_page( # type: ignore[misc]
189
+ page: str | Path | StreamlitPage,
190
+ *,
191
+ query_params: QueryParamsInput | None = None,
192
+ ) -> NoReturn: # ty: ignore[invalid-return-type]
159
193
  """Programmatically switch the current page in a multipage app.
160
194
 
161
195
  When ``st.switch_page`` is called, the current page execution stops and
@@ -166,20 +200,31 @@ def switch_page(page: str | Path | StreamlitPage) -> NoReturn: # type: ignore[m
166
200
 
167
201
  Parameters
168
202
  ----------
169
- page: str, Path, or st.Page
203
+ page : str, Path, or st.Page
170
204
  The file path (relative to the main script) or an st.Page indicating
171
205
  the page to switch to.
172
206
 
207
+ query_params : dict, list of tuples, or None
208
+ Query parameters to apply when navigating to the target page.
209
+ This can be a dictionary or an iterable of key-value tuples. Values can
210
+ be strings or iterables of strings (for repeated keys). When this is
211
+ ``None`` (default), all non-embed query parameters are cleared during
212
+ navigation.
173
213
 
174
- Example
175
- -------
176
- Consider the following example given this file structure:
214
+ Examples
215
+ --------
216
+ **Example 1: Basic usage**
217
+
218
+ The following example shows how to switch to a different page in a
219
+ multipage app that uses the ``pages/`` directory:
177
220
 
178
- >>> your-repository/
179
- >>> ├── pages/
180
- >>> │ ├── page_1.py
181
- >>> │ └── page_2.py
182
- >>> └── your_app.py
221
+ .. code-block:: text
222
+
223
+ your-repository/
224
+ ├── pages/
225
+ │ ├── page_1.py
226
+ │ └── page_2.py
227
+ └── your_app.py
183
228
 
184
229
  >>> import streamlit as st
185
230
  >>>
@@ -190,10 +235,35 @@ def switch_page(page: str | Path | StreamlitPage) -> NoReturn: # type: ignore[m
190
235
  >>> if st.button("Page 2"):
191
236
  >>> st.switch_page("pages/page_2.py")
192
237
 
193
- .. output ::
238
+ .. output::
194
239
  https://doc-switch-page.streamlit.app/
195
240
  height: 350px
196
241
 
242
+ **Example 2: Passing query parameters**
243
+
244
+ The following example shows how to pass query parameters when switching to a
245
+ different page. This example uses ``st.navigation`` to create a multipage app.
246
+
247
+ .. code-block:: text
248
+
249
+ your-repository/
250
+ ├── page_2.py
251
+ └── your_app.py
252
+
253
+ >>> import streamlit as st
254
+ >>>
255
+ >>> def page_1():
256
+ >>> st.title("Page 1")
257
+ >>> if st.button("Switch to Page 2"):
258
+ >>> st.switch_page("page_2.py", query_params={"utm_source": "page_1"})
259
+ >>>
260
+ >>> pg = st.navigation([page_1, "page_2.py"])
261
+ >>> pg.run()
262
+
263
+ .. output::
264
+ https://doc-switch-page-query-params.streamlit.app/
265
+ height: 350px
266
+
197
267
  """
198
268
 
199
269
  ctx = get_script_run_ctx()
@@ -227,9 +297,14 @@ def switch_page(page: str | Path | StreamlitPage) -> NoReturn: # type: ignore[m
227
297
 
228
298
  page_script_hash = matched_pages[0]["page_script_hash"]
229
299
 
230
- # We want to reset query params (with exception of embed) when switching pages
300
+ # Reset query params (with exception of embed) and optionally apply overrides.
231
301
  with ctx.session_state.query_params() as qp:
232
- qp.clear()
302
+ _set_query_params_for_switch(qp, query_params)
303
+ # Additional safeguard to ensure the query params
304
+ # are sent out to the frontend before the new rerun might clear
305
+ # outstanding messages. This uses the same time that is used as waiting
306
+ # in our event loop.
307
+ time.sleep(0.01)
233
308
 
234
309
  ctx.script_requests.request_rerun(
235
310
  RerunData(
@@ -24,7 +24,7 @@ from streamlit import dataframe_util
24
24
  from streamlit.elements.lib import pandas_styler_utils
25
25
 
26
26
  if TYPE_CHECKING:
27
- from pandas import DataFrame, Index, Series
27
+ from pandas import DataFrame, Index
28
28
 
29
29
  from streamlit.proto.Components_pb2 import ArrowTable as ArrowTableProto
30
30
 
@@ -57,7 +57,7 @@ def marshall(
57
57
  _marshall_data(proto, df)
58
58
 
59
59
 
60
- def _marshall_index(proto: ArrowTableProto, index: Index) -> None:
60
+ def _marshall_index(proto: ArrowTableProto, index: Index[Any]) -> None:
61
61
  """Marshall pandas.DataFrame index into an ArrowTable proto.
62
62
 
63
63
  Parameters
@@ -72,12 +72,12 @@ def _marshall_index(proto: ArrowTableProto, index: Index) -> None:
72
72
  """
73
73
  import pandas as pd
74
74
 
75
- index_values = map(_maybe_tuple_to_list, index.values)
75
+ index_values = list(map(_maybe_tuple_to_list, index.values))
76
76
  index_df = pd.DataFrame(index_values)
77
77
  proto.index = dataframe_util.convert_pandas_df_to_arrow_bytes(index_df)
78
78
 
79
79
 
80
- def _marshall_columns(proto: ArrowTableProto, columns: Series) -> None:
80
+ def _marshall_columns(proto: ArrowTableProto, columns: Index[Any]) -> None:
81
81
  """Marshall pandas.DataFrame columns into an ArrowTable proto.
82
82
 
83
83
  Parameters
@@ -85,15 +85,15 @@ def _marshall_columns(proto: ArrowTableProto, columns: Series) -> None:
85
85
  proto : proto.ArrowTable
86
86
  Output. The protobuf for a Streamlit ArrowTable proto.
87
87
 
88
- columns : Series
88
+ columns : Index
89
89
  Column labels to use for resulting frame.
90
90
  Will default to RangeIndex (0, 1, 2, ..., n) if no column labels are provided.
91
91
 
92
92
  """
93
93
  import pandas as pd
94
94
 
95
- values = map(_maybe_tuple_to_list, columns.values)
96
- columns_df = pd.DataFrame(values)
95
+ column_values = list(map(_maybe_tuple_to_list, columns.values))
96
+ columns_df = pd.DataFrame(column_values)
97
97
  proto.columns = dataframe_util.convert_pandas_df_to_arrow_bytes(columns_df)
98
98
 
99
99
 
@@ -322,7 +322,7 @@ def component(
322
322
  if result.clicked:
323
323
  st.write(f"You clicked {result.clicked}!")
324
324
 
325
- .. output ::
325
+ .. output::
326
326
  https://doc-components-markdown-links.streamlit.app/
327
327
  height: 250px
328
328
 
@@ -386,7 +386,7 @@ def component(
386
386
  elif result.clicked == "link_2":
387
387
  st.write("You clicked the second link!")
388
388
 
389
- .. output ::
389
+ .. output::
390
390
  https://doc-components-custom-anchors.streamlit.app/
391
391
  height: 250px
392
392
 
@@ -445,10 +445,66 @@ def component(
445
445
  result = my_component(on_clicked_change=lambda: None)
446
446
  result
447
447
 
448
- .. output ::
448
+ .. output::
449
449
  https://doc-components-interactive-svg.streamlit.app/
450
450
  height: 550px
451
451
 
452
+ **Example 4: Clean up your component's resources**
453
+
454
+ You can use the return value of the component's JavaScript function to
455
+ clean up any resources when the component is unmounted. For example, you
456
+ can disconnect a MutationObserver that was monitoring changes in the DOM.
457
+
458
+ .. code-block:: python
459
+
460
+ import streamlit as st
461
+
462
+ JS = """
463
+ export default function(component) {
464
+ const { setStateValue, parentElement } = component;
465
+ const sidebar = document.querySelector('section.stSidebar');
466
+ const initialState = sidebar.getAttribute('aria-expanded') === 'true';
467
+
468
+ // Create observer to watch for aria-expanded attribute changes
469
+ const observer = new MutationObserver((mutations) => {
470
+ mutations.forEach((mutation) => {
471
+ if (mutation.type === 'attributes' && mutation.attributeName === 'aria-expanded') {
472
+ const newIsExpanded = sidebar.getAttribute('aria-expanded') === 'true';
473
+ setStateValue('expanded', newIsExpanded);
474
+ }
475
+ });
476
+ });
477
+
478
+ // Start observing
479
+ observer.observe(sidebar, {
480
+ attributes: true,
481
+ attributeFilter: ['aria-expanded']
482
+ });
483
+
484
+ // Set initial state
485
+ setStateValue('expanded', initialState);
486
+
487
+ // Cleanup function to remove the observer
488
+ return () => {
489
+ observer.disconnect();
490
+ };
491
+
492
+ };
493
+ """
494
+
495
+ my_component = st.components.v2.component(
496
+ "sidebar_expansion_detector",
497
+ js=JS,
498
+ )
499
+
500
+ st.sidebar.write("Sidebar content")
501
+ result = my_component(on_expanded_change=lambda: None)
502
+ result
503
+
504
+ .. output::
505
+ https://doc-components-cleanup-function.streamlit.app/
506
+ height: 250px
507
+
452
508
  '''
453
509
  return _create_component_callable(name, html=html, css=css, js=js)
454
510
 
@@ -55,9 +55,11 @@ from streamlit.errors import (
55
55
  )
56
56
  from streamlit.proto.ArrowData_pb2 import ArrowData as ArrowDataProto
57
57
  from streamlit.proto.BidiComponent_pb2 import BidiComponent as BidiComponentProto
58
+ from streamlit.proto.BidiComponent_pb2 import MixedData as MixedDataProto
58
59
  from streamlit.runtime.metrics_util import gather_metrics
59
60
  from streamlit.runtime.scriptrunner_utils.script_run_context import get_script_run_ctx
60
61
  from streamlit.runtime.state import register_widget
62
+ from streamlit.util import calc_md5
61
63
 
62
64
  if TYPE_CHECKING:
63
65
  from streamlit.components.v2.types import (
@@ -117,6 +119,144 @@ def _make_trigger_id(base: str, event: str) -> str:
117
119
  class BidiComponentMixin:
118
120
  """Mixin class for the bidi_component DeltaGenerator method."""
119
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
+
120
260
  @gather_metrics("_bidi_component")
121
261
  def _bidi_component(
122
262
  self,
@@ -206,18 +346,6 @@ class BidiComponentMixin:
206
346
  if not has_js and not has_html:
207
347
  raise BidiComponentMissingContentError(component_name)
208
348
 
209
- # Compute a unique ID for this component instance
210
- computed_id = compute_and_register_element_id(
211
- "bidi_component",
212
- user_key=key,
213
- component_name=component_name,
214
- isolate_styles=isolate_styles,
215
- width=width,
216
- height=height,
217
- dg=self.dg,
218
- key_as_main_identity=True,
219
- )
220
-
221
349
  # ------------------------------------------------------------------
222
350
  # 1. Parse user-supplied callbacks
223
351
  # ------------------------------------------------------------------
@@ -253,7 +381,6 @@ class BidiComponentMixin:
253
381
 
254
382
  # Set up the component proto
255
383
  bidi_component_proto = BidiComponentProto()
256
- bidi_component_proto.id = computed_id
257
384
  bidi_component_proto.component_name = component_name
258
385
  bidi_component_proto.isolate_styles = isolate_styles
259
386
  bidi_component_proto.js_content = component_def.js_content or ""
@@ -298,6 +425,27 @@ class BidiComponentMixin:
298
425
  raise BidiComponentUnserializableDataError()
299
426
  bidi_component_proto.form_id = current_form_id(self.dg)
300
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
+
301
449
  # Instantiate the Serde for this component instance
302
450
  serde = BidiComponentSerde(default=default)
303
451
 
@@ -23,7 +23,7 @@ from streamlit.dataframe_util import convert_anything_to_arrow_bytes, is_datafra
23
23
  from streamlit.logger import get_logger
24
24
  from streamlit.proto.BidiComponent_pb2 import BidiComponent as BidiComponentProto
25
25
  from streamlit.proto.BidiComponent_pb2 import MixedData as MixedDataProto
26
- from streamlit.util import AttributeDictionary
26
+ from streamlit.util import AttributeDictionary, calc_md5
27
27
 
28
28
  if TYPE_CHECKING:
29
29
  from streamlit.components.v2.bidi_component.state import BidiComponentState
@@ -56,8 +56,6 @@ def _extract_dataframes_from_dict(
56
56
  dict[str, Any]
57
57
  A new dictionary with dataframe-like objects replaced by placeholders.
58
58
  """
59
- import uuid
60
-
61
59
  if arrow_blobs is None:
62
60
  arrow_blobs = {}
63
61
 
@@ -68,11 +66,20 @@ def _extract_dataframes_from_dict(
68
66
  # This is a dataframe-like object, serialize it to Arrow
69
67
  try:
70
68
  arrow_bytes = convert_anything_to_arrow_bytes(value)
71
- ref_id = str(uuid.uuid4())
69
+ # Use deterministic, content-addressed ref IDs so placeholders
70
+ # are stable for identical content on each run. This also provides
71
+ # natural deduplication - identical DataFrames share a single blob.
72
+ ref_id = calc_md5(arrow_bytes)
72
73
  arrow_blobs[ref_id] = arrow_bytes
73
74
  processed_data[key] = {ARROW_REF_KEY: ref_id}
74
- except Exception:
75
- # If Arrow serialization fails, keep the original value for JSON serialization
75
+ except Exception as e:
76
+ # If Arrow serialization fails, keep the original value for JSON
77
+ # serialization attempt downstream.
78
+ _LOGGER.debug(
79
+ "Arrow serialization failed for key %r, keeping original value: %s",
80
+ key,
81
+ e,
82
+ )
76
83
  processed_data[key] = value
77
84
  else:
78
85
  # Not dataframe-like, keep as-is
@@ -304,11 +304,18 @@ class BidiComponentManager:
304
304
  else:
305
305
  _LOGGER.debug("File watching not started")
306
306
 
307
- def discover_and_register_components(self) -> None:
307
+ def discover_and_register_components(
308
+ self, *, start_file_watching: bool = True
309
+ ) -> None:
308
310
  """Discover installed v2 components and register them.
309
311
 
310
312
  This scans installed distributions for manifests, registers all discovered
311
313
  components, and starts file watching for development workflows.
314
+
315
+ Parameters
316
+ ----------
317
+ start_file_watching : bool
318
+ Whether to start file watching after components are registered.
312
319
  """
313
320
  try:
314
321
  from streamlit.components.v2.manifest_scanner import (
@@ -318,14 +325,15 @@ class BidiComponentManager:
318
325
  manifests = scan_component_manifests()
319
326
  for manifest, package_root in manifests:
320
327
  self.register_from_manifest(manifest, package_root)
321
- _LOGGER.info(
328
+ _LOGGER.debug(
322
329
  "Registered components from pyproject.toml: %s v%s",
323
330
  manifest.name,
324
331
  manifest.version,
325
332
  )
326
333
 
327
334
  # Start file watching for development mode after all components are registered
328
- self.start_file_watching()
335
+ if start_file_watching:
336
+ self.start_file_watching()
329
337
 
330
338
  except Exception as e:
331
339
  _LOGGER.warning("Failed to scan component manifests: %s", e)
@@ -164,6 +164,16 @@ class BidiComponentDefinition:
164
164
  # If we get here, it's content, not a path
165
165
  return False, None
166
166
 
167
+ @property
168
+ def is_placeholder(self) -> bool:
169
+ """Return True if this definition is a placeholder (no content).
170
+
171
+ Placeholders are typically created during the manifest scanning phase
172
+ when we discover a component's existence but haven't yet loaded its
173
+ content via the public API.
174
+ """
175
+ return self.html is None and self.css is None and self.js is None
176
+
167
177
  @property
168
178
  def css_url(self) -> str | None:
169
179
  """Return the asset-dir-relative URL path for CSS when file-backed.
@@ -329,7 +339,14 @@ class BidiComponentRegistry:
329
339
  name = definition.name
330
340
  if name in self._components:
331
341
  existing_definition = self._components[name]
332
- if existing_definition != definition:
342
+ # Check if the existing definition is different and NOT a placeholder.
343
+ # We expect placeholders (from manifest scanning) to be overwritten
344
+ # by the actual definition from the script execution, so we silence
345
+ # the warning in that specific case.
346
+ if (
347
+ existing_definition != definition
348
+ and not existing_definition.is_placeholder
349
+ ):
333
350
  _LOGGER.warning(
334
351
  "Component %s is already registered. Overwriting "
335
352
  "previous definition. This may lead to unexpected behavior "
@@ -245,7 +245,7 @@ class BidiComponentCallable(Protocol):
245
245
  st.write("Result:", result)
246
246
  st.write("Session state:", st.session_state)
247
247
 
248
- .. output ::
248
+ .. output::
249
249
  https://doc-components-text-input.streamlit.app/
250
250
  height: 600px
251
251
 
@@ -296,7 +296,7 @@ class BidiComponentCallable(Protocol):
296
296
  )
297
297
  result_2
298
298
 
299
- .. output ::
299
+ .. output::
300
300
  https://doc-components-tailwind-button.streamlit.app/
301
301
  height: 350px
302
302
 
@@ -357,7 +357,7 @@ class SnowflakeConnection(BaseConnection["InternalSnowflakeConnection"]):
357
357
  def _query(sql: str) -> DataFrame:
358
358
  cur = self._instance.cursor()
359
359
  cur.execute(sql, params=params, **kwargs)
360
- return cur.fetch_pandas_all()
360
+ return cur.fetch_pandas_all() # type: ignore
361
361
 
362
362
  # We modify our helper function's `__qualname__` here to work around default
363
363
  # `@st.cache_data` behavior. Otherwise, `.query()` being called with different
@@ -146,7 +146,7 @@ class SnowparkConnection(BaseConnection["Session"]):
146
146
  )
147
147
  def _query(sql: str) -> DataFrame:
148
148
  with self._lock:
149
- return self._instance.sql(sql).to_pandas()
149
+ return self._instance.sql(sql).to_pandas() # type: ignore
150
150
 
151
151
  # We modify our helper function's `__qualname__` here to work around default
152
152
  # `@st.cache_data` behavior. Otherwise, `.query()` being called with different