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.
Files changed (82) hide show
  1. streamlit/commands/execution_control.py +1 -4
  2. streamlit/commands/experimental_query_params.py +1 -1
  3. streamlit/commands/logo.py +1 -1
  4. streamlit/commands/navigation.py +1 -1
  5. streamlit/commands/page_config.py +1 -1
  6. streamlit/components/v1/component_registry.py +1 -1
  7. streamlit/components/v1/custom_component.py +1 -1
  8. streamlit/cursor.py +1 -1
  9. streamlit/dataframe_util.py +91 -0
  10. streamlit/elements/arrow.py +1 -1
  11. streamlit/elements/json.py +1 -2
  12. streamlit/elements/lib/dialog.py +1 -1
  13. streamlit/elements/lib/mutable_status_container.py +1 -1
  14. streamlit/elements/lib/policies.py +1 -1
  15. streamlit/elements/media.py +3 -5
  16. streamlit/elements/plotly_chart.py +1 -1
  17. streamlit/elements/vega_charts.py +1 -1
  18. streamlit/elements/widgets/button.py +7 -4
  19. streamlit/elements/widgets/button_group.py +1 -1
  20. streamlit/elements/widgets/chat.py +1 -1
  21. streamlit/elements/widgets/data_editor.py +1 -1
  22. streamlit/error_util.py +10 -8
  23. streamlit/navigation/page.py +1 -1
  24. streamlit/platform.py +1 -1
  25. streamlit/runtime/caching/cache_data_api.py +1 -1
  26. streamlit/runtime/caching/cache_resource_api.py +1 -1
  27. streamlit/runtime/caching/cached_message_replay.py +1 -1
  28. streamlit/runtime/context.py +6 -5
  29. streamlit/runtime/forward_msg_queue.py +18 -1
  30. streamlit/runtime/fragment.py +7 -5
  31. streamlit/runtime/media_file_manager.py +3 -1
  32. streamlit/runtime/metrics_util.py +2 -7
  33. streamlit/runtime/scriptrunner/__init__.py +7 -4
  34. streamlit/runtime/scriptrunner/exec_code.py +6 -3
  35. streamlit/runtime/scriptrunner/script_runner.py +10 -9
  36. streamlit/runtime/scriptrunner_utils/__init__.py +19 -0
  37. streamlit/runtime/{scriptrunner → scriptrunner_utils}/exceptions.py +1 -1
  38. streamlit/runtime/{scriptrunner → scriptrunner_utils}/script_requests.py +61 -6
  39. streamlit/runtime/{scriptrunner → scriptrunner_utils}/script_run_context.py +1 -1
  40. streamlit/runtime/state/__init__.py +0 -2
  41. streamlit/runtime/state/common.py +1 -1
  42. streamlit/runtime/state/query_params.py +1 -6
  43. streamlit/runtime/state/session_state.py +1 -5
  44. streamlit/runtime/state/session_state_proxy.py +3 -1
  45. streamlit/runtime/state/widgets.py +0 -59
  46. streamlit/static/asset-manifest.json +17 -17
  47. streamlit/static/index.html +1 -1
  48. streamlit/static/static/js/{1168.2a7e18da.chunk.js → 1168.2a9806f0.chunk.js} +1 -1
  49. streamlit/static/static/js/{1451.3d44ca81.chunk.js → 1451.d93e956f.chunk.js} +1 -1
  50. streamlit/static/static/js/{178.7bea8c5d.chunk.js → 178.ddebe26b.chunk.js} +1 -1
  51. streamlit/static/static/js/2469.6217c5c3.chunk.js +1 -0
  52. streamlit/static/static/js/{2634.1249dc7a.chunk.js → 2634.4e2535ee.chunk.js} +1 -1
  53. streamlit/static/static/js/{2736.dcbc9141.chunk.js → 2736.3d50ec7f.chunk.js} +1 -1
  54. streamlit/static/static/js/{3301.45709e64.chunk.js → 3301.7379a9fd.chunk.js} +5 -5
  55. streamlit/static/static/js/4113.786b0142.chunk.js +1 -0
  56. streamlit/static/static/js/4500.d884c792.chunk.js +1 -0
  57. streamlit/static/static/js/6853.a1c4fa00.chunk.js +1 -0
  58. streamlit/static/static/js/{7602.2331daf7.chunk.js → 7602.33571c14.chunk.js} +1 -1
  59. streamlit/static/static/js/7805.ba32ae70.chunk.js +1 -0
  60. streamlit/static/static/js/8148.b905db99.chunk.js +1 -0
  61. streamlit/static/static/js/8427.b1a68937.chunk.js +1 -0
  62. streamlit/static/static/js/{9330.2b4c99e0.chunk.js → 9330.32e8a53a.chunk.js} +1 -1
  63. streamlit/static/static/js/main.90c4efd0.js +28 -0
  64. streamlit/testing/v1/local_script_runner.py +1 -1
  65. streamlit/user_info.py +4 -2
  66. streamlit/web/server/stats_request_handler.py +1 -3
  67. streamlit/web/server/websocket_headers.py +1 -1
  68. {streamlit_nightly-1.37.2.dev20240814.dist-info → streamlit_nightly-1.37.2.dev20240815.dist-info}/METADATA +1 -1
  69. {streamlit_nightly-1.37.2.dev20240814.dist-info → streamlit_nightly-1.37.2.dev20240815.dist-info}/RECORD +74 -73
  70. streamlit/static/static/js/2469.4bb197dd.chunk.js +0 -1
  71. streamlit/static/static/js/4113.ca4d2d7b.chunk.js +0 -1
  72. streamlit/static/static/js/4500.c007e274.chunk.js +0 -1
  73. streamlit/static/static/js/6853.5d19f25b.chunk.js +0 -1
  74. streamlit/static/static/js/7805.f7c8d475.chunk.js +0 -1
  75. streamlit/static/static/js/8148.7805e73f.chunk.js +0 -1
  76. streamlit/static/static/js/8427.69ce2c45.chunk.js +0 -1
  77. streamlit/static/static/js/main.b519dd78.js +0 -28
  78. /streamlit/static/static/js/{main.b519dd78.js.LICENSE.txt → main.90c4efd0.js.LICENSE.txt} +0 -0
  79. {streamlit_nightly-1.37.2.dev20240814.data → streamlit_nightly-1.37.2.dev20240815.data}/scripts/streamlit.cmd +0 -0
  80. {streamlit_nightly-1.37.2.dev20240814.dist-info → streamlit_nightly-1.37.2.dev20240815.dist-info}/WHEEL +0 -0
  81. {streamlit_nightly-1.37.2.dev20240814.dist-info → streamlit_nightly-1.37.2.dev20240815.dist-info}/entry_points.txt +0 -0
  82. {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 Final, Literal, NoReturn
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.scriptrunner import get_script_run_ctx
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")
@@ -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.scriptrunner import get_script_run_ctx
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):
@@ -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.scriptrunner.script_run_context import (
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.scriptrunner import get_script_run_ctx
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.scriptrunner import get_script_run_ctx
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.scriptrunner import get_script_run_ctx
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.scriptrunner import get_script_run_ctx
20
+ from streamlit.runtime.scriptrunner_utils.script_run_context import get_script_run_ctx
21
21
 
22
22
 
23
23
  def make_delta_path(
@@ -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:
@@ -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.scriptrunner.script_run_context import (
51
+ from streamlit.runtime.scriptrunner_utils.script_run_context import (
52
52
  enqueue_message,
53
53
  get_script_run_ctx,
54
54
  )
@@ -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
- st.warning(
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
  )
@@ -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.scriptrunner.script_run_context import (
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.scriptrunner.script_run_context import enqueue_message
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.scriptrunner.script_run_context import get_script_run_ctx
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:
@@ -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.scriptrunner import get_script_run_ctx
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
- st.warning(
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.scriptrunner import get_script_run_ctx
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.scriptrunner import get_script_run_ctx
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
- if page_link_proto.page_script_hash == "":
744
- raise StreamlitAPIException(
745
- f"Could not find page: `{page}`. Must be the file path relative to the main script, from the directory: `{os.path.basename(main_script_directory)}`. Only the main app file and files in the `pages/` directory are supported."
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.scriptrunner import get_script_run_ctx
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.scriptrunner import get_script_run_ctx
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.scriptrunner import get_script_run_ctx
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 as st
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=[script_runner], # Ignore script runner
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
- st.exception(ex)
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
- st.exception(UncaughtAppException(ex))
108
+ _show_exception(UncaughtAppException(ex))
@@ -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.scriptrunner.script_run_context import get_script_run_ctx
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.scriptrunner import get_script_run_ctx
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.scriptrunner.script_run_context import get_script_run_ctx
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.scriptrunner.script_run_context import get_script_run_ctx
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.scriptrunner.script_run_context import (
28
+ from streamlit.runtime.scriptrunner_utils.script_run_context import (
29
29
  ScriptRunContext,
30
30
  get_script_run_ctx,
31
31
  )
@@ -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.scriptrunner import get_script_run_ctx
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
- if not is_type(
46
- session_client,
47
- "streamlit.web.server.browser_websocket_handler.BrowserWebSocketHandler",
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
@@ -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.scriptrunner.exceptions import RerunException, StopException
34
- from streamlit.runtime.scriptrunner.script_run_context import get_script_run_ctx
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
- if not ctx.fragment_storage.contains(fragment_id):
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.scriptrunner import get_script_run_ctx
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: