streamlit-nightly 1.36.1.dev20240702__py2.py3-none-any.whl → 1.36.1.dev20240703__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.
- streamlit/commands/navigation.py +1 -1
- streamlit/components/v1/component_arrow.py +16 -11
- streamlit/components/v1/custom_component.py +2 -1
- streamlit/dataframe_util.py +835 -0
- streamlit/delta_generator.py +5 -3
- streamlit/elements/arrow.py +17 -13
- streamlit/elements/lib/built_in_chart_utils.py +78 -12
- streamlit/elements/lib/column_config_utils.py +1 -1
- streamlit/elements/lib/pandas_styler_utils.py +2 -2
- streamlit/elements/lib/policies.py +20 -2
- streamlit/elements/lib/utils.py +100 -10
- streamlit/elements/map.py +2 -2
- streamlit/elements/metric.py +5 -2
- streamlit/elements/plotly_chart.py +1 -1
- streamlit/elements/vega_charts.py +6 -5
- streamlit/elements/widgets/button.py +1 -1
- streamlit/elements/widgets/camera_input.py +7 -2
- streamlit/elements/widgets/chat.py +1 -1
- streamlit/elements/widgets/checkbox.py +7 -2
- streamlit/elements/widgets/color_picker.py +7 -2
- streamlit/elements/widgets/data_editor.py +10 -9
- streamlit/elements/widgets/file_uploader.py +7 -2
- streamlit/elements/widgets/multiselect.py +6 -7
- streamlit/elements/widgets/number_input.py +7 -2
- streamlit/elements/widgets/radio.py +6 -7
- streamlit/elements/widgets/select_slider.py +6 -7
- streamlit/elements/widgets/selectbox.py +6 -7
- streamlit/elements/widgets/slider.py +7 -2
- streamlit/elements/widgets/text_widgets.py +8 -5
- streamlit/elements/widgets/time_widgets.py +7 -2
- streamlit/elements/write.py +5 -5
- streamlit/runtime/caching/cache_utils.py +1 -1
- streamlit/runtime/state/common.py +51 -2
- streamlit/runtime/state/session_state.py +2 -1
- streamlit/runtime/state/session_state_proxy.py +1 -1
- streamlit/runtime/state/widgets.py +1 -1
- streamlit/static/asset-manifest.json +2 -2
- streamlit/static/index.html +1 -1
- streamlit/static/static/js/{main.e2ab315a.js → main.28e3c6e9.js} +2 -2
- streamlit/testing/v1/element_tree.py +3 -3
- streamlit/type_util.py +0 -1069
- {streamlit_nightly-1.36.1.dev20240702.dist-info → streamlit_nightly-1.36.1.dev20240703.dist-info}/METADATA +1 -1
- {streamlit_nightly-1.36.1.dev20240702.dist-info → streamlit_nightly-1.36.1.dev20240703.dist-info}/RECORD +48 -47
- /streamlit/static/static/js/{main.e2ab315a.js.LICENSE.txt → main.28e3c6e9.js.LICENSE.txt} +0 -0
- {streamlit_nightly-1.36.1.dev20240702.data → streamlit_nightly-1.36.1.dev20240703.data}/scripts/streamlit.cmd +0 -0
- {streamlit_nightly-1.36.1.dev20240702.dist-info → streamlit_nightly-1.36.1.dev20240703.dist-info}/WHEEL +0 -0
- {streamlit_nightly-1.36.1.dev20240702.dist-info → streamlit_nightly-1.36.1.dev20240703.dist-info}/entry_points.txt +0 -0
- {streamlit_nightly-1.36.1.dev20240702.dist-info → streamlit_nightly-1.36.1.dev20240703.dist-info}/top_level.txt +0 -0
streamlit/delta_generator.py
CHANGED
@@ -38,10 +38,10 @@ from streamlit import (
|
|
38
38
|
cli_util,
|
39
39
|
config,
|
40
40
|
cursor,
|
41
|
+
dataframe_util,
|
41
42
|
env_util,
|
42
43
|
logger,
|
43
44
|
runtime,
|
44
|
-
type_util,
|
45
45
|
util,
|
46
46
|
)
|
47
47
|
from streamlit.elements.alert import AlertMixin
|
@@ -705,8 +705,10 @@ def _prep_data_for_add_rows(
|
|
705
705
|
add_rows_metadata: AddRowsMetadata | None,
|
706
706
|
) -> tuple[Data, AddRowsMetadata | None]:
|
707
707
|
if not add_rows_metadata:
|
708
|
-
|
709
|
-
|
708
|
+
if dataframe_util.is_pandas_styler(data):
|
709
|
+
# When calling add_rows on st.table or st.dataframe we want styles to pass through.
|
710
|
+
return data, None
|
711
|
+
return dataframe_util.convert_anything_to_pandas_df(data), None
|
710
712
|
|
711
713
|
# If add_rows_metadata is set, it indicates that the add_rows used called
|
712
714
|
# on a chart based on our built-in chart commands.
|
streamlit/elements/arrow.py
CHANGED
@@ -32,7 +32,7 @@ from typing import (
|
|
32
32
|
|
33
33
|
from typing_extensions import TypeAlias
|
34
34
|
|
35
|
-
from streamlit import
|
35
|
+
from streamlit import dataframe_util
|
36
36
|
from streamlit.elements.lib.column_config_utils import (
|
37
37
|
INDEX_IDENTIFIER,
|
38
38
|
ColumnConfigMappingInput,
|
@@ -48,13 +48,13 @@ from streamlit.elements.lib.policies import (
|
|
48
48
|
check_callback_rules,
|
49
49
|
check_session_state_rules,
|
50
50
|
)
|
51
|
+
from streamlit.elements.lib.utils import Key, to_key
|
51
52
|
from streamlit.errors import StreamlitAPIException
|
52
53
|
from streamlit.proto.Arrow_pb2 import Arrow as ArrowProto
|
53
54
|
from streamlit.runtime.metrics_util import gather_metrics
|
54
55
|
from streamlit.runtime.scriptrunner import get_script_run_ctx
|
55
56
|
from streamlit.runtime.state import WidgetCallback, register_widget
|
56
57
|
from streamlit.runtime.state.common import compute_widget_id
|
57
|
-
from streamlit.type_util import Key, to_key
|
58
58
|
|
59
59
|
if TYPE_CHECKING:
|
60
60
|
import pyarrow as pa
|
@@ -511,15 +511,15 @@ class ArrowMixin:
|
|
511
511
|
|
512
512
|
if isinstance(data, pa.Table):
|
513
513
|
# For pyarrow tables, we can just serialize the table directly
|
514
|
-
proto.data =
|
514
|
+
proto.data = dataframe_util.pyarrow_table_to_bytes(data)
|
515
515
|
else:
|
516
516
|
# For all other data formats, we need to convert them to a pandas.DataFrame
|
517
517
|
# thereby, we also apply some data specific configs
|
518
518
|
|
519
519
|
# Determine the input data format
|
520
|
-
data_format =
|
520
|
+
data_format = dataframe_util.determine_data_format(data)
|
521
521
|
|
522
|
-
if
|
522
|
+
if dataframe_util.is_pandas_styler(data):
|
523
523
|
# If pandas.Styler uuid is not provided, a hash of the position
|
524
524
|
# of the element will be used. This will cause a rerender of the table
|
525
525
|
# when the position of the element is changed.
|
@@ -528,7 +528,9 @@ class ArrowMixin:
|
|
528
528
|
marshall_styler(proto, data, default_uuid)
|
529
529
|
|
530
530
|
# Convert the input data into a pandas.DataFrame
|
531
|
-
data_df =
|
531
|
+
data_df = dataframe_util.convert_anything_to_pandas_df(
|
532
|
+
data, ensure_copy=False
|
533
|
+
)
|
532
534
|
apply_data_specific_configs(
|
533
535
|
column_config_mapping,
|
534
536
|
data_df,
|
@@ -536,7 +538,7 @@ class ArrowMixin:
|
|
536
538
|
check_arrow_compatibility=False,
|
537
539
|
)
|
538
540
|
# Serialize the data to bytes:
|
539
|
-
proto.data =
|
541
|
+
proto.data = dataframe_util.data_frame_to_bytes(data_df)
|
540
542
|
|
541
543
|
if hide_index is not None:
|
542
544
|
update_column_config(
|
@@ -615,8 +617,10 @@ class ArrowMixin:
|
|
615
617
|
|
616
618
|
# Check if data is uncollected, and collect it but with 100 rows max, instead of 10k rows, which is done in all other cases.
|
617
619
|
# Avoid this and use 100 rows in st.table, because large tables render slowly, take too much screen space, and can crush the app.
|
618
|
-
if
|
619
|
-
data =
|
620
|
+
if dataframe_util.is_unevaluated_data_object(data):
|
621
|
+
data = dataframe_util.convert_anything_to_pandas_df(
|
622
|
+
data, max_unevaluated_rows=100
|
623
|
+
)
|
620
624
|
|
621
625
|
# If pandas.Styler uuid is not provided, a hash of the position
|
622
626
|
# of the element will be used. This will cause a rerender of the table
|
@@ -707,7 +711,7 @@ def marshall(proto: ArrowProto, data: Data, default_uuid: str | None = None) ->
|
|
707
711
|
"""
|
708
712
|
import pyarrow as pa
|
709
713
|
|
710
|
-
if
|
714
|
+
if dataframe_util.is_pandas_styler(data):
|
711
715
|
# default_uuid is a string only if the data is a `Styler`,
|
712
716
|
# and `None` otherwise.
|
713
717
|
assert isinstance(
|
@@ -716,7 +720,7 @@ def marshall(proto: ArrowProto, data: Data, default_uuid: str | None = None) ->
|
|
716
720
|
marshall_styler(proto, data, default_uuid)
|
717
721
|
|
718
722
|
if isinstance(data, pa.Table):
|
719
|
-
proto.data =
|
723
|
+
proto.data = dataframe_util.pyarrow_table_to_bytes(data)
|
720
724
|
else:
|
721
|
-
df =
|
722
|
-
proto.data =
|
725
|
+
df = dataframe_util.convert_anything_to_pandas_df(data)
|
726
|
+
proto.data = dataframe_util.data_frame_to_bytes(df)
|
@@ -25,12 +25,15 @@ from typing import (
|
|
25
25
|
Collection,
|
26
26
|
Final,
|
27
27
|
Hashable,
|
28
|
+
Literal,
|
28
29
|
Sequence,
|
29
30
|
TypedDict,
|
30
31
|
cast,
|
31
32
|
)
|
32
33
|
|
33
|
-
from
|
34
|
+
from typing_extensions import TypeAlias
|
35
|
+
|
36
|
+
from streamlit import dataframe_util, type_util
|
34
37
|
from streamlit.color_util import (
|
35
38
|
Color,
|
36
39
|
is_color_like,
|
@@ -44,8 +47,11 @@ if TYPE_CHECKING:
|
|
44
47
|
import altair as alt
|
45
48
|
import pandas as pd
|
46
49
|
|
50
|
+
from streamlit.dataframe_util import DataFrameCompatible
|
47
51
|
from streamlit.elements.arrow import Data
|
48
|
-
|
52
|
+
|
53
|
+
VegaLiteType: TypeAlias = Literal["quantitative", "ordinal", "temporal", "nominal"]
|
54
|
+
ChartStackType: TypeAlias = Literal["normalize", "center", "layered"]
|
49
55
|
|
50
56
|
|
51
57
|
class PrepDataColumns(TypedDict):
|
@@ -129,7 +135,7 @@ def generate_chart(
|
|
129
135
|
"""Function to use the chart's type, data columns and indices to figure out the chart's spec."""
|
130
136
|
import altair as alt
|
131
137
|
|
132
|
-
df =
|
138
|
+
df = dataframe_util.convert_anything_to_pandas_df(data, ensure_copy=True)
|
133
139
|
|
134
140
|
# From now on, use "df" instead of "data". Deleting "data" to guarantee we follow this.
|
135
141
|
del data
|
@@ -248,7 +254,7 @@ def prep_chart_data_for_add_rows(
|
|
248
254
|
"""
|
249
255
|
import pandas as pd
|
250
256
|
|
251
|
-
df = cast(pd.DataFrame,
|
257
|
+
df = cast(pd.DataFrame, dataframe_util.convert_anything_to_pandas_df(data))
|
252
258
|
|
253
259
|
# Make range indices start at last_index.
|
254
260
|
if isinstance(df.index, pd.RangeIndex):
|
@@ -273,6 +279,66 @@ def prep_chart_data_for_add_rows(
|
|
273
279
|
return out_data, add_rows_metadata
|
274
280
|
|
275
281
|
|
282
|
+
def _infer_vegalite_type(
|
283
|
+
data: pd.Series[Any],
|
284
|
+
) -> VegaLiteType:
|
285
|
+
"""
|
286
|
+
From an array-like input, infer the correct vega typecode
|
287
|
+
('ordinal', 'nominal', 'quantitative', or 'temporal')
|
288
|
+
|
289
|
+
Parameters
|
290
|
+
----------
|
291
|
+
data: Numpy array or Pandas Series
|
292
|
+
"""
|
293
|
+
# The code below is copied from Altair, and slightly modified.
|
294
|
+
# We copy this code here so we don't depend on private Altair functions.
|
295
|
+
# Source: https://github.com/altair-viz/altair/blob/62ca5e37776f5cecb27e83c1fbd5d685a173095d/altair/utils/core.py#L193
|
296
|
+
|
297
|
+
from pandas.api.types import infer_dtype
|
298
|
+
|
299
|
+
# STREAMLIT MOD: I'm using infer_dtype directly here, rather than using Altair's wrapper. Their
|
300
|
+
# wrapper is only there to support Pandas < 0.20, but Streamlit requires Pandas 1.3.
|
301
|
+
typ = infer_dtype(data)
|
302
|
+
|
303
|
+
if typ in [
|
304
|
+
"floating",
|
305
|
+
"mixed-integer-float",
|
306
|
+
"integer",
|
307
|
+
"mixed-integer",
|
308
|
+
"complex",
|
309
|
+
]:
|
310
|
+
return "quantitative"
|
311
|
+
|
312
|
+
elif typ == "categorical" and data.cat.ordered:
|
313
|
+
# STREAMLIT MOD: The original code returns a tuple here:
|
314
|
+
# return ("ordinal", data.cat.categories.tolist())
|
315
|
+
# But returning the tuple here isn't compatible with our
|
316
|
+
# built-in chart implementation. And it also doesn't seem to be necessary.
|
317
|
+
# Altair already extracts the correct sort order somewhere else.
|
318
|
+
# More info about the issue here: https://github.com/streamlit/streamlit/issues/7776
|
319
|
+
return "ordinal"
|
320
|
+
elif typ in ["string", "bytes", "categorical", "boolean", "mixed", "unicode"]:
|
321
|
+
return "nominal"
|
322
|
+
elif typ in [
|
323
|
+
"datetime",
|
324
|
+
"datetime64",
|
325
|
+
"timedelta",
|
326
|
+
"timedelta64",
|
327
|
+
"date",
|
328
|
+
"time",
|
329
|
+
"period",
|
330
|
+
]:
|
331
|
+
return "temporal"
|
332
|
+
else:
|
333
|
+
# STREAMLIT MOD: I commented this out since Streamlit doesn't have a warnings object.
|
334
|
+
# warnings.warn(
|
335
|
+
# "I don't know how to infer vegalite type from '{}'. "
|
336
|
+
# "Defaulting to nominal.".format(typ),
|
337
|
+
# stacklevel=1,
|
338
|
+
# )
|
339
|
+
return "nominal"
|
340
|
+
|
341
|
+
|
276
342
|
def _get_pandas_index_attr(
|
277
343
|
data: pd.DataFrame | pd.Series,
|
278
344
|
attr: str,
|
@@ -327,8 +393,8 @@ def _prep_data(
|
|
327
393
|
def _last_index_for_melted_dataframes(
|
328
394
|
data: DataFrameCompatible | Any,
|
329
395
|
) -> Hashable | None:
|
330
|
-
if
|
331
|
-
data =
|
396
|
+
if dataframe_util.is_dataframe_compatible(data):
|
397
|
+
data = dataframe_util.convert_anything_to_pandas_df(data)
|
332
398
|
|
333
399
|
if data.index.size > 0:
|
334
400
|
return cast(Hashable, data.index[-1])
|
@@ -434,7 +500,7 @@ def _melt_data(
|
|
434
500
|
|
435
501
|
# Arrow has problems with object types after melting two different dtypes
|
436
502
|
# pyarrow.lib.ArrowTypeError: "Expected a <TYPE> object, got a object"
|
437
|
-
fixed_df =
|
503
|
+
fixed_df = dataframe_util.fix_arrow_incompatible_column_types(
|
438
504
|
melted_df,
|
439
505
|
selected_columns=[
|
440
506
|
*columns_to_leave_alone,
|
@@ -862,7 +928,7 @@ def _get_color_encoding(
|
|
862
928
|
if color_column == _MELTED_COLOR_COLUMN_NAME:
|
863
929
|
column_type = "nominal"
|
864
930
|
else:
|
865
|
-
column_type =
|
931
|
+
column_type = _infer_vegalite_type(df[color_column])
|
866
932
|
|
867
933
|
color_enc = alt.Color(
|
868
934
|
field=color_column, legend=_COLOR_LEGEND_SETTINGS, type=column_type
|
@@ -982,7 +1048,7 @@ def _get_tooltip_encoding(
|
|
982
1048
|
|
983
1049
|
def _get_x_encoding_type(
|
984
1050
|
df: pd.DataFrame, chart_type: ChartType, x_column: str | None
|
985
|
-
) ->
|
1051
|
+
) -> VegaLiteType:
|
986
1052
|
if x_column is None:
|
987
1053
|
return "quantitative" # Anything. If None, Vega-Lite may hide the axis.
|
988
1054
|
|
@@ -991,18 +1057,18 @@ def _get_x_encoding_type(
|
|
991
1057
|
if chart_type == ChartType.VERTICAL_BAR and not _is_date_column(df, x_column):
|
992
1058
|
return "ordinal"
|
993
1059
|
|
994
|
-
return
|
1060
|
+
return _infer_vegalite_type(df[x_column])
|
995
1061
|
|
996
1062
|
|
997
1063
|
def _get_y_encoding_type(
|
998
1064
|
df: pd.DataFrame, chart_type: ChartType, y_column: str | None
|
999
|
-
) ->
|
1065
|
+
) -> VegaLiteType:
|
1000
1066
|
# Horizontal bar charts should have a discrete (ordinal) y-axis, UNLESS type is date/time
|
1001
1067
|
if chart_type == ChartType.HORIZONTAL_BAR and not _is_date_column(df, y_column):
|
1002
1068
|
return "ordinal"
|
1003
1069
|
|
1004
1070
|
if y_column:
|
1005
|
-
return
|
1071
|
+
return _infer_vegalite_type(df[y_column])
|
1006
1072
|
|
1007
1073
|
return "quantitative" # Pick anything. If undefined, Vega-Lite may hide the axis.
|
1008
1074
|
|
@@ -21,10 +21,10 @@ from typing import TYPE_CHECKING, Dict, Final, Literal, Mapping, Union
|
|
21
21
|
|
22
22
|
from typing_extensions import TypeAlias
|
23
23
|
|
24
|
+
from streamlit.dataframe_util import DataFormat, is_colum_type_arrow_incompatible
|
24
25
|
from streamlit.elements.lib.column_types import ColumnConfig, ColumnType
|
25
26
|
from streamlit.elements.lib.dicttools import remove_none_values
|
26
27
|
from streamlit.errors import StreamlitAPIException
|
27
|
-
from streamlit.type_util import DataFormat, is_colum_type_arrow_incompatible
|
28
28
|
|
29
29
|
if TYPE_CHECKING:
|
30
30
|
import pyarrow as pa
|
@@ -16,7 +16,7 @@ from __future__ import annotations
|
|
16
16
|
|
17
17
|
from typing import TYPE_CHECKING, Any, Mapping, TypeVar
|
18
18
|
|
19
|
-
from streamlit import
|
19
|
+
from streamlit import dataframe_util
|
20
20
|
from streamlit.errors import StreamlitAPIException
|
21
21
|
|
22
22
|
if TYPE_CHECKING:
|
@@ -236,7 +236,7 @@ def _marshall_display_values(
|
|
236
236
|
|
237
237
|
"""
|
238
238
|
new_df = _use_display_values(df, styles)
|
239
|
-
proto.styler.display_values =
|
239
|
+
proto.styler.display_values = dataframe_util.data_frame_to_bytes(new_df)
|
240
240
|
|
241
241
|
|
242
242
|
def _use_display_values(df: DataFrame, styles: Mapping[str, Any]) -> DataFrame:
|
@@ -14,9 +14,9 @@
|
|
14
14
|
|
15
15
|
from __future__ import annotations
|
16
16
|
|
17
|
-
from typing import TYPE_CHECKING, Any
|
17
|
+
from typing import TYPE_CHECKING, Any, Final
|
18
18
|
|
19
|
-
from streamlit import config, runtime
|
19
|
+
from streamlit import config, errors, logger, runtime
|
20
20
|
from streamlit.elements.form import is_in_form
|
21
21
|
from streamlit.errors import StreamlitAPIException, StreamlitAPIWarning
|
22
22
|
from streamlit.runtime.scriptrunner.script_run_context import get_script_run_ctx
|
@@ -26,6 +26,9 @@ if TYPE_CHECKING:
|
|
26
26
|
from streamlit.delta_generator import DeltaGenerator
|
27
27
|
|
28
28
|
|
29
|
+
_LOGGER: Final = logger.get_logger(__name__)
|
30
|
+
|
31
|
+
|
29
32
|
def check_callback_rules(dg: DeltaGenerator, on_change: WidgetCallback | None) -> None:
|
30
33
|
"""Ensures that widgets other than `st.form_submit` within a form don't have an on_change callback set.
|
31
34
|
|
@@ -143,3 +146,18 @@ def check_fragment_path_policy(dg: DeltaGenerator):
|
|
143
146
|
for index, path_index in enumerate(current_fragment_delta_path):
|
144
147
|
if current_cursor_delta_path[index] != path_index:
|
145
148
|
raise StreamlitAPIException(_fragment_writes_widget_to_outside_error)
|
149
|
+
|
150
|
+
|
151
|
+
def maybe_raise_label_warnings(label: str | None, label_visibility: str | None):
|
152
|
+
if not label:
|
153
|
+
_LOGGER.warning(
|
154
|
+
"`label` got an empty value. This is discouraged for accessibility "
|
155
|
+
"reasons and may be disallowed in the future by raising an exception. "
|
156
|
+
"Please provide a non-empty label and hide it with label_visibility "
|
157
|
+
"if needed."
|
158
|
+
)
|
159
|
+
if label_visibility not in ("visible", "hidden", "collapsed"):
|
160
|
+
raise errors.StreamlitAPIException(
|
161
|
+
f"Unsupported label_visibility option '{label_visibility}'. "
|
162
|
+
f"Valid values are 'visible', 'hidden' or 'collapsed'."
|
163
|
+
)
|
streamlit/elements/lib/utils.py
CHANGED
@@ -15,9 +15,21 @@
|
|
15
15
|
from __future__ import annotations
|
16
16
|
|
17
17
|
from enum import Enum, EnumMeta
|
18
|
-
from typing import
|
19
|
-
|
20
|
-
|
18
|
+
from typing import (
|
19
|
+
TYPE_CHECKING,
|
20
|
+
Any,
|
21
|
+
Final,
|
22
|
+
Iterable,
|
23
|
+
Literal,
|
24
|
+
Sequence,
|
25
|
+
TypeVar,
|
26
|
+
Union,
|
27
|
+
overload,
|
28
|
+
)
|
29
|
+
|
30
|
+
from typing_extensions import TypeAlias
|
31
|
+
|
32
|
+
from streamlit import config, dataframe_util, errors, logger
|
21
33
|
from streamlit.proto.LabelVisibilityMessage_pb2 import LabelVisibilityMessage
|
22
34
|
from streamlit.runtime.state.common import RegisterWidgetResult
|
23
35
|
|
@@ -25,8 +37,15 @@ if TYPE_CHECKING:
|
|
25
37
|
from streamlit.type_util import T
|
26
38
|
|
27
39
|
|
40
|
+
_LOGGER: Final = logger.get_logger(__name__)
|
41
|
+
|
42
|
+
Key: TypeAlias = Union[str, int]
|
43
|
+
|
44
|
+
LabelVisibility: TypeAlias = Literal["visible", "hidden", "collapsed"]
|
45
|
+
|
46
|
+
|
28
47
|
def get_label_visibility_proto_value(
|
29
|
-
label_visibility_string:
|
48
|
+
label_visibility_string: LabelVisibility,
|
30
49
|
) -> LabelVisibilityMessage.LabelVisibilityOptions.ValueType:
|
31
50
|
"""Returns one of LabelVisibilityMessage enum constants.py based on string value."""
|
32
51
|
|
@@ -40,6 +59,78 @@ def get_label_visibility_proto_value(
|
|
40
59
|
raise ValueError(f"Unknown label visibility value: {label_visibility_string}")
|
41
60
|
|
42
61
|
|
62
|
+
@overload
|
63
|
+
def to_key(key: None) -> None: ...
|
64
|
+
|
65
|
+
|
66
|
+
@overload
|
67
|
+
def to_key(key: Key) -> str: ...
|
68
|
+
|
69
|
+
|
70
|
+
def to_key(key: Key | None) -> str | None:
|
71
|
+
return None if key is None else str(key)
|
72
|
+
|
73
|
+
|
74
|
+
E1 = TypeVar("E1", bound=Enum)
|
75
|
+
E2 = TypeVar("E2", bound=Enum)
|
76
|
+
|
77
|
+
_ALLOWED_ENUM_COERCION_CONFIG_SETTINGS = ("off", "nameOnly", "nameAndValue")
|
78
|
+
|
79
|
+
|
80
|
+
def _coerce_enum(from_enum_value: E1, to_enum_class: type[E2]) -> E1 | E2:
|
81
|
+
"""Attempt to coerce an Enum value to another EnumMeta.
|
82
|
+
|
83
|
+
An Enum value of EnumMeta E1 is considered coercable to EnumType E2
|
84
|
+
if the EnumMeta __qualname__ match and the names of their members
|
85
|
+
match as well. (This is configurable in streamlist configs)
|
86
|
+
"""
|
87
|
+
if not isinstance(from_enum_value, Enum):
|
88
|
+
raise ValueError(
|
89
|
+
f"Expected an Enum in the first argument. Got {type(from_enum_value)}"
|
90
|
+
)
|
91
|
+
if not isinstance(to_enum_class, EnumMeta):
|
92
|
+
raise ValueError(
|
93
|
+
f"Expected an EnumMeta/Type in the second argument. Got {type(to_enum_class)}"
|
94
|
+
)
|
95
|
+
if isinstance(from_enum_value, to_enum_class):
|
96
|
+
return from_enum_value # Enum is already a member, no coersion necessary
|
97
|
+
|
98
|
+
coercion_type = config.get_option("runner.enumCoercion")
|
99
|
+
if coercion_type not in _ALLOWED_ENUM_COERCION_CONFIG_SETTINGS:
|
100
|
+
raise errors.StreamlitAPIException(
|
101
|
+
"Invalid value for config option runner.enumCoercion. "
|
102
|
+
f"Expected one of {_ALLOWED_ENUM_COERCION_CONFIG_SETTINGS}, "
|
103
|
+
f"but got '{coercion_type}'."
|
104
|
+
)
|
105
|
+
if coercion_type == "off":
|
106
|
+
return from_enum_value # do not attempt to coerce
|
107
|
+
|
108
|
+
# We now know this is an Enum AND the user has configured coercion enabled.
|
109
|
+
# Check if we do NOT meet the required conditions and log a failure message
|
110
|
+
# if that is the case.
|
111
|
+
from_enum_class = from_enum_value.__class__
|
112
|
+
if (
|
113
|
+
from_enum_class.__qualname__ != to_enum_class.__qualname__
|
114
|
+
or (
|
115
|
+
coercion_type == "nameOnly"
|
116
|
+
and set(to_enum_class._member_names_) != set(from_enum_class._member_names_)
|
117
|
+
)
|
118
|
+
or (
|
119
|
+
coercion_type == "nameAndValue"
|
120
|
+
and set(to_enum_class._value2member_map_)
|
121
|
+
!= set(from_enum_class._value2member_map_)
|
122
|
+
)
|
123
|
+
):
|
124
|
+
_LOGGER.debug("Failed to coerce %s to class %s", from_enum_value, to_enum_class)
|
125
|
+
return from_enum_value # do not attempt to coerce
|
126
|
+
|
127
|
+
# At this point we think the Enum is coercable, and we know
|
128
|
+
# E1 and E2 have the same member names. We convert from E1 to E2 using _name_
|
129
|
+
# (since user Enum subclasses can override the .name property in 3.11)
|
130
|
+
_LOGGER.debug("Coerced %s to class %s", from_enum_value, to_enum_class)
|
131
|
+
return to_enum_class[from_enum_value._name_]
|
132
|
+
|
133
|
+
|
43
134
|
@overload
|
44
135
|
def maybe_coerce_enum(
|
45
136
|
register_widget_result: RegisterWidgetResult[Enum],
|
@@ -51,7 +142,7 @@ def maybe_coerce_enum(
|
|
51
142
|
@overload
|
52
143
|
def maybe_coerce_enum(
|
53
144
|
register_widget_result: RegisterWidgetResult[T],
|
54
|
-
options:
|
145
|
+
options: dataframe_util.OptionSequence[T],
|
55
146
|
opt_sequence: Sequence[T],
|
56
147
|
) -> RegisterWidgetResult[T]: ...
|
57
148
|
|
@@ -74,7 +165,7 @@ def maybe_coerce_enum(register_widget_result, options, opt_sequence):
|
|
74
165
|
return register_widget_result
|
75
166
|
|
76
167
|
return RegisterWidgetResult(
|
77
|
-
|
168
|
+
_coerce_enum(register_widget_result.value, coerce_class),
|
78
169
|
register_widget_result.value_changed,
|
79
170
|
)
|
80
171
|
|
@@ -84,7 +175,7 @@ def maybe_coerce_enum(register_widget_result, options, opt_sequence):
|
|
84
175
|
@overload
|
85
176
|
def maybe_coerce_enum_sequence(
|
86
177
|
register_widget_result: RegisterWidgetResult[list[T]],
|
87
|
-
options:
|
178
|
+
options: dataframe_util.OptionSequence[T],
|
88
179
|
opt_sequence: Sequence[T],
|
89
180
|
) -> RegisterWidgetResult[list[T]]: ...
|
90
181
|
|
@@ -92,7 +183,7 @@ def maybe_coerce_enum_sequence(
|
|
92
183
|
@overload
|
93
184
|
def maybe_coerce_enum_sequence(
|
94
185
|
register_widget_result: RegisterWidgetResult[tuple[T, T]],
|
95
|
-
options:
|
186
|
+
options: dataframe_util.OptionSequence[T],
|
96
187
|
opt_sequence: Sequence[T],
|
97
188
|
) -> RegisterWidgetResult[tuple[T, T]]: ...
|
98
189
|
|
@@ -118,8 +209,7 @@ def maybe_coerce_enum_sequence(register_widget_result, options, opt_sequence):
|
|
118
209
|
# Return a new RegisterWidgetResult with the coerced enum values sequence
|
119
210
|
return RegisterWidgetResult(
|
120
211
|
type(register_widget_result.value)(
|
121
|
-
|
122
|
-
for val in register_widget_result.value
|
212
|
+
_coerce_enum(val, coerce_class) for val in register_widget_result.value
|
123
213
|
),
|
124
214
|
register_widget_result.value_changed,
|
125
215
|
)
|
streamlit/elements/map.py
CHANGED
@@ -24,7 +24,7 @@ from typing import TYPE_CHECKING, Any, Collection, Dict, Final, Iterable, Union,
|
|
24
24
|
from typing_extensions import TypeAlias
|
25
25
|
|
26
26
|
import streamlit.elements.deck_gl_json_chart as deck_gl_json_chart
|
27
|
-
from streamlit import config,
|
27
|
+
from streamlit import config, dataframe_util
|
28
28
|
from streamlit.color_util import Color, IntColorTuple, is_color_like, to_int_color_tuple
|
29
29
|
from streamlit.errors import StreamlitAPIException
|
30
30
|
from streamlit.proto.DeckGlJsonChart_pb2 import DeckGlJsonChart as DeckGlJsonChartProto
|
@@ -263,7 +263,7 @@ def to_deckgl_json(
|
|
263
263
|
if hasattr(data, "empty") and data.empty:
|
264
264
|
return json.dumps(_DEFAULT_MAP)
|
265
265
|
|
266
|
-
df =
|
266
|
+
df = dataframe_util.convert_anything_to_pandas_df(data)
|
267
267
|
|
268
268
|
lat_col_name = _get_lat_or_lon_col_name(df, "latitude", lat, _DEFAULT_LAT_COL_NAMES)
|
269
269
|
lon_col_name = _get_lat_or_lon_col_name(
|
streamlit/elements/metric.py
CHANGED
@@ -20,12 +20,15 @@ from typing import TYPE_CHECKING, Literal, Union, cast
|
|
20
20
|
|
21
21
|
from typing_extensions import TypeAlias
|
22
22
|
|
23
|
-
from streamlit.elements.lib.
|
23
|
+
from streamlit.elements.lib.policies import maybe_raise_label_warnings
|
24
|
+
from streamlit.elements.lib.utils import (
|
25
|
+
LabelVisibility,
|
26
|
+
get_label_visibility_proto_value,
|
27
|
+
)
|
24
28
|
from streamlit.errors import StreamlitAPIException
|
25
29
|
from streamlit.proto.Metric_pb2 import Metric as MetricProto
|
26
30
|
from streamlit.runtime.metrics_util import gather_metrics
|
27
31
|
from streamlit.string_util import clean_text
|
28
|
-
from streamlit.type_util import LabelVisibility, maybe_raise_label_warnings
|
29
32
|
|
30
33
|
if TYPE_CHECKING:
|
31
34
|
import numpy as np
|
@@ -47,13 +47,13 @@ from streamlit.elements.lib.policies import (
|
|
47
47
|
from streamlit.elements.lib.streamlit_plotly_theme import (
|
48
48
|
configure_streamlit_plotly_theme,
|
49
49
|
)
|
50
|
+
from streamlit.elements.lib.utils import Key, to_key
|
50
51
|
from streamlit.errors import StreamlitAPIException
|
51
52
|
from streamlit.proto.PlotlyChart_pb2 import PlotlyChart as PlotlyChartProto
|
52
53
|
from streamlit.runtime.metrics_util import gather_metrics
|
53
54
|
from streamlit.runtime.scriptrunner import get_script_run_ctx
|
54
55
|
from streamlit.runtime.state import WidgetCallback, register_widget
|
55
56
|
from streamlit.runtime.state.common import compute_widget_id
|
56
|
-
from streamlit.type_util import Key, to_key
|
57
57
|
|
58
58
|
if TYPE_CHECKING:
|
59
59
|
import matplotlib
|
@@ -36,9 +36,10 @@ from typing import (
|
|
36
36
|
from typing_extensions import TypeAlias
|
37
37
|
|
38
38
|
import streamlit.elements.lib.dicttools as dicttools
|
39
|
-
from streamlit import type_util
|
39
|
+
from streamlit import dataframe_util, type_util
|
40
40
|
from streamlit.elements.lib.built_in_chart_utils import (
|
41
41
|
AddRowsMetadata,
|
42
|
+
ChartStackType,
|
42
43
|
ChartType,
|
43
44
|
generate_chart,
|
44
45
|
)
|
@@ -49,6 +50,7 @@ from streamlit.elements.lib.policies import (
|
|
49
50
|
check_fragment_path_policy,
|
50
51
|
check_session_state_rules,
|
51
52
|
)
|
53
|
+
from streamlit.elements.lib.utils import Key, to_key
|
52
54
|
from streamlit.errors import StreamlitAPIException
|
53
55
|
from streamlit.proto.ArrowVegaLiteChart_pb2 import (
|
54
56
|
ArrowVegaLiteChart as ArrowVegaLiteChartProto,
|
@@ -57,7 +59,6 @@ from streamlit.runtime.metrics_util import gather_metrics
|
|
57
59
|
from streamlit.runtime.scriptrunner import get_script_run_ctx
|
58
60
|
from streamlit.runtime.state import register_widget
|
59
61
|
from streamlit.runtime.state.common import compute_widget_id
|
60
|
-
from streamlit.type_util import ChartStackType, Key, to_key
|
61
62
|
from streamlit.util import HASHLIB_KWARGS
|
62
63
|
|
63
64
|
if TYPE_CHECKING:
|
@@ -279,10 +280,10 @@ def _serialize_data(data: Any) -> bytes:
|
|
279
280
|
import pyarrow as pa
|
280
281
|
|
281
282
|
if isinstance(data, pa.Table):
|
282
|
-
return
|
283
|
+
return dataframe_util.pyarrow_table_to_bytes(data)
|
283
284
|
|
284
|
-
df =
|
285
|
-
return
|
285
|
+
df = dataframe_util.convert_anything_to_pandas_df(data)
|
286
|
+
return dataframe_util.data_frame_to_bytes(df)
|
286
287
|
|
287
288
|
|
288
289
|
def _marshall_chart_data(
|
@@ -30,6 +30,7 @@ from streamlit.elements.lib.policies import (
|
|
30
30
|
check_fragment_path_policy,
|
31
31
|
check_session_state_rules,
|
32
32
|
)
|
33
|
+
from streamlit.elements.lib.utils import Key, to_key
|
33
34
|
from streamlit.errors import StreamlitAPIException
|
34
35
|
from streamlit.file_util import get_main_script_directory, normalize_path_join
|
35
36
|
from streamlit.navigation.page import StreamlitPage
|
@@ -47,7 +48,6 @@ from streamlit.runtime.state import (
|
|
47
48
|
)
|
48
49
|
from streamlit.runtime.state.common import compute_widget_id, save_for_app_testing
|
49
50
|
from streamlit.string_util import validate_icon_or_emoji
|
50
|
-
from streamlit.type_util import Key, to_key
|
51
51
|
from streamlit.url_util import is_url
|
52
52
|
|
53
53
|
if TYPE_CHECKING:
|
@@ -26,8 +26,14 @@ from streamlit.elements.lib.policies import (
|
|
26
26
|
check_callback_rules,
|
27
27
|
check_fragment_path_policy,
|
28
28
|
check_session_state_rules,
|
29
|
+
maybe_raise_label_warnings,
|
30
|
+
)
|
31
|
+
from streamlit.elements.lib.utils import (
|
32
|
+
Key,
|
33
|
+
LabelVisibility,
|
34
|
+
get_label_visibility_proto_value,
|
35
|
+
to_key,
|
29
36
|
)
|
30
|
-
from streamlit.elements.lib.utils import get_label_visibility_proto_value
|
31
37
|
from streamlit.elements.widgets.file_uploader import _get_upload_files
|
32
38
|
from streamlit.proto.CameraInput_pb2 import CameraInput as CameraInputProto
|
33
39
|
from streamlit.proto.Common_pb2 import FileUploaderState as FileUploaderStateProto
|
@@ -42,7 +48,6 @@ from streamlit.runtime.state import (
|
|
42
48
|
)
|
43
49
|
from streamlit.runtime.state.common import compute_widget_id
|
44
50
|
from streamlit.runtime.uploaded_file_manager import DeletedFile, UploadedFile
|
45
|
-
from streamlit.type_util import Key, LabelVisibility, maybe_raise_label_warnings, to_key
|
46
51
|
|
47
52
|
if TYPE_CHECKING:
|
48
53
|
from streamlit.delta_generator import DeltaGenerator
|