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,1168 @@
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 json
18
+ from dataclasses import dataclass
19
+ from decimal import Decimal
20
+ from typing import (
21
+ TYPE_CHECKING,
22
+ Any,
23
+ Final,
24
+ Literal,
25
+ TypeAlias,
26
+ TypedDict,
27
+ TypeVar,
28
+ Union,
29
+ cast,
30
+ overload,
31
+ )
32
+
33
+ from typing_extensions import Required
34
+
35
+ from streamlit import dataframe_util
36
+ from streamlit import logger as _logger
37
+ from streamlit.deprecation_util import (
38
+ make_deprecated_name_warning,
39
+ show_deprecation_warning,
40
+ )
41
+ from streamlit.elements.lib.column_config_utils import (
42
+ INDEX_IDENTIFIER,
43
+ ColumnConfigMapping,
44
+ ColumnConfigMappingInput,
45
+ ColumnDataKind,
46
+ DataframeSchema,
47
+ apply_data_specific_configs,
48
+ determine_dataframe_schema,
49
+ is_type_compatible,
50
+ marshall_column_config,
51
+ process_config_mapping,
52
+ update_column_config,
53
+ )
54
+ from streamlit.elements.lib.form_utils import current_form_id
55
+ from streamlit.elements.lib.layout_utils import (
56
+ Height,
57
+ LayoutConfig,
58
+ Width,
59
+ validate_height,
60
+ validate_width,
61
+ )
62
+ from streamlit.elements.lib.pandas_styler_utils import marshall_styler
63
+ from streamlit.elements.lib.policies import check_widget_policies
64
+ from streamlit.elements.lib.utils import Key, compute_and_register_element_id, to_key
65
+ from streamlit.errors import StreamlitAPIException
66
+ from streamlit.proto.Dataframe_pb2 import Dataframe as DataframeProto
67
+ from streamlit.runtime.metrics_util import gather_metrics
68
+ from streamlit.runtime.scriptrunner_utils.script_run_context import get_script_run_ctx
69
+ from streamlit.runtime.state import (
70
+ WidgetArgs,
71
+ WidgetCallback,
72
+ WidgetKwargs,
73
+ register_widget,
74
+ )
75
+ from streamlit.type_util import is_list_like, is_type
76
+ from streamlit.util import calc_md5
77
+
78
+ if TYPE_CHECKING:
79
+ from collections.abc import Iterable, Mapping
80
+
81
+ import numpy as np
82
+ import pandas as pd
83
+ import pyarrow as pa
84
+ from pandas.io.formats.style import Styler
85
+
86
+ from streamlit.delta_generator import DeltaGenerator
87
+
88
+ _LOGGER: Final = _logger.get_logger(__name__)
89
+
90
+ # All formats that support direct editing, meaning that these
91
+ # formats will be returned with the same type when used with data_editor.
92
+ EditableData = TypeVar(
93
+ "EditableData",
94
+ bound=dataframe_util.DataFrameGenericAlias[Any]
95
+ | tuple[Any]
96
+ | list[Any]
97
+ | set[Any]
98
+ | dict[str, Any],
99
+ )
100
+
101
+
102
+ # All data types supported by the data editor.
103
+ DataTypes: TypeAlias = Union[
104
+ "pd.DataFrame",
105
+ "pd.Series[Any]",
106
+ "pd.Index[Any]",
107
+ "Styler",
108
+ "pa.Table",
109
+ "np.ndarray[Any, np.dtype[np.float64]]",
110
+ tuple[Any],
111
+ list[Any],
112
+ set[Any],
113
+ dict[str, Any],
114
+ ]
115
+
116
+
117
+ class EditingState(TypedDict, total=False):
118
+ """
119
+ A dictionary representing the current state of the data editor.
120
+
121
+ Attributes
122
+ ----------
123
+ edited_rows : Dict[int, Dict[str, str | int | float | bool | None]]
124
+ An hierarchical mapping of edited cells based on:
125
+ row position -> column name -> value.
126
+
127
+ added_rows : List[Dict[str, str | int | float | bool | None]]
128
+ A list of added rows, where each row is a mapping from column name to
129
+ the cell value.
130
+
131
+ deleted_rows : List[int]
132
+ A list of deleted rows, where each row is the numerical position of
133
+ the deleted row.
134
+ """
135
+
136
+ edited_rows: Required[dict[int, dict[str, str | int | float | bool | None]]]
137
+ added_rows: Required[list[dict[str, str | int | float | bool | None]]]
138
+ deleted_rows: Required[list[int]]
139
+
140
+
141
+ @dataclass
142
+ class DataEditorSerde:
143
+ """DataEditorSerde is used to serialize and deserialize the data editor state."""
144
+
145
+ def deserialize(self, ui_value: str | None) -> EditingState:
146
+ data_editor_state: EditingState = cast(
147
+ "EditingState",
148
+ {
149
+ "edited_rows": {},
150
+ "added_rows": [],
151
+ "deleted_rows": [],
152
+ }
153
+ if ui_value is None
154
+ else json.loads(ui_value),
155
+ )
156
+
157
+ # Make sure that all editing state keys are present:
158
+ if "edited_rows" not in data_editor_state:
159
+ data_editor_state["edited_rows"] = {} # type: ignore[unreachable]
160
+
161
+ if "deleted_rows" not in data_editor_state:
162
+ data_editor_state["deleted_rows"] = [] # type: ignore[unreachable]
163
+
164
+ if "added_rows" not in data_editor_state:
165
+ data_editor_state["added_rows"] = [] # type: ignore[unreachable]
166
+
167
+ # Convert the keys (numerical row positions) to integers.
168
+ # The keys are strings because they are serialized to JSON.
169
+ data_editor_state["edited_rows"] = {
170
+ int(k): v for k, v in data_editor_state["edited_rows"].items()
171
+ }
172
+ return data_editor_state
173
+
174
+ def serialize(self, editing_state: EditingState) -> str:
175
+ return json.dumps(editing_state, default=str)
176
+
177
+
178
+ def _parse_value(
179
+ value: str | int | float | bool | list[str] | None,
180
+ column_data_kind: ColumnDataKind,
181
+ ) -> Any:
182
+ """Convert a value to the correct type.
183
+
184
+ Parameters
185
+ ----------
186
+ value : str | int | float | bool | list[str] | None
187
+ The value to convert.
188
+
189
+ column_data_kind : ColumnDataKind
190
+ The determined data kind of the column. The column data kind refers to the
191
+ shared data type of the values in the column (e.g. int, float, str).
192
+
193
+ Returns
194
+ -------
195
+ The converted value.
196
+ """
197
+ if value is None:
198
+ return None
199
+
200
+ import pandas as pd
201
+
202
+ try:
203
+ if column_data_kind == ColumnDataKind.LIST:
204
+ return list(value) if is_list_like(value) else [value] # ty: ignore[invalid-argument-type]
205
+
206
+ if column_data_kind == ColumnDataKind.EMPTY:
207
+ # For empty columns, preserve the value type from the frontend.
208
+ # If it's a list (e.g., from multiselect), return as list.
209
+ # If it's a scalar (e.g., from number input), return as scalar.
210
+ return list(value) if is_list_like(value) else value # ty: ignore[invalid-argument-type]
211
+
212
+ if column_data_kind == ColumnDataKind.STRING:
213
+ return str(value)
214
+
215
+ # List values aren't supported for anything else than list column data kind.
216
+ # To make the type checker happy, we raise a TypeError here. However,
217
+ # This isn't expected to happen.
218
+ if isinstance(value, list):
219
+ raise TypeError( # noqa: TRY301
220
+ "List values are only supported by list, string and empty columns."
221
+ )
222
+
223
+ if column_data_kind == ColumnDataKind.INTEGER:
224
+ return int(value)
225
+
226
+ if column_data_kind == ColumnDataKind.FLOAT:
227
+ return float(value)
228
+
229
+ if column_data_kind == ColumnDataKind.BOOLEAN:
230
+ return bool(value)
231
+
232
+ if column_data_kind == ColumnDataKind.DECIMAL:
233
+ # Decimal theoretically can also be initialized via number values.
234
+ # However, using number values here seems to cause issues with Arrow
235
+ # serialization, once you try to render the returned dataframe.
236
+ return Decimal(str(value))
237
+
238
+ if column_data_kind == ColumnDataKind.TIMEDELTA:
239
+ return pd.Timedelta(value)
240
+
241
+ if column_data_kind in {
242
+ ColumnDataKind.DATETIME,
243
+ ColumnDataKind.DATE,
244
+ ColumnDataKind.TIME,
245
+ }:
246
+ datetime_value = pd.Timestamp(value)
247
+
248
+ if pd.isna(datetime_value):
249
+ return None # type: ignore[unreachable]
250
+
251
+ if column_data_kind == ColumnDataKind.DATETIME:
252
+ return datetime_value
253
+
254
+ if column_data_kind == ColumnDataKind.DATE:
255
+ return datetime_value.date()
256
+
257
+ if column_data_kind == ColumnDataKind.TIME:
258
+ return datetime_value.time()
259
+
260
+ except (ValueError, pd.errors.ParserError, TypeError) as ex:
261
+ _LOGGER.warning(
262
+ "Failed to parse value %s as %s.",
263
+ value,
264
+ column_data_kind,
265
+ exc_info=ex,
266
+ )
267
+ return None
268
+ return value
269
+
270
+
271
+ def _apply_cell_edits(
272
+ df: pd.DataFrame,
273
+ edited_rows: Mapping[
274
+ int, Mapping[str, str | int | float | bool | list[str] | None]
275
+ ],
276
+ dataframe_schema: DataframeSchema,
277
+ ) -> None:
278
+ """Apply cell edits to the provided dataframe (inplace).
279
+
280
+ Parameters
281
+ ----------
282
+ df : pd.DataFrame
283
+ The dataframe to apply the cell edits to.
284
+
285
+ edited_rows : Mapping[int, Mapping[str, str | int | float | bool | None]]
286
+ A hierarchical mapping based on row position -> column name -> value
287
+
288
+ dataframe_schema: DataframeSchema
289
+ The schema of the dataframe.
290
+ """
291
+ for row_id, row_changes in edited_rows.items():
292
+ row_pos = int(row_id)
293
+ for col_name, value in row_changes.items():
294
+ if col_name == INDEX_IDENTIFIER:
295
+ # The edited cell is part of the index
296
+ # TODO(lukasmasuch): To support multi-index in the future:
297
+ # use a tuple of values here instead of a single value
298
+ old_idx_value = df.index[row_pos]
299
+ new_idx_value = _parse_value(value, dataframe_schema[INDEX_IDENTIFIER])
300
+ df.rename(
301
+ index={old_idx_value: new_idx_value},
302
+ inplace=True, # noqa: PD002
303
+ )
304
+ else:
305
+ col_pos = df.columns.get_loc(col_name)
306
+ df.iat[row_pos, col_pos] = _parse_value( # type: ignore
307
+ value, dataframe_schema[col_name]
308
+ )
309
+
310
+
311
+ def _parse_added_row(
312
+ df: pd.DataFrame,
313
+ added_row: dict[str, Any],
314
+ dataframe_schema: DataframeSchema,
315
+ ) -> tuple[Any, list[Any]]:
316
+ """Parse the added row into an optional index value and a list of row values."""
317
+ index_value = None
318
+ new_row: list[Any] = [None for _ in range(df.shape[1])]
319
+ for col_name, value in added_row.items():
320
+ if col_name == INDEX_IDENTIFIER:
321
+ # TODO(lukasmasuch): To support multi-index in the future:
322
+ # use a tuple of values here instead of a single value
323
+ index_value = _parse_value(value, dataframe_schema[INDEX_IDENTIFIER])
324
+ else:
325
+ col_pos = cast("int", df.columns.get_loc(col_name))
326
+ new_row[col_pos] = _parse_value(value, dataframe_schema[col_name])
327
+
328
+ return index_value, new_row
329
+
330
+
331
+ def _assign_row_values(
332
+ df: pd.DataFrame,
333
+ row_label: Any,
334
+ row_values: list[Any],
335
+ ) -> None:
336
+ """Assign values to a dataframe row via a mapping.
337
+
338
+ This avoids numpy attempting to coerce nested sequences (e.g. lists) into
339
+ multi-dimensional arrays when a column legitimately stores list values.
340
+ """
341
+
342
+ df.loc[row_label] = dict(zip(df.columns, row_values, strict=True))
343
+
344
+
345
+ def _apply_row_additions(
346
+ df: pd.DataFrame,
347
+ added_rows: list[dict[str, Any]],
348
+ dataframe_schema: DataframeSchema,
349
+ ) -> None:
350
+ """Apply row additions to the provided dataframe (inplace).
351
+
352
+ Parameters
353
+ ----------
354
+ df : pd.DataFrame
355
+ The dataframe to apply the row additions to.
356
+
357
+ added_rows : List[Dict[str, Any]]
358
+ A list of row additions. Each row addition is a dictionary with the
359
+ column position as key and the new cell value as value.
360
+
361
+ dataframe_schema: DataframeSchema
362
+ The schema of the dataframe.
363
+ """
364
+
365
+ if not added_rows:
366
+ return
367
+
368
+ import pandas as pd
369
+
370
+ index_type: Literal["range", "integer", "other"] = "other"
371
+ # This is only used if the dataframe has a range or integer index that can be
372
+ # auto incremented:
373
+ index_stop: int | None = None
374
+ index_step: int | None = None
375
+
376
+ if isinstance(df.index, pd.RangeIndex):
377
+ # Extract metadata from the range index:
378
+ index_type = "range"
379
+ index_stop = df.index.stop
380
+ index_step = df.index.step
381
+ elif isinstance(df.index, pd.Index) and pd.api.types.is_integer_dtype(
382
+ df.index.dtype
383
+ ):
384
+ # Get highest integer value and increment it by 1 to get unique index value.
385
+ index_type = "integer"
386
+ index_stop = 0 if df.index.empty else df.index.max() + 1
387
+ index_step = 1
388
+
389
+ for added_row in added_rows:
390
+ index_value, new_row = _parse_added_row(df, added_row, dataframe_schema)
391
+
392
+ if index_value is not None and index_type != "range":
393
+ # Case 1: Non-range index with an explicitly provided index value
394
+ # Add row using the user-provided index value.
395
+ # This handles any type of index that cannot be auto incremented.
396
+
397
+ # Note: this just overwrites the row in case the index value
398
+ # already exists. In the future, it would be better to
399
+ # require users to provide unique non-None values for the index with
400
+ # some kind of visual indications.
401
+ _assign_row_values(df, index_value, new_row)
402
+ continue
403
+
404
+ if index_stop is not None and index_step is not None:
405
+ # Case 2: Range or integer index that can be auto incremented.
406
+ # Add row using the next value in the sequence
407
+ _assign_row_values(df, index_stop, new_row)
408
+ # Increment to the next range index value
409
+ index_stop += index_step
410
+ continue
411
+
412
+ # Row cannot be added -> skip it and log a warning.
413
+ _LOGGER.warning(
414
+ "Cannot automatically add row for the index "
415
+ "of type %s without an explicit index value. Row addition skipped.",
416
+ type(df.index).__name__,
417
+ )
418
+
419
+
420
+ def _apply_row_deletions(df: pd.DataFrame, deleted_rows: list[int]) -> None:
421
+ """Apply row deletions to the provided dataframe (inplace).
422
+
423
+ Parameters
424
+ ----------
425
+ df : pd.DataFrame
426
+ The dataframe to apply the row deletions to.
427
+
428
+ deleted_rows : List[int]
429
+ A list of row numbers to delete.
430
+ """
431
+ # Drop rows based in numeric row positions
432
+ df.drop(df.index[deleted_rows], inplace=True) # noqa: PD002
433
+
434
+
435
+ def _apply_dataframe_edits(
436
+ df: pd.DataFrame,
437
+ data_editor_state: EditingState,
438
+ dataframe_schema: DataframeSchema,
439
+ ) -> None:
440
+ """Apply edits to the provided dataframe (inplace).
441
+
442
+ This includes cell edits, row additions and row deletions.
443
+
444
+ Parameters
445
+ ----------
446
+ df : pd.DataFrame
447
+ The dataframe to apply the edits to.
448
+
449
+ data_editor_state : EditingState
450
+ The editing state of the data editor component.
451
+
452
+ dataframe_schema: DataframeSchema
453
+ The schema of the dataframe.
454
+ """
455
+ if data_editor_state.get("edited_rows"):
456
+ _apply_cell_edits(df, data_editor_state["edited_rows"], dataframe_schema)
457
+
458
+ if data_editor_state.get("deleted_rows"):
459
+ _apply_row_deletions(df, data_editor_state["deleted_rows"])
460
+
461
+ if data_editor_state.get("added_rows"):
462
+ # The addition of new rows needs to happen after the deletion to not have
463
+ # unexpected side-effects, like https://github.com/streamlit/streamlit/issues/8854
464
+ _apply_row_additions(df, data_editor_state["added_rows"], dataframe_schema)
465
+
466
+
467
+ def _is_supported_index(df_index: pd.Index[Any]) -> bool:
468
+ """Check if the index is supported by the data editor component.
469
+
470
+ Parameters
471
+ ----------
472
+ df_index : pd.Index
473
+ The index to check.
474
+
475
+ Returns
476
+ -------
477
+ bool
478
+ True if the index is supported, False otherwise.
479
+ """
480
+ import pandas as pd
481
+
482
+ return (
483
+ type(df_index)
484
+ in {
485
+ pd.RangeIndex,
486
+ pd.Index,
487
+ pd.DatetimeIndex,
488
+ pd.CategoricalIndex,
489
+ # Interval type isn't editable currently:
490
+ # pd.IntervalIndex,
491
+ # Period type isn't editable currently:
492
+ # pd.PeriodIndex,
493
+ }
494
+ # We need to check these index types without importing, since they are
495
+ # deprecated and planned to be removed soon.
496
+ or is_type(df_index, "pandas.core.indexes.numeric.Int64Index")
497
+ or is_type(df_index, "pandas.core.indexes.numeric.Float64Index")
498
+ or is_type(df_index, "pandas.core.indexes.numeric.UInt64Index")
499
+ )
500
+
501
+
502
+ def _fix_column_headers(data_df: pd.DataFrame) -> None:
503
+ """Fix the column headers of the provided dataframe inplace to work
504
+ correctly for data editing.
505
+ """
506
+ import pandas as pd
507
+
508
+ if isinstance(data_df.columns, pd.MultiIndex):
509
+ # Flatten hierarchical column headers to a single level:
510
+ data_df.columns = [
511
+ "_".join(map(str, header)) for header in data_df.columns.to_flat_index()
512
+ ]
513
+ elif pd.api.types.infer_dtype(data_df.columns) != "string":
514
+ # If the column names are not all strings, we need to convert them to strings
515
+ # to avoid issues with editing:
516
+ data_df.rename(
517
+ columns={column: str(column) for column in data_df.columns},
518
+ inplace=True, # noqa: PD002
519
+ )
520
+
521
+
522
+ def _check_column_names(data_df: pd.DataFrame) -> None:
523
+ """Check if the column names in the provided dataframe are valid.
524
+
525
+ It's not allowed to have duplicate column names or column names that are
526
+ named ``_index``. If the column names are not valid, a ``StreamlitAPIException``
527
+ is raised.
528
+ """
529
+
530
+ if data_df.columns.empty:
531
+ return
532
+
533
+ # Check if the column names are unique and raise an exception if not.
534
+ # Add the names of the duplicated columns to the exception message.
535
+ duplicated_columns = data_df.columns[data_df.columns.duplicated()]
536
+ if len(duplicated_columns) > 0:
537
+ raise StreamlitAPIException(
538
+ f"All column names are required to be unique for usage with data editor. "
539
+ f"The following column names are duplicated: {list(duplicated_columns)}. "
540
+ f"Please rename the duplicated columns in the provided data."
541
+ )
542
+
543
+ # Check if the column names are not named "_index" and raise an exception if so.
544
+ if INDEX_IDENTIFIER in data_df.columns:
545
+ raise StreamlitAPIException(
546
+ f"The column name '{INDEX_IDENTIFIER}' is reserved for the index column "
547
+ f"and can't be used for data columns. Please rename the column in the "
548
+ f"provided data."
549
+ )
550
+
551
+
552
+ def _check_type_compatibilities(
553
+ data_df: pd.DataFrame,
554
+ columns_config: ColumnConfigMapping,
555
+ dataframe_schema: DataframeSchema,
556
+ ) -> None:
557
+ """Check column type to data type compatibility.
558
+
559
+ Iterates the index and all columns of the dataframe to check if
560
+ the configured column types are compatible with the underlying data types.
561
+
562
+ Parameters
563
+ ----------
564
+ data_df : pd.DataFrame
565
+ The dataframe to check the type compatibilities for.
566
+
567
+ columns_config : ColumnConfigMapping
568
+ A mapping of column to column configurations.
569
+
570
+ dataframe_schema : DataframeSchema
571
+ The schema of the dataframe.
572
+
573
+ Raises
574
+ ------
575
+ StreamlitAPIException
576
+ If a configured column type is editable and not compatible with the
577
+ underlying data type.
578
+ """
579
+ # TODO(lukasmasuch): Update this here to support multi-index in the future:
580
+ indices = [(INDEX_IDENTIFIER, data_df.index)]
581
+
582
+ for column in indices + list(data_df.items()):
583
+ column_name = str(column[0])
584
+ column_data_kind = dataframe_schema[column_name]
585
+
586
+ # TODO(lukasmasuch): support column config via numerical index here?
587
+ if column_name in columns_config:
588
+ column_config = columns_config[column_name]
589
+ if column_config.get("disabled") is True:
590
+ # Disabled columns are not checked for compatibility.
591
+ # This might change in the future.
592
+ continue
593
+
594
+ type_config = column_config.get("type_config")
595
+
596
+ if type_config is None:
597
+ continue
598
+
599
+ configured_column_type = type_config.get("type")
600
+
601
+ if configured_column_type is None:
602
+ # Just a safeguard, is not expected to happen.
603
+ continue # type: ignore[unreachable]
604
+
605
+ if is_type_compatible(configured_column_type, column_data_kind) is False:
606
+ raise StreamlitAPIException(
607
+ f"The configured column type `{configured_column_type}` for column "
608
+ f"`{column_name}` is not compatible for editing the underlying "
609
+ f"data type `{column_data_kind}`.\n\nYou have following options to "
610
+ f"fix this: 1) choose a compatible type 2) disable the column "
611
+ f"3) convert the column into a compatible data type."
612
+ )
613
+
614
+
615
+ class DataEditorMixin:
616
+ @overload
617
+ def data_editor(
618
+ self,
619
+ data: EditableData,
620
+ *,
621
+ width: Width = "stretch",
622
+ height: Height | Literal["auto"] = "auto",
623
+ use_container_width: bool | None = None,
624
+ hide_index: bool | None = None,
625
+ column_order: Iterable[str] | None = None,
626
+ column_config: ColumnConfigMappingInput | None = None,
627
+ num_rows: Literal["fixed", "dynamic", "add", "delete"] = "fixed",
628
+ disabled: bool | Iterable[str | int] = False,
629
+ key: Key | None = None,
630
+ on_change: WidgetCallback | None = None,
631
+ args: WidgetArgs | None = None,
632
+ kwargs: WidgetKwargs | None = None,
633
+ row_height: int | None = None,
634
+ placeholder: str | None = None,
635
+ ) -> EditableData:
636
+ pass
637
+
638
+ @overload
639
+ def data_editor(
640
+ self,
641
+ data: Any,
642
+ *,
643
+ width: Width = "stretch",
644
+ height: Height | Literal["auto"] = "auto",
645
+ use_container_width: bool | None = None,
646
+ hide_index: bool | None = None,
647
+ column_order: Iterable[str] | None = None,
648
+ column_config: ColumnConfigMappingInput | None = None,
649
+ num_rows: Literal["fixed", "dynamic", "add", "delete"] = "fixed",
650
+ disabled: bool | Iterable[str | int] = False,
651
+ key: Key | None = None,
652
+ on_change: WidgetCallback | None = None,
653
+ args: WidgetArgs | None = None,
654
+ kwargs: WidgetKwargs | None = None,
655
+ row_height: int | None = None,
656
+ placeholder: str | None = None,
657
+ ) -> pd.DataFrame:
658
+ pass
659
+
660
+ @gather_metrics("data_editor")
661
+ def data_editor(
662
+ self,
663
+ data: DataTypes,
664
+ *,
665
+ width: Width = "stretch",
666
+ height: Height | Literal["auto"] = "auto",
667
+ use_container_width: bool | None = None,
668
+ hide_index: bool | None = None,
669
+ column_order: Iterable[str] | None = None,
670
+ column_config: ColumnConfigMappingInput | None = None,
671
+ num_rows: Literal["fixed", "dynamic", "add", "delete"] = "fixed",
672
+ disabled: bool | Iterable[str | int] = False,
673
+ key: Key | None = None,
674
+ on_change: WidgetCallback | None = None,
675
+ args: WidgetArgs | None = None,
676
+ kwargs: WidgetKwargs | None = None,
677
+ row_height: int | None = None,
678
+ placeholder: str | None = None,
679
+ ) -> DataTypes:
680
+ """Display a data editor widget.
681
+
682
+ The data editor widget allows you to edit dataframes and many other data structures in a table-like UI.
683
+
684
+ Parameters
685
+ ----------
686
+ data : Anything supported by st.dataframe
687
+ The data to edit in the data editor.
688
+
689
+ .. note::
690
+ - Styles from ``pandas.Styler`` will only be applied to non-editable columns.
691
+ - Text and number formatting from ``column_config`` always takes
692
+ precedence over text and number formatting from ``pandas.Styler``.
693
+ - If your dataframe starts with an empty column, you should set
694
+ the column datatype in the underlying dataframe to ensure your
695
+ intended datatype, especially for integers versus floats.
696
+ - Mixing data types within a column can make the column uneditable.
697
+ - Additionally, the following data types are not yet supported for editing:
698
+ ``complex``, ``tuple``, ``bytes``, ``bytearray``,
699
+ ``memoryview``, ``dict``, ``set``, ``frozenset``,
700
+ ``fractions.Fraction``, ``pandas.Interval``, and
701
+ ``pandas.Period``.
702
+ - To prevent overflow in JavaScript, columns containing
703
+ ``datetime.timedelta`` and ``pandas.Timedelta`` values will
704
+ default to uneditable, but this can be changed through column
705
+ configuration.
706
+
707
+ width : "stretch", "content", or int
708
+ The width of the data editor. This can be one of the following:
709
+
710
+ - ``"stretch"`` (default): The width of the editor matches the
711
+ width of the parent container.
712
+ - ``"content"``: The width of the editor matches the width of its
713
+ content, but doesn't exceed the width of the parent container.
714
+ - An integer specifying the width in pixels: The editor has a
715
+ fixed width. If the specified width is greater than the width of
716
+ the parent container, the width of the editor matches the width
717
+ of the parent container.
718
+
719
+ height : "auto", "content", "stretch", or int
720
+ The height of the data editor. This can be one of the following:
721
+
722
+ - ``"auto"`` (default): Streamlit sets the height to show at most
723
+ ten rows.
724
+ - ``"content"``: The height of the editor matches the height of
725
+ its content. The height is capped at 10,000 pixels to prevent
726
+ performance issues with very large dataframes.
727
+ - ``"stretch"``: The height of the editor expands to fill the
728
+ available vertical space in its parent container. When multiple
729
+ elements with stretch height are in the same container, they
730
+ share the available vertical space evenly. The editor will
731
+ maintain a minimum height to display up to three rows, but
732
+ otherwise won't exceed the available height in its parent
733
+ container.
734
+ - An integer specifying the height in pixels: The editor has a
735
+ fixed height.
736
+
737
+ Vertical scrolling within the editor is enabled when the height
738
+ does not accommodate all rows.
739
+
740
+ use_container_width : bool
741
+ Whether to override ``width`` with the width of the parent
742
+ container. If this is ``True`` (default), Streamlit sets the width
743
+ of the data editor to match the width of the parent container. If
744
+ this is ``False``, Streamlit sets the data editor's width according
745
+ to ``width``.
746
+
747
+ .. deprecated::
748
+ ``use_container_width`` is deprecated and will be removed in a
749
+ future release. For ``use_container_width=True``, use
750
+ ``width="stretch"``.
751
+
752
+ hide_index : bool or None
753
+ Whether to hide the index column(s). If ``hide_index`` is ``None``
754
+ (default), the visibility of index columns is automatically
755
+ determined based on the data.
756
+
757
+ column_order : Iterable[str] or None
758
+ The ordered list of columns to display. If this is ``None``
759
+ (default), Streamlit displays all columns in the order inherited
760
+ from the underlying data structure. If this is a list, the
761
+ indicated columns will display in the order they appear within the
762
+ list. Columns may be omitted or repeated within the list.
763
+
764
+ For example, ``column_order=("col2", "col1")`` will display
765
+ ``"col2"`` first, followed by ``"col1"``, and will hide all other
766
+ non-index columns.
767
+
768
+ ``column_order`` does not accept positional column indices and
769
+ can't move the index column(s).
770
+
771
+ column_config : dict or None
772
+ Configuration to customize how columns are displayed. If this is
773
+ ``None`` (default), columns are styled based on the underlying data
774
+ type of each column.
775
+
776
+ Column configuration can modify column names, visibility, type,
777
+ width, format, editing properties like min/max, and more. If this
778
+ is a dictionary, the keys are column names (strings) and/or
779
+ positional column indices (integers), and the values are one of the
780
+ following:
781
+
782
+ - ``None`` to hide the column.
783
+ - A string to set the display label of the column.
784
+ - One of the column types defined under ``st.column_config``. For
785
+ example, to show a column as dollar amounts, use
786
+ ``st.column_config.NumberColumn("Dollar values", format="$ %d")``.
787
+ See more info on the available column types and config options
788
+ `here <https://docs.streamlit.io/develop/api-reference/data/st.column_config>`_.
789
+
790
+ To configure the index column(s), use ``"_index"`` as the column
791
+ name, or use a positional column index where ``0`` refers to the
792
+ first index column.
793
+
794
+ num_rows : "fixed", "dynamic", "add", or "delete"
795
+ Specifies if the user can add and/or delete rows in the data editor.
796
+
797
+ - ``"fixed"`` (default): The user can't add or delete rows.
798
+ - ``"dynamic"``: The user can add and delete rows, and column
799
+ sorting is disabled.
800
+ - ``"add"``: The user can only add rows (no deleting), and column
801
+ sorting is disabled.
802
+ - ``"delete"``: The user can only delete rows (no adding), and
803
+ column sorting remains enabled.
804
+
805
+ disabled : bool or Iterable[str | int]
806
+ Controls the editing of columns. This can be one of the following:
807
+
808
+ - ``False`` (default): All columns that support editing are editable.
809
+ - ``True``: All columns are disabled for editing.
810
+ - An Iterable of column names and/or positional indices: The
811
+ specified columns are disabled for editing while the remaining
812
+ columns are editable where supported. For example,
813
+ ``disabled=["col1", "col2"]`` will disable editing for the
814
+ columns named "col1" and "col2".
815
+
816
+ To disable editing for the index column(s), use ``"_index"`` as the
817
+ column name, or use a positional column index where ``0`` refers to
818
+ the first index column.
819
+
820
+ key : str
821
+ An optional string to use as the unique key for this widget. If this
822
+ is omitted, a key will be generated for the widget based on its
823
+ content. No two widgets may have the same key.
824
+
825
+ on_change : callable
826
+ An optional callback invoked when this data_editor's value changes.
827
+
828
+ args : list or tuple
829
+ An optional list or tuple of args to pass to the callback.
830
+
831
+ kwargs : dict
832
+ An optional dict of kwargs to pass to the callback.
833
+
834
+ row_height : int or None
835
+ The height of each row in the data editor in pixels. If ``row_height``
836
+ is ``None`` (default), Streamlit will use a default row height,
837
+ which fits one line of text.
838
+
839
+ placeholder : str or None
840
+ The text that should be shown for missing values. If this is
841
+ ``None`` (default), missing values are displayed as "None". To
842
+ leave a cell empty, use an empty string (``""``). Other common
843
+ values are ``"null"``, ``"NaN"`` and ``"-"``.
844
+
845
+ Returns
846
+ -------
847
+ pandas.DataFrame, pandas.Series, pyarrow.Table, numpy.ndarray, list, set, tuple, or dict.
848
+ The edited data. The edited data is returned in its original data type if
849
+ it corresponds to any of the supported return types. All other data types
850
+ are returned as a ``pandas.DataFrame``.
851
+
852
+ Examples
853
+ --------
854
+ **Example 1: Basic usage**
855
+
856
+ >>> import pandas as pd
857
+ >>> import streamlit as st
858
+ >>>
859
+ >>> df = pd.DataFrame(
860
+ >>> [
861
+ >>> {"command": "st.selectbox", "rating": 4, "is_widget": True},
862
+ >>> {"command": "st.balloons", "rating": 5, "is_widget": False},
863
+ >>> {"command": "st.time_input", "rating": 3, "is_widget": True},
864
+ >>> ]
865
+ >>> )
866
+ >>> edited_df = st.data_editor(df)
867
+ >>>
868
+ >>> favorite_command = edited_df.loc[edited_df["rating"].idxmax()]["command"]
869
+ >>> st.markdown(f"Your favorite command is **{favorite_command}** 🎈")
870
+
871
+ .. output::
872
+ https://doc-data-editor.streamlit.app/
873
+ height: 350px
874
+
875
+ **Example 2: Allowing users to add and delete rows**
876
+
877
+ You can allow your users to add and delete rows by setting ``num_rows``
878
+ to "dynamic":
879
+
880
+ >>> import streamlit as st
881
+ >>> import pandas as pd
882
+ >>>
883
+ >>> df = pd.DataFrame(
884
+ >>> [
885
+ >>> {"command": "st.selectbox", "rating": 4, "is_widget": True},
886
+ >>> {"command": "st.balloons", "rating": 5, "is_widget": False},
887
+ >>> {"command": "st.time_input", "rating": 3, "is_widget": True},
888
+ >>> ]
889
+ >>> )
890
+ >>> edited_df = st.data_editor(df, num_rows="dynamic")
891
+ >>>
892
+ >>> favorite_command = edited_df.loc[edited_df["rating"].idxmax()]["command"]
893
+ >>> st.markdown(f"Your favorite command is **{favorite_command}** 🎈")
894
+
895
+ .. output::
896
+ https://doc-data-editor1.streamlit.app/
897
+ height: 450px
898
+
899
+ **Example 3: Data editor configuration**
900
+
901
+ You can customize the data editor via ``column_config``, ``hide_index``,
902
+ ``column_order``, or ``disabled``:
903
+
904
+ >>> import pandas as pd
905
+ >>> import streamlit as st
906
+ >>>
907
+ >>> df = pd.DataFrame(
908
+ >>> [
909
+ >>> {"command": "st.selectbox", "rating": 4, "is_widget": True},
910
+ >>> {"command": "st.balloons", "rating": 5, "is_widget": False},
911
+ >>> {"command": "st.time_input", "rating": 3, "is_widget": True},
912
+ >>> ]
913
+ >>> )
914
+ >>> edited_df = st.data_editor(
915
+ >>> df,
916
+ >>> column_config={
917
+ >>> "command": "Streamlit Command",
918
+ >>> "rating": st.column_config.NumberColumn(
919
+ >>> "Your rating",
920
+ >>> help="How much do you like this command (1-5)?",
921
+ >>> min_value=1,
922
+ >>> max_value=5,
923
+ >>> step=1,
924
+ >>> format="%d ⭐",
925
+ >>> ),
926
+ >>> "is_widget": "Widget ?",
927
+ >>> },
928
+ >>> disabled=["command", "is_widget"],
929
+ >>> hide_index=True,
930
+ >>> )
931
+ >>>
932
+ >>> favorite_command = edited_df.loc[edited_df["rating"].idxmax()]["command"]
933
+ >>> st.markdown(f"Your favorite command is **{favorite_command}** 🎈")
934
+
935
+
936
+ .. output::
937
+ https://doc-data-editor-config.streamlit.app/
938
+ height: 350px
939
+
940
+ """
941
+ # Lazy-loaded import
942
+ import pandas as pd
943
+ import pyarrow as pa
944
+
945
+ key = to_key(key)
946
+
947
+ validate_width(width, allow_content=True)
948
+ validate_height(
949
+ height,
950
+ allow_content=True,
951
+ allow_stretch=True,
952
+ additional_allowed=["auto"],
953
+ )
954
+
955
+ check_widget_policies(
956
+ self.dg,
957
+ key,
958
+ on_change,
959
+ default_value=None,
960
+ writes_allowed=False,
961
+ )
962
+
963
+ if use_container_width is not None:
964
+ show_deprecation_warning(
965
+ make_deprecated_name_warning(
966
+ "use_container_width",
967
+ "width",
968
+ "2025-12-31",
969
+ "For `use_container_width=True`, use `width='stretch'`. "
970
+ "For `use_container_width=False`, use `width='content'`.",
971
+ include_st_prefix=False,
972
+ ),
973
+ show_in_browser=False,
974
+ )
975
+ if use_container_width:
976
+ width = "stretch"
977
+ elif not isinstance(width, int):
978
+ width = "content"
979
+
980
+ if column_order is not None:
981
+ column_order = list(column_order)
982
+
983
+ column_config_mapping: ColumnConfigMapping = {}
984
+
985
+ data_format = dataframe_util.determine_data_format(data)
986
+ if data_format == dataframe_util.DataFormat.UNKNOWN:
987
+ raise StreamlitAPIException(
988
+ f"The data type ({type(data).__name__}) or format is not supported by "
989
+ "the data editor. Please convert your data into a Pandas Dataframe or "
990
+ "another supported data format."
991
+ )
992
+
993
+ # The dataframe should always be a copy of the original data
994
+ # since we will apply edits directly to it.
995
+ data_df = dataframe_util.convert_anything_to_pandas_df(data, ensure_copy=True)
996
+
997
+ # Check if the index is supported.
998
+ if not _is_supported_index(data_df.index):
999
+ raise StreamlitAPIException(
1000
+ f"The type of the dataframe index - {type(data_df.index).__name__} - is not "
1001
+ "yet supported by the data editor."
1002
+ )
1003
+
1004
+ # Check if the column names are valid and unique.
1005
+ _check_column_names(data_df)
1006
+
1007
+ # Convert the user provided column config into the frontend compatible format:
1008
+ column_config_mapping = process_config_mapping(column_config)
1009
+
1010
+ # Deactivate editing for columns that are not compatible with arrow
1011
+ for column_name, column_data in data_df.items():
1012
+ if dataframe_util.is_colum_type_arrow_incompatible(column_data):
1013
+ update_column_config(
1014
+ column_config_mapping, str(column_name), {"disabled": True}
1015
+ )
1016
+ # Convert incompatible type to string
1017
+ data_df[cast("Any", column_name)] = column_data.astype("string")
1018
+
1019
+ apply_data_specific_configs(column_config_mapping, data_format)
1020
+
1021
+ # Fix the column headers to work correctly for data editing:
1022
+ _fix_column_headers(data_df)
1023
+
1024
+ has_range_index = isinstance(data_df.index, pd.RangeIndex)
1025
+
1026
+ if not has_range_index:
1027
+ # If the index is not a range index, we will configure it as required
1028
+ # since the user is required to provide a (unique) value for editing.
1029
+ update_column_config(
1030
+ column_config_mapping, INDEX_IDENTIFIER, {"required": True}
1031
+ )
1032
+ if num_rows in {"dynamic", "add"} and hide_index is True:
1033
+ _LOGGER.warning(
1034
+ "Setting `hide_index=True` in data editor with a non-range index will not have any effect "
1035
+ "when `num_rows` is '%s'. It is required for the user to fill in index values for "
1036
+ "adding new rows. To hide the index, make sure to set the DataFrame "
1037
+ "index to a range index.",
1038
+ num_rows,
1039
+ )
1040
+
1041
+ if hide_index is None and has_range_index and num_rows in {"dynamic", "add"}:
1042
+ # Temporary workaround:
1043
+ # We hide range indices if num_rows allows adding rows.
1044
+ # since the current way of handling this index during editing is a
1045
+ # bit confusing. The user can still decide to show the index by
1046
+ # setting hide_index explicitly to False.
1047
+ hide_index = True
1048
+
1049
+ if hide_index is not None:
1050
+ update_column_config(
1051
+ column_config_mapping, INDEX_IDENTIFIER, {"hidden": hide_index}
1052
+ )
1053
+
1054
+ # If disabled not a boolean, we assume it is a list of columns to disable.
1055
+ # This gets translated into the columns configuration:
1056
+ if not isinstance(disabled, bool):
1057
+ for column in disabled:
1058
+ update_column_config(column_config_mapping, column, {"disabled": True})
1059
+
1060
+ # Convert the dataframe to an arrow table which is used as the main
1061
+ # serialization format for sending the data to the frontend.
1062
+ # We also utilize the arrow schema to determine the data kinds of every column.
1063
+ arrow_table = pa.Table.from_pandas(data_df)
1064
+
1065
+ # Determine the dataframe schema which is required for parsing edited values
1066
+ # and for checking type compatibilities.
1067
+ dataframe_schema = determine_dataframe_schema(data_df, arrow_table.schema)
1068
+
1069
+ # Check if all configured column types are compatible with the underlying data.
1070
+ # Throws an exception if any of the configured types are incompatible.
1071
+ _check_type_compatibilities(data_df, column_config_mapping, dataframe_schema)
1072
+
1073
+ arrow_bytes = dataframe_util.convert_arrow_table_to_arrow_bytes(arrow_table)
1074
+
1075
+ # We want to do this as early as possible to avoid introducing nondeterminism,
1076
+ # but it isn't clear how much processing is needed to have the data in a
1077
+ # format that will hash consistently, so we do it late here to have it
1078
+ # as close as possible to how it used to be.
1079
+ ctx = get_script_run_ctx()
1080
+ element_id = compute_and_register_element_id(
1081
+ "data_editor",
1082
+ user_key=key,
1083
+ key_as_main_identity=False,
1084
+ dg=self.dg,
1085
+ data=arrow_bytes,
1086
+ width=width,
1087
+ height=height,
1088
+ use_container_width=use_container_width,
1089
+ column_order=column_order,
1090
+ column_config_mapping=str(column_config_mapping),
1091
+ num_rows=num_rows,
1092
+ row_height=row_height,
1093
+ placeholder=placeholder,
1094
+ )
1095
+
1096
+ proto = DataframeProto()
1097
+ proto.id = element_id
1098
+
1099
+ if row_height:
1100
+ proto.row_height = row_height
1101
+
1102
+ if column_order:
1103
+ proto.column_order[:] = column_order
1104
+
1105
+ if placeholder is not None:
1106
+ proto.placeholder = placeholder
1107
+
1108
+ # Only set disabled to true if it is actually true
1109
+ # It can also be a list of columns, which should result in false here.
1110
+ proto.disabled = disabled is True
1111
+
1112
+ if num_rows == "dynamic":
1113
+ proto.editing_mode = DataframeProto.EditingMode.DYNAMIC
1114
+ elif num_rows == "add":
1115
+ proto.editing_mode = DataframeProto.EditingMode.ADD_ONLY
1116
+ elif num_rows == "delete":
1117
+ proto.editing_mode = DataframeProto.EditingMode.DELETE_ONLY
1118
+ else:
1119
+ proto.editing_mode = DataframeProto.EditingMode.FIXED
1120
+
1121
+ proto.form_id = current_form_id(self.dg)
1122
+
1123
+ if dataframe_util.is_pandas_styler(data):
1124
+ # Pandas styler will only work for non-editable/disabled columns.
1125
+ # Get first 10 chars of md5 hash of the key or delta path as styler uuid
1126
+ # and set it as styler uuid.
1127
+ # We are only using the first 10 chars to keep the uuid short since
1128
+ # it will be used for all the cells in the dataframe. Therefore, this
1129
+ # might have a significant impact on the message size. 10 chars
1130
+ # should be good enough to avoid potential collisions in this case.
1131
+ # Even on collisions, there should not be a big issue with the
1132
+ # rendering in the data editor.
1133
+ styler_uuid = calc_md5(key or self.dg._get_delta_path_str())[:10]
1134
+ data.set_uuid(styler_uuid) # ty: ignore[call-non-callable, possibly-missing-attribute]
1135
+ marshall_styler(proto.arrow_data, data, styler_uuid)
1136
+
1137
+ proto.arrow_data.data = arrow_bytes
1138
+
1139
+ marshall_column_config(proto, column_config_mapping)
1140
+
1141
+ # Create layout configuration
1142
+ # For height, only include it in LayoutConfig if it's not "auto"
1143
+ # "auto" is the default behavior and doesn't need to be sent
1144
+ layout_config = LayoutConfig(
1145
+ width=width, height=height if height != "auto" else None
1146
+ )
1147
+
1148
+ serde = DataEditorSerde()
1149
+
1150
+ widget_state = register_widget(
1151
+ proto.id,
1152
+ on_change_handler=on_change,
1153
+ args=args,
1154
+ kwargs=kwargs,
1155
+ deserializer=serde.deserialize,
1156
+ serializer=serde.serialize,
1157
+ ctx=ctx,
1158
+ value_type="string_value",
1159
+ )
1160
+
1161
+ _apply_dataframe_edits(data_df, widget_state.value, dataframe_schema)
1162
+ self.dg._enqueue("dataframe", proto, layout_config=layout_config)
1163
+ return dataframe_util.convert_pandas_df_to_data_format(data_df, data_format)
1164
+
1165
+ @property
1166
+ def dg(self) -> DeltaGenerator:
1167
+ """Get our DeltaGenerator."""
1168
+ return cast("DeltaGenerator", self)