streamlit-nightly 1.37.2.dev20240814__py2.py3-none-any.whl → 1.37.2.dev20240815__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/commands/execution_control.py +1 -4
- streamlit/commands/experimental_query_params.py +1 -1
- streamlit/commands/logo.py +1 -1
- streamlit/commands/navigation.py +1 -1
- streamlit/commands/page_config.py +1 -1
- streamlit/components/v1/component_registry.py +1 -1
- streamlit/components/v1/custom_component.py +1 -1
- streamlit/cursor.py +1 -1
- streamlit/dataframe_util.py +91 -0
- streamlit/elements/arrow.py +1 -1
- streamlit/elements/json.py +1 -2
- streamlit/elements/lib/dialog.py +1 -1
- streamlit/elements/lib/mutable_status_container.py +1 -1
- streamlit/elements/lib/policies.py +1 -1
- streamlit/elements/media.py +3 -5
- streamlit/elements/plotly_chart.py +1 -1
- streamlit/elements/vega_charts.py +1 -1
- streamlit/elements/widgets/button.py +7 -4
- streamlit/elements/widgets/button_group.py +1 -1
- streamlit/elements/widgets/chat.py +1 -1
- streamlit/elements/widgets/data_editor.py +1 -1
- streamlit/error_util.py +10 -8
- streamlit/navigation/page.py +1 -1
- streamlit/platform.py +1 -1
- streamlit/runtime/caching/cache_data_api.py +1 -1
- streamlit/runtime/caching/cache_resource_api.py +1 -1
- streamlit/runtime/caching/cached_message_replay.py +1 -1
- streamlit/runtime/context.py +6 -5
- streamlit/runtime/forward_msg_queue.py +18 -1
- streamlit/runtime/fragment.py +7 -5
- streamlit/runtime/media_file_manager.py +3 -1
- streamlit/runtime/metrics_util.py +2 -7
- streamlit/runtime/scriptrunner/__init__.py +7 -4
- streamlit/runtime/scriptrunner/exec_code.py +6 -3
- streamlit/runtime/scriptrunner/script_runner.py +10 -9
- streamlit/runtime/scriptrunner_utils/__init__.py +19 -0
- streamlit/runtime/{scriptrunner → scriptrunner_utils}/exceptions.py +1 -1
- streamlit/runtime/{scriptrunner → scriptrunner_utils}/script_requests.py +61 -6
- streamlit/runtime/{scriptrunner → scriptrunner_utils}/script_run_context.py +1 -1
- streamlit/runtime/state/__init__.py +0 -2
- streamlit/runtime/state/common.py +1 -1
- streamlit/runtime/state/query_params.py +1 -6
- streamlit/runtime/state/session_state.py +1 -5
- streamlit/runtime/state/session_state_proxy.py +3 -1
- streamlit/runtime/state/widgets.py +0 -59
- streamlit/static/asset-manifest.json +17 -17
- streamlit/static/index.html +1 -1
- streamlit/static/static/js/{1168.2a7e18da.chunk.js → 1168.2a9806f0.chunk.js} +1 -1
- streamlit/static/static/js/{1451.3d44ca81.chunk.js → 1451.d93e956f.chunk.js} +1 -1
- streamlit/static/static/js/{178.7bea8c5d.chunk.js → 178.ddebe26b.chunk.js} +1 -1
- streamlit/static/static/js/2469.6217c5c3.chunk.js +1 -0
- streamlit/static/static/js/{2634.1249dc7a.chunk.js → 2634.4e2535ee.chunk.js} +1 -1
- streamlit/static/static/js/{2736.dcbc9141.chunk.js → 2736.3d50ec7f.chunk.js} +1 -1
- streamlit/static/static/js/{3301.45709e64.chunk.js → 3301.7379a9fd.chunk.js} +5 -5
- streamlit/static/static/js/4113.786b0142.chunk.js +1 -0
- streamlit/static/static/js/4500.d884c792.chunk.js +1 -0
- streamlit/static/static/js/6853.a1c4fa00.chunk.js +1 -0
- streamlit/static/static/js/{7602.2331daf7.chunk.js → 7602.33571c14.chunk.js} +1 -1
- streamlit/static/static/js/7805.ba32ae70.chunk.js +1 -0
- streamlit/static/static/js/8148.b905db99.chunk.js +1 -0
- streamlit/static/static/js/8427.b1a68937.chunk.js +1 -0
- streamlit/static/static/js/{9330.2b4c99e0.chunk.js → 9330.32e8a53a.chunk.js} +1 -1
- streamlit/static/static/js/main.90c4efd0.js +28 -0
- streamlit/testing/v1/local_script_runner.py +1 -1
- streamlit/user_info.py +4 -2
- streamlit/web/server/stats_request_handler.py +1 -3
- streamlit/web/server/websocket_headers.py +1 -1
- {streamlit_nightly-1.37.2.dev20240814.dist-info → streamlit_nightly-1.37.2.dev20240815.dist-info}/METADATA +1 -1
- {streamlit_nightly-1.37.2.dev20240814.dist-info → streamlit_nightly-1.37.2.dev20240815.dist-info}/RECORD +74 -73
- streamlit/static/static/js/2469.4bb197dd.chunk.js +0 -1
- streamlit/static/static/js/4113.ca4d2d7b.chunk.js +0 -1
- streamlit/static/static/js/4500.c007e274.chunk.js +0 -1
- streamlit/static/static/js/6853.5d19f25b.chunk.js +0 -1
- streamlit/static/static/js/7805.f7c8d475.chunk.js +0 -1
- streamlit/static/static/js/8148.7805e73f.chunk.js +0 -1
- streamlit/static/static/js/8427.69ce2c45.chunk.js +0 -1
- streamlit/static/static/js/main.b519dd78.js +0 -28
- /streamlit/static/static/js/{main.b519dd78.js.LICENSE.txt → main.90c4efd0.js.LICENSE.txt} +0 -0
- {streamlit_nightly-1.37.2.dev20240814.data → streamlit_nightly-1.37.2.dev20240815.data}/scripts/streamlit.cmd +0 -0
- {streamlit_nightly-1.37.2.dev20240814.dist-info → streamlit_nightly-1.37.2.dev20240815.dist-info}/WHEEL +0 -0
- {streamlit_nightly-1.37.2.dev20240814.dist-info → streamlit_nightly-1.37.2.dev20240815.dist-info}/entry_points.txt +0 -0
- {streamlit_nightly-1.37.2.dev20240814.dist-info → streamlit_nightly-1.37.2.dev20240815.dist-info}/top_level.txt +0 -0
@@ -16,12 +16,11 @@ from __future__ import annotations
|
|
16
16
|
|
17
17
|
import os
|
18
18
|
from itertools import dropwhile
|
19
|
-
from typing import
|
19
|
+
from typing import Literal, NoReturn
|
20
20
|
|
21
21
|
import streamlit as st
|
22
22
|
from streamlit.errors import NoSessionContext, StreamlitAPIException
|
23
23
|
from streamlit.file_util import get_main_script_directory, normalize_path_join
|
24
|
-
from streamlit.logger import get_logger
|
25
24
|
from streamlit.navigation.page import StreamlitPage
|
26
25
|
from streamlit.runtime.metrics_util import gather_metrics
|
27
26
|
from streamlit.runtime.scriptrunner import (
|
@@ -30,8 +29,6 @@ from streamlit.runtime.scriptrunner import (
|
|
30
29
|
get_script_run_ctx,
|
31
30
|
)
|
32
31
|
|
33
|
-
_LOGGER: Final = get_logger(__name__)
|
34
|
-
|
35
32
|
|
36
33
|
@gather_metrics("stop")
|
37
34
|
def stop() -> NoReturn: # type: ignore[misc]
|
@@ -26,7 +26,7 @@ from streamlit.constants import (
|
|
26
26
|
from streamlit.errors import StreamlitAPIException
|
27
27
|
from streamlit.proto.ForwardMsg_pb2 import ForwardMsg
|
28
28
|
from streamlit.runtime.metrics_util import gather_metrics
|
29
|
-
from streamlit.runtime.
|
29
|
+
from streamlit.runtime.scriptrunner_utils.script_run_context import get_script_run_ctx
|
30
30
|
|
31
31
|
|
32
32
|
@gather_metrics("experimental_get_query_params")
|
streamlit/commands/logo.py
CHANGED
@@ -21,7 +21,7 @@ from streamlit.elements.image import AtomicImage, WidthBehaviour, image_to_url
|
|
21
21
|
from streamlit.errors import StreamlitAPIException
|
22
22
|
from streamlit.proto.ForwardMsg_pb2 import ForwardMsg
|
23
23
|
from streamlit.runtime.metrics_util import gather_metrics
|
24
|
-
from streamlit.runtime.
|
24
|
+
from streamlit.runtime.scriptrunner_utils.script_run_context import get_script_run_ctx
|
25
25
|
|
26
26
|
|
27
27
|
def _invalid_logo_text(field_name: str):
|
streamlit/commands/navigation.py
CHANGED
@@ -23,7 +23,7 @@ from streamlit.errors import StreamlitAPIException
|
|
23
23
|
from streamlit.proto.ForwardMsg_pb2 import ForwardMsg
|
24
24
|
from streamlit.proto.Navigation_pb2 import Navigation as NavigationProto
|
25
25
|
from streamlit.runtime.metrics_util import gather_metrics
|
26
|
-
from streamlit.runtime.
|
26
|
+
from streamlit.runtime.scriptrunner_utils.script_run_context import (
|
27
27
|
ScriptRunContext,
|
28
28
|
get_script_run_ctx,
|
29
29
|
)
|
@@ -25,7 +25,7 @@ from streamlit.errors import StreamlitAPIException
|
|
25
25
|
from streamlit.proto.ForwardMsg_pb2 import ForwardMsg as ForwardProto
|
26
26
|
from streamlit.proto.PageConfig_pb2 import PageConfig as PageConfigProto
|
27
27
|
from streamlit.runtime.metrics_util import gather_metrics
|
28
|
-
from streamlit.runtime.
|
28
|
+
from streamlit.runtime.scriptrunner_utils.script_run_context import get_script_run_ctx
|
29
29
|
from streamlit.string_util import is_emoji, validate_material_icon
|
30
30
|
from streamlit.url_util import is_url
|
31
31
|
from streamlit.util import lower_clean_dict_keys
|
@@ -20,7 +20,7 @@ from typing import TYPE_CHECKING
|
|
20
20
|
|
21
21
|
from streamlit.components.v1.custom_component import CustomComponent
|
22
22
|
from streamlit.runtime import get_instance
|
23
|
-
from streamlit.runtime.
|
23
|
+
from streamlit.runtime.scriptrunner_utils.script_run_context import get_script_run_ctx
|
24
24
|
|
25
25
|
if TYPE_CHECKING:
|
26
26
|
from types import FrameType
|
@@ -27,7 +27,7 @@ from streamlit.proto.Components_pb2 import ArrowTable as ArrowTableProto
|
|
27
27
|
from streamlit.proto.Components_pb2 import SpecialArg
|
28
28
|
from streamlit.proto.Element_pb2 import Element
|
29
29
|
from streamlit.runtime.metrics_util import gather_metrics
|
30
|
-
from streamlit.runtime.
|
30
|
+
from streamlit.runtime.scriptrunner_utils.script_run_context import get_script_run_ctx
|
31
31
|
from streamlit.runtime.state import NoValue, register_widget
|
32
32
|
from streamlit.runtime.state.common import compute_widget_id
|
33
33
|
from streamlit.type_util import is_bytes_like, to_bytes
|
streamlit/cursor.py
CHANGED
@@ -17,7 +17,7 @@ from __future__ import annotations
|
|
17
17
|
from typing import Any
|
18
18
|
|
19
19
|
from streamlit import util
|
20
|
-
from streamlit.runtime.
|
20
|
+
from streamlit.runtime.scriptrunner_utils.script_run_context import get_script_run_ctx
|
21
21
|
|
22
22
|
|
23
23
|
def make_delta_path(
|
streamlit/dataframe_util.py
CHANGED
@@ -33,9 +33,11 @@ from typing import (
|
|
33
33
|
Iterable,
|
34
34
|
List,
|
35
35
|
Protocol,
|
36
|
+
Sequence,
|
36
37
|
TypeVar,
|
37
38
|
Union,
|
38
39
|
cast,
|
40
|
+
runtime_checkable,
|
39
41
|
)
|
40
42
|
|
41
43
|
from typing_extensions import TypeAlias, TypeGuard
|
@@ -87,6 +89,7 @@ _DASK_SERIES: Final = "dask.dataframe.core.Series"
|
|
87
89
|
_DASK_INDEX: Final = "dask.dataframe.core.Index"
|
88
90
|
_RAY_MATERIALIZED_DATASET: Final = "ray.data.dataset.MaterializedDataset"
|
89
91
|
_RAY_DATASET: Final = "ray.data.dataset.Dataset"
|
92
|
+
_DUCKDB_RELATION: Final = "duckdb.duckdb.DuckDBPyRelation"
|
90
93
|
|
91
94
|
V_co = TypeVar(
|
92
95
|
"V_co",
|
@@ -94,6 +97,39 @@ V_co = TypeVar(
|
|
94
97
|
)
|
95
98
|
|
96
99
|
|
100
|
+
@runtime_checkable
|
101
|
+
class DBAPICursor(Protocol):
|
102
|
+
"""Protocol for DBAPI 2.0 Cursor objects (PEP 249).
|
103
|
+
|
104
|
+
This is a simplified version of the DBAPI Cursor protocol
|
105
|
+
that only contains the methods that are relevant or used for
|
106
|
+
our DB API Integration.
|
107
|
+
|
108
|
+
Specification: https://peps.python.org/pep-0249/
|
109
|
+
Inspired by: https://github.com/python/typeshed/blob/main/stdlib/_typeshed/dbapi.pyi
|
110
|
+
"""
|
111
|
+
|
112
|
+
@property
|
113
|
+
def description(
|
114
|
+
self,
|
115
|
+
) -> (
|
116
|
+
Sequence[
|
117
|
+
tuple[
|
118
|
+
str,
|
119
|
+
Any | None,
|
120
|
+
int | None,
|
121
|
+
int | None,
|
122
|
+
int | None,
|
123
|
+
int | None,
|
124
|
+
bool | None,
|
125
|
+
]
|
126
|
+
]
|
127
|
+
| None
|
128
|
+
): ...
|
129
|
+
def fetchmany(self, size: int = ..., /) -> Sequence[Sequence[Any]]: ...
|
130
|
+
def fetchall(self) -> Sequence[Sequence[Any]]: ...
|
131
|
+
|
132
|
+
|
97
133
|
class DataFrameGenericAlias(Protocol[V_co]):
|
98
134
|
"""Technically not a GenericAlias, but serves the same purpose in
|
99
135
|
OptionSequence below, in that it is a type which admits DataFrame,
|
@@ -125,6 +161,7 @@ Data: TypeAlias = Union[
|
|
125
161
|
"np.ndarray[Any, np.dtype[Any]]",
|
126
162
|
Iterable[Any],
|
127
163
|
Dict[Any, Any],
|
164
|
+
DBAPICursor,
|
128
165
|
None,
|
129
166
|
]
|
130
167
|
|
@@ -163,6 +200,8 @@ class DataFormat(Enum):
|
|
163
200
|
COLUMN_VALUE_MAPPING = auto() # {column: List[values]}
|
164
201
|
COLUMN_SERIES_MAPPING = auto() # {column: Series(values)}
|
165
202
|
KEY_VALUE_DICT = auto() # {index: value}
|
203
|
+
DBAPI_CURSOR = auto() # DBAPI Cursor (PEP 249)
|
204
|
+
DUCKDB_RELATION = auto() # DuckDB Relation
|
166
205
|
|
167
206
|
|
168
207
|
def is_dataframe_like(obj: object) -> bool:
|
@@ -200,6 +239,7 @@ def is_dataframe_like(obj: object) -> bool:
|
|
200
239
|
DataFormat.DASK_OBJECT,
|
201
240
|
DataFormat.RAY_DATASET,
|
202
241
|
DataFormat.COLUMN_SERIES_MAPPING,
|
242
|
+
DataFormat.DBAPI_CURSOR,
|
203
243
|
]
|
204
244
|
|
205
245
|
|
@@ -215,6 +255,8 @@ def is_unevaluated_data_object(obj: object) -> bool:
|
|
215
255
|
- Ray Dataset
|
216
256
|
- Polars LazyFrame
|
217
257
|
- Generator functions
|
258
|
+
- DB API 2.0 Cursor (PEP 249)
|
259
|
+
- DuckDB Relation (Relational API)
|
218
260
|
|
219
261
|
Unevaluated means that the data is not yet in the local memory.
|
220
262
|
Unevaluated data objects are treated differently from other data objects by only
|
@@ -228,6 +270,8 @@ def is_unevaluated_data_object(obj: object) -> bool:
|
|
228
270
|
or is_ray_dataset(obj)
|
229
271
|
or is_polars_lazyframe(obj)
|
230
272
|
or is_dask_object(obj)
|
273
|
+
or is_duckdb_relation(obj)
|
274
|
+
or is_dbapi_cursor(obj)
|
231
275
|
or inspect.isgeneratorfunction(obj)
|
232
276
|
)
|
233
277
|
|
@@ -319,6 +363,23 @@ def is_pandas_styler(obj: object) -> TypeGuard[Styler]:
|
|
319
363
|
return is_type(obj, _PANDAS_STYLER_TYPE_STR)
|
320
364
|
|
321
365
|
|
366
|
+
def is_dbapi_cursor(obj: object) -> TypeGuard[DBAPICursor]:
|
367
|
+
"""True if obj looks like a DB API 2.0 Cursor.
|
368
|
+
|
369
|
+
https://peps.python.org/pep-0249/
|
370
|
+
"""
|
371
|
+
return isinstance(obj, DBAPICursor)
|
372
|
+
|
373
|
+
|
374
|
+
def is_duckdb_relation(obj: object) -> bool:
|
375
|
+
"""True if obj is a DuckDB relation.
|
376
|
+
|
377
|
+
https://duckdb.org/docs/api/python/relational_api
|
378
|
+
"""
|
379
|
+
|
380
|
+
return is_type(obj, _DUCKDB_RELATION)
|
381
|
+
|
382
|
+
|
322
383
|
def _is_list_of_scalars(data: Iterable[Any]) -> bool:
|
323
384
|
"""Check if the list only contains scalar values."""
|
324
385
|
from pandas.api.types import infer_dtype
|
@@ -533,6 +594,29 @@ def convert_anything_to_pandas_df(
|
|
533
594
|
)
|
534
595
|
return cast(pd.DataFrame, data)
|
535
596
|
|
597
|
+
if is_duckdb_relation(data):
|
598
|
+
data = data.limit(max_unevaluated_rows).df()
|
599
|
+
if data.shape[0] == max_unevaluated_rows:
|
600
|
+
_show_data_information(
|
601
|
+
f"⚠️ Showing only {string_util.simplify_number(max_unevaluated_rows)} "
|
602
|
+
"rows. Call `df()` on the relation to show more."
|
603
|
+
)
|
604
|
+
return data
|
605
|
+
|
606
|
+
if is_dbapi_cursor(data):
|
607
|
+
# Based on the specification, the first item in the description is the
|
608
|
+
# column name (if available)
|
609
|
+
columns = (
|
610
|
+
[d[0] if d else "" for d in data.description] if data.description else None
|
611
|
+
)
|
612
|
+
data = pd.DataFrame(data.fetchmany(max_unevaluated_rows), columns=columns)
|
613
|
+
if data.shape[0] == max_unevaluated_rows:
|
614
|
+
_show_data_information(
|
615
|
+
f"⚠️ Showing only {string_util.simplify_number(max_unevaluated_rows)} "
|
616
|
+
"rows. Call `fetchall()` on the Cursor to show more."
|
617
|
+
)
|
618
|
+
return data
|
619
|
+
|
536
620
|
if is_snowpark_row_list(data):
|
537
621
|
return pd.DataFrame([row.as_dict() for row in data])
|
538
622
|
|
@@ -891,6 +975,7 @@ def is_colum_type_arrow_incompatible(column: Series[Any] | Index) -> bool:
|
|
891
975
|
"period[ns]",
|
892
976
|
"period[U]",
|
893
977
|
"period[us]",
|
978
|
+
"geometry",
|
894
979
|
}:
|
895
980
|
return True
|
896
981
|
|
@@ -1044,6 +1129,10 @@ def determine_data_format(input_data: Any) -> DataFormat:
|
|
1044
1129
|
return DataFormat.DASK_OBJECT
|
1045
1130
|
elif is_snowpark_data_object(input_data) or is_snowpark_row_list(input_data):
|
1046
1131
|
return DataFormat.SNOWPARK_OBJECT
|
1132
|
+
elif is_duckdb_relation(input_data):
|
1133
|
+
return DataFormat.DUCKDB_RELATION
|
1134
|
+
elif is_dbapi_cursor(input_data):
|
1135
|
+
return DataFormat.DBAPI_CURSOR
|
1047
1136
|
elif (
|
1048
1137
|
isinstance(
|
1049
1138
|
input_data,
|
@@ -1164,6 +1253,8 @@ def convert_pandas_df_to_data_format(
|
|
1164
1253
|
DataFormat.SNOWPANDAS_OBJECT,
|
1165
1254
|
DataFormat.DASK_OBJECT,
|
1166
1255
|
DataFormat.RAY_DATASET,
|
1256
|
+
DataFormat.DBAPI_CURSOR,
|
1257
|
+
DataFormat.DUCKDB_RELATION,
|
1167
1258
|
]:
|
1168
1259
|
return df
|
1169
1260
|
elif data_format == DataFormat.NUMPY_LIST:
|
streamlit/elements/arrow.py
CHANGED
@@ -48,7 +48,7 @@ from streamlit.errors import StreamlitAPIException
|
|
48
48
|
from streamlit.proto.Arrow_pb2 import Arrow as ArrowProto
|
49
49
|
from streamlit.proto.ForwardMsg_pb2 import ForwardMsg
|
50
50
|
from streamlit.runtime.metrics_util import gather_metrics
|
51
|
-
from streamlit.runtime.
|
51
|
+
from streamlit.runtime.scriptrunner_utils.script_run_context import (
|
52
52
|
enqueue_message,
|
53
53
|
get_script_run_ctx,
|
54
54
|
)
|
streamlit/elements/json.py
CHANGED
@@ -79,7 +79,6 @@ class JsonMixin:
|
|
79
79
|
height: 385px
|
80
80
|
|
81
81
|
"""
|
82
|
-
import streamlit as st
|
83
82
|
|
84
83
|
if is_custom_dict(body):
|
85
84
|
body = body.to_dict()
|
@@ -98,7 +97,7 @@ class JsonMixin:
|
|
98
97
|
# Serialize body to string and try to interpret sets as lists
|
99
98
|
body = json.dumps(body, default=_ensure_serialization)
|
100
99
|
except TypeError as err:
|
101
|
-
|
100
|
+
self.dg.warning(
|
102
101
|
"Warning: this data structure was not fully serializable as "
|
103
102
|
f"JSON due to one or more unexpected keys. (Error was: {err})"
|
104
103
|
)
|
streamlit/elements/lib/dialog.py
CHANGED
@@ -23,7 +23,7 @@ from streamlit.delta_generator import DeltaGenerator
|
|
23
23
|
from streamlit.errors import StreamlitAPIException
|
24
24
|
from streamlit.proto.Block_pb2 import Block as BlockProto
|
25
25
|
from streamlit.proto.ForwardMsg_pb2 import ForwardMsg
|
26
|
-
from streamlit.runtime.
|
26
|
+
from streamlit.runtime.scriptrunner_utils.script_run_context import (
|
27
27
|
enqueue_message,
|
28
28
|
get_script_run_ctx,
|
29
29
|
)
|
@@ -23,7 +23,7 @@ from streamlit.delta_generator import DeltaGenerator
|
|
23
23
|
from streamlit.errors import StreamlitAPIException
|
24
24
|
from streamlit.proto.Block_pb2 import Block as BlockProto
|
25
25
|
from streamlit.proto.ForwardMsg_pb2 import ForwardMsg
|
26
|
-
from streamlit.runtime.
|
26
|
+
from streamlit.runtime.scriptrunner_utils.script_run_context import enqueue_message
|
27
27
|
|
28
28
|
if TYPE_CHECKING:
|
29
29
|
from types import TracebackType
|
@@ -19,7 +19,7 @@ from typing import TYPE_CHECKING, Any, Final, Sequence
|
|
19
19
|
from streamlit import config, errors, logger, runtime
|
20
20
|
from streamlit.elements.form_utils import is_in_form
|
21
21
|
from streamlit.errors import StreamlitAPIException, StreamlitAPIWarning
|
22
|
-
from streamlit.runtime.
|
22
|
+
from streamlit.runtime.scriptrunner_utils.script_run_context import get_script_run_ctx
|
23
23
|
from streamlit.runtime.state import WidgetCallback, get_session_state
|
24
24
|
|
25
25
|
if TYPE_CHECKING:
|
streamlit/elements/media.py
CHANGED
@@ -22,7 +22,6 @@ from typing import TYPE_CHECKING, Dict, Final, Union, cast
|
|
22
22
|
|
23
23
|
from typing_extensions import TypeAlias
|
24
24
|
|
25
|
-
import streamlit as st
|
26
25
|
from streamlit import runtime, type_util, url_util
|
27
26
|
from streamlit.elements.lib.subtitle_utils import process_subtitle_data
|
28
27
|
from streamlit.errors import StreamlitAPIException
|
@@ -30,7 +29,7 @@ from streamlit.proto.Audio_pb2 import Audio as AudioProto
|
|
30
29
|
from streamlit.proto.Video_pb2 import Video as VideoProto
|
31
30
|
from streamlit.runtime import caching
|
32
31
|
from streamlit.runtime.metrics_util import gather_metrics
|
33
|
-
from streamlit.runtime.
|
32
|
+
from streamlit.runtime.scriptrunner_utils.script_run_context import get_script_run_ctx
|
34
33
|
from streamlit.runtime.state.common import compute_widget_id
|
35
34
|
from streamlit.time_util import time_to_seconds
|
36
35
|
from streamlit.type_util import NumpyShape
|
@@ -169,7 +168,6 @@ class MediaMixin:
|
|
169
168
|
start_time, end_time = _parse_start_time_end_time(start_time, end_time)
|
170
169
|
|
171
170
|
audio_proto = AudioProto()
|
172
|
-
coordinates = self.dg._get_delta_path_str()
|
173
171
|
|
174
172
|
is_data_numpy_array = type_util.is_type(data, "numpy.ndarray")
|
175
173
|
|
@@ -178,11 +176,11 @@ class MediaMixin:
|
|
178
176
|
"`sample_rate` must be specified when `data` is a numpy array."
|
179
177
|
)
|
180
178
|
if not is_data_numpy_array and sample_rate is not None:
|
181
|
-
|
179
|
+
self.dg.warning(
|
182
180
|
"Warning: `sample_rate` will be ignored since data is not a numpy "
|
183
181
|
"array."
|
184
182
|
)
|
185
|
-
|
183
|
+
coordinates = self.dg._get_delta_path_str()
|
186
184
|
marshall_audio(
|
187
185
|
coordinates,
|
188
186
|
audio_proto,
|
@@ -46,7 +46,7 @@ from streamlit.elements.lib.utils import Key, to_key
|
|
46
46
|
from streamlit.errors import StreamlitAPIException
|
47
47
|
from streamlit.proto.PlotlyChart_pb2 import PlotlyChart as PlotlyChartProto
|
48
48
|
from streamlit.runtime.metrics_util import gather_metrics
|
49
|
-
from streamlit.runtime.
|
49
|
+
from streamlit.runtime.scriptrunner_utils.script_run_context import get_script_run_ctx
|
50
50
|
from streamlit.runtime.state import WidgetCallback, register_widget
|
51
51
|
from streamlit.runtime.state.common import compute_widget_id
|
52
52
|
|
@@ -53,7 +53,7 @@ from streamlit.proto.ArrowVegaLiteChart_pb2 import (
|
|
53
53
|
ArrowVegaLiteChart as ArrowVegaLiteChartProto,
|
54
54
|
)
|
55
55
|
from streamlit.runtime.metrics_util import gather_metrics
|
56
|
-
from streamlit.runtime.
|
56
|
+
from streamlit.runtime.scriptrunner_utils.script_run_context import get_script_run_ctx
|
57
57
|
from streamlit.runtime.state import WidgetCallback, register_widget
|
58
58
|
from streamlit.runtime.state.common import compute_widget_id
|
59
59
|
from streamlit.util import HASHLIB_KWARGS
|
@@ -740,10 +740,13 @@ class ButtonMixin:
|
|
740
740
|
page_link_proto.page = page_name
|
741
741
|
break
|
742
742
|
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
743
|
+
if page_link_proto.page_script_hash == "":
|
744
|
+
raise StreamlitAPIException(
|
745
|
+
f"Could not find page: `{page}`. Must be the file path relative to "
|
746
|
+
"the main script, from the directory: "
|
747
|
+
f"`{os.path.basename(main_script_directory)}`. Only the main app "
|
748
|
+
"file and files in the `pages/` directory are supported."
|
749
|
+
)
|
747
750
|
|
748
751
|
return self.dg._enqueue("page_link", page_link_proto)
|
749
752
|
|
@@ -43,7 +43,7 @@ from streamlit.elements.widgets.multiselect import MultiSelectSerde
|
|
43
43
|
from streamlit.errors import StreamlitAPIException
|
44
44
|
from streamlit.proto.ButtonGroup_pb2 import ButtonGroup as ButtonGroupProto
|
45
45
|
from streamlit.runtime.metrics_util import gather_metrics
|
46
|
-
from streamlit.runtime.
|
46
|
+
from streamlit.runtime.scriptrunner_utils.script_run_context import get_script_run_ctx
|
47
47
|
from streamlit.runtime.state import register_widget
|
48
48
|
from streamlit.runtime.state.common import (
|
49
49
|
RegisterWidgetResult,
|
@@ -30,7 +30,7 @@ from streamlit.proto.ChatInput_pb2 import ChatInput as ChatInputProto
|
|
30
30
|
from streamlit.proto.Common_pb2 import StringTriggerValue as StringTriggerValueProto
|
31
31
|
from streamlit.proto.RootContainer_pb2 import RootContainer
|
32
32
|
from streamlit.runtime.metrics_util import gather_metrics
|
33
|
-
from streamlit.runtime.
|
33
|
+
from streamlit.runtime.scriptrunner_utils.script_run_context import get_script_run_ctx
|
34
34
|
from streamlit.runtime.state import (
|
35
35
|
WidgetArgs,
|
36
36
|
WidgetCallback,
|
@@ -59,7 +59,7 @@ from streamlit.elements.lib.utils import Key, to_key
|
|
59
59
|
from streamlit.errors import StreamlitAPIException
|
60
60
|
from streamlit.proto.Arrow_pb2 import Arrow as ArrowProto
|
61
61
|
from streamlit.runtime.metrics_util import gather_metrics
|
62
|
-
from streamlit.runtime.
|
62
|
+
from streamlit.runtime.scriptrunner_utils.script_run_context import get_script_run_ctx
|
63
63
|
from streamlit.runtime.state import (
|
64
64
|
WidgetArgs,
|
65
65
|
WidgetCallback,
|
streamlit/error_util.py
CHANGED
@@ -16,7 +16,7 @@ from __future__ import annotations
|
|
16
16
|
|
17
17
|
from typing import Final
|
18
18
|
|
19
|
-
import streamlit
|
19
|
+
import streamlit
|
20
20
|
from streamlit import config
|
21
21
|
from streamlit.errors import UncaughtAppException
|
22
22
|
from streamlit.logger import get_logger
|
@@ -52,9 +52,6 @@ def _print_rich_exception(e: BaseException) -> None:
|
|
52
52
|
tab_size=8,
|
53
53
|
)
|
54
54
|
|
55
|
-
# Import script_runner here to prevent circular import
|
56
|
-
import streamlit.runtime.scriptrunner.script_runner as script_runner
|
57
|
-
|
58
55
|
# Print exception via rich
|
59
56
|
console.print(
|
60
57
|
rich_traceback.Traceback.from_exception(
|
@@ -66,11 +63,16 @@ def _print_rich_exception(e: BaseException) -> None:
|
|
66
63
|
max_frames=100,
|
67
64
|
word_wrap=False,
|
68
65
|
extra_lines=3,
|
69
|
-
suppress=[
|
66
|
+
suppress=[streamlit],
|
70
67
|
)
|
71
68
|
)
|
72
69
|
|
73
70
|
|
71
|
+
def _show_exception(ex: BaseException) -> None:
|
72
|
+
"""Show the exception on the frontend."""
|
73
|
+
streamlit.exception(ex)
|
74
|
+
|
75
|
+
|
74
76
|
def handle_uncaught_app_exception(ex: BaseException) -> None:
|
75
77
|
"""Handle an exception that originated from a user app.
|
76
78
|
|
@@ -78,6 +80,7 @@ def handle_uncaught_app_exception(ex: BaseException) -> None:
|
|
78
80
|
if the user has disabled client error details, we display a generic
|
79
81
|
warning in the frontend instead.
|
80
82
|
"""
|
83
|
+
|
81
84
|
error_logged = False
|
82
85
|
|
83
86
|
if config.get_option("logger.enableRich"):
|
@@ -95,12 +98,11 @@ def handle_uncaught_app_exception(ex: BaseException) -> None:
|
|
95
98
|
|
96
99
|
if config.get_option("client.showErrorDetails"):
|
97
100
|
if not error_logged:
|
98
|
-
# TODO: Clean up the stack trace, so it doesn't include ScriptRunner.
|
99
101
|
_LOGGER.warning("Uncaught app exception", exc_info=ex)
|
100
|
-
|
102
|
+
_show_exception(ex)
|
101
103
|
else:
|
102
104
|
if not error_logged:
|
103
105
|
# Use LOGGER.error, rather than LOGGER.debug, since we don't
|
104
106
|
# show debug logs by default.
|
105
107
|
_LOGGER.error("Uncaught app exception", exc_info=ex)
|
106
|
-
|
108
|
+
_show_exception(UncaughtAppException(ex))
|
streamlit/navigation/page.py
CHANGED
@@ -20,7 +20,7 @@ from typing import Callable
|
|
20
20
|
|
21
21
|
from streamlit.errors import StreamlitAPIException
|
22
22
|
from streamlit.runtime.metrics_util import gather_metrics
|
23
|
-
from streamlit.runtime.
|
23
|
+
from streamlit.runtime.scriptrunner_utils.script_run_context import get_script_run_ctx
|
24
24
|
from streamlit.source_util import page_icon_and_name
|
25
25
|
from streamlit.string_util import validate_icon_or_emoji
|
26
26
|
from streamlit.util import calc_md5
|
streamlit/platform.py
CHANGED
@@ -17,7 +17,7 @@
|
|
17
17
|
from __future__ import annotations
|
18
18
|
|
19
19
|
from streamlit.proto.ForwardMsg_pb2 import ForwardMsg
|
20
|
-
from streamlit.runtime.
|
20
|
+
from streamlit.runtime.scriptrunner_utils.script_run_context import get_script_run_ctx
|
21
21
|
|
22
22
|
|
23
23
|
def post_parent_message(message: str) -> None:
|
@@ -66,7 +66,7 @@ from streamlit.runtime.caching.storage.dummy_cache_storage import (
|
|
66
66
|
MemoryCacheStorageManager,
|
67
67
|
)
|
68
68
|
from streamlit.runtime.metrics_util import gather_metrics
|
69
|
-
from streamlit.runtime.
|
69
|
+
from streamlit.runtime.scriptrunner_utils.script_run_context import get_script_run_ctx
|
70
70
|
from streamlit.runtime.stats import CacheStat, CacheStatsProvider, group_stats
|
71
71
|
from streamlit.time_util import time_to_seconds
|
72
72
|
|
@@ -43,7 +43,7 @@ from streamlit.runtime.caching.cached_message_replay import (
|
|
43
43
|
show_widget_replay_deprecation,
|
44
44
|
)
|
45
45
|
from streamlit.runtime.metrics_util import gather_metrics
|
46
|
-
from streamlit.runtime.
|
46
|
+
from streamlit.runtime.scriptrunner_utils.script_run_context import get_script_run_ctx
|
47
47
|
from streamlit.runtime.stats import CacheStat, CacheStatsProvider, group_stats
|
48
48
|
from streamlit.time_util import time_to_seconds
|
49
49
|
|
@@ -25,7 +25,7 @@ from streamlit import runtime, util
|
|
25
25
|
from streamlit.deprecation_util import show_deprecation_warning
|
26
26
|
from streamlit.runtime.caching.cache_errors import CacheReplayClosureError
|
27
27
|
from streamlit.runtime.caching.hashing import update_hash
|
28
|
-
from streamlit.runtime.
|
28
|
+
from streamlit.runtime.scriptrunner_utils.script_run_context import (
|
29
29
|
ScriptRunContext,
|
30
30
|
get_script_run_ctx,
|
31
31
|
)
|
streamlit/runtime/context.py
CHANGED
@@ -20,8 +20,7 @@ from typing import TYPE_CHECKING, Any, Iterable, Iterator, Mapping, cast
|
|
20
20
|
|
21
21
|
from streamlit import runtime
|
22
22
|
from streamlit.runtime.metrics_util import gather_metrics
|
23
|
-
from streamlit.runtime.
|
24
|
-
from streamlit.type_util import is_type
|
23
|
+
from streamlit.runtime.scriptrunner_utils.script_run_context import get_script_run_ctx
|
25
24
|
|
26
25
|
if TYPE_CHECKING:
|
27
26
|
from http.cookies import Morsel
|
@@ -42,11 +41,13 @@ def _get_request() -> HTTPServerRequest | None:
|
|
42
41
|
# We return websocket request only if session_client is an instance of
|
43
42
|
# BrowserWebSocketHandler (which is True for the Streamlit open-source
|
44
43
|
# implementation). For any other implementation, we return None.
|
45
|
-
|
46
|
-
|
47
|
-
"
|
44
|
+
# We are not using `type_util.is_type` here to avoid circular import.
|
45
|
+
if (
|
46
|
+
f"{type(session_client).__module__}.{type(session_client).__qualname__}"
|
47
|
+
!= "streamlit.web.server.browser_websocket_handler.BrowserWebSocketHandler"
|
48
48
|
):
|
49
49
|
return None
|
50
|
+
|
50
51
|
return cast("RequestHandler", session_client).request
|
51
52
|
|
52
53
|
|
@@ -94,7 +94,7 @@ class ForwardMsgQueue:
|
|
94
94
|
self._queue = []
|
95
95
|
else:
|
96
96
|
self._queue = [
|
97
|
-
msg
|
97
|
+
_update_script_finished_message(msg)
|
98
98
|
for msg in self._queue
|
99
99
|
if msg.WhichOneof("type")
|
100
100
|
in {
|
@@ -166,3 +166,20 @@ def _maybe_compose_deltas(old_delta: Delta, new_delta: Delta) -> Delta | None:
|
|
166
166
|
return new_delta
|
167
167
|
|
168
168
|
return None
|
169
|
+
|
170
|
+
|
171
|
+
def _update_script_finished_message(msg: ForwardMsg) -> ForwardMsg:
|
172
|
+
"""
|
173
|
+
When we are here, the message queue is cleared from non-lifecycle messages
|
174
|
+
before they were flushed to the browser.
|
175
|
+
|
176
|
+
If there were no non-lifecycle messages in the queue, changing the type here
|
177
|
+
should not matter for the frontend anyways, so we optimistically change the
|
178
|
+
`script_finished` message to `FINISHED_EARLY_FOR_RERUN`. This indicates to
|
179
|
+
the frontend that the previous run was interrupted by a new script start.
|
180
|
+
Otherwise, a `FINISHED_SUCCESSFULLY` message might trigger a reset of widget
|
181
|
+
states on the frontend.
|
182
|
+
"""
|
183
|
+
if msg.WhichOneof("type") == "script_finished":
|
184
|
+
msg.script_finished = ForwardMsg.ScriptFinishedStatus.FINISHED_EARLY_FOR_RERUN
|
185
|
+
return msg
|
streamlit/runtime/fragment.py
CHANGED
@@ -30,8 +30,11 @@ from streamlit.error_util import handle_uncaught_app_exception
|
|
30
30
|
from streamlit.errors import FragmentHandledException, FragmentStorageKeyError
|
31
31
|
from streamlit.proto.ForwardMsg_pb2 import ForwardMsg
|
32
32
|
from streamlit.runtime.metrics_util import gather_metrics
|
33
|
-
from streamlit.runtime.
|
34
|
-
|
33
|
+
from streamlit.runtime.scriptrunner_utils.exceptions import (
|
34
|
+
RerunException,
|
35
|
+
StopException,
|
36
|
+
)
|
37
|
+
from streamlit.runtime.scriptrunner_utils.script_run_context import get_script_run_ctx
|
35
38
|
from streamlit.time_util import time_to_seconds
|
36
39
|
|
37
40
|
if TYPE_CHECKING:
|
@@ -160,7 +163,7 @@ def _fragment(
|
|
160
163
|
|
161
164
|
ctx = get_script_run_ctx()
|
162
165
|
if ctx is None:
|
163
|
-
return
|
166
|
+
return None
|
164
167
|
|
165
168
|
cursors_snapshot = deepcopy(ctx.cursors)
|
166
169
|
dg_stack_snapshot = deepcopy(context_dg_stack.get())
|
@@ -265,8 +268,7 @@ def _fragment(
|
|
265
268
|
ctx.current_fragment_id = prev_fragment_id
|
266
269
|
ctx.current_fragment_delta_path = []
|
267
270
|
|
268
|
-
|
269
|
-
ctx.fragment_storage.set(fragment_id, wrapped_fragment)
|
271
|
+
ctx.fragment_storage.set(fragment_id, wrapped_fragment)
|
270
272
|
|
271
273
|
if run_every:
|
272
274
|
msg = ForwardMsg()
|
@@ -28,7 +28,9 @@ _LOGGER: Final = get_logger(__name__)
|
|
28
28
|
|
29
29
|
def _get_session_id() -> str:
|
30
30
|
"""Get the active AppSession's session_id."""
|
31
|
-
from streamlit.runtime.
|
31
|
+
from streamlit.runtime.scriptrunner_utils.script_run_context import (
|
32
|
+
get_script_run_ctx,
|
33
|
+
)
|
32
34
|
|
33
35
|
ctx = get_script_run_ctx()
|
34
36
|
if ctx is None:
|