streamlit-data-editor-plus 0.1.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 (456) hide show
  1. streamlit/__init__.py +292 -0
  2. streamlit/__main__.py +20 -0
  3. streamlit/auth_util.py +583 -0
  4. streamlit/cli_util.py +107 -0
  5. streamlit/column_config.py +60 -0
  6. streamlit/commands/__init__.py +13 -0
  7. streamlit/commands/echo.py +128 -0
  8. streamlit/commands/execution_control.py +318 -0
  9. streamlit/commands/logo.py +250 -0
  10. streamlit/commands/navigation.py +430 -0
  11. streamlit/commands/page_config.py +335 -0
  12. streamlit/components/__init__.py +13 -0
  13. streamlit/components/lib/__init__.py +13 -0
  14. streamlit/components/lib/local_component_registry.py +84 -0
  15. streamlit/components/types/__init__.py +13 -0
  16. streamlit/components/types/base_component_registry.py +99 -0
  17. streamlit/components/types/base_custom_component.py +158 -0
  18. streamlit/components/v1/__init__.py +29 -0
  19. streamlit/components/v1/component_arrow.py +141 -0
  20. streamlit/components/v1/component_registry.py +147 -0
  21. streamlit/components/v1/components.py +38 -0
  22. streamlit/components/v1/custom_component.py +239 -0
  23. streamlit/components/v2/__init__.py +531 -0
  24. streamlit/components/v2/bidi_component/__init__.py +20 -0
  25. streamlit/components/v2/bidi_component/constants.py +29 -0
  26. streamlit/components/v2/bidi_component/main.py +537 -0
  27. streamlit/components/v2/bidi_component/serialization.py +272 -0
  28. streamlit/components/v2/bidi_component/state.py +92 -0
  29. streamlit/components/v2/component_definition_resolver.py +143 -0
  30. streamlit/components/v2/component_file_watcher.py +403 -0
  31. streamlit/components/v2/component_manager.py +439 -0
  32. streamlit/components/v2/component_manifest_handler.py +122 -0
  33. streamlit/components/v2/component_path_utils.py +233 -0
  34. streamlit/components/v2/component_registry.py +426 -0
  35. streamlit/components/v2/get_bidi_component_manager.py +51 -0
  36. streamlit/components/v2/manifest_scanner.py +620 -0
  37. streamlit/components/v2/presentation.py +198 -0
  38. streamlit/components/v2/types.py +317 -0
  39. streamlit/config.py +2977 -0
  40. streamlit/config_option.py +319 -0
  41. streamlit/config_util.py +887 -0
  42. streamlit/connections/__init__.py +32 -0
  43. streamlit/connections/base_connection.py +215 -0
  44. streamlit/connections/snowflake_connection.py +765 -0
  45. streamlit/connections/snowpark_connection.py +213 -0
  46. streamlit/connections/sql_connection.py +427 -0
  47. streamlit/connections/util.py +97 -0
  48. streamlit/cursor.py +314 -0
  49. streamlit/dataframe_util.py +1434 -0
  50. streamlit/delta_generator.py +696 -0
  51. streamlit/delta_generator_singletons.py +243 -0
  52. streamlit/deprecation_util.py +253 -0
  53. streamlit/development.py +21 -0
  54. streamlit/elements/__init__.py +13 -0
  55. streamlit/elements/alert.py +341 -0
  56. streamlit/elements/arrow.py +1065 -0
  57. streamlit/elements/balloons.py +47 -0
  58. streamlit/elements/bokeh_chart.py +75 -0
  59. streamlit/elements/code.py +154 -0
  60. streamlit/elements/deck_gl_json_chart.py +627 -0
  61. streamlit/elements/dialog_decorator.py +320 -0
  62. streamlit/elements/empty.py +130 -0
  63. streamlit/elements/exception.py +370 -0
  64. streamlit/elements/form.py +481 -0
  65. streamlit/elements/graphviz_chart.py +226 -0
  66. streamlit/elements/heading.py +407 -0
  67. streamlit/elements/help.py +565 -0
  68. streamlit/elements/html.py +189 -0
  69. streamlit/elements/iframe.py +245 -0
  70. streamlit/elements/image.py +221 -0
  71. streamlit/elements/json.py +171 -0
  72. streamlit/elements/layouts.py +1534 -0
  73. streamlit/elements/lib/__init__.py +13 -0
  74. streamlit/elements/lib/built_in_chart_utils.py +1316 -0
  75. streamlit/elements/lib/color_util.py +272 -0
  76. streamlit/elements/lib/column_config_utils.py +555 -0
  77. streamlit/elements/lib/column_types.py +2699 -0
  78. streamlit/elements/lib/dialog.py +212 -0
  79. streamlit/elements/lib/dicttools.py +152 -0
  80. streamlit/elements/lib/file_uploader_utils.py +91 -0
  81. streamlit/elements/lib/form_utils.py +77 -0
  82. streamlit/elements/lib/image_utils.py +447 -0
  83. streamlit/elements/lib/js_number.py +105 -0
  84. streamlit/elements/lib/layout_utils.py +325 -0
  85. streamlit/elements/lib/mutable_expander_container.py +73 -0
  86. streamlit/elements/lib/mutable_popover_container.py +73 -0
  87. streamlit/elements/lib/mutable_status_container.py +194 -0
  88. streamlit/elements/lib/mutable_tab_container.py +73 -0
  89. streamlit/elements/lib/options_selector_utils.py +480 -0
  90. streamlit/elements/lib/pandas_styler_utils.py +302 -0
  91. streamlit/elements/lib/policies.py +198 -0
  92. streamlit/elements/lib/shortcut_utils.py +152 -0
  93. streamlit/elements/lib/streamlit_plotly_theme.py +206 -0
  94. streamlit/elements/lib/subtitle_utils.py +175 -0
  95. streamlit/elements/lib/utils.py +274 -0
  96. streamlit/elements/map.py +526 -0
  97. streamlit/elements/markdown.py +529 -0
  98. streamlit/elements/media.py +843 -0
  99. streamlit/elements/metric.py +529 -0
  100. streamlit/elements/pdf.py +190 -0
  101. streamlit/elements/plotly_chart.py +779 -0
  102. streamlit/elements/progress.py +172 -0
  103. streamlit/elements/pyplot.py +240 -0
  104. streamlit/elements/snow.py +47 -0
  105. streamlit/elements/space.py +121 -0
  106. streamlit/elements/spinner.py +152 -0
  107. streamlit/elements/table.py +240 -0
  108. streamlit/elements/text.py +113 -0
  109. streamlit/elements/toast.py +175 -0
  110. streamlit/elements/vega_charts.py +2510 -0
  111. streamlit/elements/widgets/__init__.py +13 -0
  112. streamlit/elements/widgets/audio_input.py +334 -0
  113. streamlit/elements/widgets/button.py +1559 -0
  114. streamlit/elements/widgets/button_group.py +1061 -0
  115. streamlit/elements/widgets/camera_input.py +281 -0
  116. streamlit/elements/widgets/chat.py +1028 -0
  117. streamlit/elements/widgets/checkbox.py +420 -0
  118. streamlit/elements/widgets/color_picker.py +329 -0
  119. streamlit/elements/widgets/data_editor.py +1168 -0
  120. streamlit/elements/widgets/data_editor_plus.py +902 -0
  121. streamlit/elements/widgets/feedback.py +322 -0
  122. streamlit/elements/widgets/file_uploader.py +592 -0
  123. streamlit/elements/widgets/multiselect.py +654 -0
  124. streamlit/elements/widgets/number_input.py +719 -0
  125. streamlit/elements/widgets/radio.py +551 -0
  126. streamlit/elements/widgets/select_slider.py +568 -0
  127. streamlit/elements/widgets/selectbox.py +680 -0
  128. streamlit/elements/widgets/slider.py +1093 -0
  129. streamlit/elements/widgets/text_widgets.py +779 -0
  130. streamlit/elements/widgets/time_widgets.py +1712 -0
  131. streamlit/elements/write.py +585 -0
  132. streamlit/emojis.py +34 -0
  133. streamlit/env_util.py +56 -0
  134. streamlit/error_util.py +112 -0
  135. streamlit/errors.py +680 -0
  136. streamlit/external/__init__.py +13 -0
  137. streamlit/external/langchain/__init__.py +23 -0
  138. streamlit/external/langchain/streamlit_callback_handler.py +410 -0
  139. streamlit/file_util.py +266 -0
  140. streamlit/git_util.py +200 -0
  141. streamlit/hello/__init__.py +13 -0
  142. streamlit/hello/__pycache__/__init__.cpython-312.pyc +0 -0
  143. streamlit/hello/__pycache__/streamlit_app.cpython-312.pyc +0 -0
  144. streamlit/hello/animation_demo.py +82 -0
  145. streamlit/hello/dataframe_demo.py +71 -0
  146. streamlit/hello/hello.py +46 -0
  147. streamlit/hello/mapping_demo.py +113 -0
  148. streamlit/hello/plotting_demo.py +62 -0
  149. streamlit/hello/streamlit_app.py +57 -0
  150. streamlit/hello/utils.py +30 -0
  151. streamlit/logger.py +129 -0
  152. streamlit/material_icon_names.py +25 -0
  153. streamlit/navigation/__init__.py +13 -0
  154. streamlit/navigation/page.py +365 -0
  155. streamlit/net_util.py +125 -0
  156. streamlit/path_security.py +98 -0
  157. streamlit/platform.py +31 -0
  158. streamlit/proto/Alert_pb2.py +28 -0
  159. streamlit/proto/Alert_pb2.pyi +100 -0
  160. streamlit/proto/AppPage_pb2.py +25 -0
  161. streamlit/proto/AppPage_pb2.pyi +75 -0
  162. streamlit/proto/ArrowData_pb2.py +27 -0
  163. streamlit/proto/ArrowData_pb2.pyi +103 -0
  164. streamlit/proto/ArrowNamedDataSet_pb2.py +26 -0
  165. streamlit/proto/ArrowNamedDataSet_pb2.pyi +65 -0
  166. streamlit/proto/AudioInput_pb2.py +26 -0
  167. streamlit/proto/AudioInput_pb2.pyi +72 -0
  168. streamlit/proto/Audio_pb2.py +26 -0
  169. streamlit/proto/Audio_pb2.pyi +75 -0
  170. streamlit/proto/AuthRedirect_pb2.py +25 -0
  171. streamlit/proto/AuthRedirect_pb2.pyi +48 -0
  172. streamlit/proto/AutoRerun_pb2.py +25 -0
  173. streamlit/proto/AutoRerun_pb2.pyi +52 -0
  174. streamlit/proto/BackMsg_pb2.py +29 -0
  175. streamlit/proto/BackMsg_pb2.pyi +132 -0
  176. streamlit/proto/Balloons_pb2.py +25 -0
  177. streamlit/proto/Balloons_pb2.pyi +48 -0
  178. streamlit/proto/BidiComponent_pb2.py +32 -0
  179. streamlit/proto/BidiComponent_pb2.pyi +176 -0
  180. streamlit/proto/Block_pb2.py +62 -0
  181. streamlit/proto/Block_pb2.pyi +518 -0
  182. streamlit/proto/ButtonGroup_pb2.py +32 -0
  183. streamlit/proto/ButtonGroup_pb2.pyi +157 -0
  184. streamlit/proto/ButtonLikeIconPosition_pb2.py +25 -0
  185. streamlit/proto/ButtonLikeIconPosition_pb2.pyi +47 -0
  186. streamlit/proto/Button_pb2.py +26 -0
  187. streamlit/proto/Button_pb2.pyi +82 -0
  188. streamlit/proto/CameraInput_pb2.py +26 -0
  189. streamlit/proto/CameraInput_pb2.pyi +66 -0
  190. streamlit/proto/ChatInput_pb2.py +27 -0
  191. streamlit/proto/ChatInput_pb2.pyi +113 -0
  192. streamlit/proto/Checkbox_pb2.py +28 -0
  193. streamlit/proto/Checkbox_pb2.pyi +99 -0
  194. streamlit/proto/ClientState_pb2.py +28 -0
  195. streamlit/proto/ClientState_pb2.pyi +137 -0
  196. streamlit/proto/Code_pb2.py +25 -0
  197. streamlit/proto/Code_pb2.pyi +59 -0
  198. streamlit/proto/ColorPicker_pb2.py +26 -0
  199. streamlit/proto/ColorPicker_pb2.pyi +82 -0
  200. streamlit/proto/Common_pb2.py +49 -0
  201. streamlit/proto/Common_pb2.pyi +325 -0
  202. streamlit/proto/Components_pb2.py +33 -0
  203. streamlit/proto/Components_pb2.pyi +196 -0
  204. streamlit/proto/Dataframe_pb2.py +30 -0
  205. streamlit/proto/Dataframe_pb2.pyi +172 -0
  206. streamlit/proto/DateInput_pb2.py +26 -0
  207. streamlit/proto/DateInput_pb2.pyi +91 -0
  208. streamlit/proto/DateTimeInput_pb2.py +26 -0
  209. streamlit/proto/DateTimeInput_pb2.pyi +94 -0
  210. streamlit/proto/DeckGlJsonChart_pb2.py +27 -0
  211. streamlit/proto/DeckGlJsonChart_pb2.pyi +91 -0
  212. streamlit/proto/Delta_pb2.py +29 -0
  213. streamlit/proto/Delta_pb2.pyi +82 -0
  214. streamlit/proto/DownloadButton_pb2.py +26 -0
  215. streamlit/proto/DownloadButton_pb2.pyi +92 -0
  216. streamlit/proto/Element_pb2.py +81 -0
  217. streamlit/proto/Element_pb2.pyi +348 -0
  218. streamlit/proto/Empty_pb2.py +25 -0
  219. streamlit/proto/Empty_pb2.pyi +42 -0
  220. streamlit/proto/Exception_pb2.py +26 -0
  221. streamlit/proto/Exception_pb2.pyi +88 -0
  222. streamlit/proto/Favicon_pb2.py +25 -0
  223. streamlit/proto/Favicon_pb2.pyi +47 -0
  224. streamlit/proto/Feedback_pb2.py +27 -0
  225. streamlit/proto/Feedback_pb2.pyi +93 -0
  226. streamlit/proto/FileUploader_pb2.py +26 -0
  227. streamlit/proto/FileUploader_pb2.pyi +90 -0
  228. streamlit/proto/ForwardMsg_pb2.py +48 -0
  229. streamlit/proto/ForwardMsg_pb2.pyi +296 -0
  230. streamlit/proto/GapSize_pb2.py +27 -0
  231. streamlit/proto/GapSize_pb2.pyi +82 -0
  232. streamlit/proto/GitInfo_pb2.py +27 -0
  233. streamlit/proto/GitInfo_pb2.pyi +84 -0
  234. streamlit/proto/GraphVizChart_pb2.py +25 -0
  235. streamlit/proto/GraphVizChart_pb2.pyi +56 -0
  236. streamlit/proto/Heading_pb2.py +25 -0
  237. streamlit/proto/Heading_pb2.pyi +63 -0
  238. streamlit/proto/HeightConfig_pb2.py +25 -0
  239. streamlit/proto/HeightConfig_pb2.pyi +61 -0
  240. streamlit/proto/Help_pb2.py +27 -0
  241. streamlit/proto/Help_pb2.pyi +104 -0
  242. streamlit/proto/Html_pb2.py +25 -0
  243. streamlit/proto/Html_pb2.pyi +52 -0
  244. streamlit/proto/IFrame_pb2.py +25 -0
  245. streamlit/proto/IFrame_pb2.pyi +68 -0
  246. streamlit/proto/Image_pb2.py +27 -0
  247. streamlit/proto/Image_pb2.pyi +73 -0
  248. streamlit/proto/Json_pb2.py +25 -0
  249. streamlit/proto/Json_pb2.pyi +63 -0
  250. streamlit/proto/LabelVisibility_pb2.py +27 -0
  251. streamlit/proto/LabelVisibility_pb2.pyi +69 -0
  252. streamlit/proto/LinkButton_pb2.py +26 -0
  253. streamlit/proto/LinkButton_pb2.pyi +76 -0
  254. streamlit/proto/Logo_pb2.py +27 -0
  255. streamlit/proto/Logo_pb2.pyi +82 -0
  256. streamlit/proto/Markdown_pb2.py +27 -0
  257. streamlit/proto/Markdown_pb2.pyi +83 -0
  258. streamlit/proto/Metric_pb2.py +32 -0
  259. streamlit/proto/Metric_pb2.pyi +145 -0
  260. streamlit/proto/MetricsEvent_pb2.py +28 -0
  261. streamlit/proto/MetricsEvent_pb2.pyi +224 -0
  262. streamlit/proto/MultiSelect_pb2.py +26 -0
  263. streamlit/proto/MultiSelect_pb2.pyi +108 -0
  264. streamlit/proto/Navigation_pb2.py +28 -0
  265. streamlit/proto/Navigation_pb2.pyi +89 -0
  266. streamlit/proto/NewSession_pb2.py +47 -0
  267. streamlit/proto/NewSession_pb2.pyi +753 -0
  268. streamlit/proto/NumberInput_pb2.py +28 -0
  269. streamlit/proto/NumberInput_pb2.pyi +138 -0
  270. streamlit/proto/PageConfig_pb2.py +33 -0
  271. streamlit/proto/PageConfig_pb2.pyi +179 -0
  272. streamlit/proto/PageInfo_pb2.py +25 -0
  273. streamlit/proto/PageInfo_pb2.pyi +50 -0
  274. streamlit/proto/PageLink_pb2.py +26 -0
  275. streamlit/proto/PageLink_pb2.pyi +80 -0
  276. streamlit/proto/PageNotFound_pb2.py +25 -0
  277. streamlit/proto/PageNotFound_pb2.pyi +49 -0
  278. streamlit/proto/PageProfile_pb2.py +29 -0
  279. streamlit/proto/PageProfile_pb2.pyi +146 -0
  280. streamlit/proto/ParentMessage_pb2.py +25 -0
  281. streamlit/proto/ParentMessage_pb2.pyi +53 -0
  282. streamlit/proto/PlotlyChart_pb2.py +27 -0
  283. streamlit/proto/PlotlyChart_pb2.pyi +96 -0
  284. streamlit/proto/Progress_pb2.py +25 -0
  285. streamlit/proto/Progress_pb2.pyi +50 -0
  286. streamlit/proto/Radio_pb2.py +26 -0
  287. streamlit/proto/Radio_pb2.pyi +104 -0
  288. streamlit/proto/RootContainer_pb2.py +25 -0
  289. streamlit/proto/RootContainer_pb2.pyi +56 -0
  290. streamlit/proto/Selectbox_pb2.py +26 -0
  291. streamlit/proto/Selectbox_pb2.pyi +107 -0
  292. streamlit/proto/SessionEvent_pb2.py +26 -0
  293. streamlit/proto/SessionEvent_pb2.pyi +72 -0
  294. streamlit/proto/SessionStatus_pb2.py +25 -0
  295. streamlit/proto/SessionStatus_pb2.pyi +64 -0
  296. streamlit/proto/Skeleton_pb2.py +27 -0
  297. streamlit/proto/Skeleton_pb2.pyi +75 -0
  298. streamlit/proto/Slider_pb2.py +30 -0
  299. streamlit/proto/Slider_pb2.pyi +161 -0
  300. streamlit/proto/Snow_pb2.py +25 -0
  301. streamlit/proto/Snow_pb2.pyi +48 -0
  302. streamlit/proto/Space_pb2.py +25 -0
  303. streamlit/proto/Space_pb2.pyi +48 -0
  304. streamlit/proto/Spinner_pb2.py +25 -0
  305. streamlit/proto/Spinner_pb2.pyi +56 -0
  306. streamlit/proto/Table_pb2.py +28 -0
  307. streamlit/proto/Table_pb2.pyi +83 -0
  308. streamlit/proto/TextAlignmentConfig_pb2.py +27 -0
  309. streamlit/proto/TextAlignmentConfig_pb2.pyi +69 -0
  310. streamlit/proto/TextArea_pb2.py +26 -0
  311. streamlit/proto/TextArea_pb2.pyi +97 -0
  312. streamlit/proto/TextInput_pb2.py +28 -0
  313. streamlit/proto/TextInput_pb2.pyi +124 -0
  314. streamlit/proto/Text_pb2.py +25 -0
  315. streamlit/proto/Text_pb2.pyi +53 -0
  316. streamlit/proto/TimeInput_pb2.py +26 -0
  317. streamlit/proto/TimeInput_pb2.pyi +86 -0
  318. streamlit/proto/Toast_pb2.py +25 -0
  319. streamlit/proto/Toast_pb2.pyi +64 -0
  320. streamlit/proto/Transient_pb2.py +26 -0
  321. streamlit/proto/Transient_pb2.pyi +53 -0
  322. streamlit/proto/VegaLiteChart_pb2.py +27 -0
  323. streamlit/proto/VegaLiteChart_pb2.pyi +92 -0
  324. streamlit/proto/Video_pb2.py +30 -0
  325. streamlit/proto/Video_pb2.pyi +129 -0
  326. streamlit/proto/WidgetStates_pb2.py +31 -0
  327. streamlit/proto/WidgetStates_pb2.pyi +157 -0
  328. streamlit/proto/WidthConfig_pb2.py +25 -0
  329. streamlit/proto/WidthConfig_pb2.pyi +61 -0
  330. streamlit/proto/__init__.py +15 -0
  331. streamlit/proto/openmetrics_data_model_pb2.py +58 -0
  332. streamlit/proto/openmetrics_data_model_pb2.pyi +558 -0
  333. streamlit/py.typed +0 -0
  334. streamlit/runtime/__init__.py +50 -0
  335. streamlit/runtime/app_session.py +1302 -0
  336. streamlit/runtime/caching/__init__.py +118 -0
  337. streamlit/runtime/caching/cache_data_api.py +775 -0
  338. streamlit/runtime/caching/cache_errors.py +143 -0
  339. streamlit/runtime/caching/cache_resource_api.py +756 -0
  340. streamlit/runtime/caching/cache_type.py +33 -0
  341. streamlit/runtime/caching/cache_utils.py +601 -0
  342. streamlit/runtime/caching/cached_message_replay.py +290 -0
  343. streamlit/runtime/caching/hashing.py +655 -0
  344. streamlit/runtime/caching/legacy_cache_api.py +170 -0
  345. streamlit/runtime/caching/storage/__init__.py +29 -0
  346. streamlit/runtime/caching/storage/cache_storage_protocol.py +236 -0
  347. streamlit/runtime/caching/storage/dummy_cache_storage.py +60 -0
  348. streamlit/runtime/caching/storage/in_memory_cache_storage_wrapper.py +159 -0
  349. streamlit/runtime/caching/storage/local_disk_cache_storage.py +223 -0
  350. streamlit/runtime/caching/ttl_cleanup_cache.py +85 -0
  351. streamlit/runtime/connection_factory.py +498 -0
  352. streamlit/runtime/context.py +449 -0
  353. streamlit/runtime/context_util.py +49 -0
  354. streamlit/runtime/credentials.py +355 -0
  355. streamlit/runtime/download_data_util.py +53 -0
  356. streamlit/runtime/forward_msg_cache.py +101 -0
  357. streamlit/runtime/forward_msg_queue.py +263 -0
  358. streamlit/runtime/fragment.py +441 -0
  359. streamlit/runtime/media_file_manager.py +409 -0
  360. streamlit/runtime/media_file_storage.py +143 -0
  361. streamlit/runtime/memory_media_file_storage.py +201 -0
  362. streamlit/runtime/memory_session_storage.py +77 -0
  363. streamlit/runtime/memory_uploaded_file_manager.py +149 -0
  364. streamlit/runtime/metrics_util.py +612 -0
  365. streamlit/runtime/pages_manager.py +160 -0
  366. streamlit/runtime/runtime.py +775 -0
  367. streamlit/runtime/runtime_util.py +108 -0
  368. streamlit/runtime/script_data.py +46 -0
  369. streamlit/runtime/scriptrunner/__init__.py +38 -0
  370. streamlit/runtime/scriptrunner/exec_code.py +167 -0
  371. streamlit/runtime/scriptrunner/magic.py +277 -0
  372. streamlit/runtime/scriptrunner/magic_funcs.py +32 -0
  373. streamlit/runtime/scriptrunner/script_cache.py +89 -0
  374. streamlit/runtime/scriptrunner/script_runner.py +805 -0
  375. streamlit/runtime/scriptrunner_utils/__init__.py +19 -0
  376. streamlit/runtime/scriptrunner_utils/exceptions.py +44 -0
  377. streamlit/runtime/scriptrunner_utils/script_requests.py +311 -0
  378. streamlit/runtime/scriptrunner_utils/script_run_context.py +277 -0
  379. streamlit/runtime/secrets.py +533 -0
  380. streamlit/runtime/session_manager.py +430 -0
  381. streamlit/runtime/state/__init__.py +47 -0
  382. streamlit/runtime/state/common.py +256 -0
  383. streamlit/runtime/state/presentation.py +85 -0
  384. streamlit/runtime/state/query_params.py +767 -0
  385. streamlit/runtime/state/query_params_proxy.py +222 -0
  386. streamlit/runtime/state/safe_session_state.py +146 -0
  387. streamlit/runtime/state/session_state.py +1299 -0
  388. streamlit/runtime/state/session_state_proxy.py +153 -0
  389. streamlit/runtime/state/widgets.py +197 -0
  390. streamlit/runtime/stats.py +356 -0
  391. streamlit/runtime/theme_util.py +148 -0
  392. streamlit/runtime/uploaded_file_manager.py +152 -0
  393. streamlit/runtime/websocket_session_manager.py +301 -0
  394. streamlit/source_util.py +97 -0
  395. streamlit/starlette.py +34 -0
  396. streamlit/string_util.py +264 -0
  397. streamlit/temporary_directory.py +67 -0
  398. streamlit/testing/__init__.py +13 -0
  399. streamlit/testing/v1/__init__.py +17 -0
  400. streamlit/testing/v1/app_test.py +1089 -0
  401. streamlit/testing/v1/element_tree.py +2272 -0
  402. streamlit/testing/v1/local_script_runner.py +176 -0
  403. streamlit/testing/v1/util.py +61 -0
  404. streamlit/time_util.py +73 -0
  405. streamlit/type_util.py +480 -0
  406. streamlit/url_util.py +120 -0
  407. streamlit/user_info.py +698 -0
  408. streamlit/util.py +108 -0
  409. streamlit/vendor/__init__.py +0 -0
  410. streamlit/vendor/pympler/__init__.py +0 -0
  411. streamlit/vendor/pympler/asizeof.py +2870 -0
  412. streamlit/version.py +18 -0
  413. streamlit/watcher/__init__.py +28 -0
  414. streamlit/watcher/event_based_path_watcher.py +500 -0
  415. streamlit/watcher/folder_black_list.py +82 -0
  416. streamlit/watcher/local_sources_watcher.py +297 -0
  417. streamlit/watcher/path_watcher.py +244 -0
  418. streamlit/watcher/polling_path_watcher.py +138 -0
  419. streamlit/watcher/util.py +223 -0
  420. streamlit/web/__init__.py +13 -0
  421. streamlit/web/bootstrap.py +463 -0
  422. streamlit/web/cache_storage_manager_config.py +38 -0
  423. streamlit/web/cli.py +465 -0
  424. streamlit/web/server/__init__.py +30 -0
  425. streamlit/web/server/app_discovery.py +422 -0
  426. streamlit/web/server/app_static_file_handler.py +102 -0
  427. streamlit/web/server/authlib_tornado_integration.py +125 -0
  428. streamlit/web/server/bidi_component_request_handler.py +193 -0
  429. streamlit/web/server/browser_websocket_handler.py +341 -0
  430. streamlit/web/server/component_file_utils.py +105 -0
  431. streamlit/web/server/component_request_handler.py +107 -0
  432. streamlit/web/server/media_file_handler.py +148 -0
  433. streamlit/web/server/oauth_authlib_routes.py +314 -0
  434. streamlit/web/server/oidc_mixin.py +138 -0
  435. streamlit/web/server/routes.py +257 -0
  436. streamlit/web/server/server.py +555 -0
  437. streamlit/web/server/server_util.py +235 -0
  438. streamlit/web/server/starlette/__init__.py +23 -0
  439. streamlit/web/server/starlette/starlette_app.py +541 -0
  440. streamlit/web/server/starlette/starlette_app_utils.py +306 -0
  441. streamlit/web/server/starlette/starlette_auth_routes.py +584 -0
  442. streamlit/web/server/starlette/starlette_gzip_middleware.py +121 -0
  443. streamlit/web/server/starlette/starlette_path_security_middleware.py +97 -0
  444. streamlit/web/server/starlette/starlette_routes.py +884 -0
  445. streamlit/web/server/starlette/starlette_server.py +496 -0
  446. streamlit/web/server/starlette/starlette_server_config.py +55 -0
  447. streamlit/web/server/starlette/starlette_static_routes.py +181 -0
  448. streamlit/web/server/starlette/starlette_websocket.py +560 -0
  449. streamlit/web/server/stats_request_handler.py +116 -0
  450. streamlit/web/server/upload_file_request_handler.py +158 -0
  451. streamlit/web/server/websocket_headers.py +56 -0
  452. streamlit_data_editor_plus-0.1.0.dist-info/METADATA +76 -0
  453. streamlit_data_editor_plus-0.1.0.dist-info/RECORD +456 -0
  454. streamlit_data_editor_plus-0.1.0.dist-info/WHEEL +5 -0
  455. streamlit_data_editor_plus-0.1.0.dist-info/entry_points.txt +2 -0
  456. streamlit_data_editor_plus-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,356 @@
1
+ # Copyright (c) Streamlit Inc. (2018-2022) Snowflake Inc. (2022-2026)
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 itertools
18
+ from typing import TYPE_CHECKING, Final, NamedTuple, Protocol, runtime_checkable
19
+
20
+ CACHE_MEMORY_FAMILY: Final = "cache_memory_bytes"
21
+ SESSION_EVENTS_FAMILY: Final = "session_events_total"
22
+ SESSION_DURATION_FAMILY: Final = "session_duration_seconds_total"
23
+ ACTIVE_SESSIONS_FAMILY: Final = "active_sessions"
24
+
25
+ if TYPE_CHECKING:
26
+ from collections.abc import Mapping, Sequence
27
+
28
+ from streamlit.proto.openmetrics_data_model_pb2 import (
29
+ Metric as MetricProto,
30
+ )
31
+ from streamlit.proto.openmetrics_data_model_pb2 import (
32
+ MetricType,
33
+ )
34
+
35
+
36
+ @runtime_checkable
37
+ class Stat(Protocol):
38
+ """Protocol for a stat that can be serialized to OpenMetrics format.
39
+
40
+ All stats must have these fields to identify the metric family they belong to
41
+ and provide metadata for OpenMetrics serialization.
42
+ """
43
+
44
+ @property
45
+ def family_name(self) -> str:
46
+ """The name of the metric family (e.g. 'cache_memory_bytes')."""
47
+
48
+ @property
49
+ def type(self) -> str:
50
+ """The OpenMetrics type (e.g. 'gauge', 'counter')."""
51
+
52
+ @property
53
+ def unit(self) -> str:
54
+ """The unit of the metric (e.g. 'bytes')."""
55
+
56
+ @property
57
+ def help(self) -> str:
58
+ """A description of the metric."""
59
+
60
+ def to_metric_str(self) -> str:
61
+ """Convert this stat to an OpenMetrics-formatted string."""
62
+
63
+ def marshall_metric_proto(self, metric: MetricProto) -> None:
64
+ """Fill an OpenMetrics `Metric` protobuf object."""
65
+
66
+
67
+ # TODO(vdonato): Could we use GaugeStat below and get rid of this class?
68
+ # We'd have to make some minor changes to use the other class, but overall the
69
+ # changes should be relatively minor.
70
+ class CacheStat(NamedTuple):
71
+ """Describes a single cache entry.
72
+
73
+ Properties
74
+ ----------
75
+ category_name : str
76
+ A human-readable name for the cache "category" that the entry belongs
77
+ to - e.g. "st.memo", "session_state", etc.
78
+ cache_name : str
79
+ A human-readable name for cache instance that the entry belongs to.
80
+ For "st.memo" and other function decorator caches, this might be the
81
+ name of the cached function. If the cache category doesn't have
82
+ multiple separate cache instances, this can just be the empty string.
83
+ byte_length : int
84
+ The entry's memory footprint in bytes.
85
+ """
86
+
87
+ category_name: str
88
+ cache_name: str
89
+ byte_length: int
90
+
91
+ # Stat Protocol fields with default values for cache metrics
92
+ @property
93
+ def family_name(self) -> str:
94
+ return CACHE_MEMORY_FAMILY
95
+
96
+ @property
97
+ def type(self) -> str:
98
+ return "gauge"
99
+
100
+ @property
101
+ def unit(self) -> str:
102
+ return "bytes"
103
+
104
+ @property
105
+ def help(self) -> str:
106
+ return "Total memory consumed by a cache."
107
+
108
+ def to_metric_str(self) -> str:
109
+ return f'{self.family_name}{{cache_type="{self.category_name}",cache="{self.cache_name}"}} {self.byte_length}'
110
+
111
+ def marshall_metric_proto(self, metric: MetricProto) -> None:
112
+ """Fill an OpenMetrics `Metric` protobuf object."""
113
+ label = metric.labels.add()
114
+ label.name = "cache_type"
115
+ label.value = self.category_name
116
+
117
+ label = metric.labels.add()
118
+ label.name = "cache"
119
+ label.value = self.cache_name
120
+
121
+ metric_point = metric.metric_points.add()
122
+ metric_point.gauge_value.int_value = self.byte_length
123
+
124
+
125
+ def group_cache_stats(stats: list[CacheStat]) -> list[CacheStat]:
126
+ """Group a list of CacheStats by category_name and cache_name and sum byte_length."""
127
+
128
+ def key_function(individual_stat: CacheStat) -> tuple[str, str]:
129
+ return individual_stat.category_name, individual_stat.cache_name
130
+
131
+ result: list[CacheStat] = []
132
+
133
+ sorted_stats = sorted(stats, key=key_function)
134
+ grouped_stats = itertools.groupby(sorted_stats, key=key_function)
135
+
136
+ for (category_name, cache_name), single_group_stats in grouped_stats:
137
+ result.append(
138
+ CacheStat(
139
+ category_name=category_name,
140
+ cache_name=cache_name,
141
+ byte_length=sum(item.byte_length for item in single_group_stats),
142
+ )
143
+ )
144
+ return result
145
+
146
+
147
+ class CounterStat(NamedTuple):
148
+ """A counter stat.
149
+
150
+ Properties
151
+ ----------
152
+ family_name : str
153
+ The name of the metric family (e.g. 'session_events_total').
154
+ value : int
155
+ The current count value.
156
+ labels : dict[str, str] | None
157
+ Labels to identify this specific counter (e.g. {"type": "connection"}).
158
+ unit : str
159
+ The unit of the metric (e.g. '' for unitless).
160
+ help : str
161
+ A description of the metric.
162
+ """
163
+
164
+ family_name: str
165
+ value: int
166
+ labels: dict[str, str] | None = None
167
+ unit: str = ""
168
+ help: str = ""
169
+
170
+ @property
171
+ def type(self) -> str:
172
+ return "counter"
173
+
174
+ def to_metric_str(self) -> str:
175
+ if self.labels:
176
+ labels_str = ",".join(f'{k}="{v}"' for k, v in sorted(self.labels.items()))
177
+ return f"{self.family_name}{{{labels_str}}} {self.value}"
178
+ return f"{self.family_name} {self.value}"
179
+
180
+ def marshall_metric_proto(self, metric: MetricProto) -> None:
181
+ """Fill an OpenMetrics `Metric` protobuf object."""
182
+ if self.labels:
183
+ for name, value in sorted(self.labels.items()):
184
+ label = metric.labels.add()
185
+ label.name = name
186
+ label.value = value
187
+
188
+ metric_point = metric.metric_points.add()
189
+ metric_point.counter_value.int_value = self.value
190
+
191
+
192
+ class GaugeStat(NamedTuple):
193
+ """A gauge stat.
194
+
195
+ Properties
196
+ ----------
197
+ family_name : str
198
+ The name of the metric family (e.g. 'active_sessions').
199
+ value : int
200
+ The current gauge value.
201
+ labels : dict[str, str] | None
202
+ Optional labels to identify this specific gauge.
203
+ unit : str
204
+ The unit of the metric (e.g. '' for unitless).
205
+ help : str
206
+ A description of the metric.
207
+ """
208
+
209
+ family_name: str
210
+ value: int
211
+ labels: dict[str, str] | None = None
212
+ unit: str = ""
213
+ help: str = ""
214
+
215
+ @property
216
+ def type(self) -> str:
217
+ return "gauge"
218
+
219
+ def to_metric_str(self) -> str:
220
+ if self.labels:
221
+ labels_str = ",".join(f'{k}="{v}"' for k, v in sorted(self.labels.items()))
222
+ return f"{self.family_name}{{{labels_str}}} {self.value}"
223
+ return f"{self.family_name} {self.value}"
224
+
225
+ def marshall_metric_proto(self, metric: MetricProto) -> None:
226
+ """Fill an OpenMetrics `Metric` protobuf object."""
227
+ if self.labels:
228
+ for name, value in sorted(self.labels.items()):
229
+ label = metric.labels.add()
230
+ label.name = name
231
+ label.value = value
232
+
233
+ metric_point = metric.metric_points.add()
234
+ metric_point.gauge_value.int_value = self.value
235
+
236
+
237
+ def metric_type_string_to_proto(type_string: str) -> MetricType.ValueType:
238
+ """Convert a metric type string to its corresponding proto enum value."""
239
+ from streamlit.proto.openmetrics_data_model_pb2 import (
240
+ COUNTER,
241
+ GAUGE,
242
+ GAUGE_HISTOGRAM,
243
+ HISTOGRAM,
244
+ INFO,
245
+ STATE_SET,
246
+ SUMMARY,
247
+ UNKNOWN,
248
+ )
249
+
250
+ type_map = {
251
+ "gauge": GAUGE,
252
+ "counter": COUNTER,
253
+ "state_set": STATE_SET,
254
+ "info": INFO,
255
+ "histogram": HISTOGRAM,
256
+ "gauge_histogram": GAUGE_HISTOGRAM,
257
+ "summary": SUMMARY,
258
+ }
259
+ return type_map.get(type_string, UNKNOWN)
260
+
261
+
262
+ @runtime_checkable
263
+ class StatsProvider(Protocol):
264
+ @property
265
+ def stats_families(self) -> Sequence[str]:
266
+ """The metric family names that this provider supports.
267
+
268
+ The StatsManager uses this property to determine which providers to call
269
+ when specific metric families are requested.
270
+ """
271
+
272
+ def get_stats(
273
+ self, family_names: Sequence[str] | None = None
274
+ ) -> Mapping[str, Sequence[Stat]]:
275
+ """Return stats for the specified metric families.
276
+
277
+ Parameters
278
+ ----------
279
+ family_names : Sequence[str] | None
280
+ If provided, only stats for these metric families should be computed
281
+ and returned. If None, stats for all families this provider supports
282
+ should be returned. Providers should check this parameter and skip
283
+ computing expensive stats for families that aren't requested.
284
+
285
+ Returns
286
+ -------
287
+ Mapping[str, Sequence[Stat]]
288
+ A mapping from metric family names to sequences of Stat objects.
289
+ """
290
+ raise NotImplementedError
291
+
292
+
293
+ class StatsManager:
294
+ def __init__(self) -> None:
295
+ self._providers_by_family: dict[str, list[StatsProvider]] = {}
296
+
297
+ def register_provider(self, provider: StatsProvider) -> None:
298
+ """Register a StatsProvider with the manager.
299
+
300
+ This function is not thread-safe. Call it immediately after creation.
301
+
302
+ Parameters
303
+ ----------
304
+ provider : StatsProvider
305
+ The stats provider to register. The provider's `stats_families`
306
+ property determines which metric families it will be called for.
307
+ """
308
+ for family in provider.stats_families:
309
+ if family not in self._providers_by_family:
310
+ self._providers_by_family[family] = []
311
+ self._providers_by_family[family].append(provider)
312
+
313
+ def get_stats(
314
+ self, family_names: Sequence[str] | None = None
315
+ ) -> Mapping[str, Sequence[Stat]]:
316
+ """Return registered stats grouped by metric family name.
317
+
318
+ Parameters
319
+ ----------
320
+ family_names : Sequence[str] | None
321
+ If provided, only stats for these metric families will be returned.
322
+ If None, stats for all registered families are returned.
323
+
324
+ Returns
325
+ -------
326
+ Mapping[str, Sequence[Stat]]
327
+ A mapping from metric family names to sequences of Stat objects
328
+ from all providers.
329
+ """
330
+ result: dict[str, Sequence[Stat]] = {}
331
+
332
+ families_to_query = family_names or list(self._providers_by_family.keys())
333
+
334
+ # Track which providers we've already queried to avoid duplicates.
335
+ # The same provider may be registered for multiple families, and we call
336
+ # `provider.get_stats(family_names)` below to fetch all stat families for
337
+ # a given stats provider at once.
338
+ queried_providers: set[int] = set()
339
+
340
+ for family in families_to_query:
341
+ for provider in self._providers_by_family.get(family, []):
342
+ provider_id = id(provider)
343
+ if provider_id in queried_providers:
344
+ continue
345
+ queried_providers.add(provider_id)
346
+
347
+ provider_stats = provider.get_stats(family_names)
348
+ for fname, stats in provider_stats.items():
349
+ if fname not in result:
350
+ result[fname] = []
351
+ # Use list() to convert Sequence to list for concatenation.
352
+ # This is needed for type covariance: providers return
353
+ # Mapping[str, Sequence[Stat]] but we build a dict of lists.
354
+ result[fname] = list(result[fname]) + list(stats)
355
+
356
+ return result
@@ -0,0 +1,148 @@
1
+ # Copyright (c) Streamlit Inc. (2018-2022) Snowflake Inc. (2022-2026)
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
+
16
+ from __future__ import annotations
17
+
18
+ from typing import TYPE_CHECKING
19
+
20
+ from streamlit.errors import StreamlitAPIException
21
+ from streamlit.url_util import is_url
22
+
23
+ if TYPE_CHECKING:
24
+ from streamlit.proto.NewSession_pb2 import CustomThemeConfig
25
+
26
+
27
+ def _parse_font_config(
28
+ font_config: str | None,
29
+ property_name: str,
30
+ ) -> tuple[str, str | None]:
31
+ """Parse a single font configuration string.
32
+
33
+ Args:
34
+ font_config: The font configuration string (e.g., "Inter" or "Inter:https://...")
35
+ property_name: The property name for error messages ("font", "codeFont", "headingFont")
36
+
37
+ Returns
38
+ -------
39
+ A tuple of (font_name, source_url). source_url is None if not provided or not valid.
40
+ """
41
+ if not font_config:
42
+ return "", None
43
+
44
+ # Strip leading/trailing whitespace from the config
45
+ font_config = font_config.strip()
46
+
47
+ if ":" not in font_config:
48
+ # No colon found, treat the entire string as the font name
49
+ return font_config, None
50
+
51
+ # Note: it is possible there are multiple colons in the string, so we need to split on the first colon.
52
+ font_name, source_url = font_config.split(":", 1)
53
+ # Strip whitespace from both font name and source
54
+ font_name = font_name.strip()
55
+ source_url = source_url.strip()
56
+
57
+ # Check that the href does not contain multiple fonts, so we confirm that "family="
58
+ # only shows up once in the source string (structure applies to Google Fonts only)
59
+ family_occurrences = source_url.count("family=")
60
+ if family_occurrences > 1:
61
+ raise StreamlitAPIException(
62
+ f"The source URL specified in the {property_name} property of config.toml contains multiple fonts. "
63
+ "Please specify only one font in the source URL."
64
+ )
65
+
66
+ is_valid_url = is_url(source_url)
67
+
68
+ # If the source is a valid URL (http/https) but no font name is provided, throw an exception
69
+ if is_valid_url and not font_name:
70
+ raise StreamlitAPIException(
71
+ f"A font family name is required when specifying a source URL "
72
+ f"for the {property_name} property in config.toml."
73
+ )
74
+
75
+ if is_valid_url:
76
+ return font_name, source_url
77
+
78
+ return font_name, None
79
+
80
+
81
+ def _get_font_source_config_name(property_name: str, section: str) -> str:
82
+ """Get the config name for font sources based on property and section. This is used on the FE
83
+ as the id for the font source link in the html head.
84
+ """
85
+ if section == "theme":
86
+ return property_name
87
+ return f"{property_name}-sidebar"
88
+
89
+
90
+ def parse_fonts_with_source(
91
+ msg: CustomThemeConfig,
92
+ body_font_config: str | None,
93
+ code_font_config: str | None,
94
+ heading_font_config: str | None,
95
+ section: str,
96
+ ) -> CustomThemeConfig:
97
+ """Populate the CustomThemeConfig message with the font, codeFont, and headingFont fields set,
98
+ as well as the font_sources field to be added to the html head.
99
+
100
+ Args:
101
+ msg: CustomThemeConfig message to be populated.
102
+ body_font_config: A string with just the font name (e.g., "Inter") or in the format
103
+ "<font_family_name_here>:<source_url_here>".
104
+ code_font_config: A string with just the font name (e.g., "Roboto Mono") or in the format
105
+ "<code_font_family_name_here>:<source_url_here>".
106
+ heading_font_config: A string with just the font name (e.g., "Inter Bold") or in the format
107
+ "<heading_font_family_name_here>:<source_url_here>".
108
+ section: The section of the config.toml file to parse the fonts from.
109
+
110
+ Examples
111
+ --------
112
+ body_font_config: "Inter" (just font name)
113
+ code_font_config: "Tagesschrift:https://fonts.googleapis.com/css2?family=Tagesschrift&display=swap" (with source)
114
+ heading_font_config: "playwrite-cc-za:https://use.typekit.net/xxs7euo.css"
115
+
116
+ Returns
117
+ -------
118
+ Updated CustomThemeConfig message with the font, codeFont, and headingFont fields set.
119
+ Also sets sources in font_sources field to be added to the html (only when source URLs are provided).
120
+ """
121
+
122
+ # Parse body font config
123
+ body_font_name, body_font_source = _parse_font_config(body_font_config, "font")
124
+ if body_font_name:
125
+ msg.body_font = body_font_name
126
+ if body_font_source:
127
+ config_name = _get_font_source_config_name("font", section)
128
+ msg.font_sources.add(config_name=config_name, source_url=body_font_source)
129
+
130
+ # Parse code font config
131
+ code_font_name, code_font_source = _parse_font_config(code_font_config, "codeFont")
132
+ if code_font_name:
133
+ msg.code_font = code_font_name
134
+ if code_font_source:
135
+ config_name = _get_font_source_config_name("codeFont", section)
136
+ msg.font_sources.add(config_name=config_name, source_url=code_font_source)
137
+
138
+ # Parse heading font config
139
+ heading_font_name, heading_font_source = _parse_font_config(
140
+ heading_font_config, "headingFont"
141
+ )
142
+ if heading_font_name:
143
+ msg.heading_font = heading_font_name
144
+ if heading_font_source:
145
+ config_name = _get_font_source_config_name("headingFont", section)
146
+ msg.font_sources.add(config_name=config_name, source_url=heading_font_source)
147
+
148
+ return msg
@@ -0,0 +1,152 @@
1
+ # Copyright (c) Streamlit Inc. (2018-2022) Snowflake Inc. (2022-2026)
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 io
18
+ from abc import abstractmethod
19
+ from typing import TYPE_CHECKING, NamedTuple, Protocol
20
+
21
+ from streamlit import util
22
+ from streamlit.runtime.stats import StatsProvider
23
+
24
+ if TYPE_CHECKING:
25
+ from collections.abc import Sequence
26
+
27
+ from streamlit.proto.Common_pb2 import FileURLs as FileURLsProto
28
+
29
+
30
+ class UploadedFileRec(NamedTuple):
31
+ """Metadata and raw bytes for an uploaded file. Immutable."""
32
+
33
+ file_id: str
34
+ name: str
35
+ type: str
36
+ data: bytes
37
+
38
+
39
+ class UploadFileUrlInfo(NamedTuple):
40
+ """Information we provide for single file in get_upload_urls."""
41
+
42
+ file_id: str
43
+ upload_url: str
44
+ delete_url: str
45
+
46
+
47
+ class DeletedFile(NamedTuple):
48
+ """Represents a deleted file in deserialized values for st.file_uploader and
49
+ st.camera_input.
50
+
51
+ Return this from st.file_uploader and st.camera_input deserialize (so they can
52
+ be used in session_state), when widget value contains file record that is missing
53
+ from the storage.
54
+ DeleteFile instances filtered out before return final value to the user in script,
55
+ or before sending to frontend.
56
+ """
57
+
58
+ file_id: str
59
+
60
+
61
+ class UploadedFile(io.BytesIO):
62
+ """A mutable uploaded file.
63
+
64
+ This class extends BytesIO, which has copy-on-write semantics when
65
+ initialized with `bytes`.
66
+ """
67
+
68
+ def __init__(self, record: UploadedFileRec, file_urls: FileURLsProto) -> None:
69
+ # BytesIO's copy-on-write semantics doesn't seem to be mentioned in
70
+ # the Python docs - possibly because it's a CPython-only optimization
71
+ # and not guaranteed to be in other Python runtimes. But it's detailed
72
+ # here: https://hg.python.org/cpython/rev/79a5fbe2c78f
73
+ super().__init__(record.data)
74
+ self.file_id = record.file_id
75
+ self.name = record.name
76
+ self.type = record.type
77
+ self.size = len(record.data)
78
+ self._file_urls = file_urls
79
+
80
+ def __eq__(self, other: object) -> bool:
81
+ if not isinstance(other, UploadedFile):
82
+ return NotImplemented
83
+ return self.file_id == other.file_id
84
+
85
+ def __hash__(self) -> int:
86
+ return hash(self.file_id)
87
+
88
+ def __repr__(self) -> str:
89
+ return util.repr_(self)
90
+
91
+
92
+ class UploadedFileManager(StatsProvider, Protocol):
93
+ """UploadedFileManager protocol, that should be implemented by the concrete
94
+ uploaded file managers.
95
+
96
+ It is responsible for:
97
+ - retrieving files by session_id and file_id for st.file_uploader and
98
+ st.camera_input
99
+ - cleaning up uploaded files associated with session on session end
100
+
101
+ It should be created during Runtime initialization.
102
+
103
+ Optionally UploadedFileManager could be responsible for issuing URLs which will be
104
+ used by frontend to upload files to.
105
+ """
106
+
107
+ @abstractmethod
108
+ def get_files(
109
+ self, session_id: str, file_ids: Sequence[str]
110
+ ) -> list[UploadedFileRec]:
111
+ """Return a list of UploadedFileRec for a given sequence of file_ids.
112
+
113
+ Parameters
114
+ ----------
115
+ session_id
116
+ The ID of the session that owns the files.
117
+ file_ids
118
+ The sequence of ids associated with files to retrieve.
119
+
120
+ Returns
121
+ -------
122
+ List[UploadedFileRec]
123
+ A list of URL UploadedFileRec instances, each instance contains information
124
+ about uploaded file.
125
+ """
126
+ raise NotImplementedError
127
+
128
+ @abstractmethod
129
+ def remove_session_files(self, session_id: str) -> None:
130
+ """Remove all files associated with a given session."""
131
+ raise NotImplementedError
132
+
133
+ def get_upload_urls(
134
+ self, session_id: str, file_names: Sequence[str]
135
+ ) -> list[UploadFileUrlInfo]:
136
+ """Return a list of UploadFileUrlInfo for a given sequence of file_names.
137
+ Optional to implement, issuing of URLs could be done by other service.
138
+
139
+ Parameters
140
+ ----------
141
+ session_id
142
+ The ID of the session that request URLs.
143
+ file_names
144
+ The sequence of file names for which URLs are requested
145
+
146
+ Returns
147
+ -------
148
+ List[UploadFileUrlInfo]
149
+ A list of UploadFileUrlInfo instances, each instance contains information
150
+ about uploaded file URLs.
151
+ """
152
+ raise NotImplementedError