streamlit-nightly 1.37.2.dev20240819__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 (23) hide show
  1. streamlit/elements/image.py +15 -25
  2. streamlit/elements/lib/policies.py +10 -9
  3. streamlit/runtime/caching/__init__.py +1 -11
  4. streamlit/runtime/caching/cache_data_api.py +11 -83
  5. streamlit/runtime/caching/cache_errors.py +13 -9
  6. streamlit/runtime/caching/cache_resource_api.py +9 -58
  7. streamlit/runtime/caching/cache_utils.py +7 -12
  8. streamlit/runtime/caching/cached_message_replay.py +29 -185
  9. streamlit/runtime/caching/legacy_cache_api.py +15 -11
  10. streamlit/runtime/scriptrunner_utils/script_run_context.py +9 -4
  11. streamlit/runtime/state/widgets.py +0 -5
  12. streamlit/static/asset-manifest.json +3 -3
  13. streamlit/static/index.html +1 -1
  14. streamlit/static/static/js/1307.74bce9ab.chunk.js +1 -0
  15. streamlit/static/static/js/{main.8c6fc86e.js → main.ff81c7a3.js} +2 -2
  16. {streamlit_nightly-1.37.2.dev20240819.dist-info → streamlit_nightly-1.37.2.dev20240820.dist-info}/METADATA +1 -1
  17. {streamlit_nightly-1.37.2.dev20240819.dist-info → streamlit_nightly-1.37.2.dev20240820.dist-info}/RECORD +22 -22
  18. {streamlit_nightly-1.37.2.dev20240819.dist-info → streamlit_nightly-1.37.2.dev20240820.dist-info}/WHEEL +1 -1
  19. streamlit/static/static/js/1307.74a443f7.chunk.js +0 -1
  20. /streamlit/static/static/js/{main.8c6fc86e.js.LICENSE.txt → main.ff81c7a3.js.LICENSE.txt} +0 -0
  21. {streamlit_nightly-1.37.2.dev20240819.data → streamlit_nightly-1.37.2.dev20240820.data}/scripts/streamlit.cmd +0 -0
  22. {streamlit_nightly-1.37.2.dev20240819.dist-info → streamlit_nightly-1.37.2.dev20240820.dist-info}/entry_points.txt +0 -0
  23. {streamlit_nightly-1.37.2.dev20240819.dist-info → streamlit_nightly-1.37.2.dev20240820.dist-info}/top_level.txt +0 -0
@@ -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
  )
@@ -67,11 +67,11 @@ def cache(
67
67
  This is not used.
68
68
 
69
69
  hash_funcs : dict or None
70
- Mapping of types or fully qualified names to hash functions. This is used to override
71
- the behavior of the hasher inside Streamlit's caching mechanism: when the hasher
72
- encounters an object, it will first check to see if its type matches a key in this
73
- dict and, if so, will use the provided function to generate a hash for it. See below
74
- for an example of how this can be used.
70
+ Mapping of types or fully qualified names to hash functions. This is used to
71
+ override the behavior of the hasher inside Streamlit's caching mechanism: when
72
+ the hasher encounters an object, it will first check to see if its type matches
73
+ a key in this dict and, if so, will use the provided function to generate a hash
74
+ for it. See below for an example of how this can be used.
75
75
 
76
76
  max_entries : int or None
77
77
  The maximum number of entries to keep in the cache, or ``None``
@@ -109,7 +109,8 @@ def cache(
109
109
  ... # Fetch data from URL here, and then clean it up.
110
110
  ... return data
111
111
 
112
- To disable hashing return values, set the ``allow_output_mutation`` parameter to ``True``:
112
+ To disable hashing return values, set the ``allow_output_mutation`` parameter to
113
+ ``True``:
113
114
 
114
115
  >>> @st.cache(allow_output_mutation=True)
115
116
  ... def fetch_and_clean_data(url):
@@ -118,7 +119,8 @@ def cache(
118
119
 
119
120
 
120
121
  To override the default hashing behavior, pass a custom hash function.
121
- You can do that by mapping a type (e.g. ``MongoClient``) to a hash function (``id``) like this:
122
+ You can do that by mapping a type (e.g. ``MongoClient``) to a hash function (``id``)
123
+ like this:
122
124
 
123
125
  >>> @st.cache(hash_funcs={MongoClient: id})
124
126
  ... def connect_to_database(url):
@@ -136,11 +138,13 @@ def cache(
136
138
 
137
139
  deprecation_util.show_deprecation_warning(
138
140
  f"""
139
- `st.cache` is deprecated and will be removed soon. Please use one of Streamlit's new caching commands, `st.cache_data` or `st.cache_resource`.
140
- More information [in our docs]({CACHE_DOCS_URL}).
141
+ `st.cache` is deprecated and will be removed soon. Please use one of Streamlit's new
142
+ caching commands, `st.cache_data` or `st.cache_resource`. More information
143
+ [in our docs]({CACHE_DOCS_URL}).
141
144
 
142
- **Note**: The behavior of `st.cache` was updated in Streamlit 1.36 to the new caching logic used by `st.cache_data` and `st.cache_resource`.
143
- This might lead to some problems or unexpected behavior in certain edge cases.
145
+ **Note**: The behavior of `st.cache` was updated in Streamlit 1.36 to the new caching
146
+ logic used by `st.cache_data` and `st.cache_resource`. This might lead to some problems
147
+ or unexpected behavior in certain edge cases.
144
148
  """
145
149
  )
146
150
 
@@ -15,6 +15,7 @@
15
15
  from __future__ import annotations
16
16
 
17
17
  import collections
18
+ import contextvars
18
19
  import threading
19
20
  from dataclasses import dataclass, field
20
21
  from typing import TYPE_CHECKING, Callable, Counter, Dict, Final, Union
@@ -39,6 +40,13 @@ _LOGGER: Final = get_logger(__name__)
39
40
  UserInfo: TypeAlias = Dict[str, Union[str, None]]
40
41
 
41
42
 
43
+ # If true, it indicates that we are in a cached function that disallows the usage of
44
+ # widgets. Using contextvars to be thread-safe.
45
+ in_cached_function: contextvars.ContextVar[bool] = contextvars.ContextVar(
46
+ "in_cached_function", default=False
47
+ )
48
+
49
+
42
50
  @dataclass
43
51
  class ScriptRunContext:
44
52
  """A context object that contains data for a "script run" - that is,
@@ -80,9 +88,6 @@ class ScriptRunContext:
80
88
  new_fragment_ids: set[str] = field(default_factory=set)
81
89
  # we allow only one dialog to be open at the same time
82
90
  has_dialog_opened: bool = False
83
- # If true, it indicates that we are in a cached function that disallows
84
- # the usage of widgets.
85
- disallow_cached_widget_usage: bool = False
86
91
 
87
92
  # TODO(willhuang1997): Remove this variable when experimental query params are removed
88
93
  _experimental_query_params_used = False
@@ -119,7 +124,7 @@ class ScriptRunContext:
119
124
  self.fragment_ids_this_run = fragment_ids_this_run
120
125
  self.new_fragment_ids = set()
121
126
  self.has_dialog_opened = False
122
- self.disallow_cached_widget_usage = False
127
+ in_cached_function.set(False)
123
128
 
124
129
  parsed_query_params = parse.parse_qs(query_string, keep_blank_values=True)
125
130
  with self.session_state.query_params() as qp:
@@ -181,9 +181,6 @@ def register_widget_from_metadata(
181
181
 
182
182
  See `register_widget` for details on what this returns.
183
183
  """
184
- # Local import to avoid import cycle
185
- import streamlit.runtime.caching as caching
186
-
187
184
  if ctx is None:
188
185
  # Early-out if we don't have a script run context (which probably means
189
186
  # we're running as a "bare" Python script, and not via `streamlit run`).
@@ -215,8 +212,6 @@ def register_widget_from_metadata(
215
212
  user_key,
216
213
  )
217
214
  )
218
- # Save the widget metadata for cached result replay
219
- caching.save_widget_metadata(metadata)
220
215
  return ctx.session_state.register_widget(metadata, user_key)
221
216
 
222
217
 
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "files": {
3
3
  "main.css": "./static/css/main.5513bd04.css",
4
- "main.js": "./static/js/main.8c6fc86e.js",
4
+ "main.js": "./static/js/main.ff81c7a3.js",
5
5
  "static/js/9336.3e046ad7.chunk.js": "./static/js/9336.3e046ad7.chunk.js",
6
6
  "static/js/9330.32e8a53a.chunk.js": "./static/js/9330.32e8a53a.chunk.js",
7
7
  "static/js/2736.3d50ec7f.chunk.js": "./static/js/2736.3d50ec7f.chunk.js",
@@ -15,7 +15,7 @@
15
15
  "static/js/8536.b7b2ef90.chunk.js": "./static/js/8536.b7b2ef90.chunk.js",
16
16
  "static/js/7805.ba32ae70.chunk.js": "./static/js/7805.ba32ae70.chunk.js",
17
17
  "static/js/4500.d884c792.chunk.js": "./static/js/4500.d884c792.chunk.js",
18
- "static/js/1307.74a443f7.chunk.js": "./static/js/1307.74a443f7.chunk.js",
18
+ "static/js/1307.74bce9ab.chunk.js": "./static/js/1307.74bce9ab.chunk.js",
19
19
  "static/js/2469.6217c5c3.chunk.js": "./static/js/2469.6217c5c3.chunk.js",
20
20
  "static/js/4113.786b0142.chunk.js": "./static/js/4113.786b0142.chunk.js",
21
21
  "static/js/1168.2a9806f0.chunk.js": "./static/js/1168.2a9806f0.chunk.js",
@@ -153,6 +153,6 @@
153
153
  },
154
154
  "entrypoints": [
155
155
  "static/css/main.5513bd04.css",
156
- "static/js/main.8c6fc86e.js"
156
+ "static/js/main.ff81c7a3.js"
157
157
  ]
158
158
  }
@@ -1 +1 @@
1
- <!doctype html><html lang="en"><head><meta charset="UTF-8"/><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"/><link rel="shortcut icon" href="./favicon.png"/><link rel="preload" href="./static/media/SourceSansPro-Regular.0d69e5ff5e92ac64a0c9.woff2" as="font" type="font/woff2" crossorigin><link rel="preload" href="./static/media/SourceSansPro-SemiBold.abed79cd0df1827e18cf.woff2" as="font" type="font/woff2" crossorigin><link rel="preload" href="./static/media/SourceSansPro-Bold.118dea98980e20a81ced.woff2" as="font" type="font/woff2" crossorigin><title>Streamlit</title><script>window.prerenderReady=!1</script><script defer="defer" src="./static/js/main.8c6fc86e.js"></script><link href="./static/css/main.5513bd04.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
1
+ <!doctype html><html lang="en"><head><meta charset="UTF-8"/><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"/><link rel="shortcut icon" href="./favicon.png"/><link rel="preload" href="./static/media/SourceSansPro-Regular.0d69e5ff5e92ac64a0c9.woff2" as="font" type="font/woff2" crossorigin><link rel="preload" href="./static/media/SourceSansPro-SemiBold.abed79cd0df1827e18cf.woff2" as="font" type="font/woff2" crossorigin><link rel="preload" href="./static/media/SourceSansPro-Bold.118dea98980e20a81ced.woff2" as="font" type="font/woff2" crossorigin><title>Streamlit</title><script>window.prerenderReady=!1</script><script defer="defer" src="./static/js/main.ff81c7a3.js"></script><link href="./static/css/main.5513bd04.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
@@ -0,0 +1 @@
1
+ "use strict";(self.webpackChunk_streamlit_app=self.webpackChunk_streamlit_app||[]).push([[1307],{51307:(e,t,n)=>{n.r(t),n.d(t,{default:()=>c});n(66845);var i=n(23593),o=n(1515);const s=(0,o.Z)("div",{target:"e115fcil2"})((e=>{let{theme:t}=e;return{display:"flex",flexDirection:"row",flexWrap:"wrap",rowGap:t.spacing.lg}}),""),r=(0,o.Z)("div",{target:"e115fcil1"})((()=>({display:"flex",flexDirection:"column",alignItems:"stretch",width:"auto",flexGrow:0})),""),l=(0,o.Z)("div",{target:"e115fcil0"})((e=>{let{theme:t}=e;return{fontFamily:t.genericFonts.bodyFont,fontSize:t.fontSizes.sm,color:t.colors.fadedText60,textAlign:"center",marginTop:t.spacing.xs,wordWrap:"break-word",padding:t.spacing.threeXS}}),"");var d,a=n(40864);!function(e){e[e.OriginalWidth=-1]="OriginalWidth",e[e.ColumnWidth=-2]="ColumnWidth",e[e.AutoWidth=-3]="AutoWidth"}(d||(d={}));const c=(0,i.Z)((function(e){let t,{width:n,isFullScreen:i,element:o,height:c,endpoints:h}=e;const m=o.width;if(m===d.OriginalWidth||m===d.AutoWidth)t=void 0;else if(m===d.ColumnWidth)t=n;else{if(!(m>0))throw Error(`Invalid image width: ${m}`);t=m}const u={};return c&&i?(u.maxHeight=c,u.objectFit="contain"):(u.width=t,m===d.AutoWidth&&(u.maxWidth="100%")),(0,a.jsx)(s,{className:"stImage","data-testid":"stImage",style:{width:n},children:o.imgs.map(((e,t)=>{const n=e;return(0,a.jsxs)(r,{"data-testid":"stImageContainer",children:[(0,a.jsx)("img",{style:u,src:h.buildMediaURL(n.url),alt:t.toString()}),n.caption&&(0,a.jsx)(l,{"data-testid":"stImageCaption",style:u,children:` ${n.caption} `})]},t)}))})}))},23593:(e,t,n)=>{n.d(t,{Z:()=>x});var i=n(66845),o=n(13005),s=n.n(o),r=n(25621),l=n(82218),d=n(97781),a=n(46927),c=n(66694),h=n(1515);const m=(0,h.Z)("button",{target:"e1vs0wn31"})((e=>{let{isExpanded:t,theme:n}=e;const i=t?{right:"0.4rem",top:"0.5rem",backgroundColor:"transparent"}:{right:"-3.0rem",top:"-0.375rem",opacity:0,transform:"scale(0)",backgroundColor:n.colors.lightenedBg05};return{position:"absolute",display:"flex",alignItems:"center",justifyContent:"center",zIndex:n.zIndices.sidebar+1,height:"2.5rem",width:"2.5rem",transition:"opacity 300ms 150ms, transform 300ms 150ms",border:"none",color:n.colors.fadedText60,borderRadius:"50%",...i,"&:focus":{outline:"none"},"&:active, &:focus-visible, &:hover":{opacity:1,outline:"none",transform:"scale(1)",color:n.colors.bodyText,transition:"none"}}}),""),u=(0,h.Z)("div",{target:"e1vs0wn30"})((e=>{let{theme:t,isExpanded:n}=e;return{"&:hover":{[m]:{opacity:1,transform:"scale(1)",transition:"none"}},...n?{position:"fixed",top:0,left:0,bottom:0,right:0,background:t.colors.bgColor,zIndex:t.zIndices.fullscreenWrapper,padding:t.spacing.md,paddingTop:"2.875rem",overflow:["auto","overlay"],display:"flex",alignItems:"center",justifyContent:"center"}:{}}}),"");var p=n(40864);class g extends i.PureComponent{constructor(e){super(e),this.context=void 0,this.controlKeys=e=>{const{expanded:t}=this.state;27===e.keyCode&&t&&this.zoomOut()},this.zoomIn=()=>{document.body.style.overflow="hidden",this.context.setFullScreen(!0),this.setState({expanded:!0})},this.zoomOut=()=>{document.body.style.overflow="unset",this.context.setFullScreen(!1),this.setState({expanded:!1})},this.convertScssRemValueToPixels=e=>parseFloat(e)*parseFloat(getComputedStyle(document.documentElement).fontSize),this.getWindowDimensions=()=>{const e=this.convertScssRemValueToPixels(this.props.theme.spacing.md),t=this.convertScssRemValueToPixels("2.875rem");return{fullWidth:window.innerWidth-2*e,fullHeight:window.innerHeight-(e+t)}},this.updateWindowDimensions=()=>{this.setState(this.getWindowDimensions())},this.state={expanded:!1,...this.getWindowDimensions()}}componentDidMount(){window.addEventListener("resize",this.updateWindowDimensions),document.addEventListener("keydown",this.controlKeys,!1)}componentWillUnmount(){window.removeEventListener("resize",this.updateWindowDimensions),document.removeEventListener("keydown",this.controlKeys,!1)}render(){const{expanded:e,fullWidth:t,fullHeight:n}=this.state,{children:i,width:o,height:s,disableFullscreenMode:r}=this.props;let c=l.d,h=this.zoomIn,g="View fullscreen";return e&&(c=d.m,h=this.zoomOut,g="Exit fullscreen"),(0,p.jsxs)(u,{isExpanded:e,"data-testid":"stFullScreenFrame",children:[!r&&(0,p.jsx)(m,{"data-testid":"StyledFullScreenButton",onClick:h,title:g,isExpanded:e,children:(0,p.jsx)(a.Z,{content:c})}),i(e?{width:t,height:n,expanded:e,expand:this.zoomIn,collapse:this.zoomOut}:{width:o,height:s,expanded:e,expand:this.zoomIn,collapse:this.zoomOut})]})}}g.contextType=c.E;const w=(0,r.b)(g);const x=function(e){let t=arguments.length>1&&void 0!==arguments[1]&&arguments[1];class n extends i.PureComponent{constructor(){super(...arguments),this.render=()=>{const{width:n,height:i,disableFullscreenMode:o}=this.props;return(0,p.jsx)(w,{width:n,height:i,disableFullscreenMode:t||o,children:t=>{let{width:n,height:i,expanded:o,expand:s,collapse:r}=t;return(0,p.jsx)(e,{...this.props,width:n,height:i,isFullScreen:o,expand:s,collapse:r})}})}}}return n.displayName=`withFullScreenWrapper(${e.displayName||e.name})`,s()(n,e)}},82218:(e,t,n)=>{n.d(t,{d:()=>r});var i=n(25773),o=n(66845),s=n(69),r=o.forwardRef((function(e,t){return o.createElement(s.D,(0,i.Z)({iconAttrs:{fill:"currentColor",xmlns:"http://www.w3.org/2000/svg"},iconVerticalAlign:"middle",iconViewBox:"0 0 8 8"},e,{ref:t}),o.createElement("path",{d:"M0 0v4l1.5-1.5L3 4l1-1-1.5-1.5L4 0H0zm5 4L4 5l1.5 1.5L4 8h4V4L6.5 5.5 5 4z"}))}));r.displayName="FullscreenEnter"},97781:(e,t,n)=>{n.d(t,{m:()=>r});var i=n(25773),o=n(66845),s=n(69),r=o.forwardRef((function(e,t){return o.createElement(s.D,(0,i.Z)({iconAttrs:{fill:"currentColor",xmlns:"http://www.w3.org/2000/svg"},iconVerticalAlign:"middle",iconViewBox:"0 0 8 8"},e,{ref:t}),o.createElement("path",{d:"M1 0L0 1l1.5 1.5L0 4h4V0L2.5 1.5 1 0zm3 4v4l1.5-1.5L7 8l1-1-1.5-1.5L8 4H4z"}))}));r.displayName="FullscreenExit"}}]);