streamlit-nightly 1.37.2.dev20240818__py2.py3-none-any.whl → 1.37.2.dev20240820__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. streamlit/dataframe_util.py +70 -71
  2. streamlit/elements/image.py +15 -25
  3. streamlit/elements/lib/built_in_chart_utils.py +1 -1
  4. streamlit/elements/lib/options_selector_utils.py +3 -3
  5. streamlit/elements/lib/policies.py +10 -9
  6. streamlit/elements/widgets/radio.py +2 -2
  7. streamlit/elements/widgets/select_slider.py +2 -2
  8. streamlit/elements/widgets/selectbox.py +2 -2
  9. streamlit/runtime/caching/__init__.py +1 -11
  10. streamlit/runtime/caching/cache_data_api.py +11 -83
  11. streamlit/runtime/caching/cache_errors.py +13 -9
  12. streamlit/runtime/caching/cache_resource_api.py +9 -58
  13. streamlit/runtime/caching/cache_utils.py +7 -12
  14. streamlit/runtime/caching/cached_message_replay.py +29 -185
  15. streamlit/runtime/caching/legacy_cache_api.py +15 -11
  16. streamlit/runtime/scriptrunner_utils/script_run_context.py +9 -4
  17. streamlit/runtime/state/widgets.py +0 -5
  18. streamlit/static/asset-manifest.json +7 -7
  19. streamlit/static/index.html +1 -1
  20. streamlit/static/static/js/1307.74bce9ab.chunk.js +1 -0
  21. streamlit/static/static/js/3599.eaeac234.chunk.js +5 -0
  22. streamlit/static/static/js/6013.fb4531df.chunk.js +5 -0
  23. streamlit/static/static/js/7175.70728640.chunk.js +5 -0
  24. streamlit/static/static/js/8691.93a29403.chunk.js +5 -0
  25. streamlit/static/static/js/main.ff81c7a3.js +28 -0
  26. {streamlit_nightly-1.37.2.dev20240818.dist-info → streamlit_nightly-1.37.2.dev20240820.dist-info}/METADATA +1 -1
  27. {streamlit_nightly-1.37.2.dev20240818.dist-info → streamlit_nightly-1.37.2.dev20240820.dist-info}/RECORD +32 -32
  28. {streamlit_nightly-1.37.2.dev20240818.dist-info → streamlit_nightly-1.37.2.dev20240820.dist-info}/WHEEL +1 -1
  29. streamlit/static/static/js/1307.5225662c.chunk.js +0 -1
  30. streamlit/static/static/js/3599.17480cdf.chunk.js +0 -5
  31. streamlit/static/static/js/6013.fc3867be.chunk.js +0 -5
  32. streamlit/static/static/js/7175.ed4a2f0d.chunk.js +0 -5
  33. streamlit/static/static/js/8691.885f6268.chunk.js +0 -5
  34. streamlit/static/static/js/main.90c4efd0.js +0 -28
  35. /streamlit/static/static/js/{main.90c4efd0.js.LICENSE.txt → main.ff81c7a3.js.LICENSE.txt} +0 -0
  36. {streamlit_nightly-1.37.2.dev20240818.data → streamlit_nightly-1.37.2.dev20240820.data}/scripts/streamlit.cmd +0 -0
  37. {streamlit_nightly-1.37.2.dev20240818.dist-info → streamlit_nightly-1.37.2.dev20240820.dist-info}/entry_points.txt +0 -0
  38. {streamlit_nightly-1.37.2.dev20240818.dist-info → streamlit_nightly-1.37.2.dev20240820.dist-info}/top_level.txt +0 -0
@@ -29,7 +29,7 @@ CACHE_DOCS_URL = "https://docs.streamlit.io/develop/concepts/architecture/cachin
29
29
  def get_cached_func_name_md(func: Any) -> str:
30
30
  """Get markdown representation of the function name."""
31
31
  if hasattr(func, "__name__"):
32
- return "`%s()`" % func.__name__
32
+ return f"`{func.__name__}()`"
33
33
  elif hasattr(type(func), "__name__"):
34
34
  return f"`{type(func).__name__}`"
35
35
  return f"`{type(func)}`"
@@ -105,9 +105,10 @@ class CacheReplayClosureError(StreamlitAPIException):
105
105
 
106
106
  msg = (
107
107
  f"""
108
- While running {func_name}, a streamlit element is called on some layout block created outside the function.
109
- This is incompatible with replaying the cached effect of that element, because the
110
- the referenced block might not exist when the replay happens.
108
+ While running {func_name}, a streamlit element is called on some layout block
109
+ created outside the function. This is incompatible with replaying the cached
110
+ effect of that element, because the the referenced block might not exist when
111
+ the replay happens.
111
112
 
112
113
  How to fix this:
113
114
  * Move the creation of $THING inside {func_name}.
@@ -124,11 +125,14 @@ class UnserializableReturnValueError(MarkdownFormattedException):
124
125
  MarkdownFormattedException.__init__(
125
126
  self,
126
127
  f"""
127
- Cannot serialize the return value (of type {get_return_value_type(return_value)}) in {get_cached_func_name_md(func)}.
128
- `st.cache_data` uses [pickle](https://docs.python.org/3/library/pickle.html) to
129
- serialize the function’s return value and safely store it in the cache without mutating the original object. Please convert the return value to a pickle-serializable type.
130
- If you want to cache unserializable objects such as database connections or Tensorflow
131
- sessions, use `st.cache_resource` instead (see [our docs]({CACHE_DOCS_URL}) for differences).""",
128
+ Cannot serialize the return value (of type {get_return_value_type(return_value)})
129
+ in {get_cached_func_name_md(func)}. `st.cache_data` uses
130
+ [pickle](https://docs.python.org/3/library/pickle.html) to serialize the
131
+ function's return value and safely store it in the cache
132
+ without mutating the original object. Please convert the return value to a
133
+ pickle-serializable type. If you want to cache unserializable objects such
134
+ as database connections or Tensorflow sessions, use `st.cache_resource`
135
+ instead (see [our docs]({CACHE_DOCS_URL}) for differences).""",
132
136
  )
133
137
 
134
138
 
@@ -37,13 +37,10 @@ from streamlit.runtime.caching.cache_utils import (
37
37
  from streamlit.runtime.caching.cached_message_replay import (
38
38
  CachedMessageReplayContext,
39
39
  CachedResult,
40
- ElementMsgData,
41
40
  MsgData,
42
- MultiCacheResults,
43
41
  show_widget_replay_deprecation,
44
42
  )
45
43
  from streamlit.runtime.metrics_util import gather_metrics
46
- from streamlit.runtime.scriptrunner_utils.script_run_context import get_script_run_ctx
47
44
  from streamlit.runtime.stats import CacheStat, CacheStatsProvider, group_stats
48
45
  from streamlit.time_util import time_to_seconds
49
46
 
@@ -83,7 +80,6 @@ class ResourceCaches(CacheStatsProvider):
83
80
  max_entries: int | float | None,
84
81
  ttl: float | timedelta | str | None,
85
82
  validate: ValidateFunc | None,
86
- allow_widgets: bool,
87
83
  ) -> ResourceCache:
88
84
  """Return the mem cache for the given key.
89
85
 
@@ -114,7 +110,6 @@ class ResourceCaches(CacheStatsProvider):
114
110
  max_entries=max_entries,
115
111
  ttl_seconds=ttl_seconds,
116
112
  validate=validate,
117
- allow_widgets=allow_widgets,
118
113
  )
119
114
  self._function_caches[key] = cache
120
115
  return cache
@@ -155,13 +150,11 @@ class CachedResourceFuncInfo(CachedFuncInfo):
155
150
  max_entries: int | None,
156
151
  ttl: float | timedelta | str | None,
157
152
  validate: ValidateFunc | None,
158
- allow_widgets: bool,
159
153
  hash_funcs: HashFuncsDict | None = None,
160
154
  ):
161
155
  super().__init__(
162
156
  func,
163
157
  show_spinner=show_spinner,
164
- allow_widgets=allow_widgets,
165
158
  hash_funcs=hash_funcs,
166
159
  )
167
160
  self.max_entries = max_entries
@@ -188,7 +181,6 @@ class CachedResourceFuncInfo(CachedFuncInfo):
188
181
  max_entries=self.max_entries,
189
182
  ttl=self.ttl,
190
183
  validate=self.validate,
191
- allow_widgets=self.allow_widgets,
192
184
  )
193
185
 
194
186
 
@@ -315,9 +307,11 @@ class CacheResourceAPI:
315
307
 
316
308
  experimental_allow_widgets : bool
317
309
  Allow widgets to be used in the cached function. Defaults to False.
318
- Support for widgets in cached functions is currently experimental.
319
- Setting this parameter to True may lead to excessive memory use since the
320
- widget value is treated as an additional input parameter to the cache.
310
+
311
+ .. deprecated::
312
+ The cached widget replay functionality was removed in 1.38. Please
313
+ remove the ``experimental_allow_widgets`` parameter from your
314
+ caching decorators.
321
315
 
322
316
  hash_funcs : dict or None
323
317
  Mapping of types or fully qualified names to hash functions.
@@ -327,10 +321,6 @@ class CacheResourceAPI:
327
321
  the provided function to generate a hash for it. See below for an example
328
322
  of how this can be used.
329
323
 
330
- .. deprecated::
331
- ``experimental_allow_widgets`` is deprecated and will be removed in
332
- a later version.
333
-
334
324
  Example
335
325
  -------
336
326
  >>> import streamlit as st
@@ -426,7 +416,6 @@ class CacheResourceAPI:
426
416
  max_entries=max_entries,
427
417
  ttl=ttl,
428
418
  validate=validate,
429
- allow_widgets=experimental_allow_widgets,
430
419
  hash_funcs=hash_funcs,
431
420
  )
432
421
  )
@@ -438,7 +427,6 @@ class CacheResourceAPI:
438
427
  max_entries=max_entries,
439
428
  ttl=ttl,
440
429
  validate=validate,
441
- allow_widgets=experimental_allow_widgets,
442
430
  hash_funcs=hash_funcs,
443
431
  )
444
432
  )
@@ -459,17 +447,15 @@ class ResourceCache(Cache):
459
447
  ttl_seconds: float,
460
448
  validate: ValidateFunc | None,
461
449
  display_name: str,
462
- allow_widgets: bool,
463
450
  ):
464
451
  super().__init__()
465
452
  self.key = key
466
453
  self.display_name = display_name
467
- self._mem_cache: TTLCache[str, MultiCacheResults] = TTLCache(
454
+ self._mem_cache: TTLCache[str, CachedResult] = TTLCache(
468
455
  maxsize=max_entries, ttl=ttl_seconds, timer=cache_utils.TTLCACHE_TIMER
469
456
  )
470
457
  self._mem_cache_lock = threading.Lock()
471
458
  self.validate = validate
472
- self.allow_widgets = allow_widgets
473
459
 
474
460
  @property
475
461
  def max_entries(self) -> float:
@@ -488,24 +474,11 @@ class ResourceCache(Cache):
488
474
  # key does not exist in cache.
489
475
  raise CacheKeyNotFoundError()
490
476
 
491
- multi_results: MultiCacheResults = self._mem_cache[key]
492
-
493
- ctx = get_script_run_ctx()
494
- if not ctx:
495
- # ScriptRunCtx does not exist (we're probably running in "raw" mode).
496
- raise CacheKeyNotFoundError()
497
-
498
- widget_key = multi_results.get_current_widget_key(ctx, CacheType.RESOURCE)
499
- if widget_key not in multi_results.results:
500
- # widget_key does not exist in cache (this combination of widgets hasn't been
501
- # seen for the value_key yet).
502
- raise CacheKeyNotFoundError()
503
-
504
- result = multi_results.results[widget_key]
477
+ result = self._mem_cache[key]
505
478
 
506
479
  if self.validate is not None and not self.validate(result.value):
507
480
  # Validate failed: delete the entry and raise an error.
508
- del multi_results.results[widget_key]
481
+ del self._mem_cache[key]
509
482
  raise CacheKeyNotFoundError()
510
483
 
511
484
  return result
@@ -513,33 +486,11 @@ class ResourceCache(Cache):
513
486
  @gather_metrics("_cache_resource_object")
514
487
  def write_result(self, key: str, value: Any, messages: list[MsgData]) -> None:
515
488
  """Write a value and associated messages to the cache."""
516
- ctx = get_script_run_ctx()
517
- if ctx is None:
518
- return
519
-
520
489
  main_id = st._main.id
521
490
  sidebar_id = st.sidebar.id
522
- if self.allow_widgets:
523
- widgets = {
524
- msg.widget_metadata.widget_id
525
- for msg in messages
526
- if isinstance(msg, ElementMsgData) and msg.widget_metadata is not None
527
- }
528
- else:
529
- widgets = set()
530
491
 
531
492
  with self._mem_cache_lock:
532
- try:
533
- multi_results = self._mem_cache[key]
534
- except KeyError:
535
- multi_results = MultiCacheResults(widget_ids=widgets, results={})
536
-
537
- multi_results.widget_ids.update(widgets)
538
- widget_key = multi_results.get_current_widget_key(ctx, CacheType.RESOURCE)
539
-
540
- result = CachedResult(value, messages, main_id, sidebar_id)
541
- multi_results.results[widget_key] = result
542
- self._mem_cache[key] = multi_results
493
+ self._mem_cache[key] = CachedResult(value, messages, main_id, sidebar_id)
543
494
 
544
495
  def _clear(self, key: str | None = None) -> None:
545
496
  with self._mem_cache_lock:
@@ -16,6 +16,7 @@
16
16
 
17
17
  from __future__ import annotations
18
18
 
19
+ import contextlib
19
20
  import functools
20
21
  import hashlib
21
22
  import inspect
@@ -125,12 +126,10 @@ class CachedFuncInfo:
125
126
  self,
126
127
  func: FunctionType,
127
128
  show_spinner: bool | str,
128
- allow_widgets: bool,
129
129
  hash_funcs: HashFuncsDict | None,
130
130
  ):
131
131
  self.func = func
132
132
  self.show_spinner = show_spinner
133
- self.allow_widgets = allow_widgets
134
133
  self.hash_funcs = hash_funcs
135
134
 
136
135
  @property
@@ -230,11 +229,9 @@ class CachedFunc:
230
229
  hash_funcs=self._info.hash_funcs,
231
230
  )
232
231
 
233
- try:
232
+ with contextlib.suppress(CacheKeyNotFoundError):
234
233
  cached_result = cache.read_result(value_key)
235
234
  return self._handle_cache_hit(cached_result)
236
- except CacheKeyNotFoundError:
237
- pass
238
235
  return self._handle_cache_miss(cache, value_key, func_args, func_kwargs)
239
236
 
240
237
  def _handle_cache_hit(self, result: CachedResult) -> Any:
@@ -279,17 +276,14 @@ class CachedFunc:
279
276
  # We've acquired the lock - but another thread may have acquired it first
280
277
  # and already computed the value. So we need to test for a cache hit again,
281
278
  # before computing.
282
- try:
279
+ with contextlib.suppress(CacheKeyNotFoundError):
283
280
  cached_result = cache.read_result(value_key)
284
281
  # Another thread computed the value before us. Early exit!
285
282
  return self._handle_cache_hit(cached_result)
286
283
 
287
- except CacheKeyNotFoundError:
288
- pass
289
-
290
284
  # We acquired the lock before any other thread. Compute the value!
291
285
  with self._info.cached_message_replay_ctx.calling_cached_function(
292
- self._info.func, self._info.allow_widgets
286
+ self._info.func
293
287
  ):
294
288
  computed_value = self._info.func(*func_args, **func_kwargs)
295
289
 
@@ -329,8 +323,10 @@ class CachedFunc:
329
323
 
330
324
  Parameters
331
325
  ----------
326
+
332
327
  *args: Any
333
328
  Arguments of the cached functions.
329
+
334
330
  **kwargs: Any
335
331
  Keyword arguments of the cached function.
336
332
 
@@ -471,8 +467,7 @@ def _make_function_key(cache_type: CacheType, func: FunctionType) -> str:
471
467
  source_code, hasher=func_hasher, cache_type=cache_type, hash_source=func
472
468
  )
473
469
 
474
- cache_key = func_hasher.hexdigest()
475
- return cache_key
470
+ return func_hasher.hexdigest()
476
471
 
477
472
 
478
473
  def _get_positional_arg_name(func: FunctionType, arg_index: int) -> str | None:
@@ -15,7 +15,6 @@
15
15
  from __future__ import annotations
16
16
 
17
17
  import contextlib
18
- import hashlib
19
18
  import threading
20
19
  from dataclasses import dataclass
21
20
  from typing import TYPE_CHECKING, Any, Iterator, Literal, Union
@@ -24,12 +23,9 @@ import streamlit as st
24
23
  from streamlit import runtime, util
25
24
  from streamlit.deprecation_util import show_deprecation_warning
26
25
  from streamlit.runtime.caching.cache_errors import CacheReplayClosureError
27
- from streamlit.runtime.caching.hashing import update_hash
28
26
  from streamlit.runtime.scriptrunner_utils.script_run_context import (
29
- ScriptRunContext,
30
- get_script_run_ctx,
27
+ in_cached_function,
31
28
  )
32
- from streamlit.util import HASHLIB_KWARGS
33
29
 
34
30
  if TYPE_CHECKING:
35
31
  from types import FunctionType
@@ -39,18 +35,6 @@ if TYPE_CHECKING:
39
35
  from streamlit.delta_generator import DeltaGenerator
40
36
  from streamlit.proto.Block_pb2 import Block
41
37
  from streamlit.runtime.caching.cache_type import CacheType
42
- from streamlit.runtime.state.common import WidgetMetadata
43
-
44
-
45
- @dataclass(frozen=True)
46
- class WidgetMsgMetadata:
47
- """Everything needed for replaying a widget and treating it as an implicit
48
- argument to a cached function, beyond what is stored for all elements.
49
- """
50
-
51
- widget_id: str
52
- widget_value: Any
53
- metadata: WidgetMetadata[Any]
54
38
 
55
39
 
56
40
  @dataclass(frozen=True)
@@ -65,7 +49,6 @@ class ElementMsgData:
65
49
  """An element's message and related metadata for
66
50
  replaying that element's function call.
67
51
 
68
- widget_metadata is filled in if and only if this element is a widget.
69
52
  media_data is filled in iff this is a media element (image, audio, video).
70
53
  """
71
54
 
@@ -73,7 +56,6 @@ class ElementMsgData:
73
56
  message: Message
74
57
  id_of_dg_called_on: str
75
58
  returned_dgs_id: str
76
- widget_metadata: WidgetMsgMetadata | None = None
77
59
  media_data: list[MediaMsgData] | None = None
78
60
 
79
61
 
@@ -86,62 +68,6 @@ class BlockMsgData:
86
68
 
87
69
  MsgData = Union[ElementMsgData, BlockMsgData]
88
70
 
89
- """
90
- Note [Cache result structure]
91
-
92
- The cache for a decorated function's results is split into two parts to enable
93
- handling widgets invoked by the function.
94
-
95
- Widgets act as implicit additional inputs to the cached function, so they should
96
- be used when deriving the cache key. However, we don't know what widgets are
97
- involved without first calling the function! So, we use the first execution
98
- of the function with a particular cache key to record what widgets are used,
99
- and use the current values of those widgets to derive a second cache key to
100
- look up the function execution's results. The combination of first and second
101
- cache keys act as one true cache key, just split up because the second part depends
102
- on the first.
103
-
104
- We need to treat widgets as implicit arguments of the cached function, because
105
- the behavior of the function, including what elements are created and what it
106
- returns, can be and usually will be influenced by the values of those widgets.
107
- For example:
108
- > @st.cache_data
109
- > def example_fn(x):
110
- > y = x + 1
111
- > if st.checkbox("hi"):
112
- > st.write("you checked the thing")
113
- > y = 0
114
- > return y
115
- >
116
- > example_fn(2)
117
-
118
- If the checkbox is checked, the function call should return 0 and the checkbox and
119
- message should be rendered. If the checkbox isn't checked, only the checkbox should
120
- render, and the function will return 3.
121
-
122
-
123
- There is a small catch in this. Since what widgets execute could depend on the values of
124
- any prior widgets, if we replace the `st.write` call in the example with a slider,
125
- the first time it runs, we would miss the slider because it wasn't called,
126
- so when we later execute the function with the checkbox checked, the widget cache key
127
- would not include the state of the slider, and would incorrectly get a cache hit
128
- for a different slider value.
129
-
130
- In principle the cache could be function+args key -> 1st widget key -> 2nd widget key
131
- ... -> final widget key, with each widget dependent on the exact values of the widgets
132
- seen prior. This would prevent unnecessary cache misses due to differing values of widgets
133
- that wouldn't affect the function's execution because they aren't even created.
134
- But this would add even more complexity and both conceptual and runtime overhead, so it is
135
- unclear if it would be worth doing.
136
-
137
- Instead, we can keep the widgets as one cache key, and if we encounter a new widget
138
- while executing the function, we just update the list of widgets to include it.
139
- This will cause existing cached results to be invalidated, which is bad, but to
140
- avoid it we would need to keep around the full list of widgets and values for each
141
- widget cache key so we could compute the updated key, which is probably too expensive
142
- to be worth it.
143
- """
144
-
145
71
 
146
72
  @dataclass
147
73
  class CachedResult:
@@ -155,32 +81,6 @@ class CachedResult:
155
81
  sidebar_id: str
156
82
 
157
83
 
158
- @dataclass
159
- class MultiCacheResults:
160
- """Widgets called by a cache-decorated function, and a mapping of the
161
- widget-derived cache key to the final results of executing the function.
162
- """
163
-
164
- widget_ids: set[str]
165
- results: dict[str, CachedResult]
166
-
167
- def get_current_widget_key(
168
- self, ctx: ScriptRunContext, cache_type: CacheType
169
- ) -> str:
170
- state = ctx.session_state
171
- # Compute the key using only widgets that have values. A missing widget
172
- # can be ignored because we only care about getting different keys
173
- # for different widget values, and for that purpose doing nothing
174
- # to the running hash is just as good as including the widget with a
175
- # sentinel value. But by excluding it, we might get to reuse a result
176
- # saved before we knew about that widget.
177
- widget_values = [
178
- (wid, state[wid]) for wid in sorted(self.widget_ids) if wid in state
179
- ]
180
- widget_key = _make_widget_key(widget_values, cache_type)
181
- return widget_key
182
-
183
-
184
84
  """
185
85
  Note [DeltaGenerator method invocation]
186
86
  There are two top level DG instances defined for all apps:
@@ -224,52 +124,37 @@ class CachedMessageReplayContext(threading.local):
224
124
  self._cached_message_stack: list[list[MsgData]] = []
225
125
  self._seen_dg_stack: list[set[str]] = []
226
126
  self._most_recent_messages: list[MsgData] = []
227
- self._registered_metadata: WidgetMetadata[Any] | None = None
228
127
  self._media_data: list[MediaMsgData] = []
229
128
  self._cache_type = cache_type
230
- self._allow_widgets: bool = False
231
129
 
232
130
  def __repr__(self) -> str:
233
131
  return util.repr_(self)
234
132
 
235
133
  @contextlib.contextmanager
236
- def calling_cached_function(
237
- self, func: FunctionType, allow_widgets: bool
238
- ) -> Iterator[None]:
134
+ def calling_cached_function(self, func: FunctionType) -> Iterator[None]:
239
135
  """Context manager that should wrap the invocation of a cached function.
240
- It allows us to track any `st.foo` messages that are generated from inside the function
241
- for playback during cache retrieval.
136
+ It allows us to track any `st.foo` messages that are generated from inside the
137
+ function for playback during cache retrieval.
242
138
  """
243
139
  self._cached_message_stack.append([])
244
140
  self._seen_dg_stack.append(set())
245
- self._allow_widgets = allow_widgets
246
-
247
141
  nested_call = False
248
- ctx = get_script_run_ctx()
249
- if ctx:
250
- if ctx.disallow_cached_widget_usage:
251
- # The disallow_cached_widget_usage is already set to true.
252
- # This indicates that this cached function run is called from another
253
- # cached function that disallows widget usage.
254
- # We need to deactivate the widget usage for this cached function run
255
- # even if it was allowed.
256
- self._allow_widgets = False
257
- nested_call = True
258
-
259
- if not self._allow_widgets:
260
- # If we're in a cached function that disallows widget usage, we need to set
261
- # the disallow_cached_widget_usage to true for this cached function run
262
- # to prevent widget usage (triggers a warning).
263
- ctx.disallow_cached_widget_usage = True
142
+ if in_cached_function.get():
143
+ nested_call = True
144
+ # If we're in a cached function. To disallow usage of widget-like element,
145
+ # we need to set the in_cached_function to true for this cached function run
146
+ # to prevent widget usage (triggers a warning).
147
+ in_cached_function.set(True)
148
+
264
149
  try:
265
150
  yield
266
151
  finally:
267
152
  self._most_recent_messages = self._cached_message_stack.pop()
268
153
  self._seen_dg_stack.pop()
269
- if ctx and not nested_call:
270
- # Reset the disallow_cached_widget_usage flag. But only if this
154
+ if not nested_call:
155
+ # Reset the in_cached_function flag. But only if this
271
156
  # is not nested inside a cached function that disallows widget usage.
272
- ctx.disallow_cached_widget_usage = False
157
+ in_cached_function.set(False)
273
158
 
274
159
  def save_element_message(
275
160
  self,
@@ -288,23 +173,6 @@ class CachedMessageReplayContext(threading.local):
288
173
  if len(self._cached_message_stack) >= 1:
289
174
  id_to_save = self.select_dg_to_save(invoked_dg_id, used_dg_id)
290
175
 
291
- # Widget replay is deprecated and will be removed soon:
292
- # https://github.com/streamlit/streamlit/pull/8817.
293
- # Therefore, its fine to keep this part a bit messy for now.
294
-
295
- if (
296
- hasattr(element_proto, "id")
297
- and element_proto.id
298
- and self._registered_metadata
299
- ):
300
- # The element has an ID and has associated widget metadata
301
- # -> looks like a valid registered widget
302
- widget_meta = WidgetMsgMetadata(
303
- element_proto.id, None, metadata=self._registered_metadata
304
- )
305
- else:
306
- widget_meta = None
307
-
308
176
  media_data = self._media_data
309
177
 
310
178
  element_msg_data = ElementMsgData(
@@ -312,17 +180,14 @@ class CachedMessageReplayContext(threading.local):
312
180
  element_proto,
313
181
  id_to_save,
314
182
  returned_dg_id,
315
- widget_meta,
316
183
  media_data,
317
184
  )
318
185
  for msgs in self._cached_message_stack:
319
- if self._allow_widgets or widget_meta is None:
320
- msgs.append(element_msg_data)
186
+ msgs.append(element_msg_data)
321
187
 
322
188
  # Reset instance state, now that it has been used for the
323
189
  # associated element.
324
190
  self._media_data = []
325
- self._registered_metadata = None
326
191
 
327
192
  for s in self._seen_dg_stack:
328
193
  s.add(returned_dg_id)
@@ -355,9 +220,6 @@ class CachedMessageReplayContext(threading.local):
355
220
  else:
356
221
  return invoked_id
357
222
 
358
- def save_widget_metadata(self, metadata: WidgetMetadata[Any]) -> None:
359
- self._registered_metadata = metadata
360
-
361
223
  def save_image_data(
362
224
  self, image_data: bytes | str, mimetype: str, image_id: str
363
225
  ) -> None:
@@ -384,24 +246,15 @@ def replay_cached_messages(
384
246
  call is on one of them.
385
247
  """
386
248
  from streamlit.delta_generator import DeltaGenerator
387
- from streamlit.runtime.state.widgets import register_widget_from_metadata
388
249
 
389
250
  # Maps originally recorded dg ids to this script run's version of that dg
390
- returned_dgs: dict[str, DeltaGenerator] = {}
391
- returned_dgs[result.main_id] = st._main
392
- returned_dgs[result.sidebar_id] = st.sidebar
393
- ctx = get_script_run_ctx()
394
-
251
+ returned_dgs: dict[str, DeltaGenerator] = {
252
+ result.main_id: st._main,
253
+ result.sidebar_id: st.sidebar,
254
+ }
395
255
  try:
396
256
  for msg in result.messages:
397
257
  if isinstance(msg, ElementMsgData):
398
- if msg.widget_metadata is not None:
399
- register_widget_from_metadata(
400
- msg.widget_metadata.metadata,
401
- ctx,
402
- None,
403
- msg.delta_type,
404
- )
405
258
  if msg.media_data is not None:
406
259
  for data in msg.media_data:
407
260
  runtime.get_instance().media_file_mgr.add(
@@ -415,31 +268,22 @@ def replay_cached_messages(
415
268
  dg = returned_dgs[msg.id_of_dg_called_on]
416
269
  new_dg = dg._block(msg.message)
417
270
  returned_dgs[msg.returned_dgs_id] = new_dg
418
- except KeyError:
419
- raise CacheReplayClosureError(cache_type, cached_func)
420
-
421
-
422
- def _make_widget_key(widgets: list[tuple[str, Any]], cache_type: CacheType) -> str:
423
- """Generate a key for the given list of widgets used in a cache-decorated function.
424
-
425
- Keys are generated by hashing the IDs and values of the widgets in the given list.
426
- """
427
- func_hasher = hashlib.new("md5", **HASHLIB_KWARGS)
428
- for widget_id_val in widgets:
429
- update_hash(widget_id_val, func_hasher, cache_type)
430
-
431
- return func_hasher.hexdigest()
271
+ except KeyError as ex:
272
+ raise CacheReplayClosureError(cache_type, cached_func) from ex
432
273
 
433
274
 
434
275
  def show_widget_replay_deprecation(
435
276
  decorator: Literal["cache_data", "cache_resource"],
436
277
  ) -> None:
437
278
  show_deprecation_warning(
438
- "The `experimental_allow_widgets` parameter is deprecated and will be removed "
279
+ "The cached widget replay feature was removed in 1.38. The "
280
+ "`experimental_allow_widgets` parameter will also be removed "
439
281
  "in a future release. Please remove the `experimental_allow_widgets` parameter "
440
282
  f"from the `@st.{decorator}` decorator and move all widget commands outside of "
441
- "cached functions.\n\nTo speed up your app, we recommend moving your widgets into fragments. "
442
- "Find out more about fragments in [our docs](https://docs.streamlit.io/develop/api-reference/execution-flow/st.fragment). "
443
- "\n\nIf you have a specific use-case that requires the `experimental_allow_widgets` functionality, "
444
- "please tell us via an [issue on Github](https://github.com/streamlit/streamlit/issues)."
283
+ "cached functions.\n\nTo speed up your app, we recommend moving your widgets "
284
+ "into fragments. Find out more about fragments in "
285
+ "[our docs](https://docs.streamlit.io/develop/api-reference/execution-flow/st.fragment). "
286
+ "\n\nIf you have a specific use-case that requires the "
287
+ "`experimental_allow_widgets` functionality, please tell us via an "
288
+ "[issue on Github](https://github.com/streamlit/streamlit/issues)."
445
289
  )