streamlit-nightly 1.44.2.dev20250428__py3-none-any.whl → 1.45.1.dev20250430__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 (122) hide show
  1. streamlit/cli_util.py +1 -1
  2. streamlit/commands/experimental_query_params.py +1 -1
  3. streamlit/commands/page_config.py +1 -1
  4. streamlit/config.py +5 -5
  5. streamlit/elements/arrow.py +5 -5
  6. streamlit/elements/deck_gl_json_chart.py +3 -3
  7. streamlit/elements/dialog_decorator.py +0 -1
  8. streamlit/elements/doc_string.py +24 -3
  9. streamlit/elements/image.py +8 -9
  10. streamlit/elements/json.py +13 -0
  11. streamlit/elements/lib/image_utils.py +20 -21
  12. streamlit/elements/map.py +1 -1
  13. streamlit/elements/metric.py +1 -1
  14. streamlit/elements/plotly_chart.py +4 -4
  15. streamlit/elements/progress.py +25 -1
  16. streamlit/elements/vega_charts.py +1 -1
  17. streamlit/elements/widgets/audio_input.py +21 -0
  18. streamlit/elements/widgets/button.py +6 -5
  19. streamlit/elements/widgets/file_uploader.py +5 -4
  20. streamlit/elements/widgets/number_input.py +9 -10
  21. streamlit/elements/widgets/slider.py +1 -1
  22. streamlit/error_util.py +1 -1
  23. streamlit/logger.py +5 -5
  24. streamlit/navigation/page.py +1 -1
  25. streamlit/proto/AudioInput_pb2.py +4 -3
  26. streamlit/proto/AudioInput_pb2.pyi +7 -2
  27. streamlit/proto/DocString_pb2.py +6 -5
  28. streamlit/proto/DocString_pb2.pyi +9 -1
  29. streamlit/proto/Json_pb2.py +4 -3
  30. streamlit/proto/Json_pb2.pyi +9 -2
  31. streamlit/proto/Progress_pb2.py +4 -3
  32. streamlit/proto/Progress_pb2.pyi +7 -1
  33. streamlit/runtime/app_session.py +9 -9
  34. streamlit/runtime/caching/cache_data_api.py +1 -1
  35. streamlit/runtime/caching/cache_utils.py +3 -2
  36. streamlit/runtime/caching/hashing.py +3 -4
  37. streamlit/runtime/caching/storage/local_disk_cache_storage.py +2 -2
  38. streamlit/runtime/connection_factory.py +8 -8
  39. streamlit/runtime/context.py +1 -1
  40. streamlit/runtime/credentials.py +1 -0
  41. streamlit/runtime/forward_msg_queue.py +2 -2
  42. streamlit/runtime/metrics_util.py +2 -2
  43. streamlit/runtime/runtime_util.py +1 -1
  44. streamlit/runtime/scriptrunner/script_runner.py +4 -4
  45. streamlit/static/index.html +1 -1
  46. streamlit/static/static/js/{ErrorOutline.esm.BXGjCB7E.js → ErrorOutline.esm.JdVs1Qkg.js} +1 -1
  47. streamlit/static/static/js/{FileDownload.esm.sOCqSnDy.js → FileDownload.esm.BlQJ4vNG.js} +1 -1
  48. streamlit/static/static/js/{FileHelper.DuN7B5ko.js → FileHelper.V4GYCyDu.js} +1 -1
  49. streamlit/static/static/js/{FormClearHelper.mBqxy6fp.js → FormClearHelper.CyxVAl63.js} +1 -1
  50. streamlit/static/static/js/{Hooks.B8RCaOU-.js → Hooks.CwzpXjfg.js} +1 -1
  51. streamlit/static/static/js/{InputInstructions.CgQJAdmY.js → InputInstructions.DLh-ti71.js} +1 -1
  52. streamlit/static/static/js/{ProgressBar.o46iipVl.js → ProgressBar.C7bBETsY.js} +1 -1
  53. streamlit/static/static/js/{RenderInPortalIfExists.CZifGklq.js → RenderInPortalIfExists.BMvxq2hn.js} +1 -1
  54. streamlit/static/static/js/{Toolbar.CKRoYZWM.js → Toolbar.CotfqUm6.js} +1 -1
  55. streamlit/static/static/js/{base-input.Me5gYF5B.js → base-input.BxaSmpU7.js} +1 -1
  56. streamlit/static/static/js/{checkbox.CWWogItI.js → checkbox.CrglCerk.js} +1 -1
  57. streamlit/static/static/js/{createSuper.Bsmy7vnu.js → createSuper.Bs0C396a.js} +1 -1
  58. streamlit/static/static/js/{data-grid-overlay-editor.CgAv1I8N.js → data-grid-overlay-editor.D0k84F-1.js} +1 -1
  59. streamlit/static/static/js/{downloader.BbuyvUmM.js → downloader.BpZrmdUi.js} +1 -1
  60. streamlit/static/static/js/{es6.cFKClVYr.js → es6.DD8ccAPk.js} +2 -2
  61. streamlit/static/static/js/{iframeResizer.contentWindow.D00awOKx.js → iframeResizer.contentWindow.7G5YE4ki.js} +1 -1
  62. streamlit/static/static/js/{index.CZT8t1KG.js → index.5p5xlu27.js} +1 -1
  63. streamlit/static/static/js/{index.DUVjoXrp.js → index.65FBensJ.js} +1 -1
  64. streamlit/static/static/js/{index.B0eFd777.js → index.80LGX7Ne.js} +1 -1
  65. streamlit/static/static/js/{index.ew1fqjzv.js → index.9sjzZWLH.js} +1 -1
  66. streamlit/static/static/js/{index.VrX7AJMW.js → index.B2lDS5vI.js} +1 -1
  67. streamlit/static/static/js/{index.zbOUPreQ.js → index.B3VXbj_b.js} +1 -1
  68. streamlit/static/static/js/{index.GIpP3S4h.js → index.BDLXYKTS.js} +1 -1
  69. streamlit/static/static/js/{index.Db4G4s87.js → index.BF0CTyRa.js} +1 -1
  70. streamlit/static/static/js/{index.djYQBt-8.js → index.BI5f0VII.js} +1 -1
  71. streamlit/static/static/js/{index.Dn4hsDID.js → index.BNhdn2vD.js} +1 -1
  72. streamlit/static/static/js/{index.Bo5OoJ1E.js → index.BNm3tuep.js} +1 -1
  73. streamlit/static/static/js/{index.DkQYsEGq.js → index.BQqNcnRp.js} +63 -63
  74. streamlit/static/static/js/{index.CC6pozcl.js → index.BjKCKyJI.js} +1 -1
  75. streamlit/static/static/js/{index.C8S8FJep.js → index.C2kSDT38.js} +1 -1
  76. streamlit/static/static/js/{index.D67skAdZ.js → index.CMjYL7Ho.js} +1 -1
  77. streamlit/static/static/js/{index.B5KSWyCG.js → index.COBwb1mq.js} +1 -1
  78. streamlit/static/static/js/{index.Cg3APxPS.js → index.COpV4IZK.js} +1 -1
  79. streamlit/static/static/js/{index.DZSznc3f.js → index.Cgzj9ewR.js} +1 -1
  80. streamlit/static/static/js/{index.bliAXvPp.js → index.CkutRj8u.js} +1 -1
  81. streamlit/static/static/js/{index.v9S4U7E0.js → index.Co5UsG7W.js} +1 -1
  82. streamlit/static/static/js/{index.BY-1pChC.js → index.CveEeb4Q.js} +1 -1
  83. streamlit/static/static/js/{index.ZMXLPc9m.js → index.Czzj5-re.js} +1 -1
  84. streamlit/static/static/js/{index.CEFfPwWA.js → index.D1wWsFMc.js} +1 -1
  85. streamlit/static/static/js/{index.DnnK1XX4.js → index.D5GLQoRz.js} +1 -1
  86. streamlit/static/static/js/{index.B_FepcMP.js → index.DICnhvRg.js} +1 -1
  87. streamlit/static/static/js/{index.BfEtVe_N.js → index.DK_eUkea.js} +1 -1
  88. streamlit/static/static/js/{index.BtCmnwwO.js → index.DM4oCpFy.js} +1 -1
  89. streamlit/static/static/js/{index.B6NqnBxa.js → index.DO535td0.js} +1 -1
  90. streamlit/static/static/js/{index.By8gv4Ay.js → index.DUF1Zxw6.js} +1 -1
  91. streamlit/static/static/js/{index.CtsvxUli.js → index.DW80zFo4.js} +1 -1
  92. streamlit/static/static/js/{index.Zbagu1xh.js → index.DX2vW3qb.js} +1 -1
  93. streamlit/static/static/js/{index.BMizE8Sq.js → index.DfgXsqtW.js} +1 -1
  94. streamlit/static/static/js/{index.BKz9YyeL.js → index.Dq6k7Ztd.js} +1 -1
  95. streamlit/static/static/js/{index.BtTvTjVr.js → index.Dz4o-tqP.js} +5 -5
  96. streamlit/static/static/js/{index.CSZNuohX.js → index.Olz7Xaf0.js} +1 -1
  97. streamlit/static/static/js/{index.HOc29Qsj.js → index.SARy_Med.js} +1 -1
  98. streamlit/static/static/js/{index.eVt4urZS.js → index.rHb0nIsm.js} +1 -1
  99. streamlit/static/static/js/{input.E-TEQSd2.js → input.ChMez782.js} +1 -1
  100. streamlit/static/static/js/{memory.C47SiSLX.js → memory.DEIZt-uk.js} +1 -1
  101. streamlit/static/static/js/{mergeWith.CuOPq9Xx.js → mergeWith.DV3wfmZj.js} +1 -1
  102. streamlit/static/static/js/{number-overlay-editor.oJywx_AR.js → number-overlay-editor.CVWV51LZ.js} +1 -1
  103. streamlit/static/static/js/{possibleConstructorReturn.DezSYWQP.js → possibleConstructorReturn.D8SHK4fu.js} +1 -1
  104. streamlit/static/static/js/{sandbox.CpLGEYsx.js → sandbox.2Y0eB1Fb.js} +1 -1
  105. streamlit/static/static/js/{textarea.CF2OGnSF.js → textarea.CfOMMQUp.js} +1 -1
  106. streamlit/static/static/js/{timepicker.CckJhoGD.js → timepicker.BCEVqM6L.js} +1 -1
  107. streamlit/static/static/js/{toConsumableArray.DrtLgJ_5.js → toConsumableArray.CgIgbjyR.js} +1 -1
  108. streamlit/static/static/js/{uniqueId.kgGoKER7.js → uniqueId.CasOW7eQ.js} +1 -1
  109. streamlit/static/static/js/{useBasicWidgetState.CHBqT0_O.js → useBasicWidgetState.DM0uW3hG.js} +1 -1
  110. streamlit/static/static/js/{useOnInputChange.A8V2n4e2.js → useOnInputChange.C9p9DssL.js} +1 -1
  111. streamlit/static/static/js/{withFullScreenWrapper.Bh5OZGIu.js → withFullScreenWrapper.Du9h1SFo.js} +1 -1
  112. streamlit/testing/v1/app_test.py +2 -2
  113. streamlit/testing/v1/element_tree.py +7 -7
  114. streamlit/user_info.py +3 -3
  115. streamlit/web/cli.py +4 -4
  116. streamlit/web/server/server_util.py +1 -1
  117. {streamlit_nightly-1.44.2.dev20250428.dist-info → streamlit_nightly-1.45.1.dev20250430.dist-info}/METADATA +1 -1
  118. {streamlit_nightly-1.44.2.dev20250428.dist-info → streamlit_nightly-1.45.1.dev20250430.dist-info}/RECORD +122 -122
  119. {streamlit_nightly-1.44.2.dev20250428.dist-info → streamlit_nightly-1.45.1.dev20250430.dist-info}/WHEEL +1 -1
  120. {streamlit_nightly-1.44.2.dev20250428.data → streamlit_nightly-1.45.1.dev20250430.data}/scripts/streamlit.cmd +0 -0
  121. {streamlit_nightly-1.44.2.dev20250428.dist-info → streamlit_nightly-1.45.1.dev20250430.dist-info}/entry_points.txt +0 -0
  122. {streamlit_nightly-1.44.2.dev20250428.dist-info → streamlit_nightly-1.45.1.dev20250430.dist-info}/top_level.txt +0 -0
streamlit/cli_util.py CHANGED
@@ -60,7 +60,7 @@ def _open_browser_with_webbrowser(url: str) -> None:
60
60
  def _open_browser_with_command(command: str, url: str) -> None:
61
61
  cmd_line = [command, url]
62
62
  with open(os.devnull, "w") as devnull:
63
- subprocess.Popen(cmd_line, stdout=devnull, stderr=subprocess.STDOUT)
63
+ subprocess.Popen(cmd_line, stdout=devnull, stderr=subprocess.STDOUT) # noqa: S603
64
64
 
65
65
 
66
66
  def open_browser(url: str) -> None:
@@ -14,8 +14,8 @@
14
14
 
15
15
  from __future__ import annotations
16
16
 
17
- import urllib.parse as parse
18
17
  from typing import Any
18
+ from urllib import parse
19
19
 
20
20
  from streamlit.errors import StreamlitAPIException
21
21
  from streamlit.proto.ForwardMsg_pb2 import ForwardMsg
@@ -276,7 +276,7 @@ def set_page_config(
276
276
  def get_random_emoji() -> str:
277
277
  # Weigh our emojis 10x, cuz we're awesome!
278
278
  # TODO: fix the random seed with a hash of the user's app code, for stability?
279
- return random.choice(RANDOM_EMOJIS + 10 * ENG_EMOJIS)
279
+ return random.choice(RANDOM_EMOJIS + 10 * ENG_EMOJIS) # noqa: S311
280
280
 
281
281
 
282
282
  def set_menu_items_proto(lowercase_menu_items, menu_items_proto) -> None:
streamlit/config.py CHANGED
@@ -348,7 +348,7 @@ def _delete_option(key: str) -> None:
348
348
  "_config_options should always be populated here."
349
349
  )
350
350
  del _config_options[key]
351
- except Exception:
351
+ except Exception: # noqa: S110
352
352
  # We don't care if the option already doesn't exist.
353
353
  pass
354
354
 
@@ -1471,12 +1471,12 @@ def _maybe_convert_to_number(v: Any) -> Any:
1471
1471
  """Convert v to int or float, or leave it as is."""
1472
1472
  try:
1473
1473
  return int(v)
1474
- except Exception:
1474
+ except Exception: # noqa: S110
1475
1475
  pass
1476
1476
 
1477
1477
  try:
1478
1478
  return float(v)
1479
- except Exception:
1479
+ except Exception: # noqa: S110
1480
1480
  pass
1481
1481
 
1482
1482
  return v
@@ -1544,8 +1544,8 @@ def get_config_options(
1544
1544
  if not os.path.exists(filename):
1545
1545
  continue
1546
1546
 
1547
- with open(filename, encoding="utf-8") as input:
1548
- file_contents = input.read()
1547
+ with open(filename, encoding="utf-8") as file:
1548
+ file_contents = file.read()
1549
1549
 
1550
1550
  _update_config_with_toml(file_contents, filename)
1551
1551
 
@@ -208,14 +208,14 @@ def parse_selection_mode(
208
208
  )
209
209
 
210
210
  parsed_selection_modes = []
211
- for selection_mode in selection_mode_set:
212
- if selection_mode == "single-row":
211
+ for mode in selection_mode_set:
212
+ if mode == "single-row":
213
213
  parsed_selection_modes.append(ArrowProto.SelectionMode.SINGLE_ROW)
214
- elif selection_mode == "multi-row":
214
+ elif mode == "multi-row":
215
215
  parsed_selection_modes.append(ArrowProto.SelectionMode.MULTI_ROW)
216
- elif selection_mode == "single-column":
216
+ elif mode == "single-column":
217
217
  parsed_selection_modes.append(ArrowProto.SelectionMode.SINGLE_COLUMN)
218
- elif selection_mode == "multi-column":
218
+ elif mode == "multi-column":
219
219
  parsed_selection_modes.append(ArrowProto.SelectionMode.MULTI_COLUMN)
220
220
  return set(parsed_selection_modes)
221
221
 
@@ -91,10 +91,10 @@ def parse_selection_mode(
91
91
  )
92
92
 
93
93
  parsed_selection_modes = []
94
- for selection_mode in selection_mode_set:
95
- if selection_mode == "single-object":
94
+ for mode in selection_mode_set:
95
+ if mode == "single-object":
96
96
  parsed_selection_modes.append(PydeckProto.SelectionMode.SINGLE_OBJECT)
97
- elif selection_mode == "multi-object":
97
+ elif mode == "multi-object":
98
98
  parsed_selection_modes.append(PydeckProto.SelectionMode.MULTI_OBJECT)
99
99
  return set(parsed_selection_modes)
100
100
 
@@ -97,7 +97,6 @@ def _dialog_decorator(
97
97
  # if the dialog should be closed, st.rerun() has to be called
98
98
  # (same behavior as with st.fragment)
99
99
  _ = non_optional_func(*args, **kwargs)
100
- return None
101
100
 
102
101
  # the fragment decorator has multiple return types so that you can pass
103
102
  # arguments to it. Here we know the return type, so we cast
@@ -24,8 +24,10 @@ import types
24
24
  from typing import TYPE_CHECKING, Any, Final, cast
25
25
 
26
26
  import streamlit
27
+ from streamlit.elements.lib.layout_utils import validate_width
27
28
  from streamlit.proto.DocString_pb2 import DocString as DocStringProto
28
29
  from streamlit.proto.DocString_pb2 import Member as MemberProto
30
+ from streamlit.proto.WidthConfig_pb2 import WidthConfig
29
31
  from streamlit.runtime.metrics_util import gather_metrics
30
32
  from streamlit.runtime.scriptrunner.script_runner import (
31
33
  __file__ as SCRIPTRUNNER_FILENAME, # noqa: N812
@@ -35,6 +37,7 @@ from streamlit.string_util import is_mem_address_str
35
37
 
36
38
  if TYPE_CHECKING:
37
39
  from streamlit.delta_generator import DeltaGenerator
40
+ from streamlit.elements.lib.layout_utils import WidthWithoutContent
38
41
 
39
42
 
40
43
  CONFUSING_STREAMLIT_SIG_PREFIXES: Final = ("(element, ",)
@@ -42,7 +45,9 @@ CONFUSING_STREAMLIT_SIG_PREFIXES: Final = ("(element, ",)
42
45
 
43
46
  class HelpMixin:
44
47
  @gather_metrics("help")
45
- def help(self, obj: Any = streamlit) -> DeltaGenerator:
48
+ def help(
49
+ self, obj: Any = streamlit, *, width: WidthWithoutContent = "stretch"
50
+ ) -> DeltaGenerator:
46
51
  """Display help and other information for a given object.
47
52
 
48
53
  Depending on the type of object that is passed in, this displays the
@@ -54,6 +59,9 @@ class HelpMixin:
54
59
  obj : any
55
60
  The object whose information should be displayed. If left
56
61
  unspecified, this call will display help for Streamlit itself.
62
+ width : "stretch" or int
63
+ The width of the help element. Can be "stretch" to fill the container
64
+ width, or an integer to specify a fixed width in pixels.
57
65
 
58
66
  Example
59
67
  -------
@@ -115,7 +123,10 @@ class HelpMixin:
115
123
  height: 700px
116
124
  """
117
125
  doc_string_proto = DocStringProto()
118
- _marshall(doc_string_proto, obj)
126
+
127
+ validate_width(width, allow_content=False)
128
+ _marshall(doc_string_proto, obj, width)
129
+
119
130
  return self.dg._enqueue("doc_string", doc_string_proto)
120
131
 
121
132
  @property
@@ -124,7 +135,9 @@ class HelpMixin:
124
135
  return cast("DeltaGenerator", self)
125
136
 
126
137
 
127
- def _marshall(doc_string_proto: DocStringProto, obj: Any) -> None:
138
+ def _marshall(
139
+ doc_string_proto: DocStringProto, obj: Any, width: WidthWithoutContent = "stretch"
140
+ ) -> None:
128
141
  """Construct a DocString object.
129
142
 
130
143
  See DeltaGenerator.help for docs.
@@ -146,6 +159,14 @@ def _marshall(doc_string_proto: DocStringProto, obj: Any) -> None:
146
159
 
147
160
  doc_string_proto.members.extend(_get_members(obj))
148
161
 
162
+ # Set width configuration
163
+ width_config = WidthConfig()
164
+ if isinstance(width, int):
165
+ width_config.pixel_width = width
166
+ else:
167
+ width_config.use_stretch = True
168
+ doc_string_proto.width_config.CopyFrom(width_config)
169
+
149
170
 
150
171
  def _get_name(obj):
151
172
  # Try to get the fully-qualified name of the object.
@@ -167,15 +167,14 @@ class ImageMixin:
167
167
  elif use_column_width == "never" or use_column_width is False:
168
168
  image_width = WidthBehavior.ORIGINAL
169
169
 
170
- else:
171
- if use_container_width is True:
172
- image_width = WidthBehavior.MAX_IMAGE_OR_CONTAINER
173
- elif image_width is not None and image_width > 0:
174
- # Use the given width. It will be capped on the frontend if it
175
- # exceeds the container width.
176
- pass
177
- elif use_container_width is False:
178
- image_width = WidthBehavior.MIN_IMAGE_OR_CONTAINER
170
+ elif use_container_width is True:
171
+ image_width = WidthBehavior.MAX_IMAGE_OR_CONTAINER
172
+ elif image_width is not None and image_width > 0:
173
+ # Use the given width. It will be capped on the frontend if it
174
+ # exceeds the container width.
175
+ pass
176
+ elif use_container_width is False:
177
+ image_width = WidthBehavior.MIN_IMAGE_OR_CONTAINER
179
178
 
180
179
  image_list_proto = ImageListProto()
181
180
  marshall_images(
@@ -19,6 +19,7 @@ import types
19
19
  from collections import ChainMap, UserDict
20
20
  from typing import TYPE_CHECKING, Any, cast
21
21
 
22
+ from streamlit.elements.lib.layout_utils import WidthWithoutContent, validate_width
22
23
  from streamlit.proto.Json_pb2 import Json as JsonProto
23
24
  from streamlit.runtime.metrics_util import gather_metrics
24
25
  from streamlit.type_util import (
@@ -46,6 +47,7 @@ class JsonMixin:
46
47
  body: object,
47
48
  *, # keyword-only arguments:
48
49
  expanded: bool | int = True,
50
+ width: WidthWithoutContent = "stretch",
49
51
  ) -> DeltaGenerator:
50
52
  """Display an object or string as a pretty-printed, interactive JSON string.
51
53
 
@@ -69,6 +71,11 @@ class JsonMixin:
69
71
  Regardless of the initial expansion state, users can collapse or
70
72
  expand any key-value pair to show or hide any part of the object.
71
73
 
74
+ width : "stretch" or int
75
+ The width of the JSON element. This can be either:
76
+ - "stretch" (default): The element will stretch to fill the container width
77
+ - An integer: The element will have a fixed width in pixels
78
+
72
79
  Example
73
80
  -------
74
81
  >>> import streamlit as st
@@ -131,6 +138,12 @@ class JsonMixin:
131
138
  ", must be bool or int."
132
139
  )
133
140
 
141
+ validate_width(width)
142
+ if isinstance(width, int):
143
+ json_proto.width_config.pixel_width = width
144
+ else:
145
+ json_proto.width_config.use_stretch = True
146
+
134
147
  return self.dg._enqueue("json", json_proto)
135
148
 
136
149
  @property
@@ -97,12 +97,12 @@ def _validate_image_format_string(
97
97
  - For all other strings, return "PNG" if the image has an alpha channel,
98
98
  "GIF" if the image is a GIF, and "JPEG" otherwise.
99
99
  """
100
- format = format.upper()
101
- if format in {"JPEG", "PNG"}:
102
- return cast("ImageFormat", format)
100
+ img_format = format.upper()
101
+ if img_format in {"JPEG", "PNG"}:
102
+ return cast("ImageFormat", img_format)
103
103
 
104
104
  # We are forgiving on the spelling of JPEG
105
- if format == "JPG":
105
+ if img_format == "JPG":
106
106
  return "JPEG"
107
107
 
108
108
  pil_image: PILImage
@@ -149,9 +149,9 @@ def _np_array_to_bytes(array: npt.NDArray[Any], output_format: str = "JPEG") ->
149
149
  from PIL import Image
150
150
 
151
151
  img = Image.fromarray(array.astype(np.uint8))
152
- format = _validate_image_format_string(img, output_format)
152
+ img_format = _validate_image_format_string(img, output_format)
153
153
 
154
- return _pil_to_bytes(img, format)
154
+ return _pil_to_bytes(img, img_format)
155
155
 
156
156
 
157
157
  def _verify_np_shape(array: npt.NDArray[Any]) -> npt.NDArray[Any]:
@@ -216,16 +216,13 @@ def _clip_image(image: npt.NDArray[Any], clamp: bool) -> npt.NDArray[Any]:
216
216
  if issubclass(image.dtype.type, np.floating):
217
217
  if clamp:
218
218
  data = np.clip(image, 0, 1.0)
219
- else:
220
- if np.amin(image) < 0.0 or np.amax(image) > 1.0:
221
- raise RuntimeError("Data is outside [0.0, 1.0] and clamp is not set.")
219
+ elif np.amin(image) < 0.0 or np.amax(image) > 1.0:
220
+ raise RuntimeError("Data is outside [0.0, 1.0] and clamp is not set.")
222
221
  data = data * 255
223
- else:
224
- if clamp:
225
- data = np.clip(image, 0, 255)
226
- else:
227
- if np.amin(image) < 0 or np.amax(image) > 255:
228
- raise RuntimeError("Data is outside [0, 255] and clamp is not set.")
222
+ elif clamp:
223
+ data = np.clip(image, 0, 255)
224
+ elif np.amin(image) < 0 or np.amax(image) > 255:
225
+ raise RuntimeError("Data is outside [0, 255] and clamp is not set.")
229
226
  return data
230
227
 
231
228
 
@@ -301,8 +298,8 @@ def image_to_url(
301
298
 
302
299
  # PIL Images
303
300
  elif isinstance(image, (ImageFile.ImageFile, Image.Image)):
304
- format = _validate_image_format_string(image, output_format)
305
- image_data = _pil_to_bytes(image, format)
301
+ img_format = _validate_image_format_string(image, output_format)
302
+ image_data = _pil_to_bytes(image, img_format)
306
303
 
307
304
  # BytesIO
308
305
  # Note: This doesn't support SVG. We could convert to png (cairosvg.svg2png)
@@ -430,15 +427,17 @@ def marshall_images(
430
427
 
431
428
  proto_imgs.width = int(width)
432
429
  # Each image in an image list needs to be kept track of at its own coordinates.
433
- for coord_suffix, (image, caption) in enumerate(zip(images, captions)):
430
+ for coord_suffix, (single_image, single_caption) in enumerate(
431
+ zip(images, captions)
432
+ ):
434
433
  proto_img = proto_imgs.imgs.add()
435
- if caption is not None:
436
- proto_img.caption = str(caption)
434
+ if single_caption is not None:
435
+ proto_img.caption = str(single_caption)
437
436
 
438
437
  # We use the index of the image in the input image list to identify this image inside
439
438
  # MediaFileManager. For this, we just add the index to the image's "coordinates".
440
439
  image_id = "%s-%i" % (coordinates, coord_suffix)
441
440
 
442
441
  proto_img.url = image_to_url(
443
- image, width, clamp, channels, output_format, image_id
442
+ single_image, width, clamp, channels, output_format, image_id
444
443
  )
streamlit/elements/map.py CHANGED
@@ -20,8 +20,8 @@ import copy
20
20
  import json
21
21
  from typing import TYPE_CHECKING, Any, Final, cast
22
22
 
23
- import streamlit.elements.deck_gl_json_chart as deck_gl_json_chart
24
23
  from streamlit import config, dataframe_util
24
+ from streamlit.elements import deck_gl_json_chart
25
25
  from streamlit.elements.lib.color_util import (
26
26
  Color,
27
27
  IntColorTuple,
@@ -231,7 +231,7 @@ def _parse_value(value: Value) -> str:
231
231
  # Item could also be just a variable, so we use try, except
232
232
  if isinstance(value.item(), float) or isinstance(value.item(), int):
233
233
  return str(value.item())
234
- except Exception:
234
+ except Exception: # noqa: S110
235
235
  # If the numpy item is not a valid value, the TypeError below will be raised.
236
236
  pass
237
237
 
@@ -257,12 +257,12 @@ def parse_selection_mode(
257
257
  )
258
258
 
259
259
  parsed_selection_modes = []
260
- for selection_mode in selection_mode_set:
261
- if selection_mode == "points":
260
+ for mode in selection_mode_set:
261
+ if mode == "points":
262
262
  parsed_selection_modes.append(PlotlyChartProto.SelectionMode.POINTS)
263
- elif selection_mode == "lasso":
263
+ elif mode == "lasso":
264
264
  parsed_selection_modes.append(PlotlyChartProto.SelectionMode.LASSO)
265
- elif selection_mode == "box":
265
+ elif mode == "box":
266
266
  parsed_selection_modes.append(PlotlyChartProto.SelectionMode.BOX)
267
267
  return set(parsed_selection_modes)
268
268
 
@@ -19,12 +19,15 @@ from typing import TYPE_CHECKING, Union, cast
19
19
 
20
20
  from typing_extensions import TypeAlias
21
21
 
22
+ from streamlit.elements.lib.layout_utils import validate_width
22
23
  from streamlit.errors import StreamlitAPIException
23
24
  from streamlit.proto.Progress_pb2 import Progress as ProgressProto
25
+ from streamlit.proto.WidthConfig_pb2 import WidthConfig
24
26
  from streamlit.string_util import clean_text
25
27
 
26
28
  if TYPE_CHECKING:
27
29
  from streamlit.delta_generator import DeltaGenerator
30
+ from streamlit.elements.lib.layout_utils import WidthWithoutContent
28
31
 
29
32
 
30
33
  # Currently, equates to just float, but we can't use `numbers.Real` due to
@@ -92,7 +95,12 @@ def _get_text(text: str | None) -> str | None:
92
95
 
93
96
 
94
97
  class ProgressMixin:
95
- def progress(self, value: FloatOrInt, text: str | None = None) -> DeltaGenerator:
98
+ def progress(
99
+ self,
100
+ value: FloatOrInt,
101
+ text: str | None = None,
102
+ width: WidthWithoutContent = "stretch",
103
+ ) -> DeltaGenerator:
96
104
  r"""Display a progress bar.
97
105
 
98
106
  Parameters
@@ -119,6 +127,10 @@ class ProgressMixin:
119
127
  .. |st.markdown| replace:: ``st.markdown``
120
128
  .. _st.markdown: https://docs.streamlit.io/develop/api-reference/text/st.markdown
121
129
 
130
+ width : int or str
131
+ The width of the progress bar. Can be either "stretch" to use the full
132
+ container width, or an integer for a fixed width in pixels.
133
+
122
134
  Example
123
135
  -------
124
136
  Here is an example of a progress bar increasing over time and disappearing when it reaches completion:
@@ -148,6 +160,18 @@ class ProgressMixin:
148
160
  text = _get_text(text)
149
161
  if text is not None:
150
162
  progress_proto.text = text
163
+
164
+ width_config = WidthConfig()
165
+
166
+ validate_width(width)
167
+
168
+ if isinstance(width, int):
169
+ width_config.pixel_width = width
170
+ else:
171
+ width_config.use_stretch = True
172
+
173
+ progress_proto.width_config.CopyFrom(width_config)
174
+
151
175
  return self.dg._enqueue("progress", progress_proto)
152
176
 
153
177
  @property
@@ -33,8 +33,8 @@ from typing import (
33
33
 
34
34
  from typing_extensions import TypeAlias
35
35
 
36
- import streamlit.elements.lib.dicttools as dicttools
37
36
  from streamlit import dataframe_util, type_util
37
+ from streamlit.elements.lib import dicttools
38
38
  from streamlit.elements.lib.built_in_chart_utils import (
39
39
  AddRowsMetadata,
40
40
  ChartStackType,
@@ -22,6 +22,7 @@ from typing_extensions import TypeAlias
22
22
 
23
23
  from streamlit.elements.lib.file_uploader_utils import enforce_filename_restriction
24
24
  from streamlit.elements.lib.form_utils import current_form_id
25
+ from streamlit.elements.lib.layout_utils import validate_width
25
26
  from streamlit.elements.lib.policies import (
26
27
  check_widget_policies,
27
28
  maybe_raise_label_warnings,
@@ -37,6 +38,7 @@ from streamlit.elements.widgets.file_uploader import _get_upload_files
37
38
  from streamlit.proto.AudioInput_pb2 import AudioInput as AudioInputProto
38
39
  from streamlit.proto.Common_pb2 import FileUploaderState as FileUploaderStateProto
39
40
  from streamlit.proto.Common_pb2 import UploadedFileInfo as UploadedFileInfoProto
41
+ from streamlit.proto.WidthConfig_pb2 import WidthConfig
40
42
  from streamlit.runtime.metrics_util import gather_metrics
41
43
  from streamlit.runtime.scriptrunner import ScriptRunContext, get_script_run_ctx
42
44
  from streamlit.runtime.state import (
@@ -49,6 +51,7 @@ from streamlit.runtime.uploaded_file_manager import DeletedFile, UploadedFile
49
51
 
50
52
  if TYPE_CHECKING:
51
53
  from streamlit.delta_generator import DeltaGenerator
54
+ from streamlit.elements.lib.layout_utils import WidthWithoutContent
52
55
 
53
56
  SomeUploadedAudioFile: TypeAlias = Union[UploadedFile, DeletedFile, None]
54
57
 
@@ -98,6 +101,7 @@ class AudioInputMixin:
98
101
  kwargs: WidgetKwargs | None = None,
99
102
  disabled: bool = False,
100
103
  label_visibility: LabelVisibility = "visible",
104
+ width: WidthWithoutContent = "stretch",
101
105
  ) -> UploadedFile | None:
102
106
  r"""Display a widget that returns an audio recording from the user's microphone.
103
107
 
@@ -159,6 +163,11 @@ class AudioInputMixin:
159
163
  label, which can help keep the widget alligned with other widgets.
160
164
  If this is ``"collapsed"``, Streamlit displays no label or spacer.
161
165
 
166
+ width : "stretch" or int
167
+ The width of the audio input widget. If "stretch" (default), the widget
168
+ will take up the full width of its container. If an integer, the width
169
+ will be set to that number of pixels.
170
+
162
171
  Returns
163
172
  -------
164
173
  None or UploadedFile
@@ -197,6 +206,7 @@ class AudioInputMixin:
197
206
  kwargs=kwargs,
198
207
  disabled=disabled,
199
208
  label_visibility=label_visibility,
209
+ width=width,
200
210
  ctx=ctx,
201
211
  )
202
212
 
@@ -211,6 +221,7 @@ class AudioInputMixin:
211
221
  *, # keyword-only arguments:
212
222
  disabled: bool = False,
213
223
  label_visibility: LabelVisibility = "visible",
224
+ width: WidthWithoutContent = "stretch",
214
225
  ctx: ScriptRunContext | None = None,
215
226
  ) -> UploadedFile | None:
216
227
  key = to_key(key)
@@ -230,6 +241,7 @@ class AudioInputMixin:
230
241
  form_id=current_form_id(self.dg),
231
242
  label=label,
232
243
  help=help,
244
+ width=width,
233
245
  )
234
246
 
235
247
  audio_input_proto = AudioInputProto()
@@ -244,6 +256,15 @@ class AudioInputMixin:
244
256
  if label and help is not None:
245
257
  audio_input_proto.help = dedent(help)
246
258
 
259
+ # Set width configuration
260
+ validate_width(width)
261
+ width_config = WidthConfig()
262
+ if isinstance(width, int):
263
+ width_config.pixel_width = width
264
+ else:
265
+ width_config.use_stretch = True
266
+ audio_input_proto.width_config.CopyFrom(width_config)
267
+
247
268
  serde = AudioInputSerde()
248
269
 
249
270
  audio_input_state = register_widget(
@@ -799,15 +799,16 @@ class ButtonMixin:
799
799
  ) -> bool:
800
800
  key = to_key(key)
801
801
 
802
- if on_click == "ignore" or on_click == "rerun":
803
- on_click_callback = None
804
- else:
805
- on_click_callback = on_click
802
+ on_click_callback: WidgetCallback | None = (
803
+ None
804
+ if on_click is None or on_click in {"ignore", "rerun"}
805
+ else cast("WidgetCallback", on_click)
806
+ )
806
807
 
807
808
  check_widget_policies(
808
809
  self.dg,
809
810
  key,
810
- on_click_callback,
811
+ on_change=on_click_callback,
811
812
  default_value=None,
812
813
  writes_allowed=False,
813
814
  )
@@ -433,13 +433,14 @@ class FileUploaderMixin:
433
433
  help=help,
434
434
  )
435
435
 
436
- if type:
437
- type = normalize_upload_file_type(type)
436
+ normalized_type = normalize_upload_file_type(type) if type else None
438
437
 
439
438
  file_uploader_proto = FileUploaderProto()
440
439
  file_uploader_proto.id = element_id
441
440
  file_uploader_proto.label = label
442
- file_uploader_proto.type[:] = type if type is not None else []
441
+ file_uploader_proto.type[:] = (
442
+ normalized_type if normalized_type is not None else []
443
+ )
443
444
  file_uploader_proto.max_upload_size_mb = config.get_option(
444
445
  "server.maxUploadSize"
445
446
  )
@@ -453,7 +454,7 @@ class FileUploaderMixin:
453
454
  if help is not None:
454
455
  file_uploader_proto.help = dedent(help)
455
456
 
456
- serde = FileUploaderSerde(accept_multiple_files, allowed_types=type)
457
+ serde = FileUploaderSerde(accept_multiple_files, allowed_types=normalized_type)
457
458
 
458
459
  # FileUploader's widget value is a list of file IDs
459
460
  # representing the current set of files that this uploader should
@@ -443,32 +443,32 @@ class NumberInputMixin:
443
443
  # Otherwise, defaults to float:
444
444
  float_value = True
445
445
 
446
- if format is None:
447
- format = "%d" if int_value else "%0.2f"
446
+ # Use default format depending on value type if format was not provided:
447
+ number_format = ("%d" if int_value else "%0.2f") if format is None else format
448
448
 
449
449
  # Warn user if they format an int type as a float or vice versa.
450
- if format in ["%d", "%u", "%i"] and float_value:
450
+ if number_format in ["%d", "%u", "%i"] and float_value:
451
451
  import streamlit as st
452
452
 
453
453
  st.warning(
454
454
  "Warning: NumberInput value below has type float,"
455
- f" but format {format} displays as integer."
455
+ f" but format {number_format} displays as integer."
456
456
  )
457
- elif format[-1] == "f" and int_value:
457
+ elif number_format[-1] == "f" and int_value:
458
458
  import streamlit as st
459
459
 
460
460
  st.warning(
461
461
  "Warning: NumberInput value below has type int so is"
462
- f" displayed as int despite format string {format}."
462
+ f" displayed as int despite format string {number_format}."
463
463
  )
464
464
 
465
465
  if step is None:
466
466
  step = 1 if int_value else 0.01
467
467
 
468
468
  try:
469
- float(format % 2)
469
+ float(number_format % 2)
470
470
  except (TypeError, ValueError):
471
- raise StreamlitInvalidNumberFormatError(format)
471
+ raise StreamlitInvalidNumberFormatError(number_format)
472
472
 
473
473
 
474
474
  # Ensure that the value matches arguments' types.
@@ -547,8 +547,7 @@ class NumberInputMixin:
547
547
  if step is not None:
548
548
  number_input_proto.step = step
549
549
 
550
- if format is not None:
551
- number_input_proto.format = format
550
+ number_input_proto.format = number_format
552
551
 
553
552
  if icon is not None:
554
553
  number_input_proto.icon = validate_icon_or_emoji(icon)
@@ -705,7 +705,7 @@ class SliderMixin:
705
705
  ) and max_value - min_value < timedelta(days=1):
706
706
  step = timedelta(minutes=15)
707
707
  if format is None:
708
- format = cast("str", DEFAULTS[data_type]["format"])
708
+ format = cast("str", DEFAULTS[data_type]["format"]) # noqa: A001
709
709
 
710
710
  if step == 0:
711
711
  raise StreamlitAPIException(
streamlit/error_util.py CHANGED
@@ -17,9 +17,9 @@ from __future__ import annotations
17
17
  from typing import Final
18
18
 
19
19
  import streamlit
20
- import streamlit.elements.exception as exception
21
20
  from streamlit import config
22
21
  from streamlit.delta_generator_singletons import get_dg_singleton_instance
22
+ from streamlit.elements import exception
23
23
  from streamlit.logger import get_logger
24
24
 
25
25
  _LOGGER: Final = get_logger(__name__)