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.
Files changed (135) hide show
  1. streamlit/__init__.py +0 -26
  2. streamlit/commands/logo.py +2 -0
  3. streamlit/commands/page_config.py +16 -16
  4. streamlit/components/v2/__init__.py +2 -2
  5. streamlit/config.py +29 -0
  6. streamlit/connections/base_connection.py +16 -4
  7. streamlit/connections/snowflake_connection.py +254 -205
  8. streamlit/elements/form.py +2 -2
  9. streamlit/elements/lib/streamlit_plotly_theme.py +9 -11
  10. streamlit/elements/metric.py +49 -48
  11. streamlit/elements/widgets/button.py +9 -9
  12. streamlit/elements/widgets/chat.py +5 -9
  13. streamlit/elements/widgets/data_editor.py +3 -3
  14. streamlit/elements/widgets/file_uploader.py +10 -11
  15. streamlit/elements/widgets/select_slider.py +4 -0
  16. streamlit/proto/NewSession_pb2.py +18 -18
  17. streamlit/proto/NewSession_pb2.pyi +5 -1
  18. streamlit/runtime/app_session.py +78 -58
  19. streamlit/runtime/caching/cache_data_api.py +25 -21
  20. streamlit/runtime/caching/cache_resource_api.py +69 -41
  21. streamlit/runtime/connection_factory.py +67 -41
  22. streamlit/runtime/scriptrunner_utils/script_run_context.py +0 -21
  23. streamlit/runtime/state/query_params.py +0 -19
  24. streamlit/static/index.html +1 -1
  25. streamlit/static/manifest.json +296 -296
  26. streamlit/static/static/js/{ErrorOutline.esm.BjVqd_6R.js → ErrorOutline.esm.CiSfK8ht.js} +1 -1
  27. streamlit/static/static/js/{FileDownload.esm.DJCSsghl.js → FileDownload.esm.ItNjcEfs.js} +1 -1
  28. streamlit/static/static/js/{FileHelper.C---TH7o.js → FileHelper.xS7f19FE.js} +1 -1
  29. streamlit/static/static/js/{FormClearHelper.C-6BC487.js → FormClearHelper.N8_BCinn.js} +1 -1
  30. streamlit/static/static/js/{InputInstructions.sxc3InCI.js → InputInstructions.CrsdK7CQ.js} +1 -1
  31. streamlit/static/static/js/Particles.BDlTHC3I.js +1 -0
  32. streamlit/static/static/js/{ProgressBar.BiYsyZCC.js → ProgressBar.Bk2qeHfS.js} +2 -2
  33. streamlit/static/static/js/{StreamlitSyntaxHighlighter.9jZF8jX1.js → StreamlitSyntaxHighlighter.BcuPrPcw.js} +1 -1
  34. streamlit/static/static/js/{TableChart.esm.BdA4Q1rZ.js → TableChart.esm.CP7XPz8I.js} +1 -1
  35. streamlit/static/static/js/Toolbar.DCJcLwve.js +1 -0
  36. streamlit/static/static/js/{WidgetLabelHelpIconInline.DxODTLS2.js → WidgetLabelHelpIconInline.BPqxu1b-.js} +1 -1
  37. streamlit/static/static/js/{base-input.Gf1cKuQR.js → base-input.x4muJJ13.js} +4 -4
  38. streamlit/static/static/js/{checkbox.CnoNruf3.js → checkbox.C5r4AIaH.js} +1 -1
  39. streamlit/static/static/js/{createDownloadLinkElement.B48AepiL.js → createDownloadLinkElement.C83kkEeT.js} +1 -1
  40. streamlit/static/static/js/{data-grid-overlay-editor.Cmdq9aqU.js → data-grid-overlay-editor.0sOWm4IB.js} +1 -1
  41. streamlit/static/static/js/{downloader.CQLoQdMX.js → downloader.C_6FfoEv.js} +1 -1
  42. streamlit/static/static/js/{embed.oKwocwU8.js → embed.BnJ6-SK4.js} +14 -14
  43. streamlit/static/static/js/{es6.BRxlY_y5.js → es6.44_BWfFd.js} +2 -2
  44. streamlit/static/static/js/{formatNumber.DaagZyZe.js → formatNumber.DhHZAosz.js} +1 -1
  45. streamlit/static/static/js/{iconPosition.Q3hNvmK4.js → iconPosition.shOoQuRR.js} +1 -1
  46. streamlit/static/static/js/{iframeResizer.contentWindow.B6EBvI9L.js → iframeResizer.contentWindow.savEE5Vs.js} +1 -1
  47. streamlit/static/static/js/{index.BF23fbfs.js → index.AdijUi9Z.js} +1 -1
  48. streamlit/static/static/js/{index.OpATzEaW.js → index.B5HlOnvq.js} +1 -1
  49. streamlit/static/static/js/{index.Ca7MUNWJ.js → index.B6ewTTej.js} +1 -1
  50. streamlit/static/static/js/{index.CP-hoxJM.js → index.B8Of3XXR.js} +1 -1
  51. streamlit/static/static/js/{index.whRT3Vm3.js → index.BCaCSVj6.js} +1 -1
  52. streamlit/static/static/js/index.BE7Rhig1.js +1 -0
  53. streamlit/static/static/js/{index.BkSwGJoh.js → index.BHpLZ7X6.js} +2 -2
  54. streamlit/static/static/js/{index.na9UBuse.js → index.BNvP8E5Q.js} +1 -1
  55. streamlit/static/static/js/{index.CYE7b5Du.js → index.BNzuyXeN.js} +2 -2
  56. streamlit/static/static/js/{index.slgxPafU.js → index.BT7o4A9V.js} +1 -1
  57. streamlit/static/static/js/{index.BXEC4cf3.js → index.BYY3iuVE.js} +1 -1
  58. streamlit/static/static/js/index.BZI7jTDf.js +1 -0
  59. streamlit/static/static/js/{index.19_qtO6t.js → index.BZXk3Qxq.js} +1 -1
  60. streamlit/static/static/js/{index.B03eQZoH.js → index.BhQvq6YD.js} +1 -1
  61. streamlit/static/static/js/{index.WXybx2Xq.js → index.BkIReLGJ.js} +3 -3
  62. streamlit/static/static/js/{index.BoX8d5rK.js → index.Bl7SMZUw.js} +1 -1
  63. streamlit/static/static/js/{index.BGBTkulf.js → index.BqtgAGnG.js} +2 -2
  64. streamlit/static/static/js/{index.KtjGDGY5.js → index.BwnLQnAk.js} +1 -1
  65. streamlit/static/static/js/index.C1coXTgf.js +2 -0
  66. streamlit/static/static/js/{index.CVlg41MB.js → index.C6uOmY9O.js} +1 -1
  67. streamlit/static/static/js/index.CF88nImM.js +1 -0
  68. streamlit/static/static/js/{index.CFCBhOfx.js → index.CFlGfFvq.js} +1 -1
  69. streamlit/static/static/js/{index.Xg-Qttib.js → index.CQgiNpC7.js} +1 -1
  70. streamlit/static/static/js/{index.CCFwVy90.js → index.CZJkiRFm.js} +1 -1
  71. streamlit/static/static/js/index.Ch1TdQMG.js +1 -0
  72. streamlit/static/static/js/{index.CvIqsWy1.js → index.Ck2mQvBi.js} +1 -1
  73. streamlit/static/static/js/{index.BAI9aHCq.js → index.CrD2lwZG.js} +1 -1
  74. streamlit/static/static/js/index.CySNwKoN.js +2 -0
  75. streamlit/static/static/js/index.D3LEkXqN.js +1 -0
  76. streamlit/static/static/js/{index.QTaWooav.js → index.D8BQH06Z.js} +1 -1
  77. streamlit/static/static/js/{index.B9kZB0o1.js → index.DBtWixG1.js} +1 -1
  78. streamlit/static/static/js/{index.BzwlrgZO.js → index.DIsNrJpC.js} +1 -1
  79. streamlit/static/static/js/{index.Fu73QtkD.js → index.DO3HICut.js} +1 -1
  80. streamlit/static/static/js/{index.KN1VmyYN.js → index.D_ziFad8.js} +1 -1
  81. streamlit/static/static/js/{index.pU9mQeVC.js → index.Dblsdn8d.js} +1 -1
  82. streamlit/static/static/js/{index.Boa0Egng.js → index.DcdD0ROn.js} +2 -2
  83. streamlit/static/static/js/{index.CvB9JBqS.js → index.DfHm3P22.js} +51 -51
  84. streamlit/static/static/js/{index.BRfGUOQ-.js → index.DiwhD0Ic.js} +46 -46
  85. streamlit/static/static/js/index.DvZDNiBV.js +11 -0
  86. streamlit/static/static/js/{index.CJ4oJe0V.js → index.HjydQ4bj.js} +1 -1
  87. streamlit/static/static/js/{index.BbSFVZ3p.js → index.HsxzYHNf.js} +1 -1
  88. streamlit/static/static/js/{index.BVT89mQw.js → index.SVJGpnpy.js} +1 -1
  89. streamlit/static/static/js/index.SjKkVSL7.js +1 -0
  90. streamlit/static/static/js/index.hX8_3tMP.js +1 -0
  91. streamlit/static/static/js/{index.CCQ5p_WC.js → index.jZin0w6_.js} +1 -1
  92. streamlit/static/static/js/{index.BnfTPrHb.js → index.pQvPlPcA.js} +4 -4
  93. streamlit/static/static/js/index.pzQTLx9j.js +1 -0
  94. streamlit/static/static/js/{index.D6X2coHR.js → index.s44_OVd6.js} +33 -33
  95. streamlit/static/static/js/{input.CPzINTl-.js → input.jAD-v9D6.js} +2 -2
  96. streamlit/static/static/js/{main.DSPn8dUe.js → main.Cas0fuOs.js} +1 -1
  97. streamlit/static/static/js/{memory.CfD8IGoU.js → memory.ENruL8Qk.js} +1 -1
  98. streamlit/static/static/js/{number-overlay-editor.4Ae0qegV.js → number-overlay-editor.DAOTdulh.js} +2 -2
  99. streamlit/static/static/js/{pandasStylerUtils.D2EjZ7k6.js → pandasStylerUtils.DChYgcPq.js} +1 -1
  100. streamlit/static/static/js/{sandbox.C6vcPIm0.js → sandbox.DWZYRCm0.js} +1 -1
  101. streamlit/static/static/js/{styled-components.BBmp8buj.js → styled-components.3lwVqgRW.js} +1 -1
  102. streamlit/static/static/js/{throttle.BPcPpy-S.js → throttle.DfOW1Cns.js} +1 -1
  103. streamlit/static/static/js/{timepicker.ryzkTs2C.js → timepicker.CXHgL5f9.js} +1 -1
  104. streamlit/static/static/js/{toConsumableArray.Dg1nDaB_.js → toConsumableArray.DiW0GSDV.js} +1 -1
  105. streamlit/static/static/js/uniqueId.Dfi3SGKZ.js +1 -0
  106. streamlit/static/static/js/{useBasicWidgetState.A4U5lzAm.js → useBasicWidgetState.DnPEt_f3.js} +1 -1
  107. streamlit/static/static/js/{useIntlLocale.DWJgLlNz.js → useIntlLocale.BZEGSOVD.js} +8 -8
  108. streamlit/static/static/js/{useTextInputAutoExpand.BrBonw8t.js → useTextInputAutoExpand.MGVZMqyt.js} +1 -1
  109. streamlit/static/static/js/useUpdateUiValue.CPl6CEx3.js +1 -0
  110. streamlit/static/static/js/{useWaveformController.CBlvXlgZ.js → useWaveformController.DOpzDyZu.js} +1 -1
  111. streamlit/static/static/js/{withCalculatedWidth.D4cpOyNe.js → withCalculatedWidth.DgKFTeif.js} +1 -1
  112. streamlit/static/static/js/{withFullScreenWrapper.BMim3w94.js → withFullScreenWrapper.K1jkwhPu.js} +1 -1
  113. streamlit/user_info.py +225 -166
  114. {streamlit_nightly-1.52.3.dev20260113.dist-info → streamlit_nightly-1.53.1.dev20260115.dist-info}/METADATA +1 -1
  115. {streamlit_nightly-1.52.3.dev20260113.dist-info → streamlit_nightly-1.53.1.dev20260115.dist-info}/RECORD +119 -120
  116. streamlit/commands/experimental_query_params.py +0 -169
  117. streamlit/static/static/js/Particles.S8yD7iW-.js +0 -1
  118. streamlit/static/static/js/Toolbar.B9DaaDfN.js +0 -1
  119. streamlit/static/static/js/index.43b777iP.js +0 -1
  120. streamlit/static/static/js/index.C0fSEz-3.js +0 -1
  121. streamlit/static/static/js/index.CIbgt5wY.js +0 -1
  122. streamlit/static/static/js/index.CSfsEKCF.js +0 -2
  123. streamlit/static/static/js/index.CrPjcPY1.js +0 -1
  124. streamlit/static/static/js/index.D1pK_Vw2.js +0 -1
  125. streamlit/static/static/js/index.DGYHxruh.js +0 -1
  126. streamlit/static/static/js/index.DJ7P09eb.js +0 -2
  127. streamlit/static/static/js/index.Dh5SAThV.js +0 -11
  128. streamlit/static/static/js/index.QHnxuesF.js +0 -1
  129. streamlit/static/static/js/index.j4fnjyHo.js +0 -1
  130. streamlit/static/static/js/uniqueId.BFHzT5KQ.js +0 -1
  131. streamlit/static/static/js/useUpdateUiValue.BkOWyNVX.js +0 -1
  132. {streamlit_nightly-1.52.3.dev20260113.data → streamlit_nightly-1.53.1.dev20260115.data}/scripts/streamlit.cmd +0 -0
  133. {streamlit_nightly-1.52.3.dev20260113.dist-info → streamlit_nightly-1.53.1.dev20260115.dist-info}/WHEEL +0 -0
  134. {streamlit_nightly-1.52.3.dev20260113.dist-info → streamlit_nightly-1.53.1.dev20260115.dist-info}/entry_points.txt +0 -0
  135. {streamlit_nightly-1.52.3.dev20260113.dist-info → streamlit_nightly-1.53.1.dev20260115.dist-info}/top_level.txt +0 -0
@@ -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
- chart_categorical_colors = theme_opts.get("chartCategoricalColors", None)
1184
- # If chartCategoricalColors was configured via config.toml, it's already a list of
1185
- # strings. However, if it was provided via env variable or via CLI arg,
1186
- # it's a json string that needs to be parsed.
1187
- if isinstance(chart_categorical_colors, str):
1188
- try:
1189
- chart_categorical_colors = json.loads(chart_categorical_colors)
1190
- except json.JSONDecodeError as e:
1191
- _LOGGER.warning(
1192
- "Failed to parse the theme.chartCategoricalColors config option: %s.",
1193
- chart_categorical_colors,
1194
- exc_info=e,
1195
- )
1196
- chart_categorical_colors = None
1197
-
1198
- if chart_categorical_colors is not None:
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. If you have an
476
- unhashable argument (like a database connection) or an argument you
477
- want to exclude from caching, use an underscore prefix in the argument
478
- name. In this case, Streamlit will return a cached value when all other
479
- arguments match a previous function call. Alternatively, you can
480
- declare custom hashing functions with ``hash_funcs``.
481
-
482
- Cached values are available to all users of your app. If you need to
483
- save results that should only be accessible within a session, use
484
- `Session State
485
- <https://docs.streamlit.io/develop/concepts/architecture/session-state>`_
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 resource. If "global", cache globally. If "session",
548
- cache in the session.
549
-
550
- Session-scoped cache entries will be expired when a user's session is
551
- disconnected. Note that disconnected sessions can reconnect - so it is
552
- possible for the cache to populate multiple times in a single session for
553
- the same key.
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 global resources (e.g. database connections, ML models).
365
+ """Decorator to cache functions that return resource objects (e.g. database connections, ML models).
366
366
 
367
- Cached objects are shared across all users, sessions, and reruns. They
368
- must be thread-safe because they can be accessed from multiple threads
369
- concurrently. If thread safety is an issue, consider using ``st.session_state``
370
- to store resources per session instead.
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. If you have an
376
- unhashable argument (like a database connection) or an argument you
377
- want to exclude from caching, use an underscore prefix in the argument
378
- name. In this case, Streamlit will return a cached value when all other
379
- arguments match a previous function call. Alternatively, you can
380
- declare custom hashing functions with ``hash_funcs``.
381
-
382
- Cached values are available to all users of your app. If you need to
383
- save results that should only be accessible within a session, use
384
- `Session State
385
- <https://docs.streamlit.io/develop/concepts/architecture/session-state>`_
386
- instead. Within each user session, an ``@st.cache_resource``-decorated
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 time to keep an entry in the cache. Can be one of:
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
- If set, a function to call when a cache entry is removed from the cache.
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 which will remove entries normally: Those
466
- with ``max_entries`` or ``ttl`` settings. Note that TTL expiration does not
467
- happen on all reads - so ``ttl`` should not be used to guarantee timely
468
- cleanup, only cleanup when expired resources are accessed. Also note that
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
- This will NOT be called when an app is shut down.
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", cache globally. If "session",
477
- cache in the session.
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
- Session-scoped cache entries will be expired when a user's session is
480
- disconnected. Note that disconnected sessions can reconnect - so it is
481
- possible for the cache to populate multiple times in a single session for
482
- the same key.
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
- By default, all parameters to a cache_resource function must be hashable.
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
- A cache_resource function's cache can be procedurally cleared:
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
- >>> fetch_and_clean_data.clear(_sessionmaker, "https://streamlit.io/")
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
- ``.streamlit/secrets.toml``:
341
+ .. code-block:: toml
342
+ :filename: .streamlit/secrets.toml
328
343
 
329
- >>> [connections.sql]
330
- >>> dialect = "xxx"
331
- >>> host = "xxx"
332
- >>> username = "xxx"
333
- >>> password = "xxx"
344
+ [connections.sql]
345
+ dialect = "xxx"
346
+ host = "xxx"
347
+ username = "xxx"
348
+ password = "xxx"
334
349
 
335
- Your app code:
350
+ .. code-block:: python
351
+ :filename: streamlit_app.py
336
352
 
337
- >>> import streamlit as st
338
- >>> conn = st.connection("sql")
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
- ``.streamlit/secrets.toml``:
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
- >>> [connections.first_connection]
352
- >>> dialect = "xxx"
353
- >>> host = "xxx"
354
- >>> username = "xxx"
355
- >>> password = "xxx"
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
- Your app code:
382
+ .. code-block:: python
383
+ :filename: streamlit_app.py
365
384
 
366
- >>> import streamlit as st
367
- >>> conn1 = st.connection("first_connection", type="sql")
368
- >>> conn2 = st.connection("second_connection")
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
- ``.streamlit/secrets.toml``:
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
- >>> [connections.my_sql_connection]
381
- >>> url = "xxx+xxx://xxx:xxx@xxx:xxx/xxx"
404
+ .. code-block:: python
405
+ :filename: streamlit_app.py
382
406
 
383
- Your app code:
407
+ import streamlit as st
384
408
 
385
- >>> import streamlit as st
386
- >>> conn = st.connection(
387
- ... "my_sql_connection", type="streamlit.connections.SQLConnection"
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
- ``.streamlit/secrets.toml``:
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
- >>> [connections.my_sql_connection]
400
- >>> url = "xxx+xxx://xxx:xxx@xxx:xxx/xxx"
426
+ .. code-block:: python
427
+ :filename: streamlit_app.py
401
428
 
402
- Your app code:
429
+ import streamlit as st
430
+ from streamlit.connections import SQLConnection
403
431
 
404
- >>> import streamlit as st
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