streamlit-nightly 1.39.1.dev20241031__py2.py3-none-any.whl → 1.39.1.dev20241102__py2.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 (49) hide show
  1. streamlit/commands/execution_control.py +7 -2
  2. streamlit/commands/logo.py +3 -3
  3. streamlit/commands/navigation.py +48 -3
  4. streamlit/commands/page_config.py +8 -3
  5. streamlit/elements/html.py +6 -4
  6. streamlit/elements/image.py +28 -443
  7. streamlit/elements/layouts.py +12 -7
  8. streamlit/elements/lib/image_utils.py +440 -0
  9. streamlit/elements/markdown.py +6 -0
  10. streamlit/elements/media.py +22 -9
  11. streamlit/elements/metric.py +8 -5
  12. streamlit/elements/progress.py +2 -1
  13. streamlit/elements/pyplot.py +3 -5
  14. streamlit/elements/text.py +1 -1
  15. streamlit/elements/widgets/audio_input.py +12 -11
  16. streamlit/elements/widgets/button.py +28 -19
  17. streamlit/elements/widgets/button_group.py +146 -121
  18. streamlit/elements/widgets/camera_input.py +13 -11
  19. streamlit/elements/widgets/chat.py +2 -2
  20. streamlit/elements/widgets/checkbox.py +30 -24
  21. streamlit/elements/widgets/color_picker.py +15 -13
  22. streamlit/elements/widgets/file_uploader.py +12 -12
  23. streamlit/elements/widgets/multiselect.py +33 -31
  24. streamlit/elements/widgets/number_input.py +15 -12
  25. streamlit/elements/widgets/radio.py +15 -12
  26. streamlit/elements/widgets/select_slider.py +15 -12
  27. streamlit/elements/widgets/selectbox.py +19 -14
  28. streamlit/elements/widgets/slider.py +15 -12
  29. streamlit/elements/widgets/text_widgets.py +33 -27
  30. streamlit/elements/widgets/time_widgets.py +33 -25
  31. streamlit/hello/{Animation_Demo.py → animation_demo.py} +9 -10
  32. streamlit/hello/{Dataframe_Demo.py → dataframe_demo.py} +9 -15
  33. streamlit/hello/{Hello.py → hello.py} +7 -12
  34. streamlit/hello/{Mapping_Demo.py → mapping_demo.py} +10 -13
  35. streamlit/hello/{Plotting_Demo.py → plotting_demo.py} +9 -10
  36. streamlit/hello/streamlit_app.py +24 -6
  37. streamlit/proto/Image_pb2.pyi +1 -1
  38. streamlit/static/asset-manifest.json +3 -3
  39. streamlit/static/index.html +1 -1
  40. streamlit/static/static/js/3224.925d380f.chunk.js +1 -0
  41. streamlit/static/static/js/{main.754d974e.js → main.61a89bda.js} +2 -2
  42. {streamlit_nightly-1.39.1.dev20241031.dist-info → streamlit_nightly-1.39.1.dev20241102.dist-info}/METADATA +1 -1
  43. {streamlit_nightly-1.39.1.dev20241031.dist-info → streamlit_nightly-1.39.1.dev20241102.dist-info}/RECORD +48 -47
  44. streamlit/static/static/js/3224.919d670d.chunk.js +0 -1
  45. /streamlit/static/static/js/{main.754d974e.js.LICENSE.txt → main.61a89bda.js.LICENSE.txt} +0 -0
  46. {streamlit_nightly-1.39.1.dev20241031.data → streamlit_nightly-1.39.1.dev20241102.data}/scripts/streamlit.cmd +0 -0
  47. {streamlit_nightly-1.39.1.dev20241031.dist-info → streamlit_nightly-1.39.1.dev20241102.dist-info}/WHEEL +0 -0
  48. {streamlit_nightly-1.39.1.dev20241031.dist-info → streamlit_nightly-1.39.1.dev20241102.dist-info}/entry_points.txt +0 -0
  49. {streamlit_nightly-1.39.1.dev20241031.dist-info → streamlit_nightly-1.39.1.dev20241102.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,440 @@
1
+ # Copyright (c) Streamlit Inc. (2018-2022) Snowflake Inc. (2022-2024)
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from __future__ import annotations
16
+
17
+ import io
18
+ import os
19
+ import re
20
+ from enum import IntEnum
21
+ from pathlib import Path
22
+ from typing import TYPE_CHECKING, Final, Literal, Sequence, Union, cast
23
+
24
+ from typing_extensions import TypeAlias
25
+
26
+ from streamlit import runtime, url_util
27
+ from streamlit.errors import StreamlitAPIException
28
+ from streamlit.runtime import caching
29
+ from streamlit.type_util import NumpyShape
30
+
31
+ if TYPE_CHECKING:
32
+ from typing import Any
33
+
34
+ import numpy.typing as npt
35
+ from PIL import GifImagePlugin, Image, ImageFile
36
+
37
+ from streamlit.proto.Image_pb2 import ImageList as ImageListProto
38
+
39
+ PILImage: TypeAlias = Union[
40
+ "ImageFile.ImageFile", "Image.Image", "GifImagePlugin.GifImageFile"
41
+ ]
42
+ AtomicImage: TypeAlias = Union[
43
+ PILImage, "npt.NDArray[Any]", io.BytesIO, str, Path, bytes
44
+ ]
45
+
46
+ Channels: TypeAlias = Literal["RGB", "BGR"]
47
+ ImageFormat: TypeAlias = Literal["JPEG", "PNG", "GIF"]
48
+ ImageFormatOrAuto: TypeAlias = Literal[ImageFormat, "auto"]
49
+ ImageOrImageList: TypeAlias = Union[AtomicImage, Sequence[AtomicImage]]
50
+
51
+ # This constant is related to the frontend maximum content width specified
52
+ # in App.jsx main container
53
+ # 730 is the max width of element-container in the frontend, and 2x is for high
54
+ # DPI.
55
+ MAXIMUM_CONTENT_WIDTH: Final[int] = 2 * 730
56
+
57
+
58
+ # @see Image.proto
59
+ # @see WidthBehavior on the frontend
60
+ class WidthBehavior(IntEnum):
61
+ """
62
+ Special values that are recognized by the frontend and allow us to change the
63
+ behavior of the displayed image.
64
+ """
65
+
66
+ ORIGINAL = -1
67
+ COLUMN = -2
68
+ AUTO = -3
69
+ MIN_IMAGE_OR_CONTAINER = -4
70
+ MAX_IMAGE_OR_CONTAINER = -5
71
+
72
+
73
+ WidthBehavior.ORIGINAL.__doc__ = """Display the image at its original width"""
74
+ WidthBehavior.COLUMN.__doc__ = (
75
+ """Display the image at the width of the column it's in."""
76
+ )
77
+ WidthBehavior.AUTO.__doc__ = """Display the image at its original width, unless it
78
+ would exceed the width of its column in which case clamp it to
79
+ its column width"""
80
+
81
+
82
+ def _image_may_have_alpha_channel(image: PILImage) -> bool:
83
+ return image.mode in ("RGBA", "LA", "P")
84
+
85
+
86
+ def _image_is_gif(image: PILImage) -> bool:
87
+ return image.format == "GIF"
88
+
89
+
90
+ def _validate_image_format_string(
91
+ image_data: bytes | PILImage, format: str
92
+ ) -> ImageFormat:
93
+ """Return either "JPEG", "PNG", or "GIF", based on the input `format` string.
94
+ - If `format` is "JPEG" or "JPG" (or any capitalization thereof), return "JPEG"
95
+ - If `format` is "PNG" (or any capitalization thereof), return "PNG"
96
+ - For all other strings, return "PNG" if the image has an alpha channel,
97
+ "GIF" if the image is a GIF, and "JPEG" otherwise.
98
+ """
99
+ format = format.upper()
100
+ if format in {"JPEG", "PNG"}:
101
+ return cast(ImageFormat, format)
102
+
103
+ # We are forgiving on the spelling of JPEG
104
+ if format == "JPG":
105
+ return "JPEG"
106
+
107
+ pil_image: PILImage
108
+ if isinstance(image_data, bytes):
109
+ from PIL import Image
110
+
111
+ pil_image = Image.open(io.BytesIO(image_data))
112
+ else:
113
+ pil_image = image_data
114
+
115
+ if _image_is_gif(pil_image):
116
+ return "GIF"
117
+
118
+ if _image_may_have_alpha_channel(pil_image):
119
+ return "PNG"
120
+
121
+ return "JPEG"
122
+
123
+
124
+ def _PIL_to_bytes(
125
+ image: PILImage,
126
+ format: ImageFormat = "JPEG",
127
+ quality: int = 100,
128
+ ) -> bytes:
129
+ """Convert a PIL image to bytes."""
130
+ tmp = io.BytesIO()
131
+
132
+ # User must have specified JPEG, so we must convert it
133
+ if format == "JPEG" and _image_may_have_alpha_channel(image):
134
+ image = image.convert("RGB")
135
+
136
+ image.save(tmp, format=format, quality=quality)
137
+
138
+ return tmp.getvalue()
139
+
140
+
141
+ def _BytesIO_to_bytes(data: io.BytesIO) -> bytes:
142
+ data.seek(0)
143
+ return data.getvalue()
144
+
145
+
146
+ def _np_array_to_bytes(array: npt.NDArray[Any], output_format: str = "JPEG") -> bytes:
147
+ import numpy as np
148
+ from PIL import Image
149
+
150
+ img = Image.fromarray(array.astype(np.uint8))
151
+ format = _validate_image_format_string(img, output_format)
152
+
153
+ return _PIL_to_bytes(img, format)
154
+
155
+
156
+ def _verify_np_shape(array: npt.NDArray[Any]) -> npt.NDArray[Any]:
157
+ shape: NumpyShape = array.shape
158
+ if len(shape) not in (2, 3):
159
+ raise StreamlitAPIException("Numpy shape has to be of length 2 or 3.")
160
+ if len(shape) == 3 and shape[-1] not in (1, 3, 4):
161
+ raise StreamlitAPIException(
162
+ "Channel can only be 1, 3, or 4 got %d. Shape is %s"
163
+ % (shape[-1], str(shape))
164
+ )
165
+
166
+ # If there's only one channel, convert is to x, y
167
+ if len(shape) == 3 and shape[-1] == 1:
168
+ array = array[:, :, 0]
169
+
170
+ return array
171
+
172
+
173
+ def _get_image_format_mimetype(image_format: ImageFormat) -> str:
174
+ """Get the mimetype string for the given ImageFormat."""
175
+ return f"image/{image_format.lower()}"
176
+
177
+
178
+ def _ensure_image_size_and_format(
179
+ image_data: bytes, width: int, image_format: ImageFormat
180
+ ) -> bytes:
181
+ """Resize an image if it exceeds the given width, or if exceeds
182
+ MAXIMUM_CONTENT_WIDTH. Ensure the image's format corresponds to the given
183
+ ImageFormat. Return the (possibly resized and reformatted) image bytes.
184
+ """
185
+ from PIL import Image
186
+
187
+ pil_image: PILImage = Image.open(io.BytesIO(image_data))
188
+ actual_width, actual_height = pil_image.size
189
+
190
+ if width < 0 and actual_width > MAXIMUM_CONTENT_WIDTH:
191
+ width = MAXIMUM_CONTENT_WIDTH
192
+
193
+ if width > 0 and actual_width > width:
194
+ # We need to resize the image.
195
+ new_height = int(1.0 * actual_height * width / actual_width)
196
+ # pillow reexports Image.Resampling.BILINEAR as Image.BILINEAR for backwards
197
+ # compatibility reasons, so we use the reexport to support older pillow
198
+ # versions. The types don't seem to reflect this, though, hence the type: ignore
199
+ # below.
200
+ pil_image = pil_image.resize((width, new_height), resample=Image.BILINEAR) # type: ignore[attr-defined]
201
+ return _PIL_to_bytes(pil_image, format=image_format, quality=90)
202
+
203
+ if pil_image.format != image_format:
204
+ # We need to reformat the image.
205
+ return _PIL_to_bytes(pil_image, format=image_format, quality=90)
206
+
207
+ # No resizing or reformatting necessary - return the original bytes.
208
+ return image_data
209
+
210
+
211
+ def _clip_image(image: npt.NDArray[Any], clamp: bool) -> npt.NDArray[Any]:
212
+ import numpy as np
213
+
214
+ data = image
215
+ if issubclass(image.dtype.type, np.floating):
216
+ if clamp:
217
+ data = np.clip(image, 0, 1.0)
218
+ else:
219
+ if 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.")
221
+ data = data * 255
222
+ else:
223
+ if clamp:
224
+ data = np.clip(image, 0, 255)
225
+ else:
226
+ if np.amin(image) < 0 or np.amax(image) > 255:
227
+ raise RuntimeError("Data is outside [0, 255] and clamp is not set.")
228
+ return data
229
+
230
+
231
+ def image_to_url(
232
+ image: AtomicImage,
233
+ width: int,
234
+ clamp: bool,
235
+ channels: Channels,
236
+ output_format: ImageFormatOrAuto,
237
+ image_id: str,
238
+ ) -> str:
239
+ """Return a URL that an image can be served from.
240
+ If `image` is already a URL, return it unmodified.
241
+ Otherwise, add the image to the MediaFileManager and return the URL.
242
+ (When running in "raw" mode, we won't actually load data into the
243
+ MediaFileManager, and we'll return an empty URL.)
244
+ """
245
+ import numpy as np
246
+ from PIL import Image, ImageFile
247
+
248
+ image_data: bytes
249
+
250
+ # Convert Path to string if necessary
251
+ if isinstance(image, Path):
252
+ image = str(image)
253
+
254
+ # Strings
255
+ if isinstance(image, str):
256
+ if not os.path.isfile(image) and url_util.is_url(
257
+ image, allowed_schemas=("http", "https", "data")
258
+ ):
259
+ # If it's a url, return it directly.
260
+ return image
261
+
262
+ if image.endswith(".svg") and os.path.isfile(image):
263
+ # Unpack local SVG image file to an SVG string
264
+ with open(image) as textfile:
265
+ image = textfile.read()
266
+
267
+ # Following regex allows svg image files to start either via a "<?xml...>" tag
268
+ # eventually followed by a "<svg...>" tag or directly starting with a "<svg>" tag
269
+ if re.search(r"(^\s?(<\?xml[\s\S]*<svg\s)|^\s?<svg\s|^\s?<svg>\s)", image):
270
+ if "xmlns" not in image:
271
+ # The xmlns attribute is required for SVGs to render in an img tag.
272
+ # If it's not present, we add to the first SVG tag:
273
+ image = image.replace(
274
+ "<svg", '<svg xmlns="http://www.w3.org/2000/svg" ', 1
275
+ )
276
+ # Convert to base64 to prevent issues with encoding:
277
+ import base64
278
+
279
+ image_b64_encoded = base64.b64encode(image.encode("utf-8")).decode("utf-8")
280
+ # Return SVG as data URI:
281
+ return f"data:image/svg+xml;base64,{image_b64_encoded}"
282
+
283
+ # Otherwise, try to open it as a file.
284
+ try:
285
+ with open(image, "rb") as f:
286
+ image_data = f.read()
287
+ except Exception:
288
+ # When we aren't able to open the image file, we still pass the path to
289
+ # the MediaFileManager - its storage backend may have access to files
290
+ # that Streamlit does not.
291
+ import mimetypes
292
+
293
+ mimetype, _ = mimetypes.guess_type(image)
294
+ if mimetype is None:
295
+ mimetype = "application/octet-stream"
296
+
297
+ url = runtime.get_instance().media_file_mgr.add(image, mimetype, image_id)
298
+ caching.save_media_data(image, mimetype, image_id)
299
+ return url
300
+
301
+ # PIL Images
302
+ elif isinstance(image, (ImageFile.ImageFile, Image.Image)):
303
+ format = _validate_image_format_string(image, output_format)
304
+ image_data = _PIL_to_bytes(image, format)
305
+
306
+ # BytesIO
307
+ # Note: This doesn't support SVG. We could convert to png (cairosvg.svg2png)
308
+ # or just decode BytesIO to string and handle that way.
309
+ elif isinstance(image, io.BytesIO):
310
+ image_data = _BytesIO_to_bytes(image)
311
+
312
+ # Numpy Arrays (ie opencv)
313
+ elif isinstance(image, np.ndarray):
314
+ image = _clip_image(_verify_np_shape(image), clamp)
315
+
316
+ if channels == "BGR":
317
+ if len(cast(NumpyShape, image.shape)) == 3:
318
+ image = image[:, :, [2, 1, 0]]
319
+ else:
320
+ raise StreamlitAPIException(
321
+ 'When using `channels="BGR"`, the input image should '
322
+ "have exactly 3 color channels"
323
+ )
324
+
325
+ image_data = _np_array_to_bytes(array=image, output_format=output_format)
326
+
327
+ # Raw bytes
328
+ else:
329
+ image_data = image
330
+
331
+ # Determine the image's format, resize it, and get its mimetype
332
+ image_format = _validate_image_format_string(image_data, output_format)
333
+ image_data = _ensure_image_size_and_format(image_data, width, image_format)
334
+ mimetype = _get_image_format_mimetype(image_format)
335
+
336
+ if runtime.exists():
337
+ url = runtime.get_instance().media_file_mgr.add(image_data, mimetype, image_id)
338
+ caching.save_media_data(image_data, mimetype, image_id)
339
+ return url
340
+ else:
341
+ # When running in "raw mode", we can't access the MediaFileManager.
342
+ return ""
343
+
344
+
345
+ def _4d_to_list_3d(array: npt.NDArray[Any]) -> list[npt.NDArray[Any]]:
346
+ return [array[i, :, :, :] for i in range(0, array.shape[0])]
347
+
348
+
349
+ def marshall_images(
350
+ coordinates: str,
351
+ image: ImageOrImageList,
352
+ caption: str | npt.NDArray[Any] | list[str] | None,
353
+ width: int | WidthBehavior,
354
+ proto_imgs: ImageListProto,
355
+ clamp: bool,
356
+ channels: Channels = "RGB",
357
+ output_format: ImageFormatOrAuto = "auto",
358
+ ) -> None:
359
+ """Fill an ImageListProto with a list of images and their captions.
360
+ The images will be resized and reformatted as necessary.
361
+ Parameters
362
+ ----------
363
+ coordinates
364
+ A string indentifying the images' location in the frontend.
365
+ image
366
+ The image or images to include in the ImageListProto.
367
+ caption
368
+ Image caption. If displaying multiple images, caption should be a
369
+ list of captions (one for each image).
370
+ width
371
+ The desired width of the image or images. This parameter will be
372
+ passed to the frontend.
373
+ Positive values set the image width explicitly.
374
+ Negative values has some special. For details, see: `WidthBehaviour`
375
+ proto_imgs
376
+ The ImageListProto to fill in.
377
+ clamp
378
+ Clamp image pixel values to a valid range ([0-255] per channel).
379
+ This is only meaningful for byte array images; the parameter is
380
+ ignored for image URLs. If this is not set, and an image has an
381
+ out-of-range value, an error will be thrown.
382
+ channels
383
+ If image is an nd.array, this parameter denotes the format used to
384
+ represent color information. Defaults to 'RGB', meaning
385
+ `image[:, :, 0]` is the red channel, `image[:, :, 1]` is green, and
386
+ `image[:, :, 2]` is blue. For images coming from libraries like
387
+ OpenCV you should set this to 'BGR', instead.
388
+ output_format
389
+ This parameter specifies the format to use when transferring the
390
+ image data. Photos should use the JPEG format for lossy compression
391
+ while diagrams should use the PNG format for lossless compression.
392
+ Defaults to 'auto' which identifies the compression type based
393
+ on the type and format of the image argument.
394
+ """
395
+ import numpy as np
396
+
397
+ channels = cast(Channels, channels.upper())
398
+
399
+ # Turn single image and caption into one element list.
400
+ images: Sequence[AtomicImage]
401
+ if isinstance(image, (list, set, tuple)):
402
+ images = list(image)
403
+ elif isinstance(image, np.ndarray) and len(cast(NumpyShape, image.shape)) == 4:
404
+ images = _4d_to_list_3d(image)
405
+ else:
406
+ images = [image] # type: ignore
407
+
408
+ if isinstance(caption, list):
409
+ captions: Sequence[str | None] = caption
410
+ elif isinstance(caption, str):
411
+ captions = [caption]
412
+ elif isinstance(caption, np.ndarray) and len(cast(NumpyShape, caption.shape)) == 1:
413
+ captions = caption.tolist()
414
+ elif caption is None:
415
+ captions = [None] * len(images)
416
+ else:
417
+ captions = [str(caption)]
418
+
419
+ assert isinstance(
420
+ captions, list
421
+ ), "If image is a list then caption should be as well"
422
+ assert len(captions) == len(images), "Cannot pair %d captions with %d images." % (
423
+ len(captions),
424
+ len(images),
425
+ )
426
+
427
+ proto_imgs.width = int(width)
428
+ # Each image in an image list needs to be kept track of at its own coordinates.
429
+ for coord_suffix, (image, caption) in enumerate(zip(images, captions)):
430
+ proto_img = proto_imgs.imgs.add()
431
+ if caption is not None:
432
+ proto_img.caption = str(caption)
433
+
434
+ # We use the index of the image in the input image list to identify this image inside
435
+ # MediaFileManager. For this, we just add the index to the image's "coordinates".
436
+ image_id = "%s-%i" % (coordinates, coord_suffix)
437
+
438
+ proto_img.url = image_to_url(
439
+ image, width, clamp, channels, output_format, image_id
440
+ )
@@ -52,6 +52,12 @@ class MarkdownMixin:
52
52
  For a list of all supported codes,
53
53
  see https://share.streamlit.io/streamlit/emoji-shortcodes.
54
54
 
55
+ * Streamlit logo shortcode. Use ``:streamlit:`` to add a little
56
+ Streamlit flair to your text.
57
+
58
+ * A limited set of typographical symbols. ``"<- -> <-> -- >= <= ~="``
59
+ becomes "← → ↔ — ≥ ≤ ≈" when parsed as Markdown.
60
+
55
61
  * Google Material Symbols (rounded style), using the syntax
56
62
  ``:material/icon_name:``, where "icon_name" is the name of the
57
63
  icon in snake case. For a complete list of icons, see Google's
@@ -43,7 +43,14 @@ if TYPE_CHECKING:
43
43
 
44
44
 
45
45
  MediaData: TypeAlias = Union[
46
- str, bytes, io.BytesIO, io.RawIOBase, io.BufferedReader, "npt.NDArray[Any]", None
46
+ str,
47
+ Path,
48
+ bytes,
49
+ io.BytesIO,
50
+ io.RawIOBase,
51
+ io.BufferedReader,
52
+ "npt.NDArray[Any]",
53
+ None,
47
54
  ]
48
55
 
49
56
  SubtitleData: TypeAlias = Union[
@@ -78,8 +85,8 @@ class MediaMixin:
78
85
 
79
86
  Parameters
80
87
  ----------
81
- data : str, bytes, BytesIO, numpy.ndarray, or file
82
- Raw audio data, filename, or a URL pointing to the file to load.
88
+ data : str, Path, bytes, BytesIO, numpy.ndarray, or file
89
+ Raw audio data, file path (str or Path object), or a URL pointing to the file to load.
83
90
  Raw data formats must include all necessary file headers to match the file
84
91
  format specified via ``format``.
85
92
  If ``data`` is a numpy array, it must either be a 1D array of the waveform
@@ -212,8 +219,8 @@ class MediaMixin:
212
219
 
213
220
  Parameters
214
221
  ----------
215
- data : str, bytes, io.BytesIO, numpy.ndarray, or file
216
- Raw video data, filename, or URL pointing to a video to load.
222
+ data : str, Path, bytes, io.BytesIO, numpy.ndarray, or file
223
+ Raw video data, file path (str or Path object), or URL pointing to a video to load.
217
224
  Includes support for YouTube URLs.
218
225
  Numpy arrays and raw data formats must include all necessary file
219
226
  headers to match specified file format.
@@ -421,6 +428,8 @@ def _marshall_av_media(
421
428
  if isinstance(data, (str, bytes)):
422
429
  # Pass strings and bytes through unchanged
423
430
  data_or_filename = data
431
+ elif isinstance(data, Path):
432
+ data_or_filename = str(data)
424
433
  elif isinstance(data, io.BytesIO):
425
434
  data.seek(0)
426
435
  data_or_filename = data.getvalue()
@@ -467,7 +476,7 @@ def marshall_video(
467
476
  ----------
468
477
  coordinates : str
469
478
  proto : the proto to fill. Must have a string field called "data".
470
- data : str, bytes, BytesIO, numpy.ndarray, or file opened with
479
+ data : str, Path, bytes, BytesIO, numpy.ndarray, or file opened with
471
480
  io.open().
472
481
  Raw video data or a string with a URL pointing to the video
473
482
  to load. Includes support for YouTube URLs.
@@ -520,6 +529,9 @@ def marshall_video(
520
529
  # "type" distinguishes between YouTube and non-YouTube links
521
530
  proto.type = VideoProto.Type.NATIVE
522
531
 
532
+ if isinstance(data, Path):
533
+ data = str(data) # Convert Path to string
534
+
523
535
  if isinstance(data, str) and url_util.is_url(
524
536
  data, allowed_schemas=("http", "https", "data")
525
537
  ):
@@ -532,7 +544,6 @@ def marshall_video(
532
544
  )
533
545
  else:
534
546
  proto.url = data
535
-
536
547
  else:
537
548
  _marshall_av_media(coordinates, proto, data, mimetype)
538
549
 
@@ -711,7 +722,7 @@ def marshall_audio(
711
722
  ----------
712
723
  coordinates : str
713
724
  proto : The proto to fill. Must have a string field called "url".
714
- data : str, bytes, BytesIO, numpy.ndarray, or file opened with
725
+ data : str, Path, bytes, BytesIO, numpy.ndarray, or file opened with
715
726
  io.open()
716
727
  Raw audio data or a string with a URL pointing to the file to load.
717
728
  If passing the raw data, this must include headers and any other bytes
@@ -740,11 +751,13 @@ def marshall_audio(
740
751
  proto.end_time = end_time
741
752
  proto.loop = loop
742
753
 
754
+ if isinstance(data, Path):
755
+ data = str(data) # Convert Path to string
756
+
743
757
  if isinstance(data, str) and url_util.is_url(
744
758
  data, allowed_schemas=("http", "https", "data")
745
759
  ):
746
760
  proto.url = data
747
-
748
761
  else:
749
762
  data = _maybe_convert_to_wav_bytes(data, sample_rate)
750
763
  _marshall_av_media(coordinates, proto, data, mimetype)
@@ -70,7 +70,8 @@ class MetricMixin:
70
70
  label : str
71
71
  The header or title for the metric. The label can optionally
72
72
  contain GitHub-flavored Markdown of the following types: Bold, Italics,
73
- Strikethroughs, Inline Code, and Links.
73
+ Strikethroughs, Inline Code, Links, and Images. Images display like
74
+ icons, with a max height equal to the font height.
74
75
 
75
76
  Unsupported Markdown elements are unwrapped so only their children
76
77
  (text contents) render. Display unsupported elements as literal
@@ -102,12 +103,14 @@ class MetricMixin:
102
103
 
103
104
  help : str
104
105
  An optional tooltip that gets displayed next to the metric label.
106
+ Streamlit only displays the tooltip when
107
+ ``label_visibility="visible"``.
105
108
 
106
109
  label_visibility : "visible", "hidden", or "collapsed"
107
- The visibility of the label. If "hidden", the label doesn't show but there
108
- is still empty space for it (equivalent to label="").
109
- If "collapsed", both the label and the space are removed. Default is
110
- "visible".
110
+ The visibility of the label. The default is ``"visible"``. If this
111
+ is ``"hidden"``, Streamlit displays an empty spacer instead of the
112
+ label, which can help keep the widget alligned with other widgets.
113
+ If this is ``"collapsed"``, Streamlit displays no label or spacer.
111
114
 
112
115
  Example
113
116
  -------
@@ -105,7 +105,8 @@ class ProgressMixin:
105
105
  text : str or None
106
106
  A message to display above the progress bar. The text can optionally
107
107
  contain GitHub-flavored Markdown of the following types: Bold, Italics,
108
- Strikethroughs, Inline Code, and Links.
108
+ Strikethroughs, Inline Code, Links, and Images. Images display like
109
+ icons, with a max height equal to the font height.
109
110
 
110
111
  Unsupported Markdown elements are unwrapped so only their children
111
112
  (text contents) render. Display unsupported elements as literal
@@ -19,8 +19,8 @@ from __future__ import annotations
19
19
  import io
20
20
  from typing import TYPE_CHECKING, Any, cast
21
21
 
22
- import streamlit.elements.image as image_utils
23
22
  from streamlit.deprecation_util import show_deprecation_warning
23
+ from streamlit.elements.lib.image_utils import WidthBehavior, marshall_images
24
24
  from streamlit.proto.Image_pb2 import ImageList as ImageListProto
25
25
  from streamlit.runtime.metrics_util import gather_metrics
26
26
 
@@ -172,11 +172,9 @@ def marshall(
172
172
  image = io.BytesIO()
173
173
  fig.savefig(image, **kwargs)
174
174
  image_width = (
175
- image_utils.WidthBehaviour.COLUMN
176
- if use_container_width
177
- else image_utils.WidthBehaviour.ORIGINAL
175
+ WidthBehavior.COLUMN if use_container_width else WidthBehavior.ORIGINAL
178
176
  )
179
- image_utils.marshall_images(
177
+ marshall_images(
180
178
  coordinates=coordinates,
181
179
  image=image,
182
180
  caption=None,
@@ -52,7 +52,7 @@ class TextMixin:
52
52
  -------
53
53
  >>> import streamlit as st
54
54
  >>>
55
- >>> st.text("This is text/n[and more text](that's not a Markdown link).")
55
+ >>> st.text("This is text\\n[and more text](that's not a Markdown link).")
56
56
 
57
57
  .. output ::
58
58
  https://doc-text.streamlit.app/
@@ -107,8 +107,9 @@ class AudioInputMixin:
107
107
  label : str
108
108
  A short label explaining to the user what this widget is used for.
109
109
  The label can optionally contain GitHub-flavored Markdown of the
110
- following types: Bold, Italics, Strikethroughs, Inline Code, and
111
- Links.
110
+ following types: Bold, Italics, Strikethroughs, Inline Code, Links,
111
+ and Images. Images display like icons, with a max height equal to
112
+ the font height.
112
113
 
113
114
  Unsupported Markdown elements are unwrapped so only their children
114
115
  (text contents) render. Display unsupported elements as literal
@@ -118,9 +119,9 @@ class AudioInputMixin:
118
119
  See the ``body`` parameter of |st.markdown|_ for additional,
119
120
  supported Markdown directives.
120
121
 
121
- For accessibility reasons, you should never set an empty label (label="")
122
- but hide it with label_visibility if needed. In the future, we may disallow
123
- empty labels by raising an exception.
122
+ For accessibility reasons, you should never set an empty label, but
123
+ you can hide it with ``label_visibility`` if needed. In the future,
124
+ we may disallow empty labels by raising an exception.
124
125
 
125
126
  .. |st.markdown| replace:: ``st.markdown``
126
127
  .. _st.markdown: https://docs.streamlit.io/develop/api-reference/text/st.markdown
@@ -144,14 +145,14 @@ class AudioInputMixin:
144
145
  An optional dict of kwargs to pass to the callback.
145
146
 
146
147
  disabled : bool
147
- An optional boolean, which disables the audio input if set to
148
- True. Default is False.
148
+ An optional boolean that disables the audio input if set to
149
+ ``True``. Default is ``False``.
149
150
 
150
151
  label_visibility : "visible", "hidden", or "collapsed"
151
- The visibility of the label. If "hidden", the label doesn't show but there
152
- is still empty space for it above the widget (equivalent to label="").
153
- If "collapsed", both the label and the space are removed. Default is
154
- "visible".
152
+ The visibility of the label. The default is ``"visible"``. If this
153
+ is ``"hidden"``, Streamlit displays an empty spacer instead of the
154
+ label, which can help keep the widget alligned with other widgets.
155
+ If this is ``"collapsed"``, Streamlit displays no label or spacer.
155
156
 
156
157
  Returns
157
158
  -------