streamlit-nightly 1.45.1.dev20250511__py3-none-any.whl → 1.45.2.dev20250513__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.
- streamlit/__init__.py +1 -0
- streamlit/auth_util.py +6 -6
- streamlit/commands/echo.py +5 -3
- streamlit/commands/experimental_query_params.py +1 -1
- streamlit/commands/navigation.py +1 -4
- streamlit/components/v1/custom_component.py +2 -2
- streamlit/config.py +16 -18
- streamlit/config_util.py +6 -7
- streamlit/connections/sql_connection.py +1 -1
- streamlit/dataframe_util.py +50 -51
- streamlit/delta_generator.py +4 -1
- streamlit/deprecation_util.py +5 -5
- streamlit/elements/arrow.py +1 -1
- streamlit/elements/deck_gl_json_chart.py +1 -4
- streamlit/elements/doc_string.py +5 -10
- streamlit/elements/exception.py +5 -7
- streamlit/elements/layouts.py +4 -3
- streamlit/elements/lib/built_in_chart_utils.py +22 -22
- streamlit/elements/lib/pandas_styler_utils.py +6 -8
- streamlit/elements/lib/policies.py +1 -1
- streamlit/elements/map.py +2 -8
- streamlit/elements/markdown.py +1 -4
- streamlit/elements/media.py +50 -2
- streamlit/elements/metric.py +9 -10
- streamlit/elements/spinner.py +1 -1
- streamlit/elements/vega_charts.py +1 -1
- streamlit/elements/widgets/audio_input.py +1 -4
- streamlit/elements/widgets/camera_input.py +1 -4
- streamlit/elements/widgets/chat.py +52 -5
- streamlit/elements/widgets/data_editor.py +1 -1
- streamlit/elements/widgets/slider.py +4 -5
- streamlit/elements/widgets/time_widgets.py +1 -4
- streamlit/elements/write.py +2 -2
- streamlit/env_util.py +2 -7
- streamlit/error_util.py +15 -8
- streamlit/errors.py +11 -8
- streamlit/file_util.py +6 -3
- streamlit/git_util.py +26 -21
- streamlit/hello/dataframe_demo.py +1 -1
- streamlit/hello/mapping_demo.py +1 -1
- streamlit/hello/plotting_demo.py +3 -3
- streamlit/hello/streamlit_app.py +1 -1
- streamlit/hello/utils.py +2 -1
- streamlit/logger.py +4 -5
- streamlit/proto/Audio_pb2.py +4 -3
- streamlit/proto/Audio_pb2.pyi +8 -1
- streamlit/proto/Block_pb2.py +5 -5
- streamlit/proto/Block_pb2.pyi +7 -1
- streamlit/proto/ChatInput_pb2.py +8 -7
- streamlit/proto/ChatInput_pb2.pyi +10 -1
- streamlit/proto/Video_pb2.py +8 -7
- streamlit/proto/Video_pb2.pyi +8 -1
- streamlit/runtime/app_session.py +5 -5
- streamlit/runtime/caching/cache_data_api.py +2 -2
- streamlit/runtime/caching/cache_resource_api.py +1 -1
- streamlit/runtime/caching/cache_utils.py +3 -3
- streamlit/runtime/caching/hashing.py +10 -10
- streamlit/runtime/credentials.py +9 -8
- streamlit/runtime/forward_msg_queue.py +1 -1
- streamlit/runtime/memory_media_file_storage.py +5 -4
- streamlit/runtime/memory_uploaded_file_manager.py +1 -1
- streamlit/runtime/metrics_util.py +2 -2
- streamlit/runtime/runtime.py +1 -1
- streamlit/runtime/scriptrunner/exec_code.py +1 -1
- streamlit/runtime/scriptrunner/script_cache.py +1 -1
- streamlit/runtime/scriptrunner/script_runner.py +10 -3
- streamlit/runtime/scriptrunner_utils/script_requests.py +3 -3
- streamlit/runtime/scriptrunner_utils/script_run_context.py +3 -3
- streamlit/runtime/secrets.py +6 -7
- streamlit/runtime/state/query_params.py +3 -5
- streamlit/runtime/state/session_state.py +15 -15
- streamlit/runtime/stats.py +1 -1
- streamlit/static/index.html +1 -1
- streamlit/static/static/js/{ErrorOutline.esm.B5LmzpSn.js → ErrorOutline.esm.CxkgXqSh.js} +1 -1
- streamlit/static/static/js/{FileDownload.esm.BgWveG3s.js → FileDownload.esm.DVrjmwoh.js} +1 -1
- streamlit/static/static/js/{FileHelper.DepIpP48.js → FileHelper.CMA9s0t3.js} +1 -1
- streamlit/static/static/js/{FormClearHelper.C_BjP_35.js → FormClearHelper.Ca3GFjxv.js} +1 -1
- streamlit/static/static/js/{Hooks.BpH4YuRQ.js → Hooks.BpCPXt5n.js} +1 -1
- streamlit/static/static/js/{InputInstructions.CjdwGigq.js → InputInstructions.BO_BnHv5.js} +1 -1
- streamlit/static/static/js/{ProgressBar.D1hXcW3N.js → ProgressBar.Ctk1m4EX.js} +1 -1
- streamlit/static/static/js/{RenderInPortalIfExists.A1T2s6z-.js → RenderInPortalIfExists.kuKoxpXt.js} +1 -1
- streamlit/static/static/js/{Toolbar.y7vr7z0G.js → Toolbar.Cde1fEcQ.js} +1 -1
- streamlit/static/static/js/{base-input.BKhd-BLG.js → base-input.BwCmIYba.js} +1 -1
- streamlit/static/static/js/{checkbox.DC-GFdrh.js → checkbox.CwPOyuag.js} +1 -1
- streamlit/static/static/js/{createSuper.D5WUtJEy.js → createSuper.BMtevhyt.js} +1 -1
- streamlit/static/static/js/{data-grid-overlay-editor.BPJ38mWp.js → data-grid-overlay-editor.gtfE9z1L.js} +1 -1
- streamlit/static/static/js/{downloader.C6a4LRBw.js → downloader.-58ZXBvx.js} +1 -1
- streamlit/static/static/js/{es6.DgMlYq8q.js → es6.6JpsZqpF.js} +2 -2
- streamlit/static/static/js/{iframeResizer.contentWindow.BpQxex73.js → iframeResizer.contentWindow.Dvm_jxul.js} +1 -1
- streamlit/static/static/js/{index.CiO2JPl_.js → index.9Bu4pGgs.js} +1 -1
- streamlit/static/static/js/{index.4Gtr9egA.js → index.B1T1N6vQ.js} +1 -1
- streamlit/static/static/js/{index.20fI9wQF.js → index.B9LBeTzL.js} +1 -1
- streamlit/static/static/js/{index.VPO2zcSN.js → index.BXdNB_A0.js} +1 -1
- streamlit/static/static/js/{index.sKXwUANU.js → index.Bd91GXu8.js} +1 -1
- streamlit/static/static/js/{index.DT0CWGt3.js → index.BdEKCy-o.js} +1 -1
- streamlit/static/static/js/{index.D3tgBU6x.js → index.BhODUTaJ.js} +1 -1
- streamlit/static/static/js/{index.BcbB70bz.js → index.BjtSRm-c.js} +1 -1
- streamlit/static/static/js/{index.DPiBGVm8.js → index.BnK8pWHN.js} +1 -1
- streamlit/static/static/js/{index.49Q6A5_9.js → index.C5xsotRs.js} +1 -1
- streamlit/static/static/js/{index.xIQLhQKv.js → index.CD3lJu6g.js} +1 -1
- streamlit/static/static/js/{index.BydIp_VR.js → index.CGJjlswG.js} +1 -1
- streamlit/static/static/js/{index.Bj81ZRkx.js → index.CIZd1q4K.js} +1 -1
- streamlit/static/static/js/{index.5k30-U6O.js → index.CZy9JHE4.js} +2 -2
- streamlit/static/static/js/{index.D5PANKHd.js → index.Ce-7kIl6.js} +1 -1
- streamlit/static/static/js/{index.Bo-z1JM2.js → index.CiiU1-bS.js} +1 -1
- streamlit/static/static/js/{index.Cqla7uBZ.js → index.ClE8XHxl.js} +1 -1
- streamlit/static/static/js/{index.CY8tg9lY.js → index.CvKH37SN.js} +1 -1
- streamlit/static/static/js/{index.CkBnHCIQ.js → index.D0G-y_z6.js} +1 -1
- streamlit/static/static/js/{index.B3UoUwtN.js → index.D1ccH_2Z.js} +1 -1
- streamlit/static/static/js/{index.DB42JCH0.js → index.D3ES4sSL.js} +1 -1
- streamlit/static/static/js/{index.BLpDfH1w.js → index.DJ0X7aeY.js} +1 -1
- streamlit/static/static/js/{index.BRN41-Jy.js → index.DNNQBTM6.js} +1 -1
- streamlit/static/static/js/{index.br6zwNIk.js → index.DQJE0i9s.js} +62 -62
- streamlit/static/static/js/{index.DSPS70gp.js → index.DR9ekgzX.js} +1 -1
- streamlit/static/static/js/{index.BbhQIRth.js → index.DUizq_aW.js} +1 -1
- streamlit/static/static/js/{index.ryD8hMpi.js → index.DVE5BhiT.js} +1 -1
- streamlit/static/static/js/{index.C2GjbQtf.js → index.DW60zbv4.js} +1 -1
- streamlit/static/static/js/{index.BhGEwO_d.js → index.DenamHJl.js} +1 -1
- streamlit/static/static/js/{index._oOkpIXS.js → index.DgnhzFgr.js} +1 -1
- streamlit/static/static/js/{index.CHnID3dI.js → index.Dk_aZplH.js} +1 -1
- streamlit/static/static/js/index.Dqcp7EZB.js +779 -0
- streamlit/static/static/js/{index.DAO4Lj-D.js → index.NfOJ2GJ6.js} +1 -1
- streamlit/static/static/js/{index.CcvbHTJu.js → index.WVgPkrrw.js} +1 -1
- streamlit/static/static/js/{index.Du1Pbz0y.js → index.bkU6rhIM.js} +1 -1
- streamlit/static/static/js/{index.Cfi3u2-T.js → index.hQ5adhxG.js} +1 -1
- streamlit/static/static/js/{index.B8ca7fYO.js → index.lYSTjxV_.js} +1 -1
- streamlit/static/static/js/{input.CNjMviuo.js → input.JEUWF6Z-.js} +1 -1
- streamlit/static/static/js/{memory.f8X97LPt.js → memory.BToPJrCN.js} +1 -1
- streamlit/static/static/js/{mergeWith.DU9BO8BA.js → mergeWith.DGon2YId.js} +1 -1
- streamlit/static/static/js/{number-overlay-editor.xJPBNdGQ.js → number-overlay-editor.kqkFTYSn.js} +1 -1
- streamlit/static/static/js/{possibleConstructorReturn.BjPX9m9m.js → possibleConstructorReturn.twGQoCQl.js} +1 -1
- streamlit/static/static/js/{sandbox.B23JuuVd.js → sandbox.o85HOKwq.js} +1 -1
- streamlit/static/static/js/{textarea.DodnI6GX.js → textarea.CdOYpTta.js} +1 -1
- streamlit/static/static/js/{timepicker.ClHKNfP9.js → timepicker.Cy1BKBo3.js} +1 -1
- streamlit/static/static/js/{toConsumableArray.CK6YGgcW.js → toConsumableArray.BVXfsvDc.js} +1 -1
- streamlit/static/static/js/{uniqueId.BAAVLIKj.js → uniqueId.Dz7-nY8K.js} +1 -1
- streamlit/static/static/js/{useBasicWidgetState.B1oropKY.js → useBasicWidgetState.CeKdNkz-.js} +1 -1
- streamlit/static/static/js/{useOnInputChange.CHQJz2sf.js → useOnInputChange.CM8BtP-c.js} +1 -1
- streamlit/static/static/js/{withFullScreenWrapper.DZ1W8JUx.js → withFullScreenWrapper.DuyW554J.js} +1 -1
- streamlit/string_util.py +1 -4
- streamlit/temporary_directory.py +2 -2
- streamlit/testing/v1/app_test.py +2 -2
- streamlit/testing/v1/element_tree.py +10 -9
- streamlit/testing/v1/local_script_runner.py +1 -4
- streamlit/type_util.py +2 -5
- streamlit/watcher/folder_black_list.py +1 -1
- streamlit/watcher/local_sources_watcher.py +5 -3
- streamlit/watcher/path_watcher.py +3 -6
- streamlit/watcher/polling_path_watcher.py +8 -7
- streamlit/watcher/util.py +6 -5
- streamlit/web/bootstrap.py +4 -4
- streamlit/web/cli.py +13 -13
- streamlit/web/server/app_static_file_handler.py +1 -1
- streamlit/web/server/authlib_tornado_integration.py +6 -1
- streamlit/web/server/oauth_authlib_routes.py +3 -3
- streamlit/web/server/oidc_mixin.py +15 -3
- streamlit/web/server/routes.py +11 -11
- streamlit/web/server/stats_request_handler.py +2 -2
- {streamlit_nightly-1.45.1.dev20250511.dist-info → streamlit_nightly-1.45.2.dev20250513.dist-info}/METADATA +1 -1
- {streamlit_nightly-1.45.1.dev20250511.dist-info → streamlit_nightly-1.45.2.dev20250513.dist-info}/RECORD +164 -164
- streamlit/static/static/js/index.BgEbLy94.js +0 -779
- {streamlit_nightly-1.45.1.dev20250511.data → streamlit_nightly-1.45.2.dev20250513.data}/scripts/streamlit.cmd +0 -0
- {streamlit_nightly-1.45.1.dev20250511.dist-info → streamlit_nightly-1.45.2.dev20250513.dist-info}/WHEEL +0 -0
- {streamlit_nightly-1.45.1.dev20250511.dist-info → streamlit_nightly-1.45.2.dev20250513.dist-info}/entry_points.txt +0 -0
- {streamlit_nightly-1.45.1.dev20250511.dist-info → streamlit_nightly-1.45.2.dev20250513.dist-info}/top_level.txt +0 -0
@@ -861,17 +861,14 @@ def _get_x_encoding(
|
|
861
861
|
# Only show a label in the x axis if the user passed a column explicitly. We
|
862
862
|
# could go either way here, but I'm keeping this to avoid breaking the existing
|
863
863
|
# behavior.
|
864
|
-
if x_from_user is None
|
865
|
-
x_title = ""
|
866
|
-
else:
|
867
|
-
x_title = x_column
|
864
|
+
x_title = "" if x_from_user is None else x_column
|
868
865
|
|
869
866
|
# User specified x-axis label takes precedence
|
870
867
|
if x_axis_label is not None:
|
871
868
|
x_title = x_axis_label
|
872
869
|
|
873
870
|
# grid lines on x axis for horizontal bar charts only
|
874
|
-
grid =
|
871
|
+
grid = chart_type == ChartType.HORIZONTAL_BAR
|
875
872
|
|
876
873
|
return alt.X(
|
877
874
|
x_field,
|
@@ -909,17 +906,14 @@ def _get_y_encoding(
|
|
909
906
|
# Only show a label in the y axis if the user passed a column explicitly. We
|
910
907
|
# could go either way here, but I'm keeping this to avoid breaking the existing
|
911
908
|
# behavior.
|
912
|
-
if y_from_user is None
|
913
|
-
y_title = ""
|
914
|
-
else:
|
915
|
-
y_title = y_column
|
909
|
+
y_title = "" if y_from_user is None else y_column
|
916
910
|
|
917
911
|
# User specified y-axis label takes precedence
|
918
912
|
if y_axis_label is not None:
|
919
913
|
y_title = y_axis_label
|
920
914
|
|
921
915
|
# grid lines on y axis for all charts except horizontal bar charts
|
922
|
-
grid =
|
916
|
+
grid = chart_type != ChartType.HORIZONTAL_BAR
|
923
917
|
|
924
918
|
return alt.Y(
|
925
919
|
field=y_field,
|
@@ -960,7 +954,9 @@ def _get_color_encoding(
|
|
960
954
|
# If the color value is color-like, return that.
|
961
955
|
if is_color_like(cast("Any", color_value)):
|
962
956
|
if len(y_column_list) != 1:
|
963
|
-
raise StreamlitColorLengthError(
|
957
|
+
raise StreamlitColorLengthError(
|
958
|
+
[color_value] if color_value else [], y_column_list
|
959
|
+
)
|
964
960
|
|
965
961
|
return alt.ColorValue(to_css_color(cast("Any", color_value)))
|
966
962
|
|
@@ -981,15 +977,16 @@ def _get_color_encoding(
|
|
981
977
|
title=" ",
|
982
978
|
)
|
983
979
|
|
984
|
-
raise StreamlitInvalidColorError(
|
980
|
+
raise StreamlitInvalidColorError(color_from_user)
|
985
981
|
|
986
982
|
if color_column is not None:
|
987
983
|
column_type: VegaLiteType
|
988
984
|
|
989
|
-
|
990
|
-
|
991
|
-
|
992
|
-
|
985
|
+
column_type = (
|
986
|
+
"nominal"
|
987
|
+
if color_column == _MELTED_COLOR_COLUMN_NAME
|
988
|
+
else _infer_vegalite_type(df[color_column])
|
989
|
+
)
|
993
990
|
|
994
991
|
color_enc = alt.Color(
|
995
992
|
field=color_column, legend=_COLOR_LEGEND_SETTINGS, type=column_type
|
@@ -1137,7 +1134,7 @@ def _get_y_encoding_type(
|
|
1137
1134
|
|
1138
1135
|
|
1139
1136
|
class StreamlitColumnNotFoundError(StreamlitAPIException):
|
1140
|
-
def __init__(self, df, col_name, *args):
|
1137
|
+
def __init__(self, df: pd.DataFrame, col_name: str, *args: Any) -> None:
|
1141
1138
|
available_columns = ", ".join(str(c) for c in list(df.columns))
|
1142
1139
|
message = (
|
1143
1140
|
f'Data does not have a column named `"{col_name}"`. '
|
@@ -1147,8 +1144,7 @@ class StreamlitColumnNotFoundError(StreamlitAPIException):
|
|
1147
1144
|
|
1148
1145
|
|
1149
1146
|
class StreamlitInvalidColorError(StreamlitAPIException):
|
1150
|
-
def __init__(self,
|
1151
|
-
", ".join(str(c) for c in list(df.columns))
|
1147
|
+
def __init__(self, color_from_user: str | Color | list[Color] | None) -> None:
|
1152
1148
|
message = f"""
|
1153
1149
|
This does not look like a valid color argument: `{color_from_user}`.
|
1154
1150
|
|
@@ -1161,14 +1157,18 @@ The color argument can be:
|
|
1161
1157
|
* The name of a column.
|
1162
1158
|
* Or a list of colors, matching the number of y columns to draw.
|
1163
1159
|
"""
|
1164
|
-
super().__init__(message
|
1160
|
+
super().__init__(message)
|
1165
1161
|
|
1166
1162
|
|
1167
1163
|
class StreamlitColorLengthError(StreamlitAPIException):
|
1168
|
-
def __init__(
|
1164
|
+
def __init__(
|
1165
|
+
self,
|
1166
|
+
color_values: str | Color | Collection[Color] | None,
|
1167
|
+
y_column_list: list[str],
|
1168
|
+
) -> None:
|
1169
1169
|
message = (
|
1170
1170
|
f"The list of colors `{color_values}` must have the same "
|
1171
1171
|
"length as the list of columns to be colored "
|
1172
1172
|
f"`{y_column_list}`."
|
1173
1173
|
)
|
1174
|
-
super().__init__(message
|
1174
|
+
super().__init__(message)
|
@@ -203,10 +203,9 @@ def _pandas_style_to_css(
|
|
203
203
|
# > }
|
204
204
|
# > ...
|
205
205
|
# > ]
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
cell_selectors = style["selectors"]
|
206
|
+
cell_selectors = (
|
207
|
+
[style["selector"]] if style_type == "table_styles" else style["selectors"]
|
208
|
+
)
|
210
209
|
|
211
210
|
selectors = [
|
212
211
|
table_selector + separator + cell_selector for cell_selector in cell_selectors
|
@@ -266,9 +265,8 @@ def _use_display_values(df: DataFrame, styles: Mapping[str, Any]) -> DataFrame:
|
|
266
265
|
rows = styles["body"]
|
267
266
|
for row in rows:
|
268
267
|
for cell in row:
|
269
|
-
if "id" in cell:
|
270
|
-
|
271
|
-
|
272
|
-
new_df.iloc[r, c] = str(cell["display_value"])
|
268
|
+
if "id" in cell and (match := cell_selector_regex.match(cell["id"])):
|
269
|
+
r, c = map(int, match.groups())
|
270
|
+
new_df.iloc[r, c] = str(cell["display_value"])
|
273
271
|
|
274
272
|
return new_df
|
streamlit/elements/map.py
CHANGED
@@ -399,10 +399,7 @@ def _get_value_and_col_name(
|
|
399
399
|
else:
|
400
400
|
col_name = None
|
401
401
|
|
402
|
-
if value_or_name is None
|
403
|
-
pydeck_arg = default_value
|
404
|
-
else:
|
405
|
-
pydeck_arg = value_or_name
|
402
|
+
pydeck_arg = default_value if value_or_name is None else value_or_name
|
406
403
|
|
407
404
|
return pydeck_arg, col_name
|
408
405
|
|
@@ -462,10 +459,7 @@ def _get_viewport_details(
|
|
462
459
|
range_lat = abs(max_lat - min_lat)
|
463
460
|
|
464
461
|
if zoom is None:
|
465
|
-
|
466
|
-
longitude_distance = range_lon
|
467
|
-
else:
|
468
|
-
longitude_distance = range_lat
|
462
|
+
longitude_distance = max(range_lat, range_lon)
|
469
463
|
zoom = _get_zoom_level(longitude_distance)
|
470
464
|
|
471
465
|
return zoom, center_lat, center_lon
|
streamlit/elements/markdown.py
CHANGED
@@ -368,10 +368,7 @@ class MarkdownMixin:
|
|
368
368
|
height: 220px
|
369
369
|
|
370
370
|
"""
|
371
|
-
if icon is not None
|
372
|
-
icon_str = validate_icon_or_emoji(icon) + " "
|
373
|
-
else:
|
374
|
-
icon_str = ""
|
371
|
+
icon_str = validate_icon_or_emoji(icon) + " " if icon is not None else ""
|
375
372
|
|
376
373
|
# Escape [ and ] characters in the label to prevent breaking the directive syntax
|
377
374
|
escaped_label = label.replace("[", "\\[").replace("]", "\\]")
|
streamlit/elements/media.py
CHANGED
@@ -24,11 +24,13 @@ from typing_extensions import TypeAlias
|
|
24
24
|
|
25
25
|
from streamlit import runtime, type_util, url_util
|
26
26
|
from streamlit.elements.lib.form_utils import current_form_id
|
27
|
+
from streamlit.elements.lib.layout_utils import WidthWithoutContent, validate_width
|
27
28
|
from streamlit.elements.lib.subtitle_utils import process_subtitle_data
|
28
29
|
from streamlit.elements.lib.utils import compute_and_register_element_id
|
29
30
|
from streamlit.errors import StreamlitAPIException
|
30
31
|
from streamlit.proto.Audio_pb2 import Audio as AudioProto
|
31
32
|
from streamlit.proto.Video_pb2 import Video as VideoProto
|
33
|
+
from streamlit.proto.WidthConfig_pb2 import WidthConfig
|
32
34
|
from streamlit.runtime import caching
|
33
35
|
from streamlit.runtime.metrics_util import gather_metrics
|
34
36
|
from streamlit.time_util import time_to_seconds
|
@@ -80,6 +82,7 @@ class MediaMixin:
|
|
80
82
|
end_time: MediaTime | None = None,
|
81
83
|
loop: bool = False,
|
82
84
|
autoplay: bool = False,
|
85
|
+
width: WidthWithoutContent = "stretch",
|
83
86
|
) -> DeltaGenerator:
|
84
87
|
"""Display an audio player.
|
85
88
|
|
@@ -141,6 +144,12 @@ class MediaMixin:
|
|
141
144
|
Whether the audio file should start playing automatically. This is
|
142
145
|
``False`` by default. Browsers will not autoplay audio files if the
|
143
146
|
user has not interacted with the page by clicking somewhere.
|
147
|
+
width: int or "stretch"
|
148
|
+
The width of the audio player. This can be one of the following:
|
149
|
+
|
150
|
+
- An int: The width in pixels, e.g. ``200`` for a width of 200 pixels.
|
151
|
+
- ``"stretch"``: The default value. The audio player stretches to fill
|
152
|
+
available space in its container.
|
144
153
|
|
145
154
|
Examples
|
146
155
|
--------
|
@@ -181,6 +190,7 @@ class MediaMixin:
|
|
181
190
|
|
182
191
|
"""
|
183
192
|
start_time, end_time = _parse_start_time_end_time(start_time, end_time)
|
193
|
+
validate_width(width)
|
184
194
|
|
185
195
|
audio_proto = AudioProto()
|
186
196
|
|
@@ -207,6 +217,7 @@ class MediaMixin:
|
|
207
217
|
loop,
|
208
218
|
autoplay,
|
209
219
|
form_id=current_form_id(self.dg),
|
220
|
+
width=width,
|
210
221
|
)
|
211
222
|
return self.dg._enqueue("audio", audio_proto)
|
212
223
|
|
@@ -222,6 +233,7 @@ class MediaMixin:
|
|
222
233
|
loop: bool = False,
|
223
234
|
autoplay: bool = False,
|
224
235
|
muted: bool = False,
|
236
|
+
width: WidthWithoutContent = "stretch",
|
225
237
|
) -> DeltaGenerator:
|
226
238
|
"""Display a video player.
|
227
239
|
|
@@ -306,6 +318,12 @@ class MediaMixin:
|
|
306
318
|
Whether the video should play with the audio silenced. This is
|
307
319
|
``False`` by default. Use this in conjunction with ``autoplay=True``
|
308
320
|
to enable autoplay without user interaction.
|
321
|
+
width: int or "stretch"
|
322
|
+
The width of the video player. This can be one of the following:
|
323
|
+
|
324
|
+
- An int: The width in pixels, e.g. ``200`` for a width of 200 pixels.
|
325
|
+
- ``"stretch"``: The default value. The video player stretches to fill
|
326
|
+
available space in its container.
|
309
327
|
|
310
328
|
Example
|
311
329
|
-------
|
@@ -359,6 +377,7 @@ class MediaMixin:
|
|
359
377
|
|
360
378
|
"""
|
361
379
|
start_time, end_time = _parse_start_time_end_time(start_time, end_time)
|
380
|
+
validate_width(width)
|
362
381
|
|
363
382
|
video_proto = VideoProto()
|
364
383
|
coordinates = self.dg._get_delta_path_str()
|
@@ -374,6 +393,7 @@ class MediaMixin:
|
|
374
393
|
autoplay,
|
375
394
|
muted,
|
376
395
|
form_id=current_form_id(self.dg),
|
396
|
+
width=width,
|
377
397
|
)
|
378
398
|
return self.dg._enqueue("video", video_proto)
|
379
399
|
|
@@ -449,14 +469,14 @@ def _marshall_av_media(
|
|
449
469
|
elif isinstance(data, io.BytesIO):
|
450
470
|
data.seek(0)
|
451
471
|
data_or_filename = data.getvalue()
|
452
|
-
elif isinstance(data, io.RawIOBase
|
472
|
+
elif isinstance(data, (io.RawIOBase, io.BufferedReader)):
|
453
473
|
data.seek(0)
|
454
474
|
read_data = data.read()
|
455
475
|
if read_data is None:
|
456
476
|
return
|
457
477
|
data_or_filename = read_data
|
458
478
|
elif type_util.is_type(data, "numpy.ndarray"):
|
459
|
-
data_or_filename = data.tobytes()
|
479
|
+
data_or_filename = cast("npt.NDArray[Any]", data).tobytes()
|
460
480
|
else:
|
461
481
|
raise RuntimeError("Invalid binary data format: %s" % type(data))
|
462
482
|
|
@@ -484,6 +504,7 @@ def marshall_video(
|
|
484
504
|
autoplay: bool = False,
|
485
505
|
muted: bool = False,
|
486
506
|
form_id: str | None = None,
|
507
|
+
width: WidthWithoutContent = "stretch",
|
487
508
|
) -> None:
|
488
509
|
"""Marshalls a video proto, using url processors as needed.
|
489
510
|
|
@@ -530,6 +551,11 @@ def marshall_video(
|
|
530
551
|
form_id: str | None
|
531
552
|
The ID of the form that this element is placed in. Provide None if
|
532
553
|
the element is not placed in a form.
|
554
|
+
width: int or "stretch"
|
555
|
+
The width of the video player. This can be one of the following:
|
556
|
+
- An int: The width in pixels, e.g. 200 for a width of 200 pixels.
|
557
|
+
- "stretch": The default value. The video player stretches to fill
|
558
|
+
available space in its container.
|
533
559
|
"""
|
534
560
|
|
535
561
|
if start_time < 0 or (end_time is not None and end_time <= start_time):
|
@@ -542,6 +568,13 @@ def marshall_video(
|
|
542
568
|
proto.end_time = end_time
|
543
569
|
proto.loop = loop
|
544
570
|
|
571
|
+
width_config = WidthConfig()
|
572
|
+
if isinstance(width, int):
|
573
|
+
width_config.pixel_width = width
|
574
|
+
else:
|
575
|
+
width_config.use_stretch = True
|
576
|
+
proto.width_config.CopyFrom(width_config)
|
577
|
+
|
545
578
|
# "type" distinguishes between YouTube and non-YouTube links
|
546
579
|
proto.type = VideoProto.Type.NATIVE
|
547
580
|
|
@@ -611,6 +644,7 @@ def marshall_video(
|
|
611
644
|
loop=loop,
|
612
645
|
autoplay=autoplay,
|
613
646
|
muted=muted,
|
647
|
+
width=width,
|
614
648
|
)
|
615
649
|
|
616
650
|
|
@@ -732,6 +766,7 @@ def marshall_audio(
|
|
732
766
|
loop: bool = False,
|
733
767
|
autoplay: bool = False,
|
734
768
|
form_id: str | None = None,
|
769
|
+
width: WidthWithoutContent = "stretch",
|
735
770
|
) -> None:
|
736
771
|
"""Marshalls an audio proto, using data and url processors as needed.
|
737
772
|
|
@@ -761,6 +796,11 @@ def marshall_audio(
|
|
761
796
|
form_id: str | None
|
762
797
|
The ID of the form that this element is placed in. Provide None if
|
763
798
|
the element is not placed in a form.
|
799
|
+
width: int or "stretch"
|
800
|
+
The width of the audio player. This can be one of the following:
|
801
|
+
- An int: The width in pixels, e.g. 200 for a width of 200 pixels.
|
802
|
+
- "stretch": The default value. The audio player stretches to fill
|
803
|
+
available space in its container.
|
764
804
|
"""
|
765
805
|
|
766
806
|
proto.start_time = start_time
|
@@ -768,6 +808,13 @@ def marshall_audio(
|
|
768
808
|
proto.end_time = end_time
|
769
809
|
proto.loop = loop
|
770
810
|
|
811
|
+
width_config = WidthConfig()
|
812
|
+
if isinstance(width, int):
|
813
|
+
width_config.pixel_width = width
|
814
|
+
else:
|
815
|
+
width_config.use_stretch = True
|
816
|
+
proto.width_config.CopyFrom(width_config)
|
817
|
+
|
771
818
|
if isinstance(data, Path):
|
772
819
|
data = str(data) # Convert Path to string
|
773
820
|
|
@@ -792,4 +839,5 @@ def marshall_audio(
|
|
792
839
|
end_time=end_time,
|
793
840
|
loop=loop,
|
794
841
|
autoplay=autoplay,
|
842
|
+
width=width,
|
795
843
|
)
|
streamlit/elements/metric.py
CHANGED
@@ -223,13 +223,13 @@ def _parse_label(label: str) -> str:
|
|
223
223
|
def _parse_value(value: Value) -> str:
|
224
224
|
if value is None:
|
225
225
|
return "—"
|
226
|
-
if isinstance(value, int
|
226
|
+
if isinstance(value, (int, float, str)):
|
227
227
|
return str(value)
|
228
|
-
|
228
|
+
if hasattr(value, "item"):
|
229
229
|
# Add support for numpy values (e.g. int16, float64, etc.)
|
230
230
|
try:
|
231
231
|
# Item could also be just a variable, so we use try, except
|
232
|
-
if isinstance(value.item(), float
|
232
|
+
if isinstance(value.item(), (float, int)):
|
233
233
|
return str(value.item())
|
234
234
|
except Exception: # noqa: S110
|
235
235
|
# If the numpy item is not a valid value, the TypeError below will be raised.
|
@@ -247,14 +247,13 @@ def _parse_delta(delta: Delta) -> str:
|
|
247
247
|
return ""
|
248
248
|
if isinstance(delta, str):
|
249
249
|
return dedent(delta)
|
250
|
-
|
250
|
+
if isinstance(delta, (int, float)):
|
251
251
|
return str(delta)
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
)
|
252
|
+
raise TypeError(
|
253
|
+
f"'{delta}' is of type {type(delta)}, which is not an accepted type."
|
254
|
+
" delta only accepts: int, float, str, or None."
|
255
|
+
" Please convert the value to an accepted type."
|
256
|
+
)
|
258
257
|
|
259
258
|
|
260
259
|
def _determine_delta_color_and_direction(
|
streamlit/elements/spinner.py
CHANGED
@@ -360,7 +360,7 @@ def _convert_altair_to_vega_lite_spec(
|
|
360
360
|
datasets[name] = data_bytes
|
361
361
|
return {"name": name}
|
362
362
|
|
363
|
-
alt.data_transformers.register("id", id_transform) # type: ignore[attr-defined,unused-ignore]
|
363
|
+
alt.data_transformers.register("id", id_transform) # type: ignore[arg-type,attr-defined,unused-ignore]
|
364
364
|
|
365
365
|
# The default altair theme has some width/height defaults defined
|
366
366
|
# which are not useful for Streamlit. Therefore, we change the theme to
|
@@ -79,10 +79,7 @@ class AudioInputSerde:
|
|
79
79
|
self, ui_value: FileUploaderStateProto | None
|
80
80
|
) -> SomeUploadedAudioFile:
|
81
81
|
upload_files = _get_upload_files(ui_value)
|
82
|
-
if len(upload_files) == 0
|
83
|
-
return_value = None
|
84
|
-
else:
|
85
|
-
return_value = upload_files[0]
|
82
|
+
return_value = None if len(upload_files) == 0 else upload_files[0]
|
86
83
|
if return_value is not None and not isinstance(return_value, DeletedFile):
|
87
84
|
enforce_filename_restriction(return_value.name, [".wav"])
|
88
85
|
return return_value
|
@@ -79,10 +79,7 @@ class CameraInputSerde:
|
|
79
79
|
self, ui_value: FileUploaderStateProto | None
|
80
80
|
) -> SomeUploadedSnapshotFile:
|
81
81
|
upload_files = _get_upload_files(ui_value)
|
82
|
-
if len(upload_files) == 0
|
83
|
-
return_value = None
|
84
|
-
else:
|
85
|
-
return_value = upload_files[0]
|
82
|
+
return_value = None if len(upload_files) == 0 else upload_files[0]
|
86
83
|
if return_value is not None and not isinstance(return_value, DeletedFile):
|
87
84
|
enforce_filename_restriction(return_value.name, [".jpg"])
|
88
85
|
return return_value
|
@@ -33,6 +33,11 @@ from streamlit.elements.lib.file_uploader_utils import (
|
|
33
33
|
)
|
34
34
|
from streamlit.elements.lib.form_utils import is_in_form
|
35
35
|
from streamlit.elements.lib.image_utils import AtomicImage, WidthBehavior, image_to_url
|
36
|
+
from streamlit.elements.lib.layout_utils import (
|
37
|
+
Width,
|
38
|
+
WidthWithoutContent,
|
39
|
+
validate_width,
|
40
|
+
)
|
36
41
|
from streamlit.elements.lib.policies import check_widget_policies
|
37
42
|
from streamlit.elements.lib.utils import (
|
38
43
|
Key,
|
@@ -47,6 +52,7 @@ from streamlit.proto.ChatInput_pb2 import ChatInput as ChatInputProto
|
|
47
52
|
from streamlit.proto.Common_pb2 import ChatInputValue as ChatInputValueProto
|
48
53
|
from streamlit.proto.Common_pb2 import FileUploaderState as FileUploaderStateProto
|
49
54
|
from streamlit.proto.RootContainer_pb2 import RootContainer
|
55
|
+
from streamlit.proto.WidthConfig_pb2 import WidthConfig
|
50
56
|
from streamlit.runtime.metrics_util import gather_metrics
|
51
57
|
from streamlit.runtime.scriptrunner_utils.script_run_context import get_script_run_ctx
|
52
58
|
from streamlit.runtime.state import (
|
@@ -224,6 +230,7 @@ class ChatMixin:
|
|
224
230
|
name: Literal["user", "assistant", "ai", "human"] | str,
|
225
231
|
*,
|
226
232
|
avatar: Literal["user", "assistant"] | str | AtomicImage | None = None,
|
233
|
+
width: Width = "stretch",
|
227
234
|
) -> DeltaGenerator:
|
228
235
|
"""Insert a chat message container.
|
229
236
|
|
@@ -274,6 +281,14 @@ class ChatMixin:
|
|
274
281
|
.. |st.image| replace:: ``st.image``
|
275
282
|
.. _st.image: https://docs.streamlit.io/develop/api-reference/media/st.image
|
276
283
|
|
284
|
+
width: int, "auto", or "stretch"
|
285
|
+
The width of the chat message. This can be one of the following:
|
286
|
+
|
287
|
+
- An int: The width in pixels, e.g. ``200`` for a width of 200 pixels.
|
288
|
+
- ``"auto"``: Expands to fit the content.
|
289
|
+
- ``"stretch"``: The default value. The chat message stretches to fill
|
290
|
+
available space in its container.
|
291
|
+
|
277
292
|
Returns
|
278
293
|
-------
|
279
294
|
Container
|
@@ -322,10 +337,23 @@ class ChatMixin:
|
|
322
337
|
avatar, self.dg._get_delta_path_str()
|
323
338
|
)
|
324
339
|
|
340
|
+
validate_width(width, allow_content=True)
|
341
|
+
|
325
342
|
message_container_proto = BlockProto.ChatMessage()
|
326
343
|
message_container_proto.name = name
|
327
344
|
message_container_proto.avatar = converted_avatar
|
328
345
|
message_container_proto.avatar_type = avatar_type
|
346
|
+
|
347
|
+
# Set up width configuration
|
348
|
+
width_config = WidthConfig()
|
349
|
+
if isinstance(width, int):
|
350
|
+
width_config.pixel_width = width
|
351
|
+
elif width == "content":
|
352
|
+
width_config.use_content = True
|
353
|
+
else:
|
354
|
+
width_config.use_stretch = True
|
355
|
+
message_container_proto.width_config.CopyFrom(width_config)
|
356
|
+
|
329
357
|
block_proto = BlockProto()
|
330
358
|
block_proto.allow_empty = True
|
331
359
|
block_proto.chat_message.CopyFrom(message_container_proto)
|
@@ -345,6 +373,7 @@ class ChatMixin:
|
|
345
373
|
on_submit: WidgetCallback | None = None,
|
346
374
|
args: WidgetArgs | None = None,
|
347
375
|
kwargs: WidgetKwargs | None = None,
|
376
|
+
width: WidthWithoutContent = "stretch",
|
348
377
|
) -> str | None: ...
|
349
378
|
|
350
379
|
@overload
|
@@ -360,6 +389,7 @@ class ChatMixin:
|
|
360
389
|
on_submit: WidgetCallback | None = None,
|
361
390
|
args: WidgetArgs | None = None,
|
362
391
|
kwargs: WidgetKwargs | None = None,
|
392
|
+
width: WidthWithoutContent = "stretch",
|
363
393
|
) -> ChatInputValue | None: ...
|
364
394
|
|
365
395
|
@gather_metrics("chat_input")
|
@@ -375,6 +405,7 @@ class ChatMixin:
|
|
375
405
|
on_submit: WidgetCallback | None = None,
|
376
406
|
args: WidgetArgs | None = None,
|
377
407
|
kwargs: WidgetKwargs | None = None,
|
408
|
+
width: WidthWithoutContent = "stretch",
|
378
409
|
) -> str | ChatInputValue | None:
|
379
410
|
"""Display a chat input widget.
|
380
411
|
|
@@ -439,6 +470,13 @@ class ChatMixin:
|
|
439
470
|
kwargs : dict
|
440
471
|
An optional dict of kwargs to pass to the callback.
|
441
472
|
|
473
|
+
width: int or "stretch"
|
474
|
+
The width of the chat input widget. This can be one of the following:
|
475
|
+
|
476
|
+
- An int: The width in pixels, e.g. ``200`` for a width of 200 pixels.
|
477
|
+
- ``"stretch"``: The default value. The chat input stretches to fill
|
478
|
+
available space in its container.
|
479
|
+
|
442
480
|
Returns
|
443
481
|
-------
|
444
482
|
None, str, or dict-like
|
@@ -546,6 +584,8 @@ class ChatMixin:
|
|
546
584
|
writes_allowed=False,
|
547
585
|
)
|
548
586
|
|
587
|
+
validate_width(width)
|
588
|
+
|
549
589
|
if accept_file not in {True, False, "multiple"}:
|
550
590
|
raise StreamlitAPIException(
|
551
591
|
"The `accept_file` parameter must be a boolean or 'multiple'."
|
@@ -562,6 +602,7 @@ class ChatMixin:
|
|
562
602
|
max_chars=max_chars,
|
563
603
|
accept_file=accept_file,
|
564
604
|
file_type=file_type,
|
605
|
+
width=width,
|
565
606
|
)
|
566
607
|
|
567
608
|
if file_type:
|
@@ -571,11 +612,10 @@ class ChatMixin:
|
|
571
612
|
# We throw an error to warn the user about this.
|
572
613
|
# We omit this check for scripts running outside streamlit, because
|
573
614
|
# they will have no script_run_ctx.
|
574
|
-
if runtime.exists():
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
)
|
615
|
+
if runtime.exists() and is_in_form(self.dg):
|
616
|
+
raise StreamlitAPIException(
|
617
|
+
"`st.chat_input()` can't be used in a `st.form()`."
|
618
|
+
)
|
579
619
|
|
580
620
|
# Determine the position of the chat input:
|
581
621
|
# Use bottom position if chat input is within the main container
|
@@ -606,6 +646,13 @@ class ChatMixin:
|
|
606
646
|
chat_input_proto.file_type[:] = file_type if file_type is not None else []
|
607
647
|
chat_input_proto.max_upload_size_mb = config.get_option("server.maxUploadSize")
|
608
648
|
|
649
|
+
width_config = WidthConfig()
|
650
|
+
if isinstance(width, int):
|
651
|
+
width_config.pixel_width = width
|
652
|
+
else:
|
653
|
+
width_config.use_stretch = True
|
654
|
+
chat_input_proto.width_config.CopyFrom(width_config)
|
655
|
+
|
609
656
|
serde = ChatInputSerde(
|
610
657
|
accept_files=bool(accept_file),
|
611
658
|
allowed_types=file_type,
|
@@ -949,7 +949,7 @@ class DataEditorMixin:
|
|
949
949
|
if use_container_width is None:
|
950
950
|
# If use_container_width was not explicitly set by the user, we set
|
951
951
|
# it to True if width was not set explicitly, and False otherwise.
|
952
|
-
use_container_width =
|
952
|
+
use_container_width = width is None
|
953
953
|
|
954
954
|
proto.use_container_width = use_container_width
|
955
955
|
|
@@ -692,7 +692,7 @@ class SliderMixin:
|
|
692
692
|
if single_value:
|
693
693
|
value = [value]
|
694
694
|
|
695
|
-
def value_to_generic_type(v):
|
695
|
+
def value_to_generic_type(v: Any) -> SliderProto.DataType.ValueType:
|
696
696
|
if isinstance(v, Integral):
|
697
697
|
return SUPPORTED_TYPES[Integral]
|
698
698
|
if isinstance(v, Real):
|
@@ -708,10 +708,9 @@ class SliderMixin:
|
|
708
708
|
f"But were: {list(map(type, value))}"
|
709
709
|
)
|
710
710
|
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
data_type = value_to_generic_type(value[0])
|
711
|
+
data_type = (
|
712
|
+
SliderProto.INT if len(value) == 0 else value_to_generic_type(value[0])
|
713
|
+
)
|
715
714
|
|
716
715
|
datetime_min = time.min
|
717
716
|
datetime_max = time.max
|
@@ -517,10 +517,7 @@ class TimeWidgetsMixin:
|
|
517
517
|
validate_width(width)
|
518
518
|
|
519
519
|
parsed_time: time | None
|
520
|
-
if value is None
|
521
|
-
parsed_time = None
|
522
|
-
else:
|
523
|
-
parsed_time = _convert_timelike_to_time(value)
|
520
|
+
parsed_time = None if value is None else _convert_timelike_to_time(value)
|
524
521
|
|
525
522
|
element_id = compute_and_register_element_id(
|
526
523
|
"time_input",
|
streamlit/elements/write.py
CHANGED
@@ -156,7 +156,7 @@ class WriteMixin:
|
|
156
156
|
streamed_response: str = ""
|
157
157
|
written_content: list[Any] = StreamingOutput()
|
158
158
|
|
159
|
-
def flush_stream_response():
|
159
|
+
def flush_stream_response() -> None:
|
160
160
|
"""Write the full response to the app."""
|
161
161
|
nonlocal streamed_response
|
162
162
|
nonlocal stream_container
|
@@ -428,7 +428,7 @@ class WriteMixin:
|
|
428
428
|
"when called as `st.write()` or `st.sidebar.write()`."
|
429
429
|
)
|
430
430
|
|
431
|
-
def flush_buffer():
|
431
|
+
def flush_buffer() -> None:
|
432
432
|
if string_buffer:
|
433
433
|
text_content = " ".join(string_buffer)
|
434
434
|
# The usage of empty here prevents
|