streamlit-nightly 1.35.1.dev20240523__py2.py3-none-any.whl → 1.35.1.dev20240525__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- streamlit/__init__.py +4 -5
- streamlit/config.py +1 -15
- streamlit/elements/dialog_decorator.py +5 -3
- streamlit/elements/utils.py +3 -6
- streamlit/runtime/app_session.py +1 -2
- streamlit/runtime/caching/__init__.py +5 -0
- streamlit/runtime/caching/legacy_cache_api.py +164 -0
- streamlit/runtime/fragment.py +91 -80
- streamlit/runtime/runtime.py +0 -2
- streamlit/static/asset-manifest.json +2 -2
- streamlit/static/index.html +1 -1
- streamlit/static/static/js/{main.7e42f54d.js → main.e93f99a3.js} +2 -2
- streamlit/web/cli.py +1 -8
- {streamlit_nightly-1.35.1.dev20240523.dist-info → streamlit_nightly-1.35.1.dev20240525.dist-info}/METADATA +1 -1
- {streamlit_nightly-1.35.1.dev20240523.dist-info → streamlit_nightly-1.35.1.dev20240525.dist-info}/RECORD +20 -22
- streamlit/runtime/legacy_caching/__init__.py +0 -17
- streamlit/runtime/legacy_caching/caching.py +0 -810
- streamlit/runtime/legacy_caching/hashing.py +0 -1005
- /streamlit/static/static/js/{main.7e42f54d.js.LICENSE.txt → main.e93f99a3.js.LICENSE.txt} +0 -0
- {streamlit_nightly-1.35.1.dev20240523.data → streamlit_nightly-1.35.1.dev20240525.data}/scripts/streamlit.cmd +0 -0
- {streamlit_nightly-1.35.1.dev20240523.dist-info → streamlit_nightly-1.35.1.dev20240525.dist-info}/WHEEL +0 -0
- {streamlit_nightly-1.35.1.dev20240523.dist-info → streamlit_nightly-1.35.1.dev20240525.dist-info}/entry_points.txt +0 -0
- {streamlit_nightly-1.35.1.dev20240523.dist-info → streamlit_nightly-1.35.1.dev20240525.dist-info}/top_level.txt +0 -0
streamlit/__init__.py
CHANGED
@@ -77,6 +77,7 @@ from streamlit.elements.dialog_decorator import dialog_decorator as _dialog_deco
|
|
77
77
|
from streamlit.runtime.caching import (
|
78
78
|
cache_resource as _cache_resource,
|
79
79
|
cache_data as _cache_data,
|
80
|
+
cache as _cache,
|
80
81
|
experimental_singleton as _experimental_singleton,
|
81
82
|
experimental_memo as _experimental_memo,
|
82
83
|
)
|
@@ -104,7 +105,6 @@ import streamlit.column_config as _column_config
|
|
104
105
|
# You can check the export behavior by running 'mypy --strict example_app.py', which disables implicit_reexport, where you use the respective command in the example_app.py Streamlit app.
|
105
106
|
|
106
107
|
from streamlit.echo import echo as echo
|
107
|
-
from streamlit.runtime.legacy_caching import cache as _cache
|
108
108
|
from streamlit.commands.logo import logo as logo
|
109
109
|
from streamlit.elements.spinner import spinner as spinner
|
110
110
|
|
@@ -116,10 +116,6 @@ from streamlit.commands.execution_control import (
|
|
116
116
|
switch_page as switch_page,
|
117
117
|
)
|
118
118
|
|
119
|
-
# We add the metrics tracking for caching here,
|
120
|
-
# since the actual cache function calls itself recursively
|
121
|
-
cache = _gather_metrics("cache", _cache)
|
122
|
-
|
123
119
|
|
124
120
|
def _update_logger() -> None:
|
125
121
|
_logger.set_log_level(_config.get_option("logger.level").upper())
|
@@ -230,6 +226,8 @@ query_params = _QueryParamsProxy()
|
|
230
226
|
# Caching
|
231
227
|
cache_data = _cache_data
|
232
228
|
cache_resource = _cache_resource
|
229
|
+
# `st.cache` is deprecated and should be removed soon
|
230
|
+
cache = _cache
|
233
231
|
|
234
232
|
# Namespaces
|
235
233
|
column_config = _column_config
|
@@ -244,6 +242,7 @@ experimental_memo = _experimental_memo
|
|
244
242
|
experimental_singleton = _experimental_singleton
|
245
243
|
experimental_user = _UserInfoProxy()
|
246
244
|
|
245
|
+
|
247
246
|
_EXPERIMENTAL_QUERY_PARAMS_DEPRECATE_MSG = "Refer to our [docs page](https://docs.streamlit.io/library/api-reference/utilities/st.query_params) for more information."
|
248
247
|
|
249
248
|
experimental_get_query_params = _deprecate_func_name(
|
streamlit/config.py
CHANGED
@@ -473,19 +473,6 @@ _create_option(
|
|
473
473
|
|
474
474
|
_create_section("client", "Settings for scripts that use Streamlit.")
|
475
475
|
|
476
|
-
_create_option(
|
477
|
-
"client.caching",
|
478
|
-
description="""
|
479
|
-
Whether to enable st.cache. This does not affect st.cache_data or
|
480
|
-
st.cache_resource.""",
|
481
|
-
default_val=True,
|
482
|
-
type_=bool,
|
483
|
-
scriptable=True,
|
484
|
-
deprecated=True,
|
485
|
-
deprecation_text="client.caching has been deprecated and is not required anymore for our new caching commands.",
|
486
|
-
expiration_date="2024-01-20",
|
487
|
-
)
|
488
|
-
|
489
476
|
_create_option(
|
490
477
|
"client.displayEnabled",
|
491
478
|
description="""If false, makes your Streamlit script not draw to a
|
@@ -647,8 +634,7 @@ _create_section("server", "Settings for the Streamlit server")
|
|
647
634
|
|
648
635
|
_create_option(
|
649
636
|
"server.folderWatchBlacklist",
|
650
|
-
description="""List of folders that should not be watched for changes.
|
651
|
-
impacts both "Run on Save" and @st.cache.
|
637
|
+
description="""List of folders that should not be watched for changes.
|
652
638
|
|
653
639
|
Relative paths will be taken as relative to the current working directory.
|
654
640
|
|
@@ -20,7 +20,7 @@ from typing import Callable, TypeVar, cast, overload
|
|
20
20
|
from streamlit.delta_generator import event_dg, get_last_dg_added_to_context_stack
|
21
21
|
from streamlit.elements.lib.dialog import DialogWidth
|
22
22
|
from streamlit.errors import StreamlitAPIException
|
23
|
-
from streamlit.runtime.fragment import
|
23
|
+
from streamlit.runtime.fragment import _fragment
|
24
24
|
from streamlit.runtime.metrics_util import gather_metrics
|
25
25
|
|
26
26
|
|
@@ -64,14 +64,16 @@ def _dialog_decorator(
|
|
64
64
|
dialog = event_dg._dialog(title=title, dismissible=True, width=width)
|
65
65
|
dialog.open()
|
66
66
|
|
67
|
-
@_fragment
|
68
67
|
def dialog_content() -> None:
|
69
68
|
# if the dialog should be closed, st.rerun() has to be called (same behavior as with st.fragment)
|
70
69
|
_ = non_optional_func(*args, **kwargs)
|
71
70
|
return None
|
72
71
|
|
72
|
+
# the fragment decorator has multiple return types so that you can pass arguments to it. Here we know the return type, so we cast
|
73
|
+
fragmented_dialog_content = cast(Callable[[], None], _fragment(dialog_content))
|
73
74
|
with dialog:
|
74
|
-
|
75
|
+
fragmented_dialog_content()
|
76
|
+
return None
|
75
77
|
|
76
78
|
return cast(F, wrap)
|
77
79
|
|
streamlit/elements/utils.py
CHANGED
@@ -40,11 +40,6 @@ def check_callback_rules(dg: DeltaGenerator, on_change: WidgetCallback | None) -
|
|
40
40
|
|
41
41
|
_shown_default_value_warning: bool = False
|
42
42
|
|
43
|
-
SESSION_STATE_WRITES_NOT_ALLOWED_ERROR_TEXT = """
|
44
|
-
Values for st.button, st.download_button, st.file_uploader, st.data_editor,
|
45
|
-
st.chat_input, and st.form cannot be set using st.session_state.
|
46
|
-
"""
|
47
|
-
|
48
43
|
|
49
44
|
def check_session_state_rules(
|
50
45
|
default_value: Any, key: str | None, writes_allowed: bool = True
|
@@ -59,7 +54,9 @@ def check_session_state_rules(
|
|
59
54
|
return
|
60
55
|
|
61
56
|
if not writes_allowed:
|
62
|
-
raise StreamlitAPIException(
|
57
|
+
raise StreamlitAPIException(
|
58
|
+
f'Values for the widget with key "{key}" cannot be set using `st.session_state`.'
|
59
|
+
)
|
63
60
|
|
64
61
|
if (
|
65
62
|
default_value is not None
|
streamlit/runtime/app_session.py
CHANGED
@@ -36,7 +36,7 @@ from streamlit.proto.NewSession_pb2 import (
|
|
36
36
|
UserInfo,
|
37
37
|
)
|
38
38
|
from streamlit.proto.PagesChanged_pb2 import PagesChanged
|
39
|
-
from streamlit.runtime import caching
|
39
|
+
from streamlit.runtime import caching
|
40
40
|
from streamlit.runtime.forward_msg_queue import ForwardMsgQueue
|
41
41
|
from streamlit.runtime.fragment import FragmentStorage, MemoryFragmentStorage
|
42
42
|
from streamlit.runtime.metrics_util import Installation
|
@@ -780,7 +780,6 @@ class AppSession:
|
|
780
780
|
Because this cache is global, it will be cleared for all users.
|
781
781
|
|
782
782
|
"""
|
783
|
-
legacy_caching.clear_cache()
|
784
783
|
caching.cache_data.clear()
|
785
784
|
caching.cache_resource.clear()
|
786
785
|
self._session_state.clear()
|
@@ -30,6 +30,7 @@ from streamlit.runtime.caching.cache_resource_api import (
|
|
30
30
|
CacheResourceAPI,
|
31
31
|
_resource_caches,
|
32
32
|
)
|
33
|
+
from streamlit.runtime.caching.legacy_cache_api import cache as _cache
|
33
34
|
from streamlit.runtime.state.common import WidgetMetadata
|
34
35
|
|
35
36
|
|
@@ -92,6 +93,9 @@ from streamlit.runtime.caching.cache_resource_api import (
|
|
92
93
|
# Create and export public API singletons.
|
93
94
|
cache_data = CacheDataAPI(decorator_metric_name="cache_data")
|
94
95
|
cache_resource = CacheResourceAPI(decorator_metric_name="cache_resource")
|
96
|
+
# TODO(lukasmasuch): This is the legacy cache API name which is deprecated
|
97
|
+
# and it should be removed in the future.
|
98
|
+
cache = _cache
|
95
99
|
|
96
100
|
# Deprecated singletons
|
97
101
|
_MEMO_WARNING = (
|
@@ -115,6 +119,7 @@ experimental_singleton = CacheResourceAPI(
|
|
115
119
|
|
116
120
|
|
117
121
|
__all__ = [
|
122
|
+
"cache",
|
118
123
|
"CACHE_DOCS_URL",
|
119
124
|
"save_element_message",
|
120
125
|
"save_block_message",
|
@@ -0,0 +1,164 @@
|
|
1
|
+
# Copyright (c) Streamlit Inc. (2018-2022) Snowflake Inc. (2022-2024)
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
"""A library of caching utilities."""
|
16
|
+
|
17
|
+
from __future__ import annotations
|
18
|
+
|
19
|
+
from typing import TYPE_CHECKING, Any, Callable, TypeVar
|
20
|
+
|
21
|
+
from streamlit import deprecation_util
|
22
|
+
from streamlit.runtime.caching import CACHE_DOCS_URL
|
23
|
+
from streamlit.runtime.metrics_util import gather_metrics
|
24
|
+
|
25
|
+
if TYPE_CHECKING:
|
26
|
+
from streamlit.runtime.caching.hashing import HashFuncsDict
|
27
|
+
|
28
|
+
# Type-annotate the decorator function.
|
29
|
+
# (See https://mypy.readthedocs.io/en/stable/generics.html#decorator-factories)
|
30
|
+
F = TypeVar("F", bound=Callable[..., Any])
|
31
|
+
|
32
|
+
|
33
|
+
@gather_metrics("cache")
|
34
|
+
def cache(
|
35
|
+
func: F | None = None,
|
36
|
+
persist: bool = False,
|
37
|
+
allow_output_mutation: bool = False,
|
38
|
+
show_spinner: bool = True,
|
39
|
+
suppress_st_warning: bool = False,
|
40
|
+
hash_funcs: HashFuncsDict | None = None,
|
41
|
+
max_entries: int | None = None,
|
42
|
+
ttl: float | None = None,
|
43
|
+
):
|
44
|
+
"""Function decorator to memoize function executions.
|
45
|
+
|
46
|
+
Parameters
|
47
|
+
----------
|
48
|
+
func : callable
|
49
|
+
The function to cache. Streamlit hashes the function and dependent code.
|
50
|
+
|
51
|
+
persist : bool
|
52
|
+
Whether to persist the cache on disk.
|
53
|
+
|
54
|
+
allow_output_mutation : bool
|
55
|
+
Streamlit shows a warning when return values are mutated, as that
|
56
|
+
can have unintended consequences. This is done by hashing the return value internally.
|
57
|
+
|
58
|
+
If you know what you're doing and would like to override this warning, set this to True.
|
59
|
+
|
60
|
+
show_spinner : bool
|
61
|
+
Enable the spinner. Default is True to show a spinner when there is
|
62
|
+
a cache miss.
|
63
|
+
|
64
|
+
suppress_st_warning : bool
|
65
|
+
Suppress warnings about calling Streamlit commands from within
|
66
|
+
the cached function.
|
67
|
+
|
68
|
+
hash_funcs : dict or None
|
69
|
+
Mapping of types or fully qualified names to hash functions. This is used to override
|
70
|
+
the behavior of the hasher inside Streamlit's caching mechanism: when the hasher
|
71
|
+
encounters an object, it will first check to see if its type matches a key in this
|
72
|
+
dict and, if so, will use the provided function to generate a hash for it. See below
|
73
|
+
for an example of how this can be used.
|
74
|
+
|
75
|
+
max_entries : int or None
|
76
|
+
The maximum number of entries to keep in the cache, or None
|
77
|
+
for an unbounded cache. (When a new entry is added to a full cache,
|
78
|
+
the oldest cached entry will be removed.) The default is None.
|
79
|
+
|
80
|
+
ttl : float or None
|
81
|
+
The maximum number of seconds to keep an entry in the cache, or
|
82
|
+
None if cache entries should not expire. The default is None.
|
83
|
+
|
84
|
+
Example
|
85
|
+
-------
|
86
|
+
>>> import streamlit as st
|
87
|
+
>>>
|
88
|
+
>>> @st.cache
|
89
|
+
... def fetch_and_clean_data(url):
|
90
|
+
... # Fetch data from URL here, and then clean it up.
|
91
|
+
... return data
|
92
|
+
...
|
93
|
+
>>> d1 = fetch_and_clean_data(DATA_URL_1)
|
94
|
+
>>> # Actually executes the function, since this is the first time it was
|
95
|
+
>>> # encountered.
|
96
|
+
>>>
|
97
|
+
>>> d2 = fetch_and_clean_data(DATA_URL_1)
|
98
|
+
>>> # Does not execute the function. Instead, returns its previously computed
|
99
|
+
>>> # value. This means that now the data in d1 is the same as in d2.
|
100
|
+
>>>
|
101
|
+
>>> d3 = fetch_and_clean_data(DATA_URL_2)
|
102
|
+
>>> # This is a different URL, so the function executes.
|
103
|
+
|
104
|
+
To set the ``persist`` parameter, use this command as follows:
|
105
|
+
|
106
|
+
>>> @st.cache(persist=True)
|
107
|
+
... def fetch_and_clean_data(url):
|
108
|
+
... # Fetch data from URL here, and then clean it up.
|
109
|
+
... return data
|
110
|
+
|
111
|
+
To disable hashing return values, set the ``allow_output_mutation`` parameter to ``True``:
|
112
|
+
|
113
|
+
>>> @st.cache(allow_output_mutation=True)
|
114
|
+
... def fetch_and_clean_data(url):
|
115
|
+
... # Fetch data from URL here, and then clean it up.
|
116
|
+
... return data
|
117
|
+
|
118
|
+
|
119
|
+
To override the default hashing behavior, pass a custom hash function.
|
120
|
+
You can do that by mapping a type (e.g. ``MongoClient``) to a hash function (``id``) like this:
|
121
|
+
|
122
|
+
>>> @st.cache(hash_funcs={MongoClient: id})
|
123
|
+
... def connect_to_database(url):
|
124
|
+
... return MongoClient(url)
|
125
|
+
|
126
|
+
Alternatively, you can map the type's fully-qualified name
|
127
|
+
(e.g. ``"pymongo.mongo_client.MongoClient"``) to the hash function instead:
|
128
|
+
|
129
|
+
>>> @st.cache(hash_funcs={"pymongo.mongo_client.MongoClient": id})
|
130
|
+
... def connect_to_database(url):
|
131
|
+
... return MongoClient(url)
|
132
|
+
|
133
|
+
"""
|
134
|
+
import streamlit as st
|
135
|
+
|
136
|
+
deprecation_util.show_deprecation_warning(
|
137
|
+
f"""
|
138
|
+
`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`.
|
139
|
+
More information [in our docs]({CACHE_DOCS_URL}).
|
140
|
+
|
141
|
+
**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`.
|
142
|
+
This might lead to some problems or unexpected behavior in certain edge cases.
|
143
|
+
"""
|
144
|
+
)
|
145
|
+
|
146
|
+
# suppress_st_warning is unused since its not supported by the new caching commands
|
147
|
+
|
148
|
+
if allow_output_mutation:
|
149
|
+
return st.cache_resource( # type: ignore
|
150
|
+
func,
|
151
|
+
show_spinner=show_spinner,
|
152
|
+
hash_funcs=hash_funcs,
|
153
|
+
max_entries=max_entries,
|
154
|
+
ttl=ttl,
|
155
|
+
)
|
156
|
+
|
157
|
+
return st.cache_data( # type: ignore
|
158
|
+
func,
|
159
|
+
persist=persist,
|
160
|
+
show_spinner=show_spinner,
|
161
|
+
hash_funcs=hash_funcs,
|
162
|
+
max_entries=max_entries,
|
163
|
+
ttl=ttl,
|
164
|
+
)
|
streamlit/runtime/fragment.py
CHANGED
@@ -93,6 +93,96 @@ class MemoryFragmentStorage(FragmentStorage):
|
|
93
93
|
self._fragments.clear()
|
94
94
|
|
95
95
|
|
96
|
+
def _fragment(
|
97
|
+
func: F | None = None, *, run_every: int | float | timedelta | str | None = None
|
98
|
+
) -> Callable[[F], F] | F:
|
99
|
+
"""Contains the actual fragment logic.
|
100
|
+
|
101
|
+
This function should be used by our internal functions that use fragments under-the-hood,
|
102
|
+
so that fragment metrics are not tracked for those elements (note that the @gather_metrics annotation is only on the publicly exposed function)
|
103
|
+
"""
|
104
|
+
|
105
|
+
if func is None:
|
106
|
+
# Support passing the params via function decorator
|
107
|
+
def wrapper(f: F) -> F:
|
108
|
+
return fragment(
|
109
|
+
func=f,
|
110
|
+
run_every=run_every,
|
111
|
+
)
|
112
|
+
|
113
|
+
return wrapper
|
114
|
+
else:
|
115
|
+
non_optional_func = func
|
116
|
+
|
117
|
+
@wraps(non_optional_func)
|
118
|
+
def wrap(*args, **kwargs):
|
119
|
+
from streamlit.delta_generator import dg_stack
|
120
|
+
|
121
|
+
ctx = get_script_run_ctx()
|
122
|
+
if ctx is None:
|
123
|
+
return
|
124
|
+
|
125
|
+
cursors_snapshot = deepcopy(ctx.cursors)
|
126
|
+
dg_stack_snapshot = deepcopy(dg_stack.get())
|
127
|
+
active_dg = dg_stack_snapshot[-1]
|
128
|
+
h = hashlib.new("md5")
|
129
|
+
h.update(
|
130
|
+
f"{non_optional_func.__module__}.{non_optional_func.__qualname__}{active_dg._get_delta_path_str()}".encode(
|
131
|
+
"utf-8"
|
132
|
+
)
|
133
|
+
)
|
134
|
+
fragment_id = h.hexdigest()
|
135
|
+
|
136
|
+
def wrapped_fragment():
|
137
|
+
import streamlit as st
|
138
|
+
|
139
|
+
# NOTE: We need to call get_script_run_ctx here again and can't just use the
|
140
|
+
# value of ctx from above captured by the closure because subsequent
|
141
|
+
# fragment runs will generally run in a new script run, thus we'll have a
|
142
|
+
# new ctx.
|
143
|
+
ctx = get_script_run_ctx(suppress_warning=True)
|
144
|
+
assert ctx is not None
|
145
|
+
|
146
|
+
if ctx.fragment_ids_this_run:
|
147
|
+
# This script run is a run of one or more fragments. We restore the
|
148
|
+
# state of ctx.cursors and dg_stack to the snapshots we took when this
|
149
|
+
# fragment was declared.
|
150
|
+
ctx.cursors = deepcopy(cursors_snapshot)
|
151
|
+
dg_stack.set(deepcopy(dg_stack_snapshot))
|
152
|
+
else:
|
153
|
+
# Otherwise, we must be in a full script run. We need to temporarily set
|
154
|
+
# ctx.current_fragment_id so that elements corresponding to this
|
155
|
+
# fragment get tagged with the appropriate ID. ctx.current_fragment_id
|
156
|
+
# gets reset after the fragment function finishes running.
|
157
|
+
ctx.current_fragment_id = fragment_id
|
158
|
+
|
159
|
+
try:
|
160
|
+
with st.container():
|
161
|
+
result = non_optional_func(*args, **kwargs)
|
162
|
+
finally:
|
163
|
+
ctx.current_fragment_id = None
|
164
|
+
|
165
|
+
return result
|
166
|
+
|
167
|
+
ctx.fragment_storage.set(fragment_id, wrapped_fragment)
|
168
|
+
|
169
|
+
if run_every:
|
170
|
+
msg = ForwardMsg()
|
171
|
+
msg.auto_rerun.interval = time_to_seconds(run_every)
|
172
|
+
msg.auto_rerun.fragment_id = fragment_id
|
173
|
+
ctx.enqueue(msg)
|
174
|
+
|
175
|
+
return wrapped_fragment()
|
176
|
+
|
177
|
+
with contextlib.suppress(AttributeError):
|
178
|
+
# Make this a well-behaved decorator by preserving important function
|
179
|
+
# attributes.
|
180
|
+
wrap.__dict__.update(non_optional_func.__dict__)
|
181
|
+
wrap.__signature__ = inspect.signature(non_optional_func) # type: ignore
|
182
|
+
|
183
|
+
return wrap
|
184
|
+
|
185
|
+
|
96
186
|
@overload
|
97
187
|
def fragment(
|
98
188
|
func: F,
|
@@ -228,83 +318,4 @@ def fragment(
|
|
228
318
|
height: 400px
|
229
319
|
|
230
320
|
"""
|
231
|
-
|
232
|
-
if func is None:
|
233
|
-
# Support passing the params via function decorator
|
234
|
-
def wrapper(f: F) -> F:
|
235
|
-
return fragment(
|
236
|
-
func=f,
|
237
|
-
run_every=run_every,
|
238
|
-
)
|
239
|
-
|
240
|
-
return wrapper
|
241
|
-
else:
|
242
|
-
non_optional_func = func
|
243
|
-
|
244
|
-
@wraps(non_optional_func)
|
245
|
-
def wrap(*args, **kwargs):
|
246
|
-
from streamlit.delta_generator import dg_stack
|
247
|
-
|
248
|
-
ctx = get_script_run_ctx()
|
249
|
-
if ctx is None:
|
250
|
-
return
|
251
|
-
|
252
|
-
cursors_snapshot = deepcopy(ctx.cursors)
|
253
|
-
dg_stack_snapshot = deepcopy(dg_stack.get())
|
254
|
-
active_dg = dg_stack_snapshot[-1]
|
255
|
-
h = hashlib.new("md5")
|
256
|
-
h.update(
|
257
|
-
f"{non_optional_func.__module__}.{non_optional_func.__qualname__}{active_dg._get_delta_path_str()}".encode(
|
258
|
-
"utf-8"
|
259
|
-
)
|
260
|
-
)
|
261
|
-
fragment_id = h.hexdigest()
|
262
|
-
|
263
|
-
def wrapped_fragment():
|
264
|
-
import streamlit as st
|
265
|
-
|
266
|
-
# NOTE: We need to call get_script_run_ctx here again and can't just use the
|
267
|
-
# value of ctx from above captured by the closure because subsequent
|
268
|
-
# fragment runs will generally run in a new script run, thus we'll have a
|
269
|
-
# new ctx.
|
270
|
-
ctx = get_script_run_ctx(suppress_warning=True)
|
271
|
-
assert ctx is not None
|
272
|
-
|
273
|
-
if ctx.fragment_ids_this_run:
|
274
|
-
# This script run is a run of one or more fragments. We restore the
|
275
|
-
# state of ctx.cursors and dg_stack to the snapshots we took when this
|
276
|
-
# fragment was declared.
|
277
|
-
ctx.cursors = deepcopy(cursors_snapshot)
|
278
|
-
dg_stack.set(deepcopy(dg_stack_snapshot))
|
279
|
-
else:
|
280
|
-
# Otherwise, we must be in a full script run. We need to temporarily set
|
281
|
-
# ctx.current_fragment_id so that elements corresponding to this
|
282
|
-
# fragment get tagged with the appropriate ID. ctx.current_fragment_id
|
283
|
-
# gets reset after the fragment function finishes running.
|
284
|
-
ctx.current_fragment_id = fragment_id
|
285
|
-
|
286
|
-
try:
|
287
|
-
with st.container():
|
288
|
-
result = non_optional_func(*args, **kwargs)
|
289
|
-
finally:
|
290
|
-
ctx.current_fragment_id = None
|
291
|
-
|
292
|
-
return result
|
293
|
-
|
294
|
-
ctx.fragment_storage.set(fragment_id, wrapped_fragment)
|
295
|
-
|
296
|
-
if run_every:
|
297
|
-
msg = ForwardMsg()
|
298
|
-
msg.auto_rerun.interval = time_to_seconds(run_every)
|
299
|
-
msg.auto_rerun.fragment_id = fragment_id
|
300
|
-
ctx.enqueue(msg)
|
301
|
-
|
302
|
-
return wrapped_fragment()
|
303
|
-
|
304
|
-
with contextlib.suppress(AttributeError):
|
305
|
-
# Make this a well-behaved decorator by preserving important function
|
306
|
-
# attributes.
|
307
|
-
wrap.__dict__.update(non_optional_func.__dict__)
|
308
|
-
wrap.__signature__ = inspect.signature(non_optional_func) # type: ignore
|
309
|
-
|
310
|
-
return wrap
|
321
|
+
return _fragment(func, run_every=run_every)
|
streamlit/runtime/runtime.py
CHANGED
@@ -40,7 +40,6 @@ from streamlit.runtime.forward_msg_cache import (
|
|
40
40
|
create_reference_msg,
|
41
41
|
populate_hash_if_needed,
|
42
42
|
)
|
43
|
-
from streamlit.runtime.legacy_caching.caching import _mem_caches
|
44
43
|
from streamlit.runtime.media_file_manager import MediaFileManager
|
45
44
|
from streamlit.runtime.media_file_storage import MediaFileStorage
|
46
45
|
from streamlit.runtime.memory_session_storage import MemorySessionStorage
|
@@ -218,7 +217,6 @@ class Runtime:
|
|
218
217
|
self._stats_mgr = StatsManager()
|
219
218
|
self._stats_mgr.register_provider(get_data_cache_stats_provider())
|
220
219
|
self._stats_mgr.register_provider(get_resource_cache_stats_provider())
|
221
|
-
self._stats_mgr.register_provider(_mem_caches)
|
222
220
|
self._stats_mgr.register_provider(self._message_cache)
|
223
221
|
self._stats_mgr.register_provider(self._uploaded_file_mgr)
|
224
222
|
self._stats_mgr.register_provider(SessionStateStatProvider(self._session_mgr))
|
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"files": {
|
3
3
|
"main.css": "./static/css/main.3aaaea00.css",
|
4
|
-
"main.js": "./static/js/main.
|
4
|
+
"main.js": "./static/js/main.e93f99a3.js",
|
5
5
|
"static/js/9336.3e046ad7.chunk.js": "./static/js/9336.3e046ad7.chunk.js",
|
6
6
|
"static/js/9330.2b4c99e0.chunk.js": "./static/js/9330.2b4c99e0.chunk.js",
|
7
7
|
"static/js/2736.4336e2b9.chunk.js": "./static/js/2736.4336e2b9.chunk.js",
|
@@ -151,6 +151,6 @@
|
|
151
151
|
},
|
152
152
|
"entrypoints": [
|
153
153
|
"static/css/main.3aaaea00.css",
|
154
|
-
"static/js/main.
|
154
|
+
"static/js/main.e93f99a3.js"
|
155
155
|
]
|
156
156
|
}
|
streamlit/static/index.html
CHANGED
@@ -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.
|
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.e93f99a3.js"></script><link href="./static/css/main.3aaaea00.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|