streamlit-nightly 1.53.2.dev20260131__py3-none-any.whl → 1.53.2.dev20260203__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 (205) hide show
  1. streamlit/commands/execution_control.py +2 -2
  2. streamlit/commands/logo.py +6 -10
  3. streamlit/components/v2/component_path_utils.py +17 -29
  4. streamlit/config.py +4 -2
  5. streamlit/delta_generator.py +2 -0
  6. streamlit/elements/lib/column_types.py +6 -2
  7. streamlit/elements/lib/utils.py +6 -6
  8. streamlit/elements/markdown.py +0 -1
  9. streamlit/elements/metric.py +2 -1
  10. streamlit/elements/widgets/button_group.py +6 -276
  11. streamlit/elements/widgets/feedback.py +322 -0
  12. streamlit/elements/widgets/number_input.py +2 -1
  13. streamlit/elements/widgets/slider.py +2 -1
  14. streamlit/material_icon_names.py +1 -1
  15. streamlit/path_security.py +98 -0
  16. streamlit/proto/AudioInput_pb2.py +4 -4
  17. streamlit/proto/AudioInput_pb2.pyi +3 -3
  18. streamlit/proto/Audio_pb2.py +2 -2
  19. streamlit/proto/BackMsg_pb2.pyi +2 -10
  20. streamlit/proto/Balloons_pb2.pyi +0 -2
  21. streamlit/proto/Block_pb2.py +35 -35
  22. streamlit/proto/ButtonGroup_pb2.py +10 -12
  23. streamlit/proto/ButtonGroup_pb2.pyi +6 -41
  24. streamlit/proto/Button_pb2.py +2 -2
  25. streamlit/proto/CameraInput_pb2.py +4 -4
  26. streamlit/proto/CameraInput_pb2.pyi +3 -3
  27. streamlit/proto/ChatInput_pb2.py +2 -2
  28. streamlit/proto/Checkbox_pb2.py +6 -6
  29. streamlit/proto/Checkbox_pb2.pyi +3 -3
  30. streamlit/proto/Code_pb2.py +2 -2
  31. streamlit/proto/ColorPicker_pb2.py +4 -4
  32. streamlit/proto/ColorPicker_pb2.pyi +3 -3
  33. streamlit/proto/Common_pb2.py +6 -6
  34. streamlit/proto/DateInput_pb2.py +4 -4
  35. streamlit/proto/DateInput_pb2.pyi +3 -3
  36. streamlit/proto/DateTimeInput_pb2.py +4 -4
  37. streamlit/proto/DateTimeInput_pb2.pyi +3 -3
  38. streamlit/proto/DeckGlJsonChart_pb2.py +2 -2
  39. streamlit/proto/Delta_pb2.py +2 -2
  40. streamlit/proto/DocString_pb2.py +1 -1
  41. streamlit/proto/Element_pb2.py +4 -4
  42. streamlit/proto/Element_pb2.pyi +9 -9
  43. streamlit/proto/Feedback_pb2.py +28 -0
  44. streamlit/proto/Feedback_pb2.pyi +93 -0
  45. streamlit/proto/FileUploader_pb2.py +4 -4
  46. streamlit/proto/FileUploader_pb2.pyi +3 -3
  47. streamlit/proto/ForwardMsg_pb2.py +8 -8
  48. streamlit/proto/GraphVizChart_pb2.py +2 -2
  49. streamlit/proto/IFrame_pb2.py +3 -3
  50. streamlit/proto/Image_pb2.py +4 -4
  51. streamlit/proto/Image_pb2.pyi +1 -7
  52. streamlit/proto/{BokehChart_pb2.py → LabelVisibility_pb2.py} +7 -5
  53. streamlit/proto/{LabelVisibilityMessage_pb2.pyi → LabelVisibility_pb2.pyi} +14 -14
  54. streamlit/proto/Markdown_pb2.py +4 -4
  55. streamlit/proto/Markdown_pb2.pyi +1 -5
  56. streamlit/proto/Metric_pb2.py +10 -10
  57. streamlit/proto/Metric_pb2.pyi +3 -3
  58. streamlit/proto/MultiSelect_pb2.py +4 -4
  59. streamlit/proto/MultiSelect_pb2.pyi +3 -3
  60. streamlit/proto/NewSession_pb2.py +38 -26
  61. streamlit/proto/NewSession_pb2.pyi +42 -8
  62. streamlit/proto/NumberInput_pb2.py +6 -6
  63. streamlit/proto/NumberInput_pb2.pyi +3 -3
  64. streamlit/proto/PlotlyChart_pb2.py +2 -2
  65. streamlit/proto/Radio_pb2.py +4 -4
  66. streamlit/proto/Radio_pb2.pyi +3 -3
  67. streamlit/proto/Selectbox_pb2.py +4 -4
  68. streamlit/proto/Selectbox_pb2.pyi +3 -6
  69. streamlit/proto/Slider_pb2.py +8 -8
  70. streamlit/proto/Slider_pb2.pyi +3 -3
  71. streamlit/proto/Snow_pb2.pyi +0 -2
  72. streamlit/proto/TextArea_pb2.py +4 -4
  73. streamlit/proto/TextArea_pb2.pyi +3 -3
  74. streamlit/proto/TextInput_pb2.py +6 -6
  75. streamlit/proto/TextInput_pb2.pyi +3 -3
  76. streamlit/proto/TimeInput_pb2.py +4 -4
  77. streamlit/proto/TimeInput_pb2.pyi +3 -3
  78. streamlit/proto/Video_pb2.py +2 -2
  79. streamlit/runtime/app_session.py +9 -1
  80. streamlit/static/index.html +2 -2
  81. streamlit/static/manifest.json +325 -310
  82. streamlit/static/static/css/{index.BUP6fTcR.css → index.C8MrxwGF.css} +1 -1
  83. streamlit/static/static/js/{ErrorOutline.esm.DC6KVDKK.js → ErrorOutline.esm.C9uHPmIj.js} +1 -1
  84. streamlit/static/static/js/{FileDownload.esm.Z9hRQIHi.js → FileDownload.esm.D-YPxF3t.js} +1 -1
  85. streamlit/static/static/js/{FileHelper.DqvW90pm.js → FileHelper.DQSH0zYW.js} +1 -1
  86. streamlit/static/static/js/{FormClearHelper.DTFnX0js.js → FormClearHelper.DQoXcOWo.js} +1 -1
  87. streamlit/static/static/js/{InputInstructions.CdzsN_Va.js → InputInstructions.C7VMyGT7.js} +1 -1
  88. streamlit/static/static/js/{Particles.12xFSjcn.js → Particles.BdQSRZde.js} +1 -1
  89. streamlit/static/static/js/{ProgressBar.Dg-oMbWg.js → ProgressBar.DNF_pWKr.js} +2 -2
  90. streamlit/static/static/js/{StreamlitSyntaxHighlighter.rbzmcipw.js → StreamlitSyntaxHighlighter.Cys9Bt18.js} +2 -2
  91. streamlit/static/static/js/{TableChart.esm.CzJtGIR-.js → TableChart.esm.B9SMgSK4.js} +1 -1
  92. streamlit/static/static/js/{Toolbar.COH7NaOE.js → Toolbar.BXfC9Z-W.js} +1 -1
  93. streamlit/static/static/js/{WidgetLabelHelpIconInline.Dlc8f0Ji.js → WidgetLabelHelpIconInline.gkreC55g.js} +1 -1
  94. streamlit/static/static/js/{base-input.Q-zJLgRK.js → base-input.iB32RS3w.js} +4 -4
  95. streamlit/static/static/js/{checkbox.BKgWNdeI.js → checkbox.Bqz68SYq.js} +1 -1
  96. streamlit/static/static/js/{createDownloadLinkElement.6oO-YlYv.js → createDownloadLinkElement.YxVC9Qur.js} +1 -1
  97. streamlit/static/static/js/data-grid-overlay-editor.sBsdk5Xg.js +1 -0
  98. streamlit/static/static/js/{downloader.BBXcXdX1.js → downloader.Bzxqt3AW.js} +1 -1
  99. streamlit/static/static/js/{embed.CJzOXYBF.js → embed.CDzakah3.js} +1 -1
  100. streamlit/static/static/js/{es6.CdxPQzwJ.js → es6.CxCc4bfn.js} +2 -2
  101. streamlit/static/static/js/formatNumber.L8T7D36k.js +1 -0
  102. streamlit/static/static/js/{iconPosition.BVScIr6G.js → iconPosition.C47DkA-1.js} +1 -1
  103. streamlit/static/static/js/{iframeResizer.contentWindow.D_QHVqPM.js → iframeResizer.contentWindow.uEFLXEg3.js} +1 -1
  104. streamlit/static/static/js/{index.CvtybR-u.js → index.B3zULhHv.js} +1 -1
  105. streamlit/static/static/js/{index.DAyGxxdm.js → index.B60AZFRh.js} +3 -3
  106. streamlit/static/static/js/{index.BED2_zc7.js → index.BG4RxMOI.js} +1 -1
  107. streamlit/static/static/js/{index.CPc_uZux.js → index.BHyzKS4e.js} +45 -45
  108. streamlit/static/static/js/{index.Dud7RRHc.js → index.BVTW_o-a.js} +1 -1
  109. streamlit/static/static/js/{index.BQnLeHnr.js → index.BV_YgIHe.js} +3 -3
  110. streamlit/static/static/js/index.B_LfkwqU.js +2 -0
  111. streamlit/static/static/js/{index.DCe7fo-m.js → index.Ba8L-ulI.js} +1 -1
  112. streamlit/static/static/js/{index.DAfIQKfP.js → index.Bh5BZaHG.js} +2 -2
  113. streamlit/static/static/js/{index.DU68jVpM.js → index.Bnwh8oZr.js} +16 -16
  114. streamlit/static/static/js/index.BrZtYm2A.js +2 -0
  115. streamlit/static/static/js/index.BsrhCS7f.js +1 -0
  116. streamlit/static/static/js/{index.CxoREvnF.js → index.BuJPJSD7.js} +2 -2
  117. streamlit/static/static/js/{index.6DFY6LUF.js → index.BvHsyiyy.js} +1 -1
  118. streamlit/static/static/js/{index.Biyf9aUg.js → index.BwTkGOAy.js} +2 -2
  119. streamlit/static/static/js/{index.DNfyKqhQ.js → index.BwvxzVOo.js} +1 -1
  120. streamlit/static/static/js/{index.iXh5nbLZ.js → index.BzdcdLDK.js} +1 -1
  121. streamlit/static/static/js/{index.YULCxEtm.js → index.C1d2QjTR.js} +1 -1
  122. streamlit/static/static/js/index.C1uZrWog.js +1 -0
  123. streamlit/static/static/js/{index.C5oqIM3a.js → index.C5-TpWis.js} +1 -1
  124. streamlit/static/static/js/{index.D6OexhdL.js → index.C6dhwBSe.js} +1 -1
  125. streamlit/static/static/js/{index.y-pa6LIX.js → index.CAbQaUvi.js} +1 -1
  126. streamlit/static/static/js/{index.BSpYHDvk.js → index.CAbafj7s.js} +1 -1
  127. streamlit/static/static/js/{index.BDtN2n7T.js → index.CCLteRW6.js} +1 -1
  128. streamlit/static/static/js/{index.mSdC1FV6.js → index.CQ713nQM.js} +1 -1
  129. streamlit/static/static/js/index.CcBYyLfq.js +2 -0
  130. streamlit/static/static/js/{index.CBE2cIbj.js → index.CjBDVb1a.js} +1 -1
  131. streamlit/static/static/js/{index.BxQxTpWl.js → index.Ck0ZkOfK.js} +1 -1
  132. streamlit/static/static/js/{index.B80gSxrS.js → index.CzwJzgQs.js} +1 -1
  133. streamlit/static/static/js/{index.DyfvmNCy.js → index.D-9VyyiA.js} +1 -1
  134. streamlit/static/static/js/{index.nL1fkE1D.js → index.D2R3Co5f.js} +1 -1
  135. streamlit/static/static/js/{index.DZmBuE3z.js → index.D7L9gHlE.js} +3 -3
  136. streamlit/static/static/js/{index.BqxwnMem.js → index.DEKnCsY-.js} +2 -2
  137. streamlit/static/static/js/{index.D9v2Y8Gk.js → index.DHrByikW.js} +1 -1
  138. streamlit/static/static/js/index.DN_oudQl.js +1 -0
  139. streamlit/static/static/js/{index.DrcbvB2t.js → index.DO55kRo5.js} +1 -1
  140. streamlit/static/static/js/{index.BqbKiDp2.js → index.D_cvtSlg.js} +1 -1
  141. streamlit/static/static/js/{index.CrY1BsL3.js → index.DgqmsDCJ.js} +1 -1
  142. streamlit/static/static/js/{index.BtOoVQt7.js → index.DjgdCvlK.js} +1 -1
  143. streamlit/static/static/js/{index.BxMkW82k.js → index.DqhZqWYB.js} +1 -1
  144. streamlit/static/static/js/{index.bQJYmJ2T.js → index.Dtbj_oyb.js} +1 -1
  145. streamlit/static/static/js/{index.CUYi3FrD.js → index.QXukCzoh.js} +1 -1
  146. streamlit/static/static/js/{index.BiCbrx53.js → index.XJY9qZ6a.js} +1 -1
  147. streamlit/static/static/js/{index.GieKl4BG.js → index.aZRhdEuX.js} +1 -1
  148. streamlit/static/static/js/{index._1zqETQ9.js → index.fUsWkW8E.js} +1 -1
  149. streamlit/static/static/js/index.h2N-W51I.js +11 -0
  150. streamlit/static/static/js/index.iUHLeAvv.js +1 -0
  151. streamlit/static/static/js/{index.DRoJNzFX.js → index.kBgXO7Vv.js} +1 -1
  152. streamlit/static/static/js/{index.BSYebegS.js → index.kEL0HsUR.js} +1 -1
  153. streamlit/static/static/js/index.w7yKy9fh.js +6 -0
  154. streamlit/static/static/js/{input.BcC6sPE_.js → input.BCHJn1Cw.js} +1 -1
  155. streamlit/static/static/js/{main.TU5_aabd.js → main.23ZP6f1E.js} +1 -1
  156. streamlit/static/static/js/{memory.By_OTlI4.js → memory.D8f8Q4mO.js} +1 -1
  157. streamlit/static/static/js/number-overlay-editor.ZWvSpjJ5.js +9 -0
  158. streamlit/static/static/js/{pandasStylerUtils.3IiIKU9-.js → pandasStylerUtils.DlZ2GBs_.js} +1 -1
  159. streamlit/static/static/js/{sandbox.DnxTbWzV.js → sandbox.BH6D3KL9.js} +1 -1
  160. streamlit/static/static/js/sprintfjs.CtrdaGLQ.js +1 -0
  161. streamlit/static/static/js/{styled-components.BeEcZ0vW.js → styled-components.iD1HRMLc.js} +1 -1
  162. streamlit/static/static/js/{throttle.emUyC44c.js → throttle.DR7d9vp_.js} +1 -1
  163. streamlit/static/static/js/{timepicker.DZ_ZufYF.js → timepicker.Bd34xjcG.js} +4 -4
  164. streamlit/static/static/js/{toConsumableArray.DDV1bN1-.js → toConsumableArray.BDTTq1c5.js} +2 -2
  165. streamlit/static/static/js/uniqueId.Bd_Iuzvc.js +1 -0
  166. streamlit/static/static/js/useBasicWidgetState.BXKaD8DQ.js +1 -0
  167. streamlit/static/static/js/{useIntlLocale.BBDLbTq9.js → useIntlLocale.CysOvegI.js} +1 -1
  168. streamlit/static/static/js/{useTextInputAutoExpand.BIApLJKn.js → useTextInputAutoExpand.CVd5Hf2S.js} +1 -1
  169. streamlit/static/static/js/{useUpdateUiValue.DQ4RuJNC.js → useUpdateUiValue.CIUgfO8X.js} +1 -1
  170. streamlit/static/static/js/{useWaveformController.B0olyXLQ.js → useWaveformController.CDLqlnLv.js} +1 -1
  171. streamlit/static/static/js/{withCalculatedWidth.DYeqePuh.js → withCalculatedWidth.Ce1Zblb2.js} +1 -1
  172. streamlit/static/static/js/{withFullScreenWrapper.DtkUCO_d.js → withFullScreenWrapper.DBm7N75M.js} +1 -1
  173. streamlit/static/static/media/MaterialSymbols-Rounded.CnH1S47a.woff2 +0 -0
  174. streamlit/testing/v1/app_test.py +21 -5
  175. streamlit/testing/v1/element_tree.py +65 -2
  176. streamlit/web/server/app_static_file_handler.py +9 -0
  177. streamlit/web/server/bidi_component_request_handler.py +4 -4
  178. streamlit/web/server/component_file_utils.py +14 -6
  179. streamlit/web/server/component_request_handler.py +2 -2
  180. streamlit/web/server/starlette/starlette_app.py +7 -1
  181. streamlit/web/server/starlette/starlette_path_security_middleware.py +97 -0
  182. streamlit/web/server/starlette/starlette_routes.py +6 -3
  183. streamlit/web/server/starlette/starlette_static_routes.py +14 -4
  184. {streamlit_nightly-1.53.2.dev20260131.dist-info → streamlit_nightly-1.53.2.dev20260203.dist-info}/METADATA +1 -1
  185. {streamlit_nightly-1.53.2.dev20260131.dist-info → streamlit_nightly-1.53.2.dev20260203.dist-info}/RECORD +188 -184
  186. streamlit/proto/BokehChart_pb2.pyi +0 -56
  187. streamlit/proto/LabelVisibilityMessage_pb2.py +0 -28
  188. streamlit/static/static/js/data-grid-overlay-editor.CO0xdNiG.js +0 -1
  189. streamlit/static/static/js/formatNumber.DB5irY8c.js +0 -1
  190. streamlit/static/static/js/index.BBTKOM0z.js +0 -6
  191. streamlit/static/static/js/index.CE2WIFD1.js +0 -2
  192. streamlit/static/static/js/index.Cpu2p5bH.js +0 -1
  193. streamlit/static/static/js/index.CtbETWQK.js +0 -2
  194. streamlit/static/static/js/index.DAnczAW2.js +0 -2
  195. streamlit/static/static/js/index.DhRAGiPR.js +0 -1
  196. streamlit/static/static/js/index.DyXcT2tD.js +0 -11
  197. streamlit/static/static/js/index.tuFFlbxa.js +0 -1
  198. streamlit/static/static/js/number-overlay-editor.FSRaRpbU.js +0 -9
  199. streamlit/static/static/js/sprintf.DpPCfzXw.js +0 -1
  200. streamlit/static/static/js/uniqueId.DTwvAE-J.js +0 -1
  201. streamlit/static/static/js/useBasicWidgetState.DvpdEDYZ.js +0 -1
  202. streamlit/static/static/media/MaterialSymbols-Rounded.C7IFxh57.woff2 +0 -0
  203. {streamlit_nightly-1.53.2.dev20260131.dist-info → streamlit_nightly-1.53.2.dev20260203.dist-info}/WHEEL +0 -0
  204. {streamlit_nightly-1.53.2.dev20260131.dist-info → streamlit_nightly-1.53.2.dev20260203.dist-info}/entry_points.txt +0 -0
  205. {streamlit_nightly-1.53.2.dev20260131.dist-info → streamlit_nightly-1.53.2.dev20260203.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,322 @@
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
+ from typing import (
18
+ TYPE_CHECKING,
19
+ Final,
20
+ Literal,
21
+ cast,
22
+ overload,
23
+ )
24
+
25
+ from streamlit.elements.lib.form_utils import current_form_id
26
+ from streamlit.elements.lib.layout_utils import (
27
+ LayoutConfig,
28
+ Width,
29
+ validate_width,
30
+ )
31
+ from streamlit.elements.lib.policies import check_widget_policies
32
+ from streamlit.elements.lib.utils import (
33
+ Key,
34
+ compute_and_register_element_id,
35
+ save_for_app_testing,
36
+ to_key,
37
+ )
38
+ from streamlit.errors import StreamlitAPIException
39
+ from streamlit.proto.Feedback_pb2 import Feedback as FeedbackProto
40
+ from streamlit.runtime.metrics_util import gather_metrics
41
+ from streamlit.runtime.scriptrunner_utils.script_run_context import get_script_run_ctx
42
+ from streamlit.runtime.state import register_widget
43
+
44
+ if TYPE_CHECKING:
45
+ from streamlit.delta_generator import DeltaGenerator
46
+ from streamlit.runtime.state import (
47
+ WidgetArgs,
48
+ WidgetCallback,
49
+ WidgetKwargs,
50
+ )
51
+
52
+
53
+ # Number of options for each feedback type
54
+ _NUM_THUMBS_OPTIONS: Final = 2
55
+ _NUM_FACES_OPTIONS: Final = 5
56
+ _NUM_STARS_OPTIONS: Final = 5
57
+
58
+
59
+ def _get_num_options(feedback_type: Literal["thumbs", "faces", "stars"]) -> int:
60
+ """Get the number of options for the given feedback type."""
61
+ if feedback_type == "thumbs":
62
+ return _NUM_THUMBS_OPTIONS
63
+ if feedback_type == "faces":
64
+ return _NUM_FACES_OPTIONS
65
+ return _NUM_STARS_OPTIONS
66
+
67
+
68
+ def _feedback_type_to_proto(
69
+ feedback_type: Literal["thumbs", "faces", "stars"],
70
+ ) -> FeedbackProto.FeedbackType.ValueType:
71
+ """Convert a feedback type string to the proto enum value."""
72
+ if feedback_type == "thumbs":
73
+ return FeedbackProto.FeedbackType.THUMBS
74
+ if feedback_type == "faces":
75
+ return FeedbackProto.FeedbackType.FACES
76
+ return FeedbackProto.FeedbackType.STARS
77
+
78
+
79
+ class FeedbackSerde:
80
+ """Serializer/deserializer for feedback widget values.
81
+
82
+ Uses string as the wire format to distinguish three states:
83
+ - None (field not set): No UI interaction yet -> use default_value
84
+ - "" (empty string): User explicitly cleared -> return None
85
+ - "2" (string with value): User selected -> return int value
86
+
87
+ This allows clearing to work correctly even when a default is set.
88
+ The session state and return values are always int | None.
89
+ """
90
+
91
+ def __init__(self, default_value: int | None = None):
92
+ self.default_value = default_value
93
+
94
+ def serialize(self, value: int | None) -> str:
95
+ """Serialize int value to string for wire format."""
96
+ return "" if value is None else str(value)
97
+
98
+ def deserialize(self, ui_value: str | None) -> int | None:
99
+ """Deserialize string wire format back to int value."""
100
+ if ui_value is None:
101
+ return self.default_value # No UI interaction yet
102
+ if ui_value == "":
103
+ return None # User explicitly cleared
104
+ return int(ui_value) # User selected a value
105
+
106
+
107
+ class FeedbackMixin:
108
+ @overload
109
+ def feedback(
110
+ self,
111
+ options: Literal["thumbs"] = ...,
112
+ *,
113
+ key: Key | None = None,
114
+ default: int | None = None,
115
+ disabled: bool = False,
116
+ on_change: WidgetCallback | None = None,
117
+ args: WidgetArgs | None = None,
118
+ kwargs: WidgetKwargs | None = None,
119
+ width: Width = "content",
120
+ ) -> Literal[0, 1] | None: ...
121
+
122
+ @overload
123
+ def feedback(
124
+ self,
125
+ options: Literal["faces", "stars"] = ...,
126
+ *,
127
+ key: Key | None = None,
128
+ default: int | None = None,
129
+ disabled: bool = False,
130
+ on_change: WidgetCallback | None = None,
131
+ args: WidgetArgs | None = None,
132
+ kwargs: WidgetKwargs | None = None,
133
+ width: Width = "content",
134
+ ) -> Literal[0, 1, 2, 3, 4] | None: ...
135
+
136
+ @gather_metrics("feedback")
137
+ def feedback(
138
+ self,
139
+ options: Literal["thumbs", "faces", "stars"] = "thumbs",
140
+ *,
141
+ key: Key | None = None,
142
+ default: int | None = None,
143
+ disabled: bool = False,
144
+ on_change: WidgetCallback | None = None,
145
+ args: WidgetArgs | None = None,
146
+ kwargs: WidgetKwargs | None = None,
147
+ width: Width = "content",
148
+ ) -> int | None:
149
+ """Display a feedback widget.
150
+
151
+ A feedback widget is an icon-based button group available in three
152
+ styles, as described in ``options``. It is commonly used in chat and AI
153
+ apps to allow users to rate responses.
154
+
155
+ Parameters
156
+ ----------
157
+ options : "thumbs", "faces", or "stars"
158
+ The feedback options displayed to the user. ``options`` can be one
159
+ of the following:
160
+
161
+ - ``"thumbs"`` (default): Streamlit displays a thumb-up and
162
+ thumb-down button group.
163
+ - ``"faces"``: Streamlit displays a row of five buttons with
164
+ facial expressions depicting increasing satisfaction from left to
165
+ right.
166
+ - ``"stars"``: Streamlit displays a row of star icons, allowing the
167
+ user to select a rating from one to five stars.
168
+
169
+ key : str or int
170
+ An optional string or integer to use as the unique key for the widget.
171
+ If this is omitted, a key will be generated for the widget
172
+ based on its content. No two widgets may have the same key.
173
+
174
+ default : int or None
175
+ Default feedback value. This must be consistent with the feedback
176
+ type in ``options``:
177
+
178
+ - 0 or 1 if ``options="thumbs"``.
179
+ - Between 0 and 4, inclusive, if ``options="faces"`` or
180
+ ``options="stars"``.
181
+
182
+ disabled : bool
183
+ An optional boolean that disables the feedback widget if set
184
+ to ``True``. The default is ``False``.
185
+
186
+ on_change : callable
187
+ An optional callback invoked when this feedback widget's value
188
+ changes.
189
+
190
+ args : list or tuple
191
+ An optional list or tuple of args to pass to the callback.
192
+
193
+ kwargs : dict
194
+ An optional dict of kwargs to pass to the callback.
195
+
196
+ width : "content", "stretch", or int
197
+ The width of the feedback widget. This can be one of the following:
198
+
199
+ - ``"content"`` (default): The width of the widget matches the
200
+ width of its content, but doesn't exceed the width of the parent
201
+ container.
202
+ - ``"stretch"``: The width of the widget matches the width of the
203
+ parent container.
204
+ - An integer specifying the width in pixels: The widget has a
205
+ fixed width. If the specified width is greater than the width of
206
+ the parent container, the width of the widget matches the width
207
+ of the parent container.
208
+
209
+ Returns
210
+ -------
211
+ int or None
212
+ An integer indicating the user's selection, where ``0`` is the
213
+ lowest feedback. Higher values indicate more positive feedback.
214
+ If no option was selected, the widget returns ``None``.
215
+
216
+ - For ``options="thumbs"``, a return value of ``0`` indicates
217
+ thumbs-down, and ``1`` indicates thumbs-up.
218
+ - For ``options="faces"`` and ``options="stars"``, return values
219
+ range from ``0`` (least satisfied) to ``4`` (most satisfied).
220
+
221
+ Examples
222
+ --------
223
+ Display a feedback widget with stars, and show the selected sentiment:
224
+
225
+ >>> import streamlit as st
226
+ >>>
227
+ >>> sentiment_mapping = ["one", "two", "three", "four", "five"]
228
+ >>> selected = st.feedback("stars")
229
+ >>> if selected is not None:
230
+ >>> st.markdown(f"You selected {sentiment_mapping[selected]} star(s).")
231
+
232
+ .. output::
233
+ https://doc-feedback-stars.streamlit.app/
234
+ height: 200px
235
+
236
+ Display a feedback widget with thumbs, and show the selected sentiment:
237
+
238
+ >>> import streamlit as st
239
+ >>>
240
+ >>> sentiment_mapping = [":material/thumb_down:", ":material/thumb_up:"]
241
+ >>> selected = st.feedback("thumbs")
242
+ >>> if selected is not None:
243
+ >>> st.markdown(f"You selected: {sentiment_mapping[selected]}")
244
+
245
+ .. output::
246
+ https://doc-feedback-thumbs.streamlit.app/
247
+ height: 200px
248
+
249
+ """
250
+ if options not in {"thumbs", "faces", "stars"}:
251
+ raise StreamlitAPIException(
252
+ "The options argument to st.feedback must be one of "
253
+ "['thumbs', 'faces', 'stars']. "
254
+ f"The argument passed was '{options}'."
255
+ )
256
+
257
+ num_options = _get_num_options(options)
258
+
259
+ if default is not None and (default < 0 or default >= num_options):
260
+ raise StreamlitAPIException(
261
+ f"The default value in '{options}' must be a number between 0 and {num_options - 1}."
262
+ f" The passed default value is {default}"
263
+ )
264
+
265
+ key = to_key(key)
266
+ validate_width(width, allow_content=True)
267
+ layout_config = LayoutConfig(width=width)
268
+
269
+ check_widget_policies(self.dg, key, on_change, default_value=default)
270
+
271
+ ctx = get_script_run_ctx()
272
+ form_id = current_form_id(self.dg)
273
+
274
+ element_id = compute_and_register_element_id(
275
+ "feedback",
276
+ user_key=key,
277
+ key_as_main_identity={"options"},
278
+ dg=self.dg,
279
+ options=options,
280
+ default=default,
281
+ width=width,
282
+ )
283
+
284
+ # Build the proto
285
+ proto = FeedbackProto()
286
+ proto.id = element_id
287
+ proto.type = _feedback_type_to_proto(options)
288
+ proto.disabled = disabled
289
+ proto.form_id = form_id
290
+
291
+ if default is not None:
292
+ proto.default = default
293
+
294
+ serde = FeedbackSerde(default_value=default)
295
+
296
+ widget_state = register_widget(
297
+ proto.id,
298
+ on_change_handler=on_change,
299
+ args=args,
300
+ kwargs=kwargs,
301
+ deserializer=serde.deserialize,
302
+ serializer=serde.serialize,
303
+ ctx=ctx,
304
+ value_type="string_value",
305
+ )
306
+
307
+ if widget_state.value_changed:
308
+ if widget_state.value is not None:
309
+ proto.value = widget_state.value
310
+ proto.set_value = True
311
+
312
+ if ctx:
313
+ save_for_app_testing(ctx, element_id, None)
314
+
315
+ self.dg._enqueue("feedback", proto, layout_config=layout_config)
316
+
317
+ return widget_state.value
318
+
319
+ @property
320
+ def dg(self) -> DeltaGenerator:
321
+ """Get our DeltaGenerator."""
322
+ return cast("DeltaGenerator", self)
@@ -296,7 +296,8 @@ class NumberInputMixin:
296
296
  <https://github.com/alexei/sprintf.js?tab=readme-ov-file#format-specification>`_.
297
297
 
298
298
  For example, ``format="%0.1f"`` adjusts the displayed decimal
299
- precision to only show one digit after the decimal.
299
+ precision to only show one digit after the decimal. Use ``,`` for
300
+ thousand separators (e.g. ``"%,d"`` yields ``"1,234"``).
300
301
 
301
302
  key : str or int
302
303
  An optional string or integer to use as the unique key for the widget.
@@ -541,7 +541,8 @@ class SliderMixin:
541
541
  `sprintf.js
542
542
  <https://github.com/alexei/sprintf.js?tab=readme-ov-file#format-specification>`_.
543
543
  For example, ``format="%0.1f"`` adjusts the displayed decimal
544
- precision to only show one digit after the decimal.
544
+ precision to only show one digit after the decimal. Use ``,`` for
545
+ thousand separators (e.g. ``"%,d"`` yields ``"1,234"``).
545
546
 
546
547
  For datetimes, dates, and times, you can use a momentJS format string
547
548
  or one of the following predefined formats: