streamlit 1.45.1__py3-none-any.whl → 1.46.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 (335) hide show
  1. streamlit/__init__.py +5 -1
  2. streamlit/auth_util.py +12 -12
  3. streamlit/cli_util.py +4 -3
  4. streamlit/column_config.py +11 -9
  5. streamlit/commands/echo.py +6 -4
  6. streamlit/commands/execution_control.py +33 -32
  7. streamlit/commands/experimental_query_params.py +2 -2
  8. streamlit/commands/logo.py +9 -4
  9. streamlit/commands/navigation.py +61 -18
  10. streamlit/commands/page_config.py +57 -47
  11. streamlit/components/types/base_custom_component.py +7 -7
  12. streamlit/components/v1/component_registry.py +7 -3
  13. streamlit/components/v1/components.py +1 -1
  14. streamlit/components/v1/custom_component.py +8 -8
  15. streamlit/config.py +289 -144
  16. streamlit/config_option.py +19 -15
  17. streamlit/config_util.py +29 -23
  18. streamlit/connections/__init__.py +2 -2
  19. streamlit/connections/base_connection.py +5 -5
  20. streamlit/connections/snowflake_connection.py +13 -11
  21. streamlit/connections/snowpark_connection.py +3 -3
  22. streamlit/connections/sql_connection.py +20 -18
  23. streamlit/connections/util.py +2 -2
  24. streamlit/cursor.py +6 -6
  25. streamlit/dataframe_util.py +52 -52
  26. streamlit/delta_generator.py +46 -48
  27. streamlit/delta_generator_singletons.py +3 -3
  28. streamlit/deprecation_util.py +6 -6
  29. streamlit/elements/alert.py +37 -29
  30. streamlit/elements/arrow.py +40 -22
  31. streamlit/elements/code.py +46 -13
  32. streamlit/elements/deck_gl_json_chart.py +38 -27
  33. streamlit/elements/dialog_decorator.py +3 -4
  34. streamlit/elements/doc_string.py +64 -58
  35. streamlit/elements/exception.py +23 -27
  36. streamlit/elements/form.py +41 -0
  37. streamlit/elements/graphviz_chart.py +1 -1
  38. streamlit/elements/heading.py +60 -9
  39. streamlit/elements/html.py +3 -4
  40. streamlit/elements/image.py +8 -9
  41. streamlit/elements/json.py +21 -2
  42. streamlit/elements/layouts.py +120 -31
  43. streamlit/elements/lib/built_in_chart_utils.py +96 -73
  44. streamlit/elements/lib/color_util.py +3 -3
  45. streamlit/elements/lib/column_config_utils.py +2 -4
  46. streamlit/elements/lib/column_types.py +14 -8
  47. streamlit/elements/lib/dialog.py +9 -5
  48. streamlit/elements/lib/image_utils.py +39 -40
  49. streamlit/elements/lib/js_number.py +4 -4
  50. streamlit/elements/lib/layout_utils.py +65 -1
  51. streamlit/elements/lib/mutable_status_container.py +14 -3
  52. streamlit/elements/lib/options_selector_utils.py +22 -12
  53. streamlit/elements/lib/pandas_styler_utils.py +25 -21
  54. streamlit/elements/lib/policies.py +6 -5
  55. streamlit/elements/lib/streamlit_plotly_theme.py +54 -53
  56. streamlit/elements/lib/subtitle_utils.py +6 -9
  57. streamlit/elements/lib/utils.py +20 -5
  58. streamlit/elements/map.py +32 -56
  59. streamlit/elements/markdown.py +101 -12
  60. streamlit/elements/media.py +78 -21
  61. streamlit/elements/metric.py +32 -16
  62. streamlit/elements/plotly_chart.py +15 -15
  63. streamlit/elements/progress.py +33 -15
  64. streamlit/elements/spinner.py +31 -6
  65. streamlit/elements/text.py +21 -1
  66. streamlit/elements/toast.py +1 -2
  67. streamlit/elements/vega_charts.py +54 -23
  68. streamlit/elements/widgets/audio_input.py +24 -7
  69. streamlit/elements/widgets/button.py +26 -19
  70. streamlit/elements/widgets/button_group.py +10 -15
  71. streamlit/elements/widgets/camera_input.py +27 -7
  72. streamlit/elements/widgets/chat.py +91 -38
  73. streamlit/elements/widgets/checkbox.py +45 -4
  74. streamlit/elements/widgets/color_picker.py +40 -17
  75. streamlit/elements/widgets/data_editor.py +76 -37
  76. streamlit/elements/widgets/file_uploader.py +42 -13
  77. streamlit/elements/widgets/multiselect.py +7 -10
  78. streamlit/elements/widgets/number_input.py +123 -47
  79. streamlit/elements/widgets/radio.py +59 -13
  80. streamlit/elements/widgets/select_slider.py +35 -30
  81. streamlit/elements/widgets/selectbox.py +56 -9
  82. streamlit/elements/widgets/slider.py +190 -99
  83. streamlit/elements/widgets/text_widgets.py +54 -8
  84. streamlit/elements/widgets/time_widgets.py +53 -14
  85. streamlit/elements/write.py +5 -8
  86. streamlit/env_util.py +2 -7
  87. streamlit/error_util.py +16 -9
  88. streamlit/errors.py +69 -48
  89. streamlit/external/langchain/streamlit_callback_handler.py +10 -5
  90. streamlit/file_util.py +27 -10
  91. streamlit/git_util.py +29 -24
  92. streamlit/hello/animation_demo.py +9 -9
  93. streamlit/hello/dataframe_demo.py +5 -5
  94. streamlit/hello/hello.py +1 -0
  95. streamlit/hello/mapping_demo.py +7 -8
  96. streamlit/hello/plotting_demo.py +3 -3
  97. streamlit/hello/streamlit_app.py +28 -26
  98. streamlit/hello/utils.py +2 -1
  99. streamlit/logger.py +10 -11
  100. streamlit/navigation/page.py +11 -8
  101. streamlit/proto/Audio_pb2.py +4 -3
  102. streamlit/proto/Audio_pb2.pyi +8 -1
  103. streamlit/proto/Block_pb2.py +38 -29
  104. streamlit/proto/Block_pb2.pyi +72 -4
  105. streamlit/proto/ClientState_pb2.py +4 -4
  106. streamlit/proto/ClientState_pb2.pyi +7 -2
  107. streamlit/proto/Code_pb2.py +4 -2
  108. streamlit/proto/Code_pb2.pyi +1 -0
  109. streamlit/proto/DataFrame_pb2.pyi +1 -1
  110. streamlit/proto/DeckGlJsonChart_pb2.pyi +1 -1
  111. streamlit/proto/Element_pb2.py +5 -3
  112. streamlit/proto/Element_pb2.pyi +20 -3
  113. streamlit/proto/GapSize_pb2.py +29 -0
  114. streamlit/proto/GapSize_pb2.pyi +70 -0
  115. streamlit/proto/HeightConfig_pb2.py +27 -0
  116. streamlit/proto/HeightConfig_pb2.pyi +48 -0
  117. streamlit/proto/NamedDataSet_pb2.pyi +1 -1
  118. streamlit/proto/Navigation_pb2.py +3 -3
  119. streamlit/proto/Navigation_pb2.pyi +4 -0
  120. streamlit/proto/NewSession_pb2.py +18 -16
  121. streamlit/proto/NewSession_pb2.pyi +29 -3
  122. streamlit/proto/PageConfig_pb2.py +7 -7
  123. streamlit/proto/PageConfig_pb2.pyi +21 -1
  124. streamlit/proto/Video_pb2.py +8 -7
  125. streamlit/proto/Video_pb2.pyi +8 -1
  126. streamlit/proto/WidthConfig_pb2.py +2 -2
  127. streamlit/proto/WidthConfig_pb2.pyi +15 -1
  128. streamlit/runtime/__init__.py +1 -1
  129. streamlit/runtime/app_session.py +53 -40
  130. streamlit/runtime/caching/__init__.py +9 -9
  131. streamlit/runtime/caching/cache_data_api.py +36 -30
  132. streamlit/runtime/caching/cache_errors.py +4 -4
  133. streamlit/runtime/caching/cache_resource_api.py +8 -8
  134. streamlit/runtime/caching/cache_utils.py +15 -14
  135. streamlit/runtime/caching/cached_message_replay.py +14 -8
  136. streamlit/runtime/caching/hashing.py +91 -97
  137. streamlit/runtime/caching/legacy_cache_api.py +2 -2
  138. streamlit/runtime/caching/storage/cache_storage_protocol.py +1 -1
  139. streamlit/runtime/caching/storage/dummy_cache_storage.py +1 -1
  140. streamlit/runtime/caching/storage/in_memory_cache_storage_wrapper.py +12 -14
  141. streamlit/runtime/caching/storage/local_disk_cache_storage.py +6 -6
  142. streamlit/runtime/connection_factory.py +36 -36
  143. streamlit/runtime/context.py +58 -9
  144. streamlit/runtime/credentials.py +29 -40
  145. streamlit/runtime/forward_msg_queue.py +11 -11
  146. streamlit/runtime/fragment.py +7 -7
  147. streamlit/runtime/media_file_manager.py +3 -4
  148. streamlit/runtime/memory_media_file_storage.py +6 -5
  149. streamlit/runtime/memory_uploaded_file_manager.py +2 -2
  150. streamlit/runtime/metrics_util.py +11 -12
  151. streamlit/runtime/pages_manager.py +4 -6
  152. streamlit/runtime/runtime.py +8 -6
  153. streamlit/runtime/runtime_util.py +7 -6
  154. streamlit/runtime/scriptrunner/__init__.py +4 -4
  155. streamlit/runtime/scriptrunner/exec_code.py +12 -5
  156. streamlit/runtime/scriptrunner/magic.py +16 -12
  157. streamlit/runtime/scriptrunner/script_cache.py +1 -1
  158. streamlit/runtime/scriptrunner/script_runner.py +53 -29
  159. streamlit/runtime/scriptrunner_utils/exceptions.py +1 -1
  160. streamlit/runtime/scriptrunner_utils/script_requests.py +7 -4
  161. streamlit/runtime/scriptrunner_utils/script_run_context.py +10 -23
  162. streamlit/runtime/secrets.py +40 -35
  163. streamlit/runtime/session_manager.py +2 -1
  164. streamlit/runtime/state/__init__.py +5 -5
  165. streamlit/runtime/state/common.py +2 -2
  166. streamlit/runtime/state/query_params.py +13 -15
  167. streamlit/runtime/state/query_params_proxy.py +17 -13
  168. streamlit/runtime/state/safe_session_state.py +2 -2
  169. streamlit/runtime/state/session_state.py +52 -34
  170. streamlit/runtime/stats.py +2 -2
  171. streamlit/runtime/uploaded_file_manager.py +1 -1
  172. streamlit/runtime/websocket_session_manager.py +10 -6
  173. streamlit/source_util.py +8 -6
  174. streamlit/static/index.html +3 -17
  175. streamlit/static/manifest.json +1180 -0
  176. streamlit/static/static/css/{index.DqDwtg6_.css → index.CJVRHjQZ.css} +1 -1
  177. streamlit/static/static/js/{ErrorOutline.esm.DU9IrB3M.js → ErrorOutline.esm.DitPpe1Y.js} +1 -1
  178. streamlit/static/static/js/{FileDownload.esm.P9rKwKo8.js → FileDownload.esm.AI3watX9.js} +1 -1
  179. streamlit/static/static/js/{FileHelper.D7RMkx0e.js → FileHelper.kt7mhnu8.js} +5 -5
  180. streamlit/static/static/js/{FormClearHelper.B67tgll0.js → FormClearHelper.D1M9GM_c.js} +1 -1
  181. streamlit/static/static/js/{Hooks.ncTJktu9.js → Hooks.BGwHKeUc.js} +1 -1
  182. streamlit/static/static/js/{InputInstructions.D-Y8geDN.js → InputInstructions.DaZ89mzH.js} +1 -1
  183. streamlit/static/static/js/{ProgressBar.B-kexwwD.js → ProgressBar.C0zPMe-p.js} +2 -2
  184. streamlit/static/static/js/{RenderInPortalIfExists.BgaoZgep.js → RenderInPortalIfExists.Ox8gQvdz.js} +1 -1
  185. streamlit/static/static/js/Toolbar.KhlcEc0K.js +1 -0
  186. streamlit/static/static/js/UploadFileInfo.0DCkpDDf.js +6 -0
  187. streamlit/static/static/js/{base-input.BoAa1U94.js → base-input.BJ4qsfSq.js} +4 -4
  188. streamlit/static/static/js/{checkbox.Z6iSfe5F.js → checkbox.DSDh78Xz.js} +2 -2
  189. streamlit/static/static/js/{createSuper.B4oGDYRm.js → createSuper.wQ9SIXEJ.js} +1 -1
  190. streamlit/static/static/js/{data-grid-overlay-editor.msYws2Ou.js → data-grid-overlay-editor.DvbdPJ15.js} +1 -1
  191. streamlit/static/static/js/{downloader.kc14n2Hv.js → downloader.CD9rzih5.js} +1 -1
  192. streamlit/static/static/js/{es6.CxQz807-.js → es6.48Q9Qjgb.js} +2 -2
  193. streamlit/static/static/js/{iframeResizer.contentWindow.B19u0ONI.js → iframeResizer.contentWindow.CKdem3Bn.js} +1 -1
  194. streamlit/static/static/js/{index.LaIasviC.js → index.6md5Qhod.js} +1 -1
  195. streamlit/static/static/js/index.7hy6AeJ1.js +1 -0
  196. streamlit/static/static/js/index.B4CGJiBW.js +1 -0
  197. streamlit/static/static/js/index.B8oW0ZTD.js +1 -0
  198. streamlit/static/static/js/index.BU6RnlHI.js +73 -0
  199. streamlit/static/static/js/index.BUq9Wcf8.js +197 -0
  200. streamlit/static/static/js/{index.BFz9U2y0.js → index.BXXo-Yoj.js} +1 -1
  201. streamlit/static/static/js/index.Bae9H0OS.js +1 -0
  202. streamlit/static/static/js/{index.-5ruC9At.js → index.BhTl2Uyb.js} +1 -1
  203. streamlit/static/static/js/{index.BpILzHf_.js → index.BiSaCB1o.js} +20 -20
  204. streamlit/static/static/js/{index.xNQq3Ei5.js → index.BulSAJ9z.js} +1 -1
  205. streamlit/static/static/js/{index.9V1KdxfP.js → index.Bv-EuTKR.js} +1 -1
  206. streamlit/static/static/js/index.BvMLYCHi.js +1 -0
  207. streamlit/static/static/js/index.C1NIn1Y2.js +783 -0
  208. streamlit/static/static/js/index.CP-fthOJ.js +2 -0
  209. streamlit/static/static/js/{index.BoigZiu7.js → index.CS9guO3p.js} +1 -1
  210. streamlit/static/static/js/index.CYTBHth8.js +1 -0
  211. streamlit/static/static/js/{index.CmTAF0dM.js → index.CcJufcuD.js} +1 -1
  212. streamlit/static/static/js/index.CnENU1yn.js +1 -0
  213. streamlit/static/static/js/index.Cns13qBb.js +1 -0
  214. streamlit/static/static/js/index.Ct_xXq7w.js +1 -0
  215. streamlit/static/static/js/{index.BqfdT8-Q.js → index.CxGSemHL.js} +1 -1
  216. streamlit/static/static/js/index.D5S0ldVb.js +1 -0
  217. streamlit/static/static/js/index.D72B_ksb.js +2 -0
  218. streamlit/static/static/js/index.DI4yZ27M.js +1 -0
  219. streamlit/static/static/js/index.DN51vLxR.js +1 -0
  220. streamlit/static/static/js/index.DRtq5dka.js +1 -0
  221. streamlit/static/static/js/{index.BHXxWdde.js → index.DX-oiXlb.js} +1 -1
  222. streamlit/static/static/js/index.DlFE4_Aq.js +12 -0
  223. streamlit/static/static/js/{index.BHGGDa8K.js → index.J7BJwXOi.js} +2 -2
  224. streamlit/static/static/js/index.Jg38kJPP.js +1 -0
  225. streamlit/static/static/js/index.JhIO6abf.js +3 -0
  226. streamlit/static/static/js/{index.DeB9iKFW.js → index.NkRcWwc5.js} +255 -255
  227. streamlit/static/static/js/{index.BGga-hcS.js → index.prekPLrm.js} +25 -25
  228. streamlit/static/static/js/{index.BRXmLIsC.js → index.wyzngKUE.js} +1 -1
  229. streamlit/static/static/js/index.xW7mVdI8.js +1 -0
  230. streamlit/static/static/js/index.yk07dYGx.js +1 -0
  231. streamlit/static/static/js/{input.DsCfafm0.js → input.CxKZ5Wrc.js} +2 -2
  232. streamlit/static/static/js/{memory.nY_lMTtu.js → memory.DeZ9VUvl.js} +1 -1
  233. streamlit/static/static/js/{mergeWith.B_7zmsM4.js → mergeWith.CVkhrWUb.js} +1 -1
  234. streamlit/static/static/js/{number-overlay-editor.CSeVhHRU.js → number-overlay-editor.Bpkm3nTq.js} +1 -1
  235. streamlit/static/static/js/{possibleConstructorReturn.nNhsvgRd.js → possibleConstructorReturn.CIDCId52.js} +1 -1
  236. streamlit/static/static/js/{sandbox.Cgm3iuL6.js → sandbox.TrkMaokR.js} +1 -1
  237. streamlit/static/static/js/{textarea.BR8rlyih.js → textarea.QKjxR64N.js} +2 -2
  238. streamlit/static/static/js/{timepicker.w4XhAenH.js → timepicker.DJYmE1dK.js} +1 -1
  239. streamlit/static/static/js/{toConsumableArray.CgkEPBwD.js → toConsumableArray.BZoworE-.js} +1 -1
  240. streamlit/static/static/js/{uniqueId.j-1rlNNH.js → uniqueId.O0UbJ2Bu.js} +1 -1
  241. streamlit/static/static/js/{useBasicWidgetState.zXY9CjFS.js → useBasicWidgetState.Ci89jaH5.js} +1 -1
  242. streamlit/static/static/js/useOnInputChange.Cxh6ExEn.js +1 -0
  243. streamlit/static/static/js/{withFullScreenWrapper.Ov13692o.js → withFullScreenWrapper.iW37lS8Z.js} +1 -1
  244. streamlit/static/static/media/SourceCodeVF-Italic.ttf.Ba1oaZG1.woff2 +0 -0
  245. streamlit/static/static/media/SourceCodeVF-Upright.ttf.BjWn63N-.woff2 +0 -0
  246. streamlit/static/static/media/SourceSansVF-Italic.ttf.Bt9VkdQ3.woff2 +0 -0
  247. streamlit/static/static/media/SourceSansVF-Upright.ttf.BsWL4Kly.woff2 +0 -0
  248. streamlit/static/static/media/SourceSerifVariable-Italic.ttf.CVdzAtxO.woff2 +0 -0
  249. streamlit/static/static/media/SourceSerifVariable-Roman.ttf.mdpVL9bi.woff2 +0 -0
  250. streamlit/string_util.py +14 -19
  251. streamlit/temporary_directory.py +13 -4
  252. streamlit/testing/v1/app_test.py +15 -10
  253. streamlit/testing/v1/element_tree.py +157 -178
  254. streamlit/testing/v1/local_script_runner.py +11 -15
  255. streamlit/testing/v1/util.py +11 -4
  256. streamlit/type_util.py +8 -12
  257. streamlit/url_util.py +1 -1
  258. streamlit/user_info.py +6 -5
  259. streamlit/util.py +25 -1
  260. streamlit/vendor/pympler/asizeof.py +3 -2
  261. streamlit/watcher/event_based_path_watcher.py +21 -2
  262. streamlit/watcher/folder_black_list.py +2 -2
  263. streamlit/watcher/local_sources_watcher.py +64 -18
  264. streamlit/watcher/path_watcher.py +6 -10
  265. streamlit/watcher/polling_path_watcher.py +8 -7
  266. streamlit/watcher/util.py +7 -6
  267. streamlit/web/bootstrap.py +16 -14
  268. streamlit/web/cli.py +52 -45
  269. streamlit/web/server/__init__.py +7 -3
  270. streamlit/web/server/app_static_file_handler.py +1 -1
  271. streamlit/web/server/authlib_tornado_integration.py +9 -4
  272. streamlit/web/server/browser_websocket_handler.py +8 -2
  273. streamlit/web/server/component_request_handler.py +14 -10
  274. streamlit/web/server/media_file_handler.py +14 -7
  275. streamlit/web/server/oauth_authlib_routes.py +41 -9
  276. streamlit/web/server/oidc_mixin.py +35 -17
  277. streamlit/web/server/routes.py +32 -22
  278. streamlit/web/server/server.py +13 -24
  279. streamlit/web/server/server_util.py +43 -9
  280. streamlit/web/server/stats_request_handler.py +7 -5
  281. streamlit/web/server/upload_file_request_handler.py +22 -19
  282. streamlit/web/server/websocket_headers.py +1 -1
  283. {streamlit-1.45.1.dist-info → streamlit-1.46.1.dist-info}/METADATA +4 -4
  284. streamlit-1.46.1.dist-info/RECORD +559 -0
  285. {streamlit-1.45.1.dist-info → streamlit-1.46.1.dist-info}/WHEEL +1 -1
  286. streamlit/elements/lib/event_utils.py +0 -39
  287. streamlit/static/static/js/Toolbar.D9RUZv9G.js +0 -1
  288. streamlit/static/static/js/UploadFileInfo.C-jY39rj.js +0 -1
  289. streamlit/static/static/js/index.8jhZBWF2.js +0 -3
  290. streamlit/static/static/js/index.BCx3C6e_.js +0 -1
  291. streamlit/static/static/js/index.BRuTz_S4.js +0 -1
  292. streamlit/static/static/js/index.Bcru_ti-.js +0 -1
  293. streamlit/static/static/js/index.Bl1FMJRd.js +0 -1
  294. streamlit/static/static/js/index.C1z8KpLA.js +0 -779
  295. streamlit/static/static/js/index.C32I2PUe.js +0 -2
  296. streamlit/static/static/js/index.C5GnDRB7.js +0 -1
  297. streamlit/static/static/js/index.CG4qPaaW.js +0 -2
  298. streamlit/static/static/js/index.C_msmT1u.js +0 -1
  299. streamlit/static/static/js/index.CbeNTdd6.js +0 -1
  300. streamlit/static/static/js/index.CnGQVJcw.js +0 -12
  301. streamlit/static/static/js/index.CopVVq4l.js +0 -1
  302. streamlit/static/static/js/index.CtXupx4d.js +0 -197
  303. streamlit/static/static/js/index.DGmCchO7.js +0 -1
  304. streamlit/static/static/js/index.DH6zBk0e.js +0 -1
  305. streamlit/static/static/js/index.DHVlVWsm.js +0 -1
  306. streamlit/static/static/js/index.DRKIVBoi.js +0 -1
  307. streamlit/static/static/js/index.DUd-lFXx.js +0 -73
  308. streamlit/static/static/js/index.D_uRBA4B.js +0 -1
  309. streamlit/static/static/js/index.QHNfgPJd.js +0 -1
  310. streamlit/static/static/js/index.a-RJocYL.js +0 -1
  311. streamlit/static/static/js/index.cvz4B1gy.js +0 -1
  312. streamlit/static/static/js/index.t--hEgTQ.js +0 -6
  313. streamlit/static/static/js/useOnInputChange.z04u96A8.js +0 -1
  314. streamlit/static/static/media/SourceCodePro-Bold.CFEfr7-q.woff2 +0 -0
  315. streamlit/static/static/media/SourceCodePro-BoldItalic.C-LkFXxa.woff2 +0 -0
  316. streamlit/static/static/media/SourceCodePro-Italic.CxFOx7N-.woff2 +0 -0
  317. streamlit/static/static/media/SourceCodePro-Regular.CBOlD63d.woff2 +0 -0
  318. streamlit/static/static/media/SourceCodePro-SemiBold.CFHwW3Wd.woff2 +0 -0
  319. streamlit/static/static/media/SourceCodePro-SemiBoldItalic.Cg2yRu82.woff2 +0 -0
  320. streamlit/static/static/media/SourceSansPro-Bold.-6c9oR8J.woff2 +0 -0
  321. streamlit/static/static/media/SourceSansPro-BoldItalic.DmM_grLY.woff2 +0 -0
  322. streamlit/static/static/media/SourceSansPro-Italic.I1ipWe7Q.woff2 +0 -0
  323. streamlit/static/static/media/SourceSansPro-Regular.DZLUzqI4.woff2 +0 -0
  324. streamlit/static/static/media/SourceSansPro-SemiBold.sKQIyTMz.woff2 +0 -0
  325. streamlit/static/static/media/SourceSansPro-SemiBoldItalic.C0wP0icr.woff2 +0 -0
  326. streamlit/static/static/media/SourceSerifPro-Bold.8TUnKj4x.woff2 +0 -0
  327. streamlit/static/static/media/SourceSerifPro-BoldItalic.CBVO7Ve7.woff2 +0 -0
  328. streamlit/static/static/media/SourceSerifPro-Italic.DkFgL2HZ.woff2 +0 -0
  329. streamlit/static/static/media/SourceSerifPro-Regular.CNJNET2S.woff2 +0 -0
  330. streamlit/static/static/media/SourceSerifPro-SemiBold.CHyh9GC5.woff2 +0 -0
  331. streamlit/static/static/media/SourceSerifPro-SemiBoldItalic.CBtz8sWN.woff2 +0 -0
  332. streamlit-1.45.1.dist-info/RECORD +0 -568
  333. {streamlit-1.45.1.data → streamlit-1.46.1.data}/scripts/streamlit.cmd +0 -0
  334. {streamlit-1.45.1.dist-info → streamlit-1.46.1.dist-info}/entry_points.txt +0 -0
  335. {streamlit-1.45.1.dist-info → streamlit-1.46.1.dist-info}/top_level.txt +0 -0
@@ -21,7 +21,6 @@ import sys
21
21
  from typing import Any, Final
22
22
 
23
23
  from streamlit import cli_util, config, env_util, file_util, net_util, secrets
24
- from streamlit.config import CONFIG_FILENAMES
25
24
  from streamlit.git_util import MIN_GIT_VERSION, GitRepo
26
25
  from streamlit.logger import get_logger
27
26
  from streamlit.watcher import report_watchdog_availability, watch_file
@@ -39,7 +38,7 @@ MAX_APP_STATIC_FOLDER_SIZE = 1 * 1024 * 1024 * 1024 # 1 GB
39
38
  def _set_up_signal_handler(server: Server) -> None:
40
39
  _LOGGER.debug("Setting up signal handler")
41
40
 
42
- def signal_handler(signal_number, stack_frame):
41
+ def signal_handler(signal_number: int, stack_frame: Any) -> None: # noqa: ARG001
43
42
  # The server will shut down its threads and exit its loop.
44
43
  server.stop()
45
44
 
@@ -98,7 +97,7 @@ def _fix_sys_argv(main_script_path: str, args: list[str]) -> None:
98
97
  """
99
98
  import sys
100
99
 
101
- sys.argv = [main_script_path] + list(args)
100
+ sys.argv = [main_script_path, *list(args)]
102
101
 
103
102
 
104
103
  def _on_server_start(server: Server) -> None:
@@ -112,10 +111,10 @@ def _on_server_start(server: Server) -> None:
112
111
  # errors and display them here.
113
112
  try:
114
113
  secrets.load_if_toml_exists()
115
- except Exception as ex:
116
- _LOGGER.error("Failed to load secrets.toml file", exc_info=ex)
114
+ except Exception:
115
+ _LOGGER.exception("Failed to load secrets.toml file")
117
116
 
118
- def maybe_open_browser():
117
+ def maybe_open_browser() -> None:
119
118
  if config.get_option("server.headless"):
120
119
  # Don't open browser when in headless mode.
121
120
  return
@@ -141,7 +140,8 @@ def _fix_pydeck_mapbox_api_warning() -> None:
141
140
  will throw an exception.
142
141
  """
143
142
 
144
- os.environ["MAPBOX_API_KEY"] = config.get_option("mapbox.token")
143
+ if "MAPBOX_API_KEY" not in os.environ:
144
+ os.environ["MAPBOX_API_KEY"] = config.get_option("mapbox.token")
145
145
 
146
146
 
147
147
  def _maybe_print_static_folder_warning(main_script_path: str) -> None:
@@ -209,7 +209,7 @@ def _print_url(is_running_hello: bool) -> None:
209
209
  named_urls.append(("External URL", server_util.get_url(external_ip)))
210
210
 
211
211
  cli_util.print_to_cli("")
212
- cli_util.print_to_cli(" %s" % title_message, fg="blue", bold=True)
212
+ cli_util.print_to_cli(f" {title_message}", fg="blue", bold=True)
213
213
  cli_util.print_to_cli("")
214
214
 
215
215
  for url_name, url in named_urls:
@@ -287,10 +287,10 @@ def load_config_options(flag_options: dict[str, Any]) -> None:
287
287
 
288
288
 
289
289
  def _install_config_watchers(flag_options: dict[str, Any]) -> None:
290
- def on_config_changed(_path):
290
+ def on_config_changed(_path: str) -> None:
291
291
  load_config_options(flag_options)
292
292
 
293
- for filename in CONFIG_FILENAMES:
293
+ for filename in config.get_config_files("config.toml"):
294
294
  if os.path.exists(filename):
295
295
  watch_file(filename, on_config_changed)
296
296
 
@@ -307,6 +307,7 @@ def run(
307
307
 
308
308
  This starts a blocking asyncio eventloop.
309
309
  """
310
+
310
311
  _fix_sys_path(main_script_path)
311
312
  _fix_tornado_crash()
312
313
  _fix_sys_argv(main_script_path, args)
@@ -335,18 +336,19 @@ def run(
335
336
  await server.stopped
336
337
 
337
338
  # Run the server. This function will not return until the server is shut down.
338
- # FIX RuntimeError: asyncio.run() cannot be called from a running event loop on Python 3.10.16
339
- # asyncio.run(run_server())
339
+ # FIX RuntimeError: asyncio.run() cannot be called from a running event loop
340
+ # asyncio.run(run_server()) # noqa: ERA001
340
341
 
341
342
  # Define a main function to handle the event loop logic
342
- async def main():
343
+ async def main() -> None:
343
344
  await run_server()
344
345
 
345
346
  try:
346
347
  # Check if we're already in an event loop
347
348
  if asyncio.get_running_loop().is_running():
348
349
  # Use `asyncio.create_task` if we're in an async context
349
- asyncio.create_task(main())
350
+ # TODO(lukasmasuch): Do we have to store a reference for the task here?
351
+ asyncio.create_task(main()) # noqa: RUF006
350
352
  else:
351
353
  # Otherwise, use `asyncio.run`
352
354
  asyncio.run(main())
streamlit/web/cli.py CHANGED
@@ -18,15 +18,15 @@ from __future__ import annotations
18
18
 
19
19
  import os
20
20
  import sys
21
- from typing import TYPE_CHECKING, Any, Callable, TypeVar
21
+ from typing import TYPE_CHECKING, Any, Callable, Final, TypeVar
22
22
 
23
23
  # We cannot lazy-load click here because its used via decorators.
24
24
  import click
25
25
 
26
- import streamlit.runtime.caching as caching
27
- import streamlit.web.bootstrap as bootstrap
28
26
  from streamlit import config as _config
27
+ from streamlit.runtime import caching
29
28
  from streamlit.runtime.credentials import Credentials, check_credentials
29
+ from streamlit.web import bootstrap
30
30
  from streamlit.web.cache_storage_manager_config import (
31
31
  create_default_cache_storage_manager,
32
32
  )
@@ -34,9 +34,9 @@ from streamlit.web.cache_storage_manager_config import (
34
34
  if TYPE_CHECKING:
35
35
  from streamlit.config_option import ConfigOption
36
36
 
37
- ACCEPTED_FILE_EXTENSIONS = ("py", "py3")
37
+ ACCEPTED_FILE_EXTENSIONS: Final = ("py", "py3")
38
38
 
39
- LOG_LEVELS = ("error", "warning", "info", "debug")
39
+ LOG_LEVELS: Final = ("error", "warning", "info", "debug")
40
40
 
41
41
 
42
42
  def _convert_config_option_to_click_option(
@@ -63,10 +63,12 @@ def _convert_config_option_to_click_option(
63
63
  }
64
64
 
65
65
 
66
- def _make_sensitive_option_callback(config_option: ConfigOption):
67
- def callback(_ctx: click.Context, _param: click.Parameter, cli_value) -> None:
66
+ def _make_sensitive_option_callback(
67
+ config_option: ConfigOption,
68
+ ) -> Callable[[click.Context, click.Parameter, Any], None]:
69
+ def callback(_ctx: click.Context, _param: click.Parameter, cli_value: Any) -> None:
68
70
  if cli_value is None:
69
- return None
71
+ return
70
72
  raise SystemExit(
71
73
  f"Setting {config_option.key!r} option using the CLI flag is not allowed. "
72
74
  f"Set this option in the configuration file or environment "
@@ -103,7 +105,7 @@ def configurator_options(func: F) -> F:
103
105
  help=parsed_parameter["description"],
104
106
  type=parsed_parameter["type"],
105
107
  multiple=parsed_parameter["multiple"],
106
- **click_option_kwargs,
108
+ **click_option_kwargs, # type: ignore
107
109
  )
108
110
  func = config_option(func)
109
111
  return func
@@ -115,7 +117,7 @@ def _download_remote(main_script_path: str, url_path: str) -> None:
115
117
 
116
118
  with open(main_script_path, "wb") as fp:
117
119
  try:
118
- resp = requests.get(url_path)
120
+ resp = requests.get(url_path, timeout=30)
119
121
  resp.raise_for_status()
120
122
  fp.write(resp.content)
121
123
  except requests.exceptions.RequestException as e:
@@ -125,7 +127,7 @@ def _download_remote(main_script_path: str, url_path: str) -> None:
125
127
  @click.group(context_settings={"auto_envvar_prefix": "STREAMLIT"})
126
128
  @click.option("--log_level", show_default=True, type=click.Choice(LOG_LEVELS))
127
129
  @click.version_option(prog_name="Streamlit")
128
- def main(log_level="info"):
130
+ def main(log_level: str = "info") -> None:
129
131
  """Try out a demo with:
130
132
 
131
133
  $ streamlit hello
@@ -138,29 +140,27 @@ def main(log_level="info"):
138
140
  if log_level:
139
141
  from streamlit.logger import get_logger
140
142
 
141
- LOGGER = get_logger(__name__)
142
- LOGGER.warning(
143
+ logger: Final = get_logger(__name__)
144
+ logger.warning(
143
145
  "Setting the log level using the --log_level flag is unsupported."
144
146
  "\nUse the --logger.level flag (after your streamlit command) instead."
145
147
  )
146
148
 
147
149
 
148
150
  @main.command("help")
149
- def help():
151
+ def help() -> None: # noqa: A001
150
152
  """Print this help message."""
151
153
  # We use _get_command_line_as_string to run some error checks but don't do
152
154
  # anything with its return value.
153
155
  _get_command_line_as_string()
154
156
 
155
- assert len(sys.argv) == 2 # This is always true, but let's assert anyway.
156
-
157
157
  # Pretend user typed 'streamlit --help' instead of 'streamlit help'.
158
158
  sys.argv[1] = "--help"
159
159
  main(prog_name="streamlit")
160
160
 
161
161
 
162
162
  @main.command("version")
163
- def main_version():
163
+ def main_version() -> None:
164
164
  """Print Streamlit's version number."""
165
165
  # Pretend user typed 'streamlit --version' instead of 'streamlit version'
166
166
  import sys
@@ -169,13 +169,12 @@ def main_version():
169
169
  # anything with its return value.
170
170
  _get_command_line_as_string()
171
171
 
172
- assert len(sys.argv) == 2 # This is always true, but let's assert anyway.
173
172
  sys.argv[1] = "--version"
174
173
  main()
175
174
 
176
175
 
177
176
  @main.command("docs")
178
- def main_docs():
177
+ def main_docs() -> None:
179
178
  """Show help in browser."""
180
179
  click.echo("Showing help page in browser...")
181
180
  from streamlit import cli_util
@@ -185,11 +184,10 @@ def main_docs():
185
184
 
186
185
  @main.command("hello")
187
186
  @configurator_options
188
- def main_hello(**kwargs):
187
+ def main_hello(**kwargs: Any) -> None:
189
188
  """Runs the Hello World script."""
190
189
  from streamlit.hello import streamlit_app
191
190
 
192
- bootstrap.load_config_options(flag_options=kwargs)
193
191
  filename = streamlit_app.__file__
194
192
  _main_run(filename, flag_options=kwargs)
195
193
 
@@ -198,7 +196,7 @@ def main_hello(**kwargs):
198
196
  @configurator_options
199
197
  @click.argument("target", required=True, envvar="STREAMLIT_RUN_TARGET")
200
198
  @click.argument("args", nargs=-1)
201
- def main_run(target: str, args=None, **kwargs):
199
+ def main_run(target: str, args: list[str] | None = None, **kwargs: Any) -> None:
202
200
  """Run a Python script, piping stderr to Streamlit.
203
201
 
204
202
  The script can be local or it can be an url. In the latter case, Streamlit
@@ -207,18 +205,16 @@ def main_run(target: str, args=None, **kwargs):
207
205
  """
208
206
  from streamlit import url_util
209
207
 
210
- bootstrap.load_config_options(flag_options=kwargs)
211
-
212
208
  _, extension = os.path.splitext(target)
213
209
  if extension[1:] not in ACCEPTED_FILE_EXTENSIONS:
214
210
  if extension[1:] == "":
215
211
  raise click.BadArgumentUsage(
216
- "Streamlit requires raw Python (.py) files, but the provided file has no extension.\nFor more information, please see https://docs.streamlit.io"
217
- )
218
- else:
219
- raise click.BadArgumentUsage(
220
- f"Streamlit requires raw Python (.py) files, not {extension}.\nFor more information, please see https://docs.streamlit.io"
212
+ "Streamlit requires raw Python (.py) files, but the provided file has no extension.\n"
213
+ "For more information, please see https://docs.streamlit.io"
221
214
  )
215
+ raise click.BadArgumentUsage(
216
+ f"Streamlit requires raw Python (.py) files, not {extension}.\nFor more information, please see https://docs.streamlit.io"
217
+ )
222
218
 
223
219
  if url_util.is_url(target):
224
220
  from streamlit.temporary_directory import TemporaryDirectory
@@ -259,10 +255,16 @@ def _get_command_line_as_string() -> str | None:
259
255
 
260
256
 
261
257
  def _main_run(
262
- file,
258
+ file: str,
263
259
  args: list[str] | None = None,
264
260
  flag_options: dict[str, Any] | None = None,
265
261
  ) -> None:
262
+ # Set the main script path to use it for config & secret files
263
+ # While its a bit suboptimal, we need to store this into a module-level
264
+ # variable before we load the config options via `load_config_options`
265
+ _config._main_script_path = os.path.abspath(file)
266
+
267
+ bootstrap.load_config_options(flag_options=flag_options or {})
266
268
  if args is None:
267
269
  args = []
268
270
 
@@ -276,17 +278,17 @@ def _main_run(
276
278
  bootstrap.run(file, is_hello, args, flag_options)
277
279
 
278
280
 
279
- # SUBCOMMAND: cache
281
+ # SUBCOMMAND cache
280
282
 
281
283
 
282
284
  @main.group("cache")
283
- def cache():
285
+ def cache() -> None:
284
286
  """Manage the Streamlit cache."""
285
287
  pass
286
288
 
287
289
 
288
290
  @cache.command("clear")
289
- def cache_clear():
291
+ def cache_clear() -> None:
290
292
  """Clear st.cache_data and st.cache_resource caches."""
291
293
 
292
294
  # in this `streamlit cache clear` cli command we cannot use the
@@ -299,18 +301,18 @@ def cache_clear():
299
301
  caching.cache_resource.clear()
300
302
 
301
303
 
302
- # SUBCOMMAND: config
304
+ # SUBCOMMAND config
303
305
 
304
306
 
305
307
  @main.group("config")
306
- def config():
308
+ def config() -> None:
307
309
  """Manage Streamlit's config settings."""
308
310
  pass
309
311
 
310
312
 
311
313
  @config.command("show")
312
314
  @configurator_options
313
- def config_show(**kwargs):
315
+ def config_show(**kwargs: Any) -> None:
314
316
  """Show all of Streamlit's config settings."""
315
317
 
316
318
  bootstrap.load_config_options(flag_options=kwargs)
@@ -318,28 +320,28 @@ def config_show(**kwargs):
318
320
  _config.show_config()
319
321
 
320
322
 
321
- # SUBCOMMAND: activate
323
+ # SUBCOMMAND activate
322
324
 
323
325
 
324
326
  @main.group("activate", invoke_without_command=True)
325
327
  @click.pass_context
326
- def activate(ctx):
328
+ def activate(ctx: click.Context) -> None:
327
329
  """Activate Streamlit by entering your email."""
328
330
  if not ctx.invoked_subcommand:
329
331
  Credentials.get_current().activate()
330
332
 
331
333
 
332
334
  @activate.command("reset")
333
- def activate_reset():
335
+ def activate_reset() -> None:
334
336
  """Reset Activation Credentials."""
335
337
  Credentials.get_current().reset()
336
338
 
337
339
 
338
- # SUBCOMMAND: test
340
+ # SUBCOMMAND test
339
341
 
340
342
 
341
343
  @main.group("test", hidden=True)
342
- def test():
344
+ def test() -> None:
343
345
  """Internal-only commands used for testing.
344
346
 
345
347
  These commands are not included in the output of `streamlit help`.
@@ -348,7 +350,7 @@ def test():
348
350
 
349
351
 
350
352
  @test.command("prog_name")
351
- def test_prog_name():
353
+ def test_prog_name() -> None:
352
354
  """Assert that the program name is set to `streamlit test`.
353
355
 
354
356
  This is used by our cli-smoke-tests to verify that the program name is set
@@ -361,13 +363,18 @@ def test_prog_name():
361
363
 
362
364
  parent = click.get_current_context().parent
363
365
 
364
- assert parent is not None
365
- assert parent.command_path == "streamlit test"
366
+ if parent is None:
367
+ raise AssertionError("parent is None")
368
+
369
+ if parent.command_path != "streamlit test":
370
+ raise AssertionError(
371
+ f"Parent command path is {parent.command_path} not streamlit test."
372
+ )
366
373
 
367
374
 
368
375
  @main.command("init")
369
376
  @click.argument("directory", required=False)
370
- def main_init(directory: str | None = None):
377
+ def main_init(directory: str | None = None) -> None:
371
378
  """Initialize a new Streamlit project.
372
379
 
373
380
  If DIRECTORY is specified, create it and initialize the project there.
@@ -13,14 +13,18 @@
13
13
  # limitations under the License.
14
14
 
15
15
  from streamlit.web.server.component_request_handler import ComponentRequestHandler
16
- from streamlit.web.server.routes import allow_cross_origin_requests
16
+ from streamlit.web.server.routes import (
17
+ allow_all_cross_origin_requests,
18
+ is_allowed_origin,
19
+ )
17
20
  from streamlit.web.server.server import Server, server_address_is_unix_socket
18
21
  from streamlit.web.server.stats_request_handler import StatsRequestHandler
19
22
 
20
23
  __all__ = [
21
24
  "ComponentRequestHandler",
22
- "allow_cross_origin_requests",
23
25
  "Server",
24
- "server_address_is_unix_socket",
25
26
  "StatsRequestHandler",
27
+ "allow_all_cross_origin_requests",
28
+ "is_allowed_origin",
29
+ "server_address_is_unix_socket",
26
30
  ]
@@ -82,7 +82,7 @@ class AppStaticFileHandler(tornado.web.StaticFileHandler):
82
82
 
83
83
  return ret_val
84
84
 
85
- def set_default_headers(self):
85
+ def set_default_headers(self) -> None:
86
86
  # CORS protection is disabled because we need access to this endpoint
87
87
  # from the inner iframe.
88
88
  self.set_header("Access-Control-Allow-Origin", "*")
@@ -16,7 +16,7 @@ from __future__ import annotations
16
16
 
17
17
  from typing import TYPE_CHECKING, Any
18
18
 
19
- from authlib.integrations.base_client import ( # type: ignore[import-untyped]
19
+ from authlib.integrations.base_client import (
20
20
  FrameworkIntegration,
21
21
  )
22
22
 
@@ -28,15 +28,20 @@ if TYPE_CHECKING:
28
28
  from streamlit.web.server.oidc_mixin import TornadoOAuth
29
29
 
30
30
 
31
- class TornadoIntegration(FrameworkIntegration): # type: ignore[misc]
32
- def update_token(self, token, refresh_token=None, access_token=None):
31
+ class TornadoIntegration(FrameworkIntegration):
32
+ def update_token(
33
+ self,
34
+ token: dict[str, Any],
35
+ refresh_token: dict[str, Any] | None = None,
36
+ access_token: dict[str, Any] | None = None,
37
+ ) -> None:
33
38
  """We do not support access token refresh, since we obtain and operate only on
34
39
  identity tokens. We override this method explicitly to implement all abstract
35
40
  methods of base class.
36
41
  """
37
42
 
38
43
  @staticmethod
39
- def load_config(
44
+ def load_config( # type: ignore[override]
40
45
  oauth: TornadoOAuth, name: str, params: Sequence[str]
41
46
  ) -> dict[str, Any]:
42
47
  """Configure Authlib integration with provider parameters
@@ -113,6 +113,12 @@ class BrowserWebSocketHandler(WebSocketHandler, SessionClient):
113
113
  del cookie_value["is_logged_in"]
114
114
  user_info.update(cookie_value)
115
115
 
116
+ else:
117
+ _LOGGER.error(
118
+ "Origin mismatch, the origin of websocket request is not the "
119
+ "same origin of redirect_uri in secrets.toml",
120
+ )
121
+
116
122
  return user_info
117
123
 
118
124
  def write_forward_msg(self, msg: ForwardMsg) -> None:
@@ -148,7 +154,7 @@ class BrowserWebSocketHandler(WebSocketHandler, SessionClient):
148
154
 
149
155
  return None
150
156
 
151
- def open(self, *args, **kwargs) -> Awaitable[None] | None:
157
+ def open(self, *args: Any, **kwargs: Any) -> Awaitable[None] | None:
152
158
  user_info: dict[str, str | bool | None] = {}
153
159
 
154
160
  existing_session_id = None
@@ -207,7 +213,7 @@ class BrowserWebSocketHandler(WebSocketHandler, SessionClient):
207
213
  if isinstance(payload, str):
208
214
  # Sanity check. (The frontend should only be sending us bytes;
209
215
  # Protobuf.ParseFromString does not accept str input.)
210
- raise RuntimeError(
216
+ raise TypeError( # noqa: TRY301
211
217
  "WebSocket received an unexpected `str` message. "
212
218
  "(We expect `bytes` only.)"
213
219
  )
@@ -16,7 +16,7 @@ from __future__ import annotations
16
16
 
17
17
  import mimetypes
18
18
  import os
19
- from typing import TYPE_CHECKING, Final
19
+ from typing import TYPE_CHECKING, Final, cast
20
20
 
21
21
  import tornado.web
22
22
 
@@ -30,7 +30,7 @@ _LOGGER: Final = get_logger(__name__)
30
30
 
31
31
 
32
32
  class ComponentRequestHandler(tornado.web.RequestHandler):
33
- def initialize(self, registry: BaseComponentRegistry):
33
+ def initialize(self, registry: BaseComponentRegistry) -> None:
34
34
  self._registry = registry
35
35
 
36
36
  def get(self, path: str) -> None:
@@ -55,9 +55,10 @@ class ComponentRequestHandler(tornado.web.RequestHandler):
55
55
  try:
56
56
  with open(abspath, "rb") as file:
57
57
  contents = file.read()
58
- except OSError as e:
59
- _LOGGER.error(
60
- "ComponentRequestHandler: GET %s read error", abspath, exc_info=e
58
+ except OSError:
59
+ sanitized_abspath = abspath.replace("\n", "").replace("\r", "")
60
+ _LOGGER.exception(
61
+ "ComponentRequestHandler: GET %s read error", sanitized_abspath
61
62
  )
62
63
  self.write("read error")
63
64
  self.set_status(404)
@@ -82,8 +83,12 @@ class ComponentRequestHandler(tornado.web.RequestHandler):
82
83
  self.set_header("Cache-Control", "public")
83
84
 
84
85
  def set_default_headers(self) -> None:
85
- if streamlit.web.server.routes.allow_cross_origin_requests():
86
+ if streamlit.web.server.routes.allow_all_cross_origin_requests():
86
87
  self.set_header("Access-Control-Allow-Origin", "*")
88
+ elif streamlit.web.server.routes.is_allowed_origin(
89
+ origin := self.request.headers.get("Origin")
90
+ ):
91
+ self.set_header("Access-Control-Allow-Origin", cast("str", origin))
87
92
 
88
93
  def options(self) -> None:
89
94
  """/OPTIONS handler for preflight CORS checks."""
@@ -102,13 +107,12 @@ class ComponentRequestHandler(tornado.web.RequestHandler):
102
107
  # As of 2015-07-21 there is no bzip2 encoding defined at
103
108
  # http://www.iana.org/assignments/media-types/media-types.xhtml
104
109
  # So for that (and any other encoding), use octet-stream.
105
- elif encoding is not None:
110
+ if encoding is not None:
106
111
  return "application/octet-stream"
107
- elif mime_type is not None:
112
+ if mime_type is not None:
108
113
  return mime_type
109
114
  # if mime_type not detected, use application/octet-stream
110
- else:
111
- return "application/octet-stream"
115
+ return "application/octet-stream"
112
116
 
113
117
  @staticmethod
114
118
  def get_url(file_id: str) -> str:
@@ -14,6 +14,7 @@
14
14
 
15
15
  from __future__ import annotations
16
16
 
17
+ from typing import Any, cast
17
18
  from urllib.parse import quote
18
19
 
19
20
  import tornado.web
@@ -24,7 +25,7 @@ from streamlit.runtime.memory_media_file_storage import (
24
25
  MemoryMediaFileStorage,
25
26
  get_extension_for_mimetype,
26
27
  )
27
- from streamlit.web.server import allow_cross_origin_requests
28
+ from streamlit.web.server import allow_all_cross_origin_requests, is_allowed_origin
28
29
 
29
30
  _LOGGER = get_logger(__name__)
30
31
 
@@ -43,8 +44,10 @@ class MediaFileHandler(tornado.web.StaticFileHandler):
43
44
  cls._storage = storage
44
45
 
45
46
  def set_default_headers(self) -> None:
46
- if allow_cross_origin_requests():
47
+ if allow_all_cross_origin_requests():
47
48
  self.set_header("Access-Control-Allow-Origin", "*")
49
+ elif is_allowed_origin(origin := self.request.headers.get("Origin")):
50
+ self.set_header("Access-Control-Allow-Origin", cast("str", origin))
48
51
 
49
52
  def set_extra_headers(self, path: str) -> None:
50
53
  """Add Content-Disposition header for downloadable files.
@@ -83,11 +86,15 @@ class MediaFileHandler(tornado.web.StaticFileHandler):
83
86
  # static content from a database), override `get_content`,
84
87
  # `get_content_size`, `get_modified_time`, `get_absolute_path`, and
85
88
  # `validate_absolute_path`.
86
- def validate_absolute_path(self, root: str, absolute_path: str) -> str:
89
+ def validate_absolute_path(
90
+ self,
91
+ root: str, # noqa: ARG002
92
+ absolute_path: str,
93
+ ) -> str:
87
94
  try:
88
95
  self._storage.get_file(absolute_path)
89
96
  except MediaFileStorageError:
90
- _LOGGER.error("MediaFileHandler: Missing file %s", absolute_path)
97
+ _LOGGER.exception("MediaFileHandler: Missing file %s", absolute_path)
91
98
  raise tornado.web.HTTPError(404, "not found")
92
99
 
93
100
  return absolute_path
@@ -106,7 +113,7 @@ class MediaFileHandler(tornado.web.StaticFileHandler):
106
113
  return None
107
114
 
108
115
  @classmethod
109
- def get_absolute_path(cls, root: str, path: str) -> str:
116
+ def get_absolute_path(cls, root: str, path: str) -> str: # noqa: ARG003
110
117
  # All files are stored in memory, so the absolute path is just the
111
118
  # path itself. In the MediaFileHandler, it's just the filename
112
119
  return path
@@ -114,14 +121,14 @@ class MediaFileHandler(tornado.web.StaticFileHandler):
114
121
  @classmethod
115
122
  def get_content(
116
123
  cls, abspath: str, start: int | None = None, end: int | None = None
117
- ):
124
+ ) -> Any:
118
125
  _LOGGER.debug("MediaFileHandler: GET %s", abspath)
119
126
 
120
127
  try:
121
128
  # abspath is the hash as used `get_absolute_path`
122
129
  media_file = cls._storage.get_file(abspath)
123
130
  except Exception:
124
- _LOGGER.error("MediaFileHandler: Missing file %s", abspath)
131
+ _LOGGER.exception("MediaFileHandler: Missing file %s", abspath)
125
132
  return None
126
133
 
127
134
  _LOGGER.debug(