streamlit-nightly 1.52.3.dev20260113__py3-none-any.whl → 1.53.1.dev20260115__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 +0 -26
- streamlit/commands/logo.py +2 -0
- streamlit/commands/page_config.py +16 -16
- streamlit/components/v2/__init__.py +2 -2
- streamlit/config.py +29 -0
- streamlit/connections/base_connection.py +16 -4
- streamlit/connections/snowflake_connection.py +254 -205
- streamlit/elements/form.py +2 -2
- streamlit/elements/lib/streamlit_plotly_theme.py +9 -11
- streamlit/elements/metric.py +49 -48
- streamlit/elements/widgets/button.py +9 -9
- streamlit/elements/widgets/chat.py +5 -9
- streamlit/elements/widgets/data_editor.py +3 -3
- streamlit/elements/widgets/file_uploader.py +10 -11
- streamlit/elements/widgets/select_slider.py +4 -0
- streamlit/proto/NewSession_pb2.py +18 -18
- streamlit/proto/NewSession_pb2.pyi +5 -1
- streamlit/runtime/app_session.py +78 -58
- streamlit/runtime/caching/cache_data_api.py +25 -21
- streamlit/runtime/caching/cache_resource_api.py +69 -41
- streamlit/runtime/connection_factory.py +67 -41
- streamlit/runtime/scriptrunner_utils/script_run_context.py +0 -21
- streamlit/runtime/state/query_params.py +0 -19
- streamlit/static/index.html +1 -1
- streamlit/static/manifest.json +296 -296
- streamlit/static/static/js/{ErrorOutline.esm.BjVqd_6R.js → ErrorOutline.esm.CiSfK8ht.js} +1 -1
- streamlit/static/static/js/{FileDownload.esm.DJCSsghl.js → FileDownload.esm.ItNjcEfs.js} +1 -1
- streamlit/static/static/js/{FileHelper.C---TH7o.js → FileHelper.xS7f19FE.js} +1 -1
- streamlit/static/static/js/{FormClearHelper.C-6BC487.js → FormClearHelper.N8_BCinn.js} +1 -1
- streamlit/static/static/js/{InputInstructions.sxc3InCI.js → InputInstructions.CrsdK7CQ.js} +1 -1
- streamlit/static/static/js/Particles.BDlTHC3I.js +1 -0
- streamlit/static/static/js/{ProgressBar.BiYsyZCC.js → ProgressBar.Bk2qeHfS.js} +2 -2
- streamlit/static/static/js/{StreamlitSyntaxHighlighter.9jZF8jX1.js → StreamlitSyntaxHighlighter.BcuPrPcw.js} +1 -1
- streamlit/static/static/js/{TableChart.esm.BdA4Q1rZ.js → TableChart.esm.CP7XPz8I.js} +1 -1
- streamlit/static/static/js/Toolbar.DCJcLwve.js +1 -0
- streamlit/static/static/js/{WidgetLabelHelpIconInline.DxODTLS2.js → WidgetLabelHelpIconInline.BPqxu1b-.js} +1 -1
- streamlit/static/static/js/{base-input.Gf1cKuQR.js → base-input.x4muJJ13.js} +4 -4
- streamlit/static/static/js/{checkbox.CnoNruf3.js → checkbox.C5r4AIaH.js} +1 -1
- streamlit/static/static/js/{createDownloadLinkElement.B48AepiL.js → createDownloadLinkElement.C83kkEeT.js} +1 -1
- streamlit/static/static/js/{data-grid-overlay-editor.Cmdq9aqU.js → data-grid-overlay-editor.0sOWm4IB.js} +1 -1
- streamlit/static/static/js/{downloader.CQLoQdMX.js → downloader.C_6FfoEv.js} +1 -1
- streamlit/static/static/js/{embed.oKwocwU8.js → embed.BnJ6-SK4.js} +14 -14
- streamlit/static/static/js/{es6.BRxlY_y5.js → es6.44_BWfFd.js} +2 -2
- streamlit/static/static/js/{formatNumber.DaagZyZe.js → formatNumber.DhHZAosz.js} +1 -1
- streamlit/static/static/js/{iconPosition.Q3hNvmK4.js → iconPosition.shOoQuRR.js} +1 -1
- streamlit/static/static/js/{iframeResizer.contentWindow.B6EBvI9L.js → iframeResizer.contentWindow.savEE5Vs.js} +1 -1
- streamlit/static/static/js/{index.BF23fbfs.js → index.AdijUi9Z.js} +1 -1
- streamlit/static/static/js/{index.OpATzEaW.js → index.B5HlOnvq.js} +1 -1
- streamlit/static/static/js/{index.Ca7MUNWJ.js → index.B6ewTTej.js} +1 -1
- streamlit/static/static/js/{index.CP-hoxJM.js → index.B8Of3XXR.js} +1 -1
- streamlit/static/static/js/{index.whRT3Vm3.js → index.BCaCSVj6.js} +1 -1
- streamlit/static/static/js/index.BE7Rhig1.js +1 -0
- streamlit/static/static/js/{index.BkSwGJoh.js → index.BHpLZ7X6.js} +2 -2
- streamlit/static/static/js/{index.na9UBuse.js → index.BNvP8E5Q.js} +1 -1
- streamlit/static/static/js/{index.CYE7b5Du.js → index.BNzuyXeN.js} +2 -2
- streamlit/static/static/js/{index.slgxPafU.js → index.BT7o4A9V.js} +1 -1
- streamlit/static/static/js/{index.BXEC4cf3.js → index.BYY3iuVE.js} +1 -1
- streamlit/static/static/js/index.BZI7jTDf.js +1 -0
- streamlit/static/static/js/{index.19_qtO6t.js → index.BZXk3Qxq.js} +1 -1
- streamlit/static/static/js/{index.B03eQZoH.js → index.BhQvq6YD.js} +1 -1
- streamlit/static/static/js/{index.WXybx2Xq.js → index.BkIReLGJ.js} +3 -3
- streamlit/static/static/js/{index.BoX8d5rK.js → index.Bl7SMZUw.js} +1 -1
- streamlit/static/static/js/{index.BGBTkulf.js → index.BqtgAGnG.js} +2 -2
- streamlit/static/static/js/{index.KtjGDGY5.js → index.BwnLQnAk.js} +1 -1
- streamlit/static/static/js/index.C1coXTgf.js +2 -0
- streamlit/static/static/js/{index.CVlg41MB.js → index.C6uOmY9O.js} +1 -1
- streamlit/static/static/js/index.CF88nImM.js +1 -0
- streamlit/static/static/js/{index.CFCBhOfx.js → index.CFlGfFvq.js} +1 -1
- streamlit/static/static/js/{index.Xg-Qttib.js → index.CQgiNpC7.js} +1 -1
- streamlit/static/static/js/{index.CCFwVy90.js → index.CZJkiRFm.js} +1 -1
- streamlit/static/static/js/index.Ch1TdQMG.js +1 -0
- streamlit/static/static/js/{index.CvIqsWy1.js → index.Ck2mQvBi.js} +1 -1
- streamlit/static/static/js/{index.BAI9aHCq.js → index.CrD2lwZG.js} +1 -1
- streamlit/static/static/js/index.CySNwKoN.js +2 -0
- streamlit/static/static/js/index.D3LEkXqN.js +1 -0
- streamlit/static/static/js/{index.QTaWooav.js → index.D8BQH06Z.js} +1 -1
- streamlit/static/static/js/{index.B9kZB0o1.js → index.DBtWixG1.js} +1 -1
- streamlit/static/static/js/{index.BzwlrgZO.js → index.DIsNrJpC.js} +1 -1
- streamlit/static/static/js/{index.Fu73QtkD.js → index.DO3HICut.js} +1 -1
- streamlit/static/static/js/{index.KN1VmyYN.js → index.D_ziFad8.js} +1 -1
- streamlit/static/static/js/{index.pU9mQeVC.js → index.Dblsdn8d.js} +1 -1
- streamlit/static/static/js/{index.Boa0Egng.js → index.DcdD0ROn.js} +2 -2
- streamlit/static/static/js/{index.CvB9JBqS.js → index.DfHm3P22.js} +51 -51
- streamlit/static/static/js/{index.BRfGUOQ-.js → index.DiwhD0Ic.js} +46 -46
- streamlit/static/static/js/index.DvZDNiBV.js +11 -0
- streamlit/static/static/js/{index.CJ4oJe0V.js → index.HjydQ4bj.js} +1 -1
- streamlit/static/static/js/{index.BbSFVZ3p.js → index.HsxzYHNf.js} +1 -1
- streamlit/static/static/js/{index.BVT89mQw.js → index.SVJGpnpy.js} +1 -1
- streamlit/static/static/js/index.SjKkVSL7.js +1 -0
- streamlit/static/static/js/index.hX8_3tMP.js +1 -0
- streamlit/static/static/js/{index.CCQ5p_WC.js → index.jZin0w6_.js} +1 -1
- streamlit/static/static/js/{index.BnfTPrHb.js → index.pQvPlPcA.js} +4 -4
- streamlit/static/static/js/index.pzQTLx9j.js +1 -0
- streamlit/static/static/js/{index.D6X2coHR.js → index.s44_OVd6.js} +33 -33
- streamlit/static/static/js/{input.CPzINTl-.js → input.jAD-v9D6.js} +2 -2
- streamlit/static/static/js/{main.DSPn8dUe.js → main.Cas0fuOs.js} +1 -1
- streamlit/static/static/js/{memory.CfD8IGoU.js → memory.ENruL8Qk.js} +1 -1
- streamlit/static/static/js/{number-overlay-editor.4Ae0qegV.js → number-overlay-editor.DAOTdulh.js} +2 -2
- streamlit/static/static/js/{pandasStylerUtils.D2EjZ7k6.js → pandasStylerUtils.DChYgcPq.js} +1 -1
- streamlit/static/static/js/{sandbox.C6vcPIm0.js → sandbox.DWZYRCm0.js} +1 -1
- streamlit/static/static/js/{styled-components.BBmp8buj.js → styled-components.3lwVqgRW.js} +1 -1
- streamlit/static/static/js/{throttle.BPcPpy-S.js → throttle.DfOW1Cns.js} +1 -1
- streamlit/static/static/js/{timepicker.ryzkTs2C.js → timepicker.CXHgL5f9.js} +1 -1
- streamlit/static/static/js/{toConsumableArray.Dg1nDaB_.js → toConsumableArray.DiW0GSDV.js} +1 -1
- streamlit/static/static/js/uniqueId.Dfi3SGKZ.js +1 -0
- streamlit/static/static/js/{useBasicWidgetState.A4U5lzAm.js → useBasicWidgetState.DnPEt_f3.js} +1 -1
- streamlit/static/static/js/{useIntlLocale.DWJgLlNz.js → useIntlLocale.BZEGSOVD.js} +8 -8
- streamlit/static/static/js/{useTextInputAutoExpand.BrBonw8t.js → useTextInputAutoExpand.MGVZMqyt.js} +1 -1
- streamlit/static/static/js/useUpdateUiValue.CPl6CEx3.js +1 -0
- streamlit/static/static/js/{useWaveformController.CBlvXlgZ.js → useWaveformController.DOpzDyZu.js} +1 -1
- streamlit/static/static/js/{withCalculatedWidth.D4cpOyNe.js → withCalculatedWidth.DgKFTeif.js} +1 -1
- streamlit/static/static/js/{withFullScreenWrapper.BMim3w94.js → withFullScreenWrapper.K1jkwhPu.js} +1 -1
- streamlit/user_info.py +225 -166
- {streamlit_nightly-1.52.3.dev20260113.dist-info → streamlit_nightly-1.53.1.dev20260115.dist-info}/METADATA +1 -1
- {streamlit_nightly-1.52.3.dev20260113.dist-info → streamlit_nightly-1.53.1.dev20260115.dist-info}/RECORD +119 -120
- streamlit/commands/experimental_query_params.py +0 -169
- streamlit/static/static/js/Particles.S8yD7iW-.js +0 -1
- streamlit/static/static/js/Toolbar.B9DaaDfN.js +0 -1
- streamlit/static/static/js/index.43b777iP.js +0 -1
- streamlit/static/static/js/index.C0fSEz-3.js +0 -1
- streamlit/static/static/js/index.CIbgt5wY.js +0 -1
- streamlit/static/static/js/index.CSfsEKCF.js +0 -2
- streamlit/static/static/js/index.CrPjcPY1.js +0 -1
- streamlit/static/static/js/index.D1pK_Vw2.js +0 -1
- streamlit/static/static/js/index.DGYHxruh.js +0 -1
- streamlit/static/static/js/index.DJ7P09eb.js +0 -2
- streamlit/static/static/js/index.Dh5SAThV.js +0 -11
- streamlit/static/static/js/index.QHnxuesF.js +0 -1
- streamlit/static/static/js/index.j4fnjyHo.js +0 -1
- streamlit/static/static/js/uniqueId.BFHzT5KQ.js +0 -1
- streamlit/static/static/js/useUpdateUiValue.BkOWyNVX.js +0 -1
- {streamlit_nightly-1.52.3.dev20260113.data → streamlit_nightly-1.53.1.dev20260115.data}/scripts/streamlit.cmd +0 -0
- {streamlit_nightly-1.52.3.dev20260113.dist-info → streamlit_nightly-1.53.1.dev20260115.dist-info}/WHEEL +0 -0
- {streamlit_nightly-1.52.3.dev20260113.dist-info → streamlit_nightly-1.53.1.dev20260115.dist-info}/entry_points.txt +0 -0
- {streamlit_nightly-1.52.3.dev20260113.dist-info → streamlit_nightly-1.53.1.dev20260115.dist-info}/top_level.txt +0 -0
streamlit/runtime/app_session.py
CHANGED
|
@@ -53,6 +53,8 @@ from streamlit.watcher import LocalSourcesWatcher
|
|
|
53
53
|
if TYPE_CHECKING:
|
|
54
54
|
from collections.abc import Callable
|
|
55
55
|
|
|
56
|
+
from google.protobuf.internal.containers import RepeatedScalarFieldContainer
|
|
57
|
+
|
|
56
58
|
from streamlit.proto.BackMsg_pb2 import BackMsg, DeferredFileRequest
|
|
57
59
|
from streamlit.runtime.script_data import ScriptData
|
|
58
60
|
from streamlit.runtime.scriptrunner.script_cache import ScriptCache
|
|
@@ -1016,6 +1018,65 @@ def _populate_config_msg(msg: Config) -> None:
|
|
|
1016
1018
|
msg.toolbar_mode = _get_toolbar_mode()
|
|
1017
1019
|
|
|
1018
1020
|
|
|
1021
|
+
def _parse_and_populate_chart_colors(
|
|
1022
|
+
theme_opts: dict[str, Any],
|
|
1023
|
+
config_key: str,
|
|
1024
|
+
msg_field: RepeatedScalarFieldContainer[str],
|
|
1025
|
+
required_length: int | None = None,
|
|
1026
|
+
) -> None:
|
|
1027
|
+
"""Parse and populate chart colors from theme config to protobuf message field.
|
|
1028
|
+
|
|
1029
|
+
Parameters
|
|
1030
|
+
----------
|
|
1031
|
+
theme_opts
|
|
1032
|
+
Dictionary of theme options from config.get_options_for_section.
|
|
1033
|
+
config_key
|
|
1034
|
+
The key in theme_opts to look for (e.g., "chartCategoricalColors").
|
|
1035
|
+
msg_field
|
|
1036
|
+
The protobuf repeated string field to append colors to.
|
|
1037
|
+
required_length
|
|
1038
|
+
If provided, log an error if the colors array doesn't have this exact length.
|
|
1039
|
+
"""
|
|
1040
|
+
colors = theme_opts.get(config_key)
|
|
1041
|
+
|
|
1042
|
+
# If colors was configured via config.toml, it's already a list of strings.
|
|
1043
|
+
# However, if it was provided via env variable or via CLI arg,
|
|
1044
|
+
# it's a JSON string that needs to be parsed.
|
|
1045
|
+
if isinstance(colors, str):
|
|
1046
|
+
try:
|
|
1047
|
+
colors = json.loads(colors)
|
|
1048
|
+
except json.JSONDecodeError as e:
|
|
1049
|
+
_LOGGER.warning(
|
|
1050
|
+
"Failed to parse the theme.%s config option: %s.",
|
|
1051
|
+
config_key,
|
|
1052
|
+
colors,
|
|
1053
|
+
exc_info=e,
|
|
1054
|
+
)
|
|
1055
|
+
colors = None
|
|
1056
|
+
|
|
1057
|
+
if colors is not None:
|
|
1058
|
+
# Check required length if specified
|
|
1059
|
+
if required_length is not None and len(colors) != required_length:
|
|
1060
|
+
_LOGGER.error(
|
|
1061
|
+
"Config theme.%s should have %s color values, "
|
|
1062
|
+
"but got %s. Defaulting to Streamlit's default colors.",
|
|
1063
|
+
config_key,
|
|
1064
|
+
required_length,
|
|
1065
|
+
len(colors),
|
|
1066
|
+
)
|
|
1067
|
+
return # Don't populate invalid data; let frontend use defaults
|
|
1068
|
+
for color in colors:
|
|
1069
|
+
try:
|
|
1070
|
+
msg_field.append(color)
|
|
1071
|
+
except Exception as e: # noqa: PERF203
|
|
1072
|
+
_LOGGER.warning(
|
|
1073
|
+
"Failed to parse the theme.%s config option: %s.",
|
|
1074
|
+
config_key,
|
|
1075
|
+
color,
|
|
1076
|
+
exc_info=e,
|
|
1077
|
+
)
|
|
1078
|
+
|
|
1079
|
+
|
|
1019
1080
|
def _populate_theme_msg(msg: CustomThemeConfig, section: str = "theme") -> None:
|
|
1020
1081
|
theme_opts = config.get_options_for_section(section)
|
|
1021
1082
|
if all(val is None for val in theme_opts.values()):
|
|
@@ -1036,6 +1097,7 @@ def _populate_theme_msg(msg: CustomThemeConfig, section: str = "theme") -> None:
|
|
|
1036
1097
|
"headingFontWeights",
|
|
1037
1098
|
"chartCategoricalColors",
|
|
1038
1099
|
"chartSequentialColors",
|
|
1100
|
+
"chartDivergingColors",
|
|
1039
1101
|
}
|
|
1040
1102
|
and option_val is not None
|
|
1041
1103
|
):
|
|
@@ -1180,64 +1242,22 @@ def _populate_theme_msg(msg: CustomThemeConfig, section: str = "theme") -> None:
|
|
|
1180
1242
|
exc_info=e,
|
|
1181
1243
|
)
|
|
1182
1244
|
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
for color in chart_categorical_colors:
|
|
1200
|
-
try:
|
|
1201
|
-
msg.chart_categorical_colors.append(color)
|
|
1202
|
-
except Exception as e: # noqa: PERF203
|
|
1203
|
-
_LOGGER.warning(
|
|
1204
|
-
"Failed to parse the theme.chartCategoricalColors config option: %s.",
|
|
1205
|
-
color,
|
|
1206
|
-
exc_info=e,
|
|
1207
|
-
)
|
|
1208
|
-
|
|
1209
|
-
chart_sequential_colors = theme_opts.get("chartSequentialColors", None)
|
|
1210
|
-
# If chartSequentialColors was configured via config.toml, it's already a list of
|
|
1211
|
-
# strings. However, if it was provided via env variable or via CLI arg,
|
|
1212
|
-
# it's a json string that needs to be parsed.
|
|
1213
|
-
if isinstance(chart_sequential_colors, str):
|
|
1214
|
-
try:
|
|
1215
|
-
chart_sequential_colors = json.loads(chart_sequential_colors)
|
|
1216
|
-
except json.JSONDecodeError as e:
|
|
1217
|
-
_LOGGER.warning(
|
|
1218
|
-
"Failed to parse the theme.chartSequentialColors config option: %s.",
|
|
1219
|
-
chart_sequential_colors,
|
|
1220
|
-
exc_info=e,
|
|
1221
|
-
)
|
|
1222
|
-
chart_sequential_colors = None
|
|
1223
|
-
|
|
1224
|
-
if chart_sequential_colors is not None:
|
|
1225
|
-
# Check that the list has 10 color values
|
|
1226
|
-
if len(chart_sequential_colors) != 10:
|
|
1227
|
-
_LOGGER.error(
|
|
1228
|
-
"Config theme.chartSequentialColors should have 10 color values, "
|
|
1229
|
-
"but got %s. Defaulting to Streamlit's default colors.",
|
|
1230
|
-
len(chart_sequential_colors),
|
|
1231
|
-
)
|
|
1232
|
-
for color in chart_sequential_colors:
|
|
1233
|
-
try:
|
|
1234
|
-
msg.chart_sequential_colors.append(color)
|
|
1235
|
-
except Exception as e: # noqa: PERF203
|
|
1236
|
-
_LOGGER.warning(
|
|
1237
|
-
"Failed to parse the theme.chartSequentialColors config option: %s.",
|
|
1238
|
-
color,
|
|
1239
|
-
exc_info=e,
|
|
1240
|
-
)
|
|
1245
|
+
# Handle chart color configurations
|
|
1246
|
+
_parse_and_populate_chart_colors(
|
|
1247
|
+
theme_opts, "chartCategoricalColors", msg.chart_categorical_colors
|
|
1248
|
+
)
|
|
1249
|
+
_parse_and_populate_chart_colors(
|
|
1250
|
+
theme_opts,
|
|
1251
|
+
"chartSequentialColors",
|
|
1252
|
+
msg.chart_sequential_colors,
|
|
1253
|
+
required_length=10,
|
|
1254
|
+
)
|
|
1255
|
+
_parse_and_populate_chart_colors(
|
|
1256
|
+
theme_opts,
|
|
1257
|
+
"chartDivergingColors",
|
|
1258
|
+
msg.chart_diverging_colors,
|
|
1259
|
+
required_length=10,
|
|
1260
|
+
)
|
|
1241
1261
|
|
|
1242
1262
|
|
|
1243
1263
|
def _populate_user_info_msg(msg: UserInfo) -> None:
|
|
@@ -465,6 +465,11 @@ class CacheDataAPI:
|
|
|
465
465
|
) -> CachedFunc[P, R] | Callable[[Callable[P, R]], CachedFunc[P, R]]:
|
|
466
466
|
"""Decorator to cache functions that return data (e.g. dataframe transforms, database queries, ML inference).
|
|
467
467
|
|
|
468
|
+
Cached objects can be global or session-scoped. Global cached data is
|
|
469
|
+
available across all users, sessions, and reruns. Session-scoped cached
|
|
470
|
+
data is only available in the current session and removed when the
|
|
471
|
+
session disconnects.
|
|
472
|
+
|
|
468
473
|
Cached objects are stored in "pickled" form, which means that the return
|
|
469
474
|
value of a cached function must be pickleable. Each caller of the cached
|
|
470
475
|
function gets its own copy of the cached data.
|
|
@@ -472,20 +477,17 @@ class CacheDataAPI:
|
|
|
472
477
|
You can clear a function's cache with ``func.clear()`` or clear the entire
|
|
473
478
|
cache with ``st.cache_data.clear()``.
|
|
474
479
|
|
|
475
|
-
A function's arguments must be hashable to cache it.
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
instead. Within each user session, an ``@st.cache_data``-decorated
|
|
487
|
-
function returns a *copy* of the cached return value (if the value is
|
|
488
|
-
already cached). To cache shared global resources (singletons), use
|
|
480
|
+
A function's arguments must be hashable to cache it. Streamlit makes a
|
|
481
|
+
best effort to hash a variety of objects, but the fallback hashing method
|
|
482
|
+
requires that the argument be pickleable, also. If you have an unhashable
|
|
483
|
+
argument (like a database connection) or an argument you want to exclude
|
|
484
|
+
from caching, use an underscore prefix in the argument name. In this case,
|
|
485
|
+
Streamlit will return a cached value when all other arguments match a
|
|
486
|
+
previous function call. Alternatively, you can declare custom hashing
|
|
487
|
+
functions with ``hash_funcs``.
|
|
488
|
+
|
|
489
|
+
Objects cached by ``st.cache_data`` are returned as copies. To cache a
|
|
490
|
+
shared resource or something you want to mutate in place, use
|
|
489
491
|
``st.cache_resource`` instead. To learn more about caching, see
|
|
490
492
|
`Caching overview
|
|
491
493
|
<https://docs.streamlit.io/develop/concepts/architecture/caching>`_.
|
|
@@ -544,13 +546,15 @@ class CacheDataAPI:
|
|
|
544
546
|
of how this can be used.
|
|
545
547
|
|
|
546
548
|
scope : "global" or "session"
|
|
547
|
-
The scope for the
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
549
|
+
The scope for the data cache. If this is ``"global"`` (default),
|
|
550
|
+
the data is cached globally. If this is ``"session"``, the data is
|
|
551
|
+
removed from the cache when the session disconnects.
|
|
552
|
+
|
|
553
|
+
Because a session-scoped cache is cleared when a session disconnects,
|
|
554
|
+
an unstable network connection can cause the cache to populate
|
|
555
|
+
multiple times in a single session. If this is a problem, you might
|
|
556
|
+
consider adjusting the ``server.websocketPingInterval``
|
|
557
|
+
configuration option.
|
|
554
558
|
|
|
555
559
|
Example
|
|
556
560
|
-------
|
|
@@ -362,33 +362,30 @@ class CacheResourceAPI:
|
|
|
362
362
|
on_release: OnRelease | None = None,
|
|
363
363
|
scope: CacheScope = "global",
|
|
364
364
|
) -> CachedFunc[P, R] | Callable[[Callable[P, R]], CachedFunc[P, R]]:
|
|
365
|
-
"""Decorator to cache functions that return
|
|
365
|
+
"""Decorator to cache functions that return resource objects (e.g. database connections, ML models).
|
|
366
366
|
|
|
367
|
-
Cached objects
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
367
|
+
Cached objects can be global or session-scoped. Global resources are
|
|
368
|
+
shared across all users, sessions, and reruns. Session-scoped resources are
|
|
369
|
+
scoped to the current session and are removed when the session disconnects.
|
|
370
|
+
Global resources must be thread-safe. If thread safety is an issue,
|
|
371
|
+
consider using a session-scoped cache or storing the resource in
|
|
372
|
+
``st.session_state`` instead.
|
|
371
373
|
|
|
372
374
|
You can clear a function's cache with ``func.clear()`` or clear the entire
|
|
373
375
|
cache with ``st.cache_resource.clear()``.
|
|
374
376
|
|
|
375
|
-
A function's arguments must be hashable to cache it.
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
function returns the cached instance of the return value (if the value
|
|
388
|
-
is already cached). Therefore, objects cached by ``st.cache_resource``
|
|
389
|
-
act like singletons and can mutate. To cache data and return copies,
|
|
390
|
-
use ``st.cache_data`` instead. To learn more about caching, see
|
|
391
|
-
`Caching overview
|
|
377
|
+
A function's arguments must be hashable to cache it. Streamlit makes a
|
|
378
|
+
best effort to hash a variety of objects, but the fallback hashing method
|
|
379
|
+
requires that the argument be pickleable, also. If you have an unhashable
|
|
380
|
+
argument (like a database connection) or an argument you want to exclude
|
|
381
|
+
from caching, use an underscore prefix in the argument name. In this case,
|
|
382
|
+
Streamlit will return a cached value when all other arguments match a
|
|
383
|
+
previous function call. Alternatively, you can declare custom hashing
|
|
384
|
+
functions with ``hash_funcs``.
|
|
385
|
+
|
|
386
|
+
Objects cached by ``st.cache_resource`` act like singletons and can
|
|
387
|
+
mutate. To cache data and return copies, use ``st.cache_data`` instead.
|
|
388
|
+
To learn more about caching, see `Caching overview
|
|
392
389
|
<https://docs.streamlit.io/develop/concepts/architecture/caching>`_.
|
|
393
390
|
|
|
394
391
|
.. warning::
|
|
@@ -410,7 +407,8 @@ class CacheResourceAPI:
|
|
|
410
407
|
function's source code.
|
|
411
408
|
|
|
412
409
|
ttl : float, timedelta, str, or None
|
|
413
|
-
The maximum
|
|
410
|
+
The maximum age of a returned entry from the cache. This can be one
|
|
411
|
+
of the following values:
|
|
414
412
|
|
|
415
413
|
- ``None`` if cache entries should never expire (default).
|
|
416
414
|
- A number specifying the time in seconds.
|
|
@@ -459,30 +457,40 @@ class CacheResourceAPI:
|
|
|
459
457
|
of how this can be used.
|
|
460
458
|
|
|
461
459
|
on_release : callable or None
|
|
462
|
-
|
|
460
|
+
A function to call when an entry is removed from the cache.
|
|
463
461
|
The removed item will be provided to the function as an argument.
|
|
464
462
|
|
|
465
|
-
This is only useful for caches
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
expiration can happen on any app render or load, so care should be taken
|
|
470
|
-
to ensure that ``on_release`` functions are thread-safe and do not rely on
|
|
471
|
-
session state.
|
|
463
|
+
This is only useful for caches that remove entries normally.
|
|
464
|
+
Most commonly, this is used session-scoped caches to release
|
|
465
|
+
per-session resources. This can also be used with ``max_entries``
|
|
466
|
+
or ``ttl`` settings.
|
|
472
467
|
|
|
473
|
-
|
|
468
|
+
TTL expiration only happens when expired resources are accessed.
|
|
469
|
+
Therefore, don't rely on TTL expiration to guarantee timely cleanup.
|
|
470
|
+
Also, expiration can happen on any script run. Ensure that
|
|
471
|
+
``on_release`` functions are thread-safe and don't rely on session
|
|
472
|
+
state.
|
|
473
|
+
|
|
474
|
+
The ``on_release`` function isn't guaranteed to be called when an
|
|
475
|
+
app is shut down.
|
|
474
476
|
|
|
475
477
|
scope : "global" or "session"
|
|
476
|
-
The scope for the resource. If "global"
|
|
477
|
-
|
|
478
|
+
The scope for the resource cache. If this is ``"global"`` (default),
|
|
479
|
+
the resource is cached globally. If this is ``"session"``, the
|
|
480
|
+
resource is removed from the cache when the session disconnects.
|
|
478
481
|
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
the
|
|
482
|
+
Because a session-scoped cache is cleared when a session disconnects,
|
|
483
|
+
an unstable network connection can cause the cache to populate
|
|
484
|
+
multiple times in a single session. If this is a problem, you might
|
|
485
|
+
consider adjusting the ``server.websocketPingInterval``
|
|
486
|
+
configuration option.
|
|
483
487
|
|
|
484
488
|
Example
|
|
485
489
|
-------
|
|
490
|
+
**Example 1: Global cache**
|
|
491
|
+
|
|
492
|
+
By default, an ``@st.cache_resource``-decorated function uses a global cache.
|
|
493
|
+
|
|
486
494
|
>>> import streamlit as st
|
|
487
495
|
>>>
|
|
488
496
|
>>> @st.cache_resource
|
|
@@ -501,7 +509,22 @@ class CacheResourceAPI:
|
|
|
501
509
|
>>> s3 = get_database_session(SESSION_URL_2)
|
|
502
510
|
>>> # This is a different URL, so the function executes.
|
|
503
511
|
|
|
504
|
-
|
|
512
|
+
**Example 2: Session-scoped cache**
|
|
513
|
+
|
|
514
|
+
By passing ``scope="session"``, an ``@st.cache_resource``-decorated function
|
|
515
|
+
uses a session-scoped cache. You can also use ``on_release`` to clean up
|
|
516
|
+
resources when they are no longer needed.
|
|
517
|
+
|
|
518
|
+
>>> import streamlit as st
|
|
519
|
+
>>>
|
|
520
|
+
>>> @st.cache_resource(scope="session", on_release=lambda sess: sess.close())
|
|
521
|
+
... def get_database_session(url):
|
|
522
|
+
... # Create a database session object that points to the URL.
|
|
523
|
+
... return session
|
|
524
|
+
|
|
525
|
+
**Example 3: Unhashable arguments**
|
|
526
|
+
|
|
527
|
+
By default, all parameters to a cached function must be hashable.
|
|
505
528
|
Any parameter whose name begins with ``_`` will not be hashed. You can use
|
|
506
529
|
this as an "escape hatch" for parameters that are not hashable:
|
|
507
530
|
|
|
@@ -521,7 +544,9 @@ class CacheResourceAPI:
|
|
|
521
544
|
>>> # value - even though the _sessionmaker parameter was different
|
|
522
545
|
>>> # in both calls.
|
|
523
546
|
|
|
524
|
-
|
|
547
|
+
**Example 4: Clearing a cache**
|
|
548
|
+
|
|
549
|
+
A cached function's cache can be procedurally cleared:
|
|
525
550
|
|
|
526
551
|
>>> import streamlit as st
|
|
527
552
|
>>>
|
|
@@ -530,12 +555,14 @@ class CacheResourceAPI:
|
|
|
530
555
|
... # Create a database connection object that points to the URL.
|
|
531
556
|
... return connection
|
|
532
557
|
>>>
|
|
533
|
-
>>>
|
|
558
|
+
>>> get_database_session.clear(_sessionmaker, "https://streamlit.io/")
|
|
534
559
|
>>> # Clear the cached entry for the arguments provided.
|
|
535
560
|
>>>
|
|
536
561
|
>>> get_database_session.clear()
|
|
537
562
|
>>> # Clear all cached entries for this function.
|
|
538
563
|
|
|
564
|
+
**Example 5: Custom hashing**
|
|
565
|
+
|
|
539
566
|
To override the default hashing behavior, pass a custom hash function.
|
|
540
567
|
You can do that by mapping a type (e.g. ``Person``) to a hash
|
|
541
568
|
function (``str``) like this:
|
|
@@ -562,6 +589,7 @@ class CacheResourceAPI:
|
|
|
562
589
|
>>> @st.cache_resource(hash_funcs={"__main__.Person": str})
|
|
563
590
|
... def get_person_name(person: Person):
|
|
564
591
|
... return person.name
|
|
592
|
+
|
|
565
593
|
"""
|
|
566
594
|
|
|
567
595
|
if scope not in ("global", "session"):
|
|
@@ -277,6 +277,10 @@ def connection_factory( # type: ignore
|
|
|
277
277
|
be specified in ``secrets.toml`` instead.
|
|
278
278
|
- ``"snowflake"``: Streamlit will initialize a connection with
|
|
279
279
|
|SnowflakeConnection|_.
|
|
280
|
+
- ``"snowflake-callers-rights"``: Streamlit will initialize a
|
|
281
|
+
``"snowflake"``-type connection, except the connection uses the
|
|
282
|
+
current viewer's identity tokens instead of the app's connection
|
|
283
|
+
configuration.
|
|
280
284
|
- ``"snowpark"``: Streamlit will initialize a connection with
|
|
281
285
|
|SnowparkConnection|_. This is deprecated.
|
|
282
286
|
- ``"sql"``: Streamlit will initialize a connection with
|
|
@@ -289,6 +293,16 @@ def connection_factory( # type: ignore
|
|
|
289
293
|
with the referenced class, which must extend
|
|
290
294
|
``st.connections.BaseConnection``.
|
|
291
295
|
|
|
296
|
+
.. Important::
|
|
297
|
+
Connections of type ``"snowflake-callers-rights"`` only work when
|
|
298
|
+
they run in a Snowflake Snowpark Container Services environment. If
|
|
299
|
+
they are used in a local environment, they will raise exceptions.
|
|
300
|
+
|
|
301
|
+
For local development, use an environment variable or secret to
|
|
302
|
+
logically switch between a ``"snowflake"`` and
|
|
303
|
+
``"snowflake-callers-rights"`` connection depending on the runtime
|
|
304
|
+
environment.
|
|
305
|
+
|
|
292
306
|
.. |SnowflakeConnection| replace:: ``SnowflakeConnection``
|
|
293
307
|
.. _SnowflakeConnection: https://docs.streamlit.io/develop/api-reference/connections/st.connections.snowflakeconnection
|
|
294
308
|
.. |SnowparkConnection| replace:: ``SnowparkConnection``
|
|
@@ -324,18 +338,21 @@ def connection_factory( # type: ignore
|
|
|
324
338
|
to use their default names and define corresponding sections in your ``secrets.toml``
|
|
325
339
|
file. The following example creates a ``"sql"``-type connection.
|
|
326
340
|
|
|
327
|
-
|
|
341
|
+
.. code-block:: toml
|
|
342
|
+
:filename: .streamlit/secrets.toml
|
|
328
343
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
344
|
+
[connections.sql]
|
|
345
|
+
dialect = "xxx"
|
|
346
|
+
host = "xxx"
|
|
347
|
+
username = "xxx"
|
|
348
|
+
password = "xxx"
|
|
334
349
|
|
|
335
|
-
|
|
350
|
+
.. code-block:: python
|
|
351
|
+
:filename: streamlit_app.py
|
|
336
352
|
|
|
337
|
-
|
|
338
|
-
|
|
353
|
+
import streamlit as st
|
|
354
|
+
|
|
355
|
+
conn = st.connection("sql")
|
|
339
356
|
|
|
340
357
|
**Example 2: Named connections**
|
|
341
358
|
|
|
@@ -346,26 +363,29 @@ def connection_factory( # type: ignore
|
|
|
346
363
|
custom name. The first defines ``type`` in the ``st.connection`` command;
|
|
347
364
|
the second defines ``type`` in ``secrets.toml``.
|
|
348
365
|
|
|
349
|
-
|
|
366
|
+
.. code-block:: toml
|
|
367
|
+
:filename: .streamlit/secrets.toml
|
|
368
|
+
|
|
369
|
+
[connections.first_connection]
|
|
370
|
+
dialect = "xxx"
|
|
371
|
+
host = "xxx"
|
|
372
|
+
username = "xxx"
|
|
373
|
+
password = "xxx"
|
|
350
374
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
>>> [connections.second_connection]
|
|
358
|
-
>>> type = "sql"
|
|
359
|
-
>>> dialect = "yyy"
|
|
360
|
-
>>> host = "yyy"
|
|
361
|
-
>>> username = "yyy"
|
|
362
|
-
>>> password = "yyy"
|
|
375
|
+
[connections.second_connection]
|
|
376
|
+
type = "sql"
|
|
377
|
+
dialect = "yyy"
|
|
378
|
+
host = "yyy"
|
|
379
|
+
username = "yyy"
|
|
380
|
+
password = "yyy"
|
|
363
381
|
|
|
364
|
-
|
|
382
|
+
.. code-block:: python
|
|
383
|
+
:filename: streamlit_app.py
|
|
365
384
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
385
|
+
import streamlit as st
|
|
386
|
+
|
|
387
|
+
conn1 = st.connection("first_connection", type="sql")
|
|
388
|
+
conn2 = st.connection("second_connection")
|
|
369
389
|
|
|
370
390
|
**Example 3: Using a path to the connection class**
|
|
371
391
|
|
|
@@ -375,17 +395,20 @@ def connection_factory( # type: ignore
|
|
|
375
395
|
creates the same type of connection as one with ``type="sql"``. Note that
|
|
376
396
|
``type`` is a string path.
|
|
377
397
|
|
|
378
|
-
|
|
398
|
+
.. code-block:: toml
|
|
399
|
+
:filename: .streamlit/secrets.toml
|
|
400
|
+
|
|
401
|
+
[connections.my_sql_connection]
|
|
402
|
+
url = "xxx+xxx://xxx:xxx@xxx:xxx/xxx"
|
|
379
403
|
|
|
380
|
-
|
|
381
|
-
|
|
404
|
+
.. code-block:: python
|
|
405
|
+
:filename: streamlit_app.py
|
|
382
406
|
|
|
383
|
-
|
|
407
|
+
import streamlit as st
|
|
384
408
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
... )
|
|
409
|
+
conn = st.connection(
|
|
410
|
+
"my_sql_connection", type="streamlit.connections.SQLConnection"
|
|
411
|
+
)
|
|
389
412
|
|
|
390
413
|
**Example 4: Importing the connection class**
|
|
391
414
|
|
|
@@ -394,16 +417,19 @@ def connection_factory( # type: ignore
|
|
|
394
417
|
infer the exact return type of ``st.connection``. The following example
|
|
395
418
|
creates the same connection as in Example 3.
|
|
396
419
|
|
|
397
|
-
|
|
420
|
+
.. code-block:: toml
|
|
421
|
+
:filename: .streamlit/secrets.toml
|
|
422
|
+
|
|
423
|
+
[connections.my_sql_connection]
|
|
424
|
+
url = "xxx+xxx://xxx:xxx@xxx:xxx/xxx"
|
|
398
425
|
|
|
399
|
-
|
|
400
|
-
|
|
426
|
+
.. code-block:: python
|
|
427
|
+
:filename: streamlit_app.py
|
|
401
428
|
|
|
402
|
-
|
|
429
|
+
import streamlit as st
|
|
430
|
+
from streamlit.connections import SQLConnection
|
|
403
431
|
|
|
404
|
-
|
|
405
|
-
>>> from streamlit.connections import SQLConnection
|
|
406
|
-
>>> conn = st.connection("my_sql_connection", type=SQLConnection)
|
|
432
|
+
conn = st.connection("my_sql_connection", type=SQLConnection)
|
|
407
433
|
|
|
408
434
|
"""
|
|
409
435
|
|
|
@@ -28,7 +28,6 @@ from urllib import parse
|
|
|
28
28
|
|
|
29
29
|
from streamlit.errors import (
|
|
30
30
|
NoSessionContext,
|
|
31
|
-
StreamlitAPIException,
|
|
32
31
|
)
|
|
33
32
|
from streamlit.logger import get_logger
|
|
34
33
|
from streamlit.runtime.forward_msg_cache import (
|
|
@@ -109,10 +108,6 @@ class ScriptRunContext:
|
|
|
109
108
|
# we allow only one dialog to be open at the same time
|
|
110
109
|
has_dialog_opened: bool = False
|
|
111
110
|
|
|
112
|
-
# TODO(willhuang1997): Remove this variable when experimental query params are removed
|
|
113
|
-
_experimental_query_params_used = False
|
|
114
|
-
_production_query_params_used = False
|
|
115
|
-
|
|
116
111
|
@property
|
|
117
112
|
def page_script_hash(self) -> str:
|
|
118
113
|
return self.pages_manager.current_page_script_hash
|
|
@@ -202,22 +197,6 @@ class ScriptRunContext:
|
|
|
202
197
|
# Pass the message up to our associated ScriptRunner.
|
|
203
198
|
self._enqueue(msg_to_send)
|
|
204
199
|
|
|
205
|
-
def ensure_single_query_api_used(self) -> None:
|
|
206
|
-
if self._experimental_query_params_used and self._production_query_params_used:
|
|
207
|
-
raise StreamlitAPIException(
|
|
208
|
-
"Using `st.query_params` together with either `st.experimental_get_query_params` "
|
|
209
|
-
"or `st.experimental_set_query_params` is not supported. Please "
|
|
210
|
-
" convert your app to only use `st.query_params`"
|
|
211
|
-
)
|
|
212
|
-
|
|
213
|
-
def mark_experimental_query_params_used(self) -> None:
|
|
214
|
-
self._experimental_query_params_used = True
|
|
215
|
-
self.ensure_single_query_api_used()
|
|
216
|
-
|
|
217
|
-
def mark_production_query_params_used(self) -> None:
|
|
218
|
-
self._production_query_params_used = True
|
|
219
|
-
self.ensure_single_query_api_used()
|
|
220
|
-
|
|
221
200
|
|
|
222
201
|
SCRIPT_RUN_CONTEXT_ATTR_NAME: Final = "streamlit_script_run_ctx"
|
|
223
202
|
|